pa.c (symbolic_expression_p): New function.
authorJeff Law <law@gcc.gnu.org>
Mon, 1 Mar 1993 11:15:59 +0000 (04:15 -0700)
committerJeff Law <law@gcc.gnu.org>
Mon, 1 Mar 1993 11:15:59 +0000 (04:15 -0700)
        * pa.c (symbolic_expression_p): New function.
        (hppa_legitimize_address): Old LEGITIMIZE_ADDRESS moved
        here.  Handle symbol_ref + displacement addresses.
        Use rounding instead of masking off lower bits.
        Avoid creating useless pseudos and strip off CONST in
        (const (...)) expressions to make processing easier.

From-SVN: r3571

gcc/config/pa/pa.c

index 9d7c5c19c70006ee6ae3881ed47bb640cb01f314..e5cf74fefb9ecbc29a53a9d286f7de9c7173f2ce 100644 (file)
@@ -67,6 +67,21 @@ call_operand_address (op, mode)
          || (CONSTANT_P (op) && ! TARGET_LONG_CALLS));
 }
 
+/* Return 1 if X contains a symbolic expression.  We know these 
+   expressions will have one of a few well defined forms, so 
+   we need only check those forms.  */
+int
+symbolic_expression_p (x)
+     register rtx x;
+{
+
+  /* Strip off any HIGH. */ 
+  if (GET_CODE (x) == HIGH)
+    x = XEXP (x, 0);
+
+  return (symbolic_operand (x, VOIDmode));
+}
+
 int
 symbolic_operand (op, mode)
      register rtx op;
@@ -470,6 +485,142 @@ finalize_pic ()
 
 }
 
+/* Try machine-dependent ways of modifying an illegitimate address
+   to be legitimate.  If we find one, return the new, valid address.
+   This macro is used in only one place: `memory_address' in explow.c.
+
+   OLDX is the address as it was before break_out_memory_refs was called.
+   In some cases it is useful to look at this to decide what needs to be done.
+
+   MODE and WIN are passed so that this macro can use
+   GO_IF_LEGITIMATE_ADDRESS.
+
+   It is always safe for this macro to do nothing.  It exists to recognize
+   opportunities to optimize the output. 
+
+   For the PA, transform:
+
+       memory(X + <large int>)
+
+   into:
+
+       if (<large int> & mask) >= 16
+         Y = (<large int> & ~mask) + mask + 1  Round up.
+       else
+         Y = (<large int> & ~mask)             Round down.
+       Z = X + Y
+       memory (Z + (<large int> - Y));
+
+   This is for CSE to find several similar references, and only use one Z. 
+
+   X can either be a SYMBOL_REF or REG, but because combine can not
+   perform a 4->2 combination we do nothing for SYMBOL_REF + D where
+   D will not fit in 14 bits.
+
+   MODE_FLOAT references allow displacements which fit in 5 bits, so use
+   0x1f as the mask.  
+
+   MODE_INT references allow displacements which fit in 14 bits, so use
+   0x3fff as the mask. 
+
+   This relies on the fact that most mode MODE_FLOAT references will use FP
+   registers and most mode MODE_INT references will use integer registers.
+   (In the rare case of an FP register used in an integer MODE, we depend
+   on secondary reloads to clean things up.)
+
+
+   It is also beneficial to handle (plus (mult (X) (Y)) (Z)) in a special
+   manner if Y is 2, 4, or 8.  (allows more shadd insns and shifted indexed
+   adressing modes to be used).
+
+   Put X and Z into registers.  Then put the entire expression into
+   a register.  */
+
+rtx
+hppa_legitimize_address (x, oldx, mode)
+     rtx x, oldx;
+     enum machine_mode mode;
+{
+  
+  rtx orig = x;
+
+  /* Strip off CONST. */
+  if (GET_CODE (x) == CONST)
+    x = XEXP (x, 0);
+
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+         || GET_CODE (XEXP (x, 0)) == REG))
+    {
+      rtx int_part, ptr_reg;
+      int newoffset;
+      int offset = INTVAL (XEXP (x, 1));
+      int mask = GET_MODE_CLASS (mode) == MODE_FLOAT ? 0x1f : 0x3fff;
+
+      /* Choose which way to round the offset.  Round up if we 
+        are >= halfway to the next boundary.  */
+      if ((offset & mask) >= ((mask + 1) / 2))
+       newoffset = (offset & ~ mask) + mask + 1;
+      else
+       newoffset = (offset & ~ mask);
+
+      /* If the newoffset will not fit in 14 bits (ldo), then
+        handling this would take 4 or 5 instructions (2 to load
+        the SYMBOL_REF + 1 or 2 to load the newoffset + 1 to
+        add the new offset and the SYMBOL_REF.)  Combine can
+        not handle 4->2 or 5->2 combinations, so do not create
+        them.  */
+      if (! VAL_14_BITS_P (newoffset)
+         && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
+       {
+         rtx const_part = gen_rtx (CONST, VOIDmode,
+                                   gen_rtx (PLUS, SImode,
+                                            XEXP (x, 0),
+                                            GEN_INT (newoffset)));
+         rtx tmp_reg
+           = force_reg (SImode,
+                        gen_rtx (HIGH, SImode, const_part));
+         ptr_reg
+           = force_reg (SImode,
+                        gen_rtx (LO_SUM, SImode,
+                                 tmp_reg, const_part));
+       }
+      else
+       {
+         if (! VAL_14_BITS_P (newoffset))
+           int_part = force_reg (SImode, GEN_INT (newoffset));
+         else
+           int_part = GEN_INT (newoffset);
+
+         ptr_reg = force_reg (SImode,
+                              gen_rtx (PLUS, SImode,
+                                       force_reg (SImode, XEXP (x, 0)),
+                                       int_part));
+       }
+      return plus_constant (ptr_reg, offset - newoffset);
+    }
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1))))
+    {
+      int val = INTVAL (XEXP (XEXP (x, 0), 1));
+      rtx reg1, reg2;
+      reg1 = force_reg (SImode, force_operand (XEXP (x, 1), 0));
+      reg2 = force_reg (SImode,
+                       force_operand (XEXP (XEXP (x, 0), 0), 0));
+      return force_reg (SImode,
+                       gen_rtx (PLUS, SImode,
+                                gen_rtx (MULT, SImode, reg2,
+                                         GEN_INT (val)),
+                                reg1));
+    }
+  if (flag_pic) 
+    return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
+
+  return orig;
+}
+
 /* For the HPPA, REG and REG+CONST is cost 0
    and addresses involving symbolic constants are cost 2.