mirror of git://gcc.gnu.org/git/gcc.git
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:
parent
f9d4ecd445
commit
277f65de19
|
|
@ -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>
|
2012-10-26 Richard Sandiford <rdsandiford@googlemail.com>
|
||||||
|
|
||||||
* lra-constraints.c (process_address): Tighten arguments to
|
* lra-constraints.c (process_address): Tighten arguments to
|
||||||
|
|
|
||||||
|
|
@ -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) \
|
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) \
|
$(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) \
|
$(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) \
|
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) \
|
$(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,13 @@ static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
|
||||||
static int new_regno_start;
|
static int new_regno_start;
|
||||||
static int new_insn_uid_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
|
/* Return hard regno of REGNO or if it is was not assigned to a hard
|
||||||
register, use a hard register from its allocno class. */
|
register, use a hard register from its allocno class. */
|
||||||
static int
|
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. */
|
/* 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. */
|
/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudos. */
|
||||||
static inline bool
|
static inline bool
|
||||||
ok_for_index_p_nonstrict (rtx reg)
|
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);
|
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
|
/* 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;
|
int regno;
|
||||||
enum reg_class rclass, new_class;
|
enum reg_class rclass, new_class;
|
||||||
rtx reg = *loc;
|
rtx reg;
|
||||||
rtx new_reg;
|
rtx new_reg;
|
||||||
enum machine_mode mode;
|
enum machine_mode mode;
|
||||||
bool before_p = false;
|
bool before_p = false;
|
||||||
|
|
||||||
|
loc = strip_subreg (loc);
|
||||||
|
reg = *loc;
|
||||||
mode = GET_MODE (reg);
|
mode = GET_MODE (reg);
|
||||||
if (! REG_P (reg))
|
if (! REG_P (reg))
|
||||||
{
|
{
|
||||||
|
|
@ -1538,21 +1226,13 @@ uses_hard_regs_p (rtx x, HARD_REG_SET set)
|
||||||
}
|
}
|
||||||
if (MEM_P (x))
|
if (MEM_P (x))
|
||||||
{
|
{
|
||||||
struct address ad;
|
struct address_info ad;
|
||||||
enum machine_mode mode = GET_MODE (x);
|
|
||||||
rtx *addr_loc = &XEXP (x, 0);
|
|
||||||
|
|
||||||
extract_address_regs (mode, MEM_ADDR_SPACE (x), addr_loc, MEM, &ad);
|
decompose_mem_address (&ad, x);
|
||||||
if (ad.base_reg_loc != NULL)
|
if (ad.base_term != NULL && uses_hard_regs_p (*ad.base_term, set))
|
||||||
{
|
return true;
|
||||||
if (uses_hard_regs_p (*ad.base_reg_loc, set))
|
if (ad.index_term != NULL && uses_hard_regs_p (*ad.index_term, set))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
if (ad.index_reg_loc != NULL)
|
|
||||||
{
|
|
||||||
if (uses_hard_regs_p (*ad.index_reg_loc, set))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fmt = GET_RTX_FORMAT (code);
|
fmt = GET_RTX_FORMAT (code);
|
||||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||||
|
|
@ -2399,115 +2079,92 @@ valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return whether address X, described by AD, is valid for mode MODE
|
/* Return whether address AD is valid. */
|
||||||
and address space AS. */
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
valid_address_p (struct address *ad, enum machine_mode mode, rtx x,
|
valid_address_p (struct address_info *ad)
|
||||||
addr_space_t as)
|
|
||||||
{
|
{
|
||||||
/* Some ports do not check displacements for eliminable registers,
|
/* Some ports do not check displacements for eliminable registers,
|
||||||
so we replace them temporarily with the elimination target. */
|
so we replace them temporarily with the elimination target. */
|
||||||
rtx saved_base_reg = NULL_RTX;
|
rtx saved_base_reg = NULL_RTX;
|
||||||
rtx saved_index_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;
|
saved_base_reg = *base_term;
|
||||||
lra_eliminate_reg_if_possible (ad->base_reg_loc);
|
lra_eliminate_reg_if_possible (base_term);
|
||||||
if (ad->base_reg_loc2 != NULL)
|
if (ad->base_term2 != NULL)
|
||||||
*ad->base_reg_loc2 = *ad->base_reg_loc;
|
*ad->base_term2 = *ad->base_term;
|
||||||
}
|
}
|
||||||
if (ad->index_reg_loc != NULL)
|
if (index_term != NULL)
|
||||||
{
|
{
|
||||||
saved_index_reg = *ad->index_reg_loc;
|
saved_index_reg = *index_term;
|
||||||
lra_eliminate_reg_if_possible (ad->index_reg_loc);
|
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)
|
if (saved_base_reg != NULL_RTX)
|
||||||
{
|
{
|
||||||
*ad->base_reg_loc = saved_base_reg;
|
*base_term = saved_base_reg;
|
||||||
if (ad->base_reg_loc2 != NULL)
|
if (ad->base_term2 != NULL)
|
||||||
*ad->base_reg_loc2 = saved_base_reg;
|
*ad->base_term2 = *ad->base_term;
|
||||||
}
|
}
|
||||||
if (saved_index_reg != NULL_RTX)
|
if (saved_index_reg != NULL_RTX)
|
||||||
*ad->index_reg_loc = saved_index_reg;
|
*index_term = saved_index_reg;
|
||||||
return ok_p;
|
return ok_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make reload base reg + disp from address AD in space AS of memory
|
/* Make reload base reg + disp from address AD. Return the new pseudo. */
|
||||||
with MODE into a new pseudo. Return the new pseudo. */
|
|
||||||
static rtx
|
static rtx
|
||||||
base_plus_disp_to_reg (enum machine_mode mode, addr_space_t as,
|
base_plus_disp_to_reg (struct address_info *ad)
|
||||||
struct address *ad)
|
|
||||||
{
|
{
|
||||||
enum reg_class cl;
|
enum reg_class cl;
|
||||||
rtx new_reg;
|
rtx new_reg;
|
||||||
|
|
||||||
lra_assert (ad->base_reg_loc != NULL && ad->disp_loc != NULL);
|
lra_assert (ad->base == ad->base_term && ad->disp == ad->disp_term);
|
||||||
cl = base_reg_class (mode, as, ad->base_outer_code, ad->index_code);
|
cl = base_reg_class (ad->mode, ad->as, ad->base_outer_code,
|
||||||
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "base + disp");
|
get_index_code (ad));
|
||||||
lra_emit_add (new_reg, *ad->base_reg_loc, *ad->disp_loc);
|
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 new_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if we can add a displacement to address ADDR_LOC,
|
/* Return true if we can add a displacement to address AD, even if that
|
||||||
which is described by AD, even if that makes the address invalid.
|
makes the address invalid. The fix-up code requires any new address
|
||||||
The fix-up code requires any new address to be the sum of the base,
|
to be the sum of the BASE_TERM, INDEX and DISP_TERM fields. */
|
||||||
index and displacement fields of an AD-like structure. */
|
|
||||||
static bool
|
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. */
|
return (!ad->autoinc_p
|
||||||
if (ad->base_modify_p)
|
&& ad->segment == NULL
|
||||||
return false;
|
&& ad->base == ad->base_term
|
||||||
|
&& ad->disp == ad->disp_term);
|
||||||
/* 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.
|
/* Make equiv substitution in address AD. Return true if a substitution
|
||||||
Update AD and ADDR_LOC if it is necessary. Return true if a
|
was made. */
|
||||||
substitution was made. */
|
|
||||||
static bool
|
static bool
|
||||||
equiv_address_substitution (struct address *ad, rtx *addr_loc,
|
equiv_address_substitution (struct address_info *ad)
|
||||||
enum machine_mode mode, addr_space_t as,
|
|
||||||
enum rtx_code code)
|
|
||||||
{
|
{
|
||||||
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;
|
HOST_WIDE_INT disp, scale;
|
||||||
bool change_p;
|
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;
|
base_reg = new_base_reg = NULL_RTX;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
base_reg = *ad->base_reg_loc;
|
base_reg = *base_term;
|
||||||
new_base_reg = get_equiv_substitution (base_reg);
|
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;
|
index_reg = new_index_reg = NULL_RTX;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index_reg = *ad->index_reg_loc;
|
index_reg = *index_term;
|
||||||
new_index_reg = get_equiv_substitution (index_reg);
|
new_index_reg = get_equiv_substitution (index_reg);
|
||||||
}
|
}
|
||||||
if (base_reg == new_base_reg && index_reg == new_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 ",
|
fprintf (lra_dump_file, "Changing address in insn %d ",
|
||||||
INSN_UID (curr_insn));
|
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 (base_reg != new_base_reg)
|
||||||
{
|
{
|
||||||
if (REG_P (new_base_reg))
|
if (REG_P (new_base_reg))
|
||||||
{
|
{
|
||||||
*ad->base_reg_loc = new_base_reg;
|
*base_term = new_base_reg;
|
||||||
change_p = true;
|
change_p = true;
|
||||||
}
|
}
|
||||||
else if (GET_CODE (new_base_reg) == PLUS
|
else if (GET_CODE (new_base_reg) == PLUS
|
||||||
&& REG_P (XEXP (new_base_reg, 0))
|
&& 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))
|
&& can_add_disp_p (ad))
|
||||||
{
|
{
|
||||||
disp += INTVAL (XEXP (new_base_reg, 1));
|
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;
|
change_p = true;
|
||||||
}
|
}
|
||||||
if (ad->base_reg_loc2 != NULL)
|
if (ad->base_term2 != NULL)
|
||||||
*ad->base_reg_loc2 = *ad->base_reg_loc;
|
*ad->base_term2 = *ad->base_term;
|
||||||
}
|
}
|
||||||
if (index_reg != new_index_reg)
|
if (index_reg != new_index_reg)
|
||||||
{
|
{
|
||||||
if (REG_P (new_index_reg))
|
if (REG_P (new_index_reg))
|
||||||
{
|
{
|
||||||
*ad->index_reg_loc = new_index_reg;
|
*index_term = new_index_reg;
|
||||||
change_p = true;
|
change_p = true;
|
||||||
}
|
}
|
||||||
else if (GET_CODE (new_index_reg) == PLUS
|
else if (GET_CODE (new_index_reg) == PLUS
|
||||||
&& REG_P (XEXP (new_index_reg, 0))
|
&& 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)
|
&& can_add_disp_p (ad)
|
||||||
&& (scale = get_index_scale (ad)))
|
&& (scale = get_index_scale (ad)))
|
||||||
{
|
{
|
||||||
disp += INTVAL (XEXP (new_index_reg, 1)) * scale;
|
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;
|
change_p = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (disp != 0)
|
if (disp != 0)
|
||||||
{
|
{
|
||||||
if (ad->disp_loc != NULL)
|
if (ad->disp != NULL)
|
||||||
*ad->disp_loc = plus_constant (Pmode, *ad->disp_loc, disp);
|
*ad->disp = plus_constant (GET_MODE (*ad->inner), *ad->disp, disp);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*addr_loc = gen_rtx_PLUS (Pmode, *addr_loc, GEN_INT (disp));
|
*ad->inner = plus_constant (GET_MODE (*ad->inner), *ad->inner, disp);
|
||||||
extract_address_regs (mode, as, addr_loc, code, ad);
|
update_address (ad);
|
||||||
}
|
}
|
||||||
change_p = true;
|
change_p = true;
|
||||||
}
|
}
|
||||||
|
|
@ -2575,7 +2232,7 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf (lra_dump_file, " on equiv ");
|
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");
|
fprintf (lra_dump_file, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2604,62 +2261,43 @@ equiv_address_substitution (struct address *ad, rtx *addr_loc,
|
||||||
static bool
|
static bool
|
||||||
process_address (int nop, rtx *before, rtx *after)
|
process_address (int nop, rtx *before, rtx *after)
|
||||||
{
|
{
|
||||||
struct address ad;
|
struct address_info ad;
|
||||||
enum machine_mode mode;
|
rtx new_reg;
|
||||||
rtx new_reg, *addr_loc;
|
|
||||||
addr_space_t as;
|
|
||||||
rtx op = *curr_id->operand_loc[nop];
|
rtx op = *curr_id->operand_loc[nop];
|
||||||
const char *constraint = curr_static_id->operand[nop].constraint;
|
const char *constraint = curr_static_id->operand[nop].constraint;
|
||||||
bool change_p;
|
bool change_p;
|
||||||
enum rtx_code code;
|
|
||||||
|
|
||||||
if (constraint[0] == 'p'
|
if (constraint[0] == 'p'
|
||||||
|| EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint))
|
|| EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint))
|
||||||
{
|
decompose_lea_address (&ad, curr_id->operand_loc[nop]);
|
||||||
mode = VOIDmode;
|
|
||||||
addr_loc = curr_id->operand_loc[nop];
|
|
||||||
as = ADDR_SPACE_GENERIC;
|
|
||||||
code = ADDRESS;
|
|
||||||
}
|
|
||||||
else if (MEM_P (op))
|
else if (MEM_P (op))
|
||||||
{
|
decompose_mem_address (&ad, op);
|
||||||
mode = GET_MODE (op);
|
|
||||||
addr_loc = &XEXP (op, 0);
|
|
||||||
as = MEM_ADDR_SPACE (op);
|
|
||||||
code = MEM;
|
|
||||||
}
|
|
||||||
else if (GET_CODE (op) == SUBREG
|
else if (GET_CODE (op) == SUBREG
|
||||||
&& MEM_P (SUBREG_REG (op)))
|
&& MEM_P (SUBREG_REG (op)))
|
||||||
{
|
decompose_mem_address (&ad, 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;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
if (GET_CODE (*addr_loc) == AND)
|
change_p = equiv_address_substitution (&ad);
|
||||||
addr_loc = &XEXP (*addr_loc, 0);
|
if (ad.base_term != NULL
|
||||||
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
|
|
||||||
&& (process_addr_reg
|
&& (process_addr_reg
|
||||||
(ad.base_reg_loc, before,
|
(ad.base_term, before,
|
||||||
(ad.base_modify_p && REG_P (*ad.base_reg_loc)
|
(ad.autoinc_p
|
||||||
&& find_regno_note (curr_insn, REG_DEAD,
|
&& !(REG_P (*ad.base_term)
|
||||||
REGNO (*ad.base_reg_loc)) == NULL_RTX
|
&& find_regno_note (curr_insn, REG_DEAD,
|
||||||
|
REGNO (*ad.base_term)) != NULL_RTX)
|
||||||
? after : NULL),
|
? 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;
|
change_p = true;
|
||||||
if (ad.base_reg_loc2 != NULL)
|
if (ad.base_term2 != NULL)
|
||||||
*ad.base_reg_loc2 = *ad.base_reg_loc;
|
*ad.base_term2 = *ad.base_term;
|
||||||
}
|
}
|
||||||
if (ad.index_reg_loc != NULL
|
if (ad.index_term != NULL
|
||||||
&& process_addr_reg (ad.index_reg_loc, before, NULL, INDEX_REG_CLASS))
|
&& process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS))
|
||||||
change_p = true;
|
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
|
1) the original address was valid, but either elimination or
|
||||||
equiv_address_substitution applied a displacement that made
|
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.
|
3) the address is a frame address with an invalid offset.
|
||||||
|
|
||||||
All these cases involve a displacement, so there is no point
|
All these cases involve a displacement and a non-autoinc address,
|
||||||
revalidating when there is no displacement. */
|
so there is no point revalidating other types. */
|
||||||
if (ad.disp_loc == NULL || valid_address_p (&ad, mode, *addr_loc, as))
|
if (ad.disp == NULL || ad.autoinc_p || valid_address_p (&ad))
|
||||||
return change_p;
|
return change_p;
|
||||||
|
|
||||||
/* Any index existed before LRA started, so we can assume that the
|
/* Any index existed before LRA started, so we can assume that the
|
||||||
presence and shape of the index is valid. */
|
presence and shape of the index is valid. */
|
||||||
push_to_sequence (*before);
|
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;
|
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");
|
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
|
||||||
#ifdef HAVE_lo_sum
|
#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. */
|
/* disp => lo_sum (new_base, disp), case (2) above. */
|
||||||
insn = emit_insn (gen_rtx_SET
|
insn = emit_insn (gen_rtx_SET
|
||||||
(VOIDmode, new_reg,
|
(VOIDmode, new_reg,
|
||||||
gen_rtx_HIGH (Pmode, copy_rtx (*ad.disp_loc))));
|
gen_rtx_HIGH (Pmode, copy_rtx (disp))));
|
||||||
code = recog_memoized (insn);
|
code = recog_memoized (insn);
|
||||||
if (code >= 0)
|
if (code >= 0)
|
||||||
{
|
{
|
||||||
rtx save = *ad.disp_loc;
|
*ad.disp = gen_rtx_LO_SUM (Pmode, new_reg, disp);
|
||||||
|
if (! valid_address_p (ad.mode, *ad.outer, ad.as))
|
||||||
*ad.disp_loc = gen_rtx_LO_SUM (Pmode, new_reg, *ad.disp_loc);
|
|
||||||
if (! valid_address_p (mode, *ad.disp_loc, as))
|
|
||||||
{
|
{
|
||||||
*ad.disp_loc = save;
|
*ad.disp = disp;
|
||||||
code = -1;
|
code = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2714,25 +2354,25 @@ process_address (int nop, rtx *before, rtx *after)
|
||||||
if (code < 0)
|
if (code < 0)
|
||||||
{
|
{
|
||||||
/* disp => new_base, case (2) above. */
|
/* disp => new_base, case (2) above. */
|
||||||
lra_emit_move (new_reg, *ad.disp_loc);
|
lra_emit_move (new_reg, disp);
|
||||||
*ad.disp_loc = new_reg;
|
*ad.disp = new_reg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* index * scale + disp => new base + index * scale,
|
/* index * scale + disp => new base + index * scale,
|
||||||
case (1) above. */
|
case (1) above. */
|
||||||
enum reg_class cl = base_reg_class (mode, as, PLUS,
|
enum reg_class cl = base_reg_class (ad.mode, ad.as, PLUS,
|
||||||
GET_CODE (*ad.index_loc));
|
GET_CODE (*ad.index));
|
||||||
|
|
||||||
lra_assert (INDEX_REG_CLASS != NO_REGS);
|
lra_assert (INDEX_REG_CLASS != NO_REGS);
|
||||||
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
|
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "disp");
|
||||||
lra_emit_move (new_reg, *ad.disp_loc);
|
lra_emit_move (new_reg, *ad.disp);
|
||||||
*addr_loc = simplify_gen_binary (PLUS, GET_MODE (new_reg),
|
*ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
|
||||||
new_reg, *ad.index_loc);
|
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. */
|
/* base + disp => new base, cases (1) and (3) above. */
|
||||||
/* Another option would be to reload the displacement into an
|
/* 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
|
address reloads that have the same base and different
|
||||||
displacements, so reloading into an index register would
|
displacements, so reloading into an index register would
|
||||||
not necessarily be a win. */
|
not necessarily be a win. */
|
||||||
new_reg = base_plus_disp_to_reg (mode, as, &ad);
|
new_reg = base_plus_disp_to_reg (&ad);
|
||||||
*addr_loc = new_reg;
|
*ad.inner = new_reg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* base + scale * index + disp => new base + scale * index,
|
/* base + scale * index + disp => new base + scale * index,
|
||||||
case (1) above. */
|
case (1) above. */
|
||||||
new_reg = base_plus_disp_to_reg (mode, as, &ad);
|
new_reg = base_plus_disp_to_reg (&ad);
|
||||||
*addr_loc = simplify_gen_binary (PLUS, GET_MODE (new_reg),
|
*ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
|
||||||
new_reg, *ad.index_loc);
|
new_reg, *ad.index);
|
||||||
}
|
}
|
||||||
*before = get_insns ();
|
*before = get_insns ();
|
||||||
end_sequence ();
|
end_sequence ();
|
||||||
|
|
|
||||||
79
gcc/rtl.h
79
gcc/rtl.h
|
|
@ -1237,6 +1237,77 @@ costs_add_n_insns (struct full_rtx_costs *c, int n)
|
||||||
c->size += COSTS_N_INSNS (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 void init_rtlanal (void);
|
||||||
extern int rtx_cost (rtx, enum rtx_code, int, bool);
|
extern int rtx_cost (rtx, enum rtx_code, int, bool);
|
||||||
extern int address_cost (rtx, enum machine_mode, addr_space_t, 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 bool truncated_to_mode (enum machine_mode, const_rtx);
|
||||||
extern int low_bitmask_len (enum machine_mode, unsigned HOST_WIDE_INT);
|
extern int low_bitmask_len (enum machine_mode, unsigned HOST_WIDE_INT);
|
||||||
extern void split_double (rtx, rtx *, rtx *);
|
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
|
#ifndef GENERATOR_FILE
|
||||||
/* Return the cost of SET X. SPEED_P is true if optimizing for speed
|
/* Return the cost of SET X. SPEED_P is true if optimizing for speed
|
||||||
|
|
|
||||||
369
gcc/rtlanal.c
369
gcc/rtlanal.c
|
|
@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "df.h"
|
#include "df.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
|
#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
|
||||||
|
#include "addresses.h"
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static void set_of_1 (rtx, const_rtx, void *);
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue