summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-26 06:38:23 +0000
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-26 06:38:23 +0000
commit809320f0ecad237a1cc34797816cf10a36456b30 (patch)
treef825b0646fb2440cbf7c5ca772ad65ec1824ea21
parentcbdc514458fcaec4bfa83f251f6f86a6abcbf5f7 (diff)
downloadgcc-809320f0ecad237a1cc34797816cf10a36456b30.tar.gz
gcc/
* lra-constraints.c (get_index_scale, can_add_disp_p): New functions. (equiv_address_substitution): Use them. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192835 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/lra-constraints.c69
2 files changed, 66 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f24eae362ce..4a93aa6e922 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 13d7a3de034..84c9e1511c9 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -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;
+}
+
/* 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);