lra-constraints.c (get_index_scale, [...]): New functions.
authorRichard Sandiford <rdsandiford@googlemail.com>
Fri, 26 Oct 2012 06:38:23 +0000 (06:38 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Fri, 26 Oct 2012 06:38:23 +0000 (06:38 +0000)
gcc/
* lra-constraints.c (get_index_scale, can_add_disp_p): New functions.
(equiv_address_substitution): Use them.

From-SVN: r192835

gcc/ChangeLog
gcc/lra-constraints.c

index f24eae3..4a93aa6 100644 (file)
@@ -1,5 +1,10 @@
 2012-10-26  Richard Sandiford  <rdsandiford@googlemail.com>
 
+       * lra-constraints.c (get_index_scale, can_add_disp_p): New functions.
+       (equiv_address_substitution): Use them.
+
+2012-10-26  Richard Sandiford  <rdsandiford@googlemail.com>
+
        * lra-constraints.c (valid_address_p): New function, split out from...
        (process_address): ...here.
 
index 13d7a3d..84c9e15 100644 (file)
@@ -756,6 +756,28 @@ extract_address_regs (enum machine_mode mem_mode, addr_space_t as,
     ad->index_loc = ad->index_reg_loc;
 }
 
+/* Return the scale applied to *AD->INDEX_REG_LOC, or 0 if the index is
+   more complicated than that.  */
+static HOST_WIDE_INT
+get_index_scale (struct address *ad)
+{
+  rtx index = *ad->index_loc;
+  if (GET_CODE (index) == MULT
+      && CONST_INT_P (XEXP (index, 1))
+      && ad->index_reg_loc == &XEXP (index, 0))
+    return INTVAL (XEXP (index, 1));
+
+  if (GET_CODE (index) == ASHIFT
+      && CONST_INT_P (XEXP (index, 1))
+      && ad->index_reg_loc == &XEXP (index, 0))
+    return (HOST_WIDE_INT) 1 << INTVAL (XEXP (index, 1));
+
+  if (ad->index_reg_loc == ad->index_loc)
+    return 1;
+
+  return 0;
+}
+
 \f
 
 /* The page contains major code to choose the current insn alternative
@@ -2428,6 +2450,40 @@ base_plus_disp_to_reg (enum machine_mode mode, addr_space_t as,
   return new_reg;
 }
 
+/* Return true if we can add a displacement to address ADDR_LOC,
+   which is described by AD, even if that makes the address invalid.
+   The fix-up code requires any new address to be the sum of the base,
+   index and displacement fields of an AD-like structure.  */
+static bool
+can_add_disp_p (struct address *ad, rtx *addr_loc)
+{
+  /* Automodified addresses have a fixed form.  */
+  if (ad->base_modify_p)
+    return false;
+
+  /* If the address already has a displacement, and is not an UNSPEC,
+     we can simply add the new displacement to it.  */
+  if (ad->disp_loc && GET_CODE (*ad->disp_loc) == UNSPEC)
+    return true;
+
+  /* If the address is entirely a base or index, we can try adding
+     a constant to it.  */
+  if (addr_loc == ad->base_reg_loc || addr_loc == ad->index_loc)
+    return true;
+
+  /* Likewise if the address is entirely a sum of the base and index.  */
+  if (GET_CODE (*addr_loc) == PLUS)
+    {
+      rtx *op0 = &XEXP (*addr_loc, 0);
+      rtx *op1 = &XEXP (*addr_loc, 1);
+      if (op0 == ad->base_reg_loc && op1 == ad->index_loc)
+       return true;
+      if (op1 == ad->base_reg_loc && op0 == ad->index_loc)
+       return true;
+    }
+  return false;
+}
+
 /* Make substitution in address AD in space AS with location ADDR_LOC.
    Update AD and ADDR_LOC if it is necessary.  Return true if a
    substitution was made.  */
@@ -2473,7 +2529,8 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
        }
       else if (GET_CODE (new_base_reg) == PLUS
               && REG_P (XEXP (new_base_reg, 0))
-              && CONST_INT_P (XEXP (new_base_reg, 1)))
+              && CONST_INT_P (XEXP (new_base_reg, 1))
+              && can_add_disp_p (ad, addr_loc))
        {
          disp += INTVAL (XEXP (new_base_reg, 1));
          *ad->base_reg_loc = XEXP (new_base_reg, 0);
@@ -2482,12 +2539,6 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
       if (ad->base_reg_loc2 != NULL)
        *ad->base_reg_loc2 = *ad->base_reg_loc;
     }
-  scale = 1;
-  if (ad->index_loc != NULL && GET_CODE (*ad->index_loc) == MULT)
-    {
-      lra_assert (CONST_INT_P (XEXP (*ad->index_loc, 1)));
-      scale = INTVAL (XEXP (*ad->index_loc, 1));
-    }
   if (index_reg != new_index_reg)
     {
       if (REG_P (new_index_reg))
@@ -2497,7 +2548,9 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
        }
       else if (GET_CODE (new_index_reg) == PLUS
               && REG_P (XEXP (new_index_reg, 0))
-              && CONST_INT_P (XEXP (new_index_reg, 1)))
+              && CONST_INT_P (XEXP (new_index_reg, 1))
+              && can_add_disp_p (ad, addr_loc)
+              && (scale = get_index_scale (ad)))
        {
          disp += INTVAL (XEXP (new_index_reg, 1)) * scale;
          *ad->index_reg_loc = XEXP (new_index_reg, 0);