From: rsandifo Date: Fri, 26 Oct 2012 06:41:53 +0000 (+0000) Subject: gcc/ X-Git-Tag: upstream/4.9.2~9708 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1efe9e9de4b6cf7c1f3b32ff67387e0888afb462;p=platform%2Fupstream%2Flinaro-gcc.git 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192837 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index be75b81..9d1dd50 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,31 @@ 2012-10-26 Richard Sandiford + 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 + * lra-constraints.c (process_address): Tighten arguments to base_reg_class. Use simplify_gen_binary to generate PLUS rtxes. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c729ee6..96765fe 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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) \ diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index ffc067b..9e4d3b1 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -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 (); diff --git a/gcc/rtl.h b/gcc/rtl.h index 361669a..43a49c4 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -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 diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index a101a29..399886c 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; +}