lra-constraints.c (get_index_scale, [...]): New functions.

gcc/
	* lra-constraints.c (get_index_scale, can_add_disp_p): New functions.
	(equiv_address_substitution): Use them.

From-SVN: r192835
This commit is contained in:
Richard Sandiford 2012-10-26 06:38:23 +00:00 committed by Richard Sandiford
parent 8bf9b48984
commit 02ea4bf41e
2 changed files with 66 additions and 8 deletions

View File

@ -1,3 +1,8 @@
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...

View 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;
}
/* 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);