diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2012-10-26 06:41:53 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2012-10-26 06:41:53 +0000 |
commit | 277f65de19c4bb93ee56a97d4a79b68d3d53dac5 (patch) | |
tree | 14915af2d40b8cb97045fa32be1ed0f4df090f74 /gcc/rtlanal.c | |
parent | f9d4ecd445d717e0309cec1882ab57f92c2dad6d (diff) | |
download | gcc-277f65de19c4bb93ee56a97d4a79b68d3d53dac5.tar.gz |
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
Diffstat (limited to 'gcc/rtlanal.c')
-rw-r--r-- | gcc/rtlanal.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index a101a292039..399886c1a94 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -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; +} |