re PR bootstrap/55049 (bootstrap failed with --with-multilib-list=m32,m64,mx32)

gcc/
	PR bootstrap/55049
	* Makefile.in (rtlanal.o): Add dependency on addresses.h.
	* rtl.h (address_info): New structure.
	(strip_address_mutations, decompose_address, decompose_lea_address)
	(decompose_mem_address, update_address, get_index_scale)
	(get_index_code): Declare.
	* rtlanal.c: Include addresses.h.
	(strip_address_mutations, must_be_base_p, must_be_index_p)
	(set_address_segment, set_address_base, set_address_index)
	(set_address_disp, decompose_incdec_address, decompose_automod_address)
	(extract_plus_operands, baseness, decompose_normal_address)
	(decompose_address, decompose_lea_address, decompose_mem_address)
	(update_address, get_index_scale, get_index_code): New functions.
	* lra-constraints.c (strip_subreg): New function.
	(address, extract_loc_address_regs, extract_address_regs)
	(get_index_scale): Delete.
	(process_addr_reg): Apply strip_subreg to the location.
	(uses_hard_regs_p): Use decompose_mem_address.
	(valid_address_p, base_plus_disp_to_reg, can_add_disp_p)
	(equiv_address_substitution): Take an address_info rather
	than an address.  Remove other arguments.  Avoid using Pmode.
	(process_address): Use decompose_mem_address and decompose_lea_address.
	Update calls to above functions.

From-SVN: r192837
This commit is contained in:
Richard Sandiford 2012-10-26 06:41:53 +00:00 committed by Richard Sandiford
parent f9d4ecd445
commit 277f65de19
5 changed files with 595 additions and 481 deletions

View File

@ -1,3 +1,29 @@
2012-10-26 Richard Sandiford <rdsandiford@googlemail.com>
PR bootstrap/55049
* Makefile.in (rtlanal.o): Add dependency on addresses.h.
* rtl.h (address_info): New structure.
(strip_address_mutations, decompose_address, decompose_lea_address)
(decompose_mem_address, update_address, get_index_scale)
(get_index_code): Declare.
* rtlanal.c: Include addresses.h.
(strip_address_mutations, must_be_base_p, must_be_index_p)
(set_address_segment, set_address_base, set_address_index)
(set_address_disp, decompose_incdec_address, decompose_automod_address)
(extract_plus_operands, baseness, decompose_normal_address)
(decompose_address, decompose_lea_address, decompose_mem_address)
(update_address, get_index_scale, get_index_code): New functions.
* lra-constraints.c (strip_subreg): New function.
(address, extract_loc_address_regs, extract_address_regs)
(get_index_scale): Delete.
(process_addr_reg): Apply strip_subreg to the location.
(uses_hard_regs_p): Use decompose_mem_address.
(valid_address_p, base_plus_disp_to_reg, can_add_disp_p)
(equiv_address_substitution): Take an address_info rather
than an address. Remove other arguments. Avoid using Pmode.
(process_address): Use decompose_mem_address and decompose_lea_address.
Update calls to above functions.
2012-10-26 Richard Sandiford <rdsandiford@googlemail.com>
* lra-constraints.c (process_address): Tighten arguments to

View File

@ -2709,7 +2709,7 @@ print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h $(TM_H)
rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(DIAGNOSTIC_CORE_H) \
$(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) \
$(FLAGS_H) $(REGS_H) output.h $(TARGET_H) $(FUNCTION_H) $(TREE_H) \
$(DF_H) $(EMIT_RTL_H)
$(DF_H) $(EMIT_RTL_H) addresses.h
varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \

View File

@ -152,6 +152,13 @@ static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
static int new_regno_start;
static int new_insn_uid_start;
/* If LOC is nonnull, strip any outer subreg from it. */
static inline rtx *
strip_subreg (rtx *loc)
{
return loc && GET_CODE (*loc) == SUBREG ? &SUBREG_REG (*loc) : loc;
}
/* Return hard regno of REGNO or if it is was not assigned to a hard
register, use a hard register from its allocno class. */
static int
@ -435,28 +442,6 @@ get_reload_reg (enum op_type type, enum machine_mode mode, rtx original,
/* The page contains code to extract memory address parts. */
/* Info about base and index regs of an address. In some rare cases,
base/index register can be actually memory. In this case we will
reload it. */
struct address
{
/* NULL if there is no a base register. */
rtx *base_reg_loc;
/* Second location of {post/pre}_modify, NULL otherwise. */
rtx *base_reg_loc2;
/* NULL if there is no an index register. */
rtx *index_reg_loc;
/* Location of index reg * scale or index_reg_loc otherwise. */
rtx *index_loc;
/* NULL if there is no a displacement. */
rtx *disp_loc;
/* Defined if base_reg_loc is not NULL. */
enum rtx_code base_outer_code, index_code;
/* True if the base register is modified in the address, for
example, in PRE_INC. */
bool base_modify_p;
};
/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudos. */
static inline bool
ok_for_index_p_nonstrict (rtx reg)
@ -479,305 +464,6 @@ ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
return ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
}
/* Process address part in space AS (or all address if TOP_P) with
location *LOC to extract address characteristics.
If CONTEXT_P is false, we are looking at the base part of an
address, otherwise we are looking at the index part.
MODE is the mode of the memory reference; OUTER_CODE and INDEX_CODE
give the context that the rtx appears in; MODIFY_P if *LOC is
modified. */
static void
extract_loc_address_regs (bool top_p, enum machine_mode mode, addr_space_t as,
rtx *loc, bool context_p, enum rtx_code outer_code,
enum rtx_code index_code,
bool modify_p, struct address *ad)
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
bool base_ok_p;
switch (code)
{
case CONST_INT:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
if (! context_p)
{
lra_assert (top_p);
ad->disp_loc = loc;
}
return;
case CC0:
case PC:
return;
case ZERO_EXTEND:
/* Pass TOP_P for displacement. */
extract_loc_address_regs (top_p, mode, as, &XEXP (*loc, 0), context_p,
code, index_code, modify_p, ad);
return;
case PLUS:
case LO_SUM:
/* When we have an address that is a sum, we must determine
whether registers are "base" or "index" regs. If there is a
sum of two registers, we must choose one to be the
"base". */
{
rtx *arg0_loc = &XEXP (x, 0);
rtx *arg1_loc = &XEXP (x, 1);
rtx *tloc;
rtx arg0 = *arg0_loc;
rtx arg1 = *arg1_loc;
enum rtx_code code0 = GET_CODE (arg0);
enum rtx_code code1 = GET_CODE (arg1);
/* Look inside subregs. */
if (code0 == SUBREG)
{
arg0_loc = &SUBREG_REG (arg0);
arg0 = *arg0_loc;
code0 = GET_CODE (arg0);
}
if (code1 == SUBREG)
{
arg1_loc = &SUBREG_REG (arg1);
arg1 = *arg1_loc;
code1 = GET_CODE (arg1);
}
if (CONSTANT_P (arg0)
|| code1 == PLUS || code1 == MULT || code1 == ASHIFT)
{
tloc = arg1_loc;
arg1_loc = arg0_loc;
arg0_loc = tloc;
arg0 = *arg0_loc;
code0 = GET_CODE (arg0);
arg1 = *arg1_loc;
code1 = GET_CODE (arg1);
}
/* If this machine only allows one register per address, it
must be in the first operand. */
if (MAX_REGS_PER_ADDRESS == 1 || code == LO_SUM)
{
lra_assert (ad->disp_loc == NULL);
ad->disp_loc = arg1_loc;
extract_loc_address_regs (false, mode, as, arg0_loc, false, code,
code1, modify_p, ad);
}
/* Base + disp addressing */
else if (code0 != PLUS && code0 != MULT && code0 != ASHIFT
&& CONSTANT_P (arg1))
{
lra_assert (ad->disp_loc == NULL);
ad->disp_loc = arg1_loc;
extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS,
code1, modify_p, ad);
}
/* If index and base registers are the same on this machine,
just record registers in any non-constant operands. We
assume here, as well as in the tests below, that all
addresses are in canonical form. */
else if (INDEX_REG_CLASS
== base_reg_class (VOIDmode, as, PLUS, SCRATCH)
&& code0 != PLUS && code0 != MULT && code0 != ASHIFT)
{
extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS,
code1, modify_p, ad);
lra_assert (! CONSTANT_P (arg1));
extract_loc_address_regs (false, mode, as, arg1_loc, true, PLUS,
code0, modify_p, ad);
}
/* It might be [base + ]index * scale + disp. */
else if (CONSTANT_P (arg1))
{
lra_assert (ad->disp_loc == NULL);
ad->disp_loc = arg1_loc;
extract_loc_address_regs (false, mode, as, arg0_loc, context_p,
PLUS, code0, modify_p, ad);
}
/* If both operands are registers but one is already a hard
register of index or reg-base class, give the other the
class that the hard register is not. */
else if (code0 == REG && code1 == REG
&& REGNO (arg0) < FIRST_PSEUDO_REGISTER
&& ((base_ok_p
= ok_for_base_p_nonstrict (arg0, mode, as, PLUS, REG))
|| ok_for_index_p_nonstrict (arg0)))
{
extract_loc_address_regs (false, mode, as, arg0_loc, ! base_ok_p,
PLUS, REG, modify_p, ad);
extract_loc_address_regs (false, mode, as, arg1_loc, base_ok_p,
PLUS, REG, modify_p, ad);
}
else if (code0 == REG && code1 == REG
&& REGNO (arg1) < FIRST_PSEUDO_REGISTER
&& ((base_ok_p
= ok_for_base_p_nonstrict (arg1, mode, as, PLUS, REG))
|| ok_for_index_p_nonstrict (arg1)))
{
extract_loc_address_regs (false, mode, as, arg0_loc, base_ok_p,
PLUS, REG, modify_p, ad);
extract_loc_address_regs (false, mode, as, arg1_loc, ! base_ok_p,
PLUS, REG, modify_p, ad);
}
/* Otherwise, count equal chances that each might be a base or
index register. This case should be rare. */
else
{
extract_loc_address_regs (false, mode, as, arg0_loc, false, PLUS,
code1, modify_p, ad);
extract_loc_address_regs (false, mode, as, arg1_loc,
ad->base_reg_loc != NULL, PLUS,
code0, modify_p, ad);
}
}
break;
case MULT:
case ASHIFT:
{
rtx *arg0_loc = &XEXP (x, 0);
enum rtx_code code0 = GET_CODE (*arg0_loc);
if (code0 == CONST_INT)
arg0_loc = &XEXP (x, 1);
extract_loc_address_regs (false, mode, as, arg0_loc, true,
outer_code, code, modify_p, ad);
lra_assert (ad->index_loc == NULL);
ad->index_loc = loc;
break;
}
case POST_MODIFY:
case PRE_MODIFY:
extract_loc_address_regs (false, mode, as, &XEXP (x, 0), false,
code, GET_CODE (XEXP (XEXP (x, 1), 1)),
true, ad);
lra_assert (rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)));
ad->base_reg_loc2 = &XEXP (XEXP (x, 1), 0);
if (REG_P (XEXP (XEXP (x, 1), 1)))
extract_loc_address_regs (false, mode, as, &XEXP (XEXP (x, 1), 1),
true, code, REG, modify_p, ad);
break;
case POST_INC:
case PRE_INC:
case POST_DEC:
case PRE_DEC:
extract_loc_address_regs (false, mode, as, &XEXP (x, 0), false, code,
SCRATCH, true, ad);
break;
/* We process memory as a register. That means we flatten
addresses. In other words, the final code will never
contains memory in an address even if the target supports
such addresses (it is too rare these days). Memory also can
occur in address as a result some previous transformations
like equivalence substitution. */
case MEM:
case REG:
if (context_p)
{
lra_assert (ad->index_reg_loc == NULL);
ad->index_reg_loc = loc;
}
else
{
lra_assert (ad->base_reg_loc == NULL);
ad->base_reg_loc = loc;
ad->base_outer_code = outer_code;
ad->index_code = index_code;
ad->base_modify_p = modify_p;
}
break;
default:
{
const char *fmt = GET_RTX_FORMAT (code);
int i;
if (GET_RTX_LENGTH (code) != 1
|| fmt[0] != 'e' || GET_CODE (XEXP (x, 0)) != UNSPEC)
{
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
extract_loc_address_regs (false, mode, as, &XEXP (x, i),
context_p, code, SCRATCH,
modify_p, ad);
break;
}
/* fall through for case UNARY_OP (UNSPEC ...) */
}
case UNSPEC:
if (ad->disp_loc == NULL)
ad->disp_loc = loc;
else if (ad->base_reg_loc == NULL)
{
ad->base_reg_loc = loc;
ad->base_outer_code = outer_code;
ad->index_code = index_code;
ad->base_modify_p = modify_p;
}
else
{
lra_assert (ad->index_reg_loc == NULL);
ad->index_reg_loc = loc;
}
break;
}
}
/* Describe address *LOC in AD. There are two cases:
- *LOC is the address in a (mem ...). In this case OUTER_CODE is MEM
and AS is the mem's address space.
- *LOC is matched to an address constraint such as 'p'. In this case
OUTER_CODE is ADDRESS and AS is ADDR_SPACE_GENERIC. */
static void
extract_address_regs (enum machine_mode mem_mode, addr_space_t as,
rtx *loc, enum rtx_code outer_code, struct address *ad)
{
ad->base_reg_loc = ad->base_reg_loc2
= ad->index_reg_loc = ad->index_loc = ad->disp_loc = NULL;
ad->base_outer_code = SCRATCH;
ad->index_code = SCRATCH;
ad->base_modify_p = false;
extract_loc_address_regs (true, mem_mode, as, loc, false, outer_code,
SCRATCH, false, ad);
if (ad->index_loc == NULL)
/* SUBREG ??? */
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
@ -1354,11 +1040,13 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
{
int regno;
enum reg_class rclass, new_class;
rtx reg = *loc;
rtx reg;
rtx new_reg;
enum machine_mode mode;
bool before_p = false;
loc = strip_subreg (loc);
reg = *loc;
mode = GET_MODE (reg);
if (! REG_P (reg))
{
@ -1538,21 +1226,13 @@ uses_hard_regs_p (rtx x, HARD_REG_SET set)
}
if (MEM_P (x))
{
struct address ad;
enum machine_mode mode = GET_MODE (x);
rtx *addr_loc = &XEXP (x, 0);
struct address_info ad;
extract_address_regs (mode, MEM_ADDR_SPACE (x), addr_loc, MEM, &ad);
if (ad.base_reg_loc != NULL)
{
if (uses_hard_regs_p (*ad.base_reg_loc, set))
return true;
}
if (ad.index_reg_loc != NULL)
{
if (uses_hard_regs_p (*ad.index_reg_loc, set))
return true;
}
decompose_mem_address (&ad, x);
if (ad.base_term != NULL && uses_hard_regs_p (*ad.base_term, set))
return true;
if (ad.index_term != NULL && uses_hard_regs_p (*ad.index_term, set))
return true;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
@ -2399,115 +2079,92 @@ valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
#endif
}
/* Return whether address X, described by AD, is valid for mode MODE
and address space AS. */
/* Return whether address AD is valid. */
static bool
valid_address_p (struct address *ad, enum machine_mode mode, rtx x,
addr_space_t as)
valid_address_p (struct address_info *ad)
{
/* Some ports do not check displacements for eliminable registers,
so we replace them temporarily with the elimination target. */
rtx saved_base_reg = NULL_RTX;
rtx saved_index_reg = NULL_RTX;
if (ad->base_reg_loc != NULL)
rtx *base_term = strip_subreg (ad->base_term);
rtx *index_term = strip_subreg (ad->index_term);
if (base_term != NULL)
{
saved_base_reg = *ad->base_reg_loc;
lra_eliminate_reg_if_possible (ad->base_reg_loc);
if (ad->base_reg_loc2 != NULL)
*ad->base_reg_loc2 = *ad->base_reg_loc;
saved_base_reg = *base_term;
lra_eliminate_reg_if_possible (base_term);
if (ad->base_term2 != NULL)
*ad->base_term2 = *ad->base_term;
}
if (ad->index_reg_loc != NULL)
if (index_term != NULL)
{
saved_index_reg = *ad->index_reg_loc;
lra_eliminate_reg_if_possible (ad->index_reg_loc);
saved_index_reg = *index_term;
lra_eliminate_reg_if_possible (index_term);
}
bool ok_p = valid_address_p (mode, x, as);
bool ok_p = valid_address_p (ad->mode, *ad->outer, ad->as);
if (saved_base_reg != NULL_RTX)
{
*ad->base_reg_loc = saved_base_reg;
if (ad->base_reg_loc2 != NULL)
*ad->base_reg_loc2 = saved_base_reg;
*base_term = saved_base_reg;
if (ad->base_term2 != NULL)
*ad->base_term2 = *ad->base_term;
}
if (saved_index_reg != NULL_RTX)
*ad->index_reg_loc = saved_index_reg;
*index_term = saved_index_reg;
return ok_p;
}
/* Make reload base reg + disp from address AD in space AS of memory
with MODE into a new pseudo. Return the new pseudo. */
/* Make reload base reg + disp from address AD. Return the new pseudo. */
static rtx
base_plus_disp_to_reg (enum machine_mode mode, addr_space_t as,
struct address *ad)
base_plus_disp_to_reg (struct address_info *ad)
{
enum reg_class cl;
rtx new_reg;
lra_assert (ad->base_reg_loc != NULL && ad->disp_loc != NULL);
cl = base_reg_class (mode, as, ad->base_outer_code, ad->index_code);
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "base + disp");
lra_emit_add (new_reg, *ad->base_reg_loc, *ad->disp_loc);
lra_assert (ad->base == ad->base_term && ad->disp == ad->disp_term);
cl = base_reg_class (ad->mode, ad->as, ad->base_outer_code,
get_index_code (ad));
new_reg = lra_create_new_reg (GET_MODE (*ad->base_term), NULL_RTX,
cl, "base + disp");
lra_emit_add (new_reg, *ad->base_term, *ad->disp_term);
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. */
/* Return true if we can add a displacement to address AD, even if that
makes the address invalid. The fix-up code requires any new address
to be the sum of the BASE_TERM, INDEX and DISP_TERM fields. */
static bool
can_add_disp_p (struct address *ad, rtx *addr_loc)
can_add_disp_p (struct address_info *ad)
{
/* 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;
return (!ad->autoinc_p
&& ad->segment == NULL
&& ad->base == ad->base_term
&& ad->disp == ad->disp_term);
}
/* 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. */
/* Make equiv substitution in address AD. Return true if a substitution
was made. */
static bool
equiv_address_substitution (struct address *ad, rtx *addr_loc,
enum machine_mode mode, addr_space_t as,
enum rtx_code code)
equiv_address_substitution (struct address_info *ad)
{
rtx base_reg, new_base_reg, index_reg, new_index_reg;
rtx base_reg, new_base_reg, index_reg, new_index_reg, *base_term, *index_term;
HOST_WIDE_INT disp, scale;
bool change_p;
if (ad->base_reg_loc == NULL)
base_term = strip_subreg (ad->base_term);
if (base_term == NULL)
base_reg = new_base_reg = NULL_RTX;
else
{
base_reg = *ad->base_reg_loc;
base_reg = *base_term;
new_base_reg = get_equiv_substitution (base_reg);
}
if (ad->index_reg_loc == NULL)
index_term = strip_subreg (ad->index_term);
if (index_term == NULL)
index_reg = new_index_reg = NULL_RTX;
else
{
index_reg = *ad->index_reg_loc;
index_reg = *index_term;
new_index_reg = get_equiv_substitution (index_reg);
}
if (base_reg == new_base_reg && index_reg == new_index_reg)
@ -2518,53 +2175,53 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
{
fprintf (lra_dump_file, "Changing address in insn %d ",
INSN_UID (curr_insn));
print_value_slim (lra_dump_file, *addr_loc, 1);
print_value_slim (lra_dump_file, *ad->outer, 1);
}
if (base_reg != new_base_reg)
{
if (REG_P (new_base_reg))
{
*ad->base_reg_loc = new_base_reg;
*base_term = new_base_reg;
change_p = true;
}
else if (GET_CODE (new_base_reg) == PLUS
&& REG_P (XEXP (new_base_reg, 0))
&& CONST_INT_P (XEXP (new_base_reg, 1))
&& can_add_disp_p (ad, addr_loc))
&& can_add_disp_p (ad))
{
disp += INTVAL (XEXP (new_base_reg, 1));
*ad->base_reg_loc = XEXP (new_base_reg, 0);
*base_term = XEXP (new_base_reg, 0);
change_p = true;
}
if (ad->base_reg_loc2 != NULL)
*ad->base_reg_loc2 = *ad->base_reg_loc;
if (ad->base_term2 != NULL)
*ad->base_term2 = *ad->base_term;
}
if (index_reg != new_index_reg)
{
if (REG_P (new_index_reg))
{
*ad->index_reg_loc = new_index_reg;
*index_term = new_index_reg;
change_p = true;
}
else if (GET_CODE (new_index_reg) == PLUS
&& REG_P (XEXP (new_index_reg, 0))
&& CONST_INT_P (XEXP (new_index_reg, 1))
&& can_add_disp_p (ad, addr_loc)
&& can_add_disp_p (ad)
&& (scale = get_index_scale (ad)))
{
disp += INTVAL (XEXP (new_index_reg, 1)) * scale;
*ad->index_reg_loc = XEXP (new_index_reg, 0);
*index_term = XEXP (new_index_reg, 0);
change_p = true;
}
}
if (disp != 0)
{
if (ad->disp_loc != NULL)
*ad->disp_loc = plus_constant (Pmode, *ad->disp_loc, disp);
if (ad->disp != NULL)
*ad->disp = plus_constant (GET_MODE (*ad->inner), *ad->disp, disp);
else
{
*addr_loc = gen_rtx_PLUS (Pmode, *addr_loc, GEN_INT (disp));
extract_address_regs (mode, as, addr_loc, code, ad);
*ad->inner = plus_constant (GET_MODE (*ad->inner), *ad->inner, disp);
update_address (ad);
}
change_p = true;
}
@ -2575,7 +2232,7 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
else
{
fprintf (lra_dump_file, " on equiv ");
print_value_slim (lra_dump_file, *addr_loc, 1);
print_value_slim (lra_dump_file, *ad->outer, 1);
fprintf (lra_dump_file, "\n");
}
}
@ -2604,62 +2261,43 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
static bool
process_address (int nop, rtx *before, rtx *after)
{
struct address ad;
enum machine_mode mode;
rtx new_reg, *addr_loc;
addr_space_t as;
struct address_info ad;
rtx new_reg;
rtx op = *curr_id->operand_loc[nop];
const char *constraint = curr_static_id->operand[nop].constraint;
bool change_p;
enum rtx_code code;
if (constraint[0] == 'p'
|| EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint))
{
mode = VOIDmode;
addr_loc = curr_id->operand_loc[nop];
as = ADDR_SPACE_GENERIC;
code = ADDRESS;
}
decompose_lea_address (&ad, curr_id->operand_loc[nop]);
else if (MEM_P (op))
{
mode = GET_MODE (op);
addr_loc = &XEXP (op, 0);
as = MEM_ADDR_SPACE (op);
code = MEM;
}
decompose_mem_address (&ad, op);
else if (GET_CODE (op) == SUBREG
&& MEM_P (SUBREG_REG (op)))
{
mode = GET_MODE (SUBREG_REG (op));
addr_loc = &XEXP (SUBREG_REG (op), 0);
as = MEM_ADDR_SPACE (SUBREG_REG (op));
code = MEM;
}
decompose_mem_address (&ad, SUBREG_REG (op));
else
return false;
if (GET_CODE (*addr_loc) == AND)
addr_loc = &XEXP (*addr_loc, 0);
extract_address_regs (mode, as, addr_loc, code, &ad);
change_p = equiv_address_substitution (&ad, addr_loc, mode, as, code);
if (ad.base_reg_loc != NULL
change_p = equiv_address_substitution (&ad);
if (ad.base_term != NULL
&& (process_addr_reg
(ad.base_reg_loc, before,
(ad.base_modify_p && REG_P (*ad.base_reg_loc)
&& find_regno_note (curr_insn, REG_DEAD,
REGNO (*ad.base_reg_loc)) == NULL_RTX
(ad.base_term, before,
(ad.autoinc_p
&& !(REG_P (*ad.base_term)
&& find_regno_note (curr_insn, REG_DEAD,
REGNO (*ad.base_term)) != NULL_RTX)
? after : NULL),
base_reg_class (mode, as, ad.base_outer_code, ad.index_code))))
base_reg_class (ad.mode, ad.as, ad.base_outer_code,
get_index_code (&ad)))))
{
change_p = true;
if (ad.base_reg_loc2 != NULL)
*ad.base_reg_loc2 = *ad.base_reg_loc;
if (ad.base_term2 != NULL)
*ad.base_term2 = *ad.base_term;
}
if (ad.index_reg_loc != NULL
&& process_addr_reg (ad.index_reg_loc, before, NULL, INDEX_REG_CLASS))
if (ad.index_term != NULL
&& process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS))
change_p = true;
/* There are three cases where the shape of *ADDR_LOC may now be invalid:
/* There are three cases where the shape of *AD.INNER may now be invalid:
1) the original address was valid, but either elimination or
equiv_address_substitution applied a displacement that made
@ -2670,21 +2308,25 @@ process_address (int nop, rtx *before, rtx *after)
3) the address is a frame address with an invalid offset.
All these cases involve a displacement, so there is no point
revalidating when there is no displacement. */
if (ad.disp_loc == NULL || valid_address_p (&ad, mode, *addr_loc, as))
All these cases involve a displacement and a non-autoinc address,
so there is no point revalidating other types. */
if (ad.disp == NULL || ad.autoinc_p || valid_address_p (&ad))
return change_p;
/* Any index existed before LRA started, so we can assume that the
presence and shape of the index is valid. */
push_to_sequence (*before);
if (ad.base_reg_loc == NULL)
gcc_assert (ad.segment == NULL);
gcc_assert (ad.disp == ad.disp_term);
if (ad.base == NULL)
{
if (ad.index_reg_loc == NULL)
if (ad.index == NULL)
{
int code = -1;
enum reg_class cl = base_reg_class (mode, as, SCRATCH, SCRATCH);
enum reg_class cl = base_reg_class (ad.mode, ad.as,
SCRATCH, SCRATCH);
rtx disp = *ad.disp;
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
#ifdef HAVE_lo_sum
{
@ -2694,16 +2336,14 @@ process_address (int nop, rtx *before, rtx *after)
/* disp => lo_sum (new_base, disp), case (2) above. */
insn = emit_insn (gen_rtx_SET
(VOIDmode, new_reg,
gen_rtx_HIGH (Pmode, copy_rtx (*ad.disp_loc))));
gen_rtx_HIGH (Pmode, copy_rtx (disp))));
code = recog_memoized (insn);
if (code >= 0)
{
rtx save = *ad.disp_loc;
*ad.disp_loc = gen_rtx_LO_SUM (Pmode, new_reg, *ad.disp_loc);
if (! valid_address_p (mode, *ad.disp_loc, as))
*ad.disp = gen_rtx_LO_SUM (Pmode, new_reg, disp);
if (! valid_address_p (ad.mode, *ad.outer, ad.as))
{
*ad.disp_loc = save;
*ad.disp = disp;
code = -1;
}
}
@ -2714,25 +2354,25 @@ process_address (int nop, rtx *before, rtx *after)
if (code < 0)
{
/* disp => new_base, case (2) above. */
lra_emit_move (new_reg, *ad.disp_loc);
*ad.disp_loc = new_reg;
lra_emit_move (new_reg, disp);
*ad.disp = new_reg;
}
}
else
{
/* index * scale + disp => new base + index * scale,
case (1) above. */
enum reg_class cl = base_reg_class (mode, as, PLUS,
GET_CODE (*ad.index_loc));
enum reg_class cl = base_reg_class (ad.mode, ad.as, PLUS,
GET_CODE (*ad.index));
lra_assert (INDEX_REG_CLASS != NO_REGS);
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
lra_emit_move (new_reg, *ad.disp_loc);
*addr_loc = simplify_gen_binary (PLUS, GET_MODE (new_reg),
new_reg, *ad.index_loc);
lra_emit_move (new_reg, *ad.disp);
*ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
new_reg, *ad.index);
}
}
else if (ad.index_reg_loc == NULL)
else if (ad.index == NULL)
{
/* base + disp => new base, cases (1) and (3) above. */
/* Another option would be to reload the displacement into an
@ -2740,16 +2380,16 @@ process_address (int nop, rtx *before, rtx *after)
address reloads that have the same base and different
displacements, so reloading into an index register would
not necessarily be a win. */
new_reg = base_plus_disp_to_reg (mode, as, &ad);
*addr_loc = new_reg;
new_reg = base_plus_disp_to_reg (&ad);
*ad.inner = new_reg;
}
else
{
/* base + scale * index + disp => new base + scale * index,
case (1) above. */
new_reg = base_plus_disp_to_reg (mode, as, &ad);
*addr_loc = simplify_gen_binary (PLUS, GET_MODE (new_reg),
new_reg, *ad.index_loc);
new_reg = base_plus_disp_to_reg (&ad);
*ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
new_reg, *ad.index);
}
*before = get_insns ();
end_sequence ();

View File

@ -1237,6 +1237,77 @@ costs_add_n_insns (struct full_rtx_costs *c, int n)
c->size += COSTS_N_INSNS (n);
}
/* Information about an address. This structure is supposed to be able
to represent all supported target addresses. Please extend it if it
is not yet general enough. */
struct address_info {
/* The mode of the value being addressed, or VOIDmode if this is
a load-address operation with no known address mode. */
enum machine_mode mode;
/* The address space. */
addr_space_t as;
/* A pointer to the top-level address. */
rtx *outer;
/* A pointer to the inner address, after all address mutations
have been stripped from the top-level address. It can be one
of the following:
- A {PRE,POST}_{INC,DEC} of *BASE. SEGMENT, INDEX and DISP are null.
- A {PRE,POST}_MODIFY of *BASE. In this case either INDEX or DISP
points to the step value, depending on whether the step is variable
or constant respectively. SEGMENT is null.
- A plain sum of the form SEGMENT + BASE + INDEX + DISP,
with null fields evaluating to 0. */
rtx *inner;
/* Components that make up *INNER. Each one may be null or nonnull.
When nonnull, their meanings are as follows:
- *SEGMENT is the "segment" of memory to which the address refers.
This value is entirely target-specific and is only called a "segment"
because that's its most typical use. It contains exactly one UNSPEC,
pointed to by SEGMENT_TERM. The contents of *SEGMENT do not need
reloading.
- *BASE is a variable expression representing a base address.
It contains exactly one REG, SUBREG or MEM, pointed to by BASE_TERM.
- *INDEX is a variable expression representing an index value.
It may be a scaled expression, such as a MULT. It has exactly
one REG, SUBREG or MEM, pointed to by INDEX_TERM.
- *DISP is a constant, possibly mutated. DISP_TERM points to the
unmutated RTX_CONST_OBJ. */
rtx *segment;
rtx *base;
rtx *index;
rtx *disp;
rtx *segment_term;
rtx *base_term;
rtx *index_term;
rtx *disp_term;
/* In a {PRE,POST}_MODIFY address, this points to a second copy
of BASE_TERM, otherwise it is null. */
rtx *base_term2;
/* ADDRESS if this structure describes an address operand, MEM if
it describes a MEM address. */
enum rtx_code addr_outer_code;
/* If BASE is nonnull, this is the code of the rtx that contains it. */
enum rtx_code base_outer_code;
/* True if this is an RTX_AUTOINC address. */
bool autoinc_p;
};
extern void init_rtlanal (void);
extern int rtx_cost (rtx, enum rtx_code, int, bool);
extern int address_cost (rtx, enum machine_mode, addr_space_t, bool);
@ -1260,6 +1331,14 @@ extern bool constant_pool_constant_p (rtx);
extern bool truncated_to_mode (enum machine_mode, const_rtx);
extern int low_bitmask_len (enum machine_mode, unsigned HOST_WIDE_INT);
extern void split_double (rtx, rtx *, rtx *);
extern rtx *strip_address_mutations (rtx *, enum rtx_code * = 0);
extern void decompose_address (struct address_info *, rtx *,
enum machine_mode, addr_space_t, enum rtx_code);
extern void decompose_lea_address (struct address_info *, rtx *);
extern void decompose_mem_address (struct address_info *, rtx);
extern void update_address (struct address_info *);
extern HOST_WIDE_INT get_index_scale (const struct address_info *);
extern enum rtx_code get_index_code (const struct address_info *);
#ifndef GENERATOR_FILE
/* Return the cost of SET X. SPEED_P is true if optimizing for speed

View File

@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "df.h"
#include "tree.h"
#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
#include "addresses.h"
/* Forward declarations */
static void set_of_1 (rtx, const_rtx, void *);
@ -5438,3 +5439,371 @@ split_double (rtx value, rtx *first, rtx *second)
}
}
/* Strip outer address "mutations" from LOC and return a pointer to the
inner value. If OUTER_CODE is nonnull, store the code of the innermost
stripped expression there.
"Mutations" either convert between modes or apply some kind of
alignment. */
rtx *
strip_address_mutations (rtx *loc, enum rtx_code *outer_code)
{
for (;;)
{
enum rtx_code code = GET_CODE (*loc);
if (GET_RTX_CLASS (code) == RTX_UNARY)
/* Things like SIGN_EXTEND, ZERO_EXTEND and TRUNCATE can be
used to convert between pointer sizes. */
loc = &XEXP (*loc, 0);
else if (code == AND && CONST_INT_P (XEXP (*loc, 1)))
/* (and ... (const_int -X)) is used to align to X bytes. */
loc = &XEXP (*loc, 0);
else
return loc;
if (outer_code)
*outer_code = code;
}
}
/* Return true if X must be a base rather than an index. */
static bool
must_be_base_p (rtx x)
{
return GET_CODE (x) == LO_SUM;
}
/* Return true if X must be an index rather than a base. */
static bool
must_be_index_p (rtx x)
{
return GET_CODE (x) == MULT || GET_CODE (x) == ASHIFT;
}
/* Set the segment part of address INFO to LOC, given that INNER is the
unmutated value. */
static void
set_address_segment (struct address_info *info, rtx *loc, rtx *inner)
{
gcc_checking_assert (GET_CODE (*inner) == UNSPEC);
gcc_assert (!info->segment);
info->segment = loc;
info->segment_term = inner;
}
/* Set the base part of address INFO to LOC, given that INNER is the
unmutated value. */
static void
set_address_base (struct address_info *info, rtx *loc, rtx *inner)
{
if (GET_CODE (*inner) == LO_SUM)
inner = strip_address_mutations (&XEXP (*inner, 0));
gcc_checking_assert (REG_P (*inner)
|| MEM_P (*inner)
|| GET_CODE (*inner) == SUBREG);
gcc_assert (!info->base);
info->base = loc;
info->base_term = inner;
}
/* Set the index part of address INFO to LOC, given that INNER is the
unmutated value. */
static void
set_address_index (struct address_info *info, rtx *loc, rtx *inner)
{
if ((GET_CODE (*inner) == MULT || GET_CODE (*inner) == ASHIFT)
&& CONSTANT_P (XEXP (*inner, 1)))
inner = strip_address_mutations (&XEXP (*inner, 0));
gcc_checking_assert (REG_P (*inner)
|| MEM_P (*inner)
|| GET_CODE (*inner) == SUBREG);
gcc_assert (!info->index);
info->index = loc;
info->index_term = inner;
}
/* Set the displacement part of address INFO to LOC, given that INNER
is the constant term. */
static void
set_address_disp (struct address_info *info, rtx *loc, rtx *inner)
{
gcc_checking_assert (CONSTANT_P (*inner));
gcc_assert (!info->disp);
info->disp = loc;
info->disp_term = inner;
}
/* INFO->INNER describes a {PRE,POST}_{INC,DEC} address. Set up the
rest of INFO accordingly. */
static void
decompose_incdec_address (struct address_info *info)
{
info->autoinc_p = true;
rtx *base = &XEXP (*info->inner, 0);
set_address_base (info, base, base);
gcc_checking_assert (info->base == info->base_term);
/* These addresses are only valid when the size of the addressed
value is known. */
gcc_checking_assert (info->mode != VOIDmode);
}
/* INFO->INNER describes a {PRE,POST}_MODIFY address. Set up the rest
of INFO accordingly. */
static void
decompose_automod_address (struct address_info *info)
{
info->autoinc_p = true;
rtx *base = &XEXP (*info->inner, 0);
set_address_base (info, base, base);
gcc_checking_assert (info->base == info->base_term);
rtx plus = XEXP (*info->inner, 1);
gcc_assert (GET_CODE (plus) == PLUS);
info->base_term2 = &XEXP (plus, 0);
gcc_checking_assert (rtx_equal_p (*info->base_term, *info->base_term2));
rtx *step = &XEXP (plus, 1);
rtx *inner_step = strip_address_mutations (step);
if (CONSTANT_P (*inner_step))
set_address_disp (info, step, inner_step);
else
set_address_index (info, step, inner_step);
}
/* Treat *LOC as a tree of PLUS operands and store pointers to the summed
values in [PTR, END). Return a pointer to the end of the used array. */
static rtx **
extract_plus_operands (rtx *loc, rtx **ptr, rtx **end)
{
rtx x = *loc;
if (GET_CODE (x) == PLUS)
{
ptr = extract_plus_operands (&XEXP (x, 0), ptr, end);
ptr = extract_plus_operands (&XEXP (x, 1), ptr, end);
}
else
{
gcc_assert (ptr != end);
*ptr++ = loc;
}
return ptr;
}
/* Evaluate the likelihood of X being a base or index value, returning
positive if it is likely to be a base, negative if it is likely to be
an index, and 0 if we can't tell. Make the magnitude of the return
value reflect the amount of confidence we have in the answer.
MODE, AS, OUTER_CODE and INDEX_CODE are as for ok_for_base_p_1. */
static int
baseness (rtx x, enum machine_mode mode, addr_space_t as,
enum rtx_code outer_code, enum rtx_code index_code)
{
/* See whether we can be certain. */
if (must_be_base_p (x))
return 3;
if (must_be_index_p (x))
return -3;
/* Believe *_POINTER unless the address shape requires otherwise. */
if (REG_P (x) && REG_POINTER (x))
return 2;
if (MEM_P (x) && MEM_POINTER (x))
return 2;
if (REG_P (x) && HARD_REGISTER_P (x))
{
/* X is a hard register. If it only fits one of the base
or index classes, choose that interpretation. */
int regno = REGNO (x);
bool base_p = ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
bool index_p = REGNO_OK_FOR_INDEX_P (regno);
if (base_p != index_p)
return base_p ? 1 : -1;
}
return 0;
}
/* INFO->INNER describes a normal, non-automodified address.
Fill in the rest of INFO accordingly. */
static void
decompose_normal_address (struct address_info *info)
{
/* Treat the address as the sum of up to four values. */
rtx *ops[4];
size_t n_ops = extract_plus_operands (info->inner, ops,
ops + ARRAY_SIZE (ops)) - ops;
/* If there is more than one component, any base component is in a PLUS. */
if (n_ops > 1)
info->base_outer_code = PLUS;
/* Separate the parts that contain a REG or MEM from those that don't.
Record the latter in INFO and leave the former in OPS. */
rtx *inner_ops[4];
size_t out = 0;
for (size_t in = 0; in < n_ops; ++in)
{
rtx *loc = ops[in];
rtx *inner = strip_address_mutations (loc);
if (CONSTANT_P (*inner))
set_address_disp (info, loc, inner);
else if (GET_CODE (*inner) == UNSPEC)
set_address_segment (info, loc, inner);
else
{
ops[out] = loc;
inner_ops[out] = inner;
++out;
}
}
/* Classify the remaining OPS members as bases and indexes. */
if (out == 1)
{
/* Assume that the remaining value is a base unless the shape
requires otherwise. */
if (!must_be_index_p (*inner_ops[0]))
set_address_base (info, ops[0], inner_ops[0]);
else
set_address_index (info, ops[0], inner_ops[0]);
}
else if (out == 2)
{
/* In the event of a tie, assume the base comes first. */
if (baseness (*inner_ops[0], info->mode, info->as, PLUS,
GET_CODE (*ops[1]))
>= baseness (*inner_ops[1], info->mode, info->as, PLUS,
GET_CODE (*ops[0])))
{
set_address_base (info, ops[0], inner_ops[0]);
set_address_index (info, ops[1], inner_ops[1]);
}
else
{
set_address_base (info, ops[1], inner_ops[1]);
set_address_index (info, ops[0], inner_ops[0]);
}
}
else
gcc_assert (out == 0);
}
/* Describe address *LOC in *INFO. MODE is the mode of the addressed value,
or VOIDmode if not known. AS is the address space associated with LOC.
OUTER_CODE is MEM if *LOC is a MEM address and ADDRESS otherwise. */
void
decompose_address (struct address_info *info, rtx *loc, enum machine_mode mode,
addr_space_t as, enum rtx_code outer_code)
{
memset (info, 0, sizeof (*info));
info->mode = mode;
info->as = as;
info->addr_outer_code = outer_code;
info->outer = loc;
info->inner = strip_address_mutations (loc, &outer_code);
info->base_outer_code = outer_code;
switch (GET_CODE (*info->inner))
{
case PRE_DEC:
case PRE_INC:
case POST_DEC:
case POST_INC:
decompose_incdec_address (info);
break;
case PRE_MODIFY:
case POST_MODIFY:
decompose_automod_address (info);
break;
default:
decompose_normal_address (info);
break;
}
}
/* Describe address operand LOC in INFO. */
void
decompose_lea_address (struct address_info *info, rtx *loc)
{
decompose_address (info, loc, VOIDmode, ADDR_SPACE_GENERIC, ADDRESS);
}
/* Describe the address of MEM X in INFO. */
void
decompose_mem_address (struct address_info *info, rtx x)
{
gcc_assert (MEM_P (x));
decompose_address (info, &XEXP (x, 0), GET_MODE (x),
MEM_ADDR_SPACE (x), MEM);
}
/* Update INFO after a change to the address it describes. */
void
update_address (struct address_info *info)
{
decompose_address (info, info->outer, info->mode, info->as,
info->addr_outer_code);
}
/* Return the scale applied to *INFO->INDEX_TERM, or 0 if the index is
more complicated than that. */
HOST_WIDE_INT
get_index_scale (const struct address_info *info)
{
rtx index = *info->index;
if (GET_CODE (index) == MULT
&& CONST_INT_P (XEXP (index, 1))
&& info->index_term == &XEXP (index, 0))
return INTVAL (XEXP (index, 1));
if (GET_CODE (index) == ASHIFT
&& CONST_INT_P (XEXP (index, 1))
&& info->index_term == &XEXP (index, 0))
return (HOST_WIDE_INT) 1 << INTVAL (XEXP (index, 1));
if (info->index == info->index_term)
return 1;
return 0;
}
/* Return the "index code" of INFO, in the form required by
ok_for_base_p_1. */
enum rtx_code
get_index_code (const struct address_info *info)
{
if (info->index)
return GET_CODE (*info->index);
if (info->disp)
return GET_CODE (*info->disp);
return SCRATCH;
}