Richard Sandiford <rdsandif...@googlemail.com> writes: > I think a cleaner way of doing it would be to have helper functions > that switch in and out of the eliminated form, storing the old form > in fields of a new structure (either separate from address_info, > or a local inheritance of it). We probably also want to have arrays > of address_infos, one for each operand, so that we don't analyse the > same address too many times during the same insn.
In the end maintaining the array of address_infos seemed like too much work. It was hard to keep it up-to-date with various other changes that can be made, including swapping commutative operands, to the point where it wasn't obvious whether it was really an optimisation or not. Here's a patch that does the first. Tested on x86_64-linux-gnu. This time I also compared the assembly output for gcc.dg, g++.dg and gcc.c-torture at -O2 on: arch64-linux-gnu arm-eabi mipsisa64-sde-elf s390x-linux-gnu powerpc64-linux-gnu x86_64-linux-gnu s390x in particular is very good at exposing problems with this code. (It caught bugs in the aborted attempt to keep an array of address_infos.) OK to install? Thanks, Richard gcc/ * lra-constraints.c (valid_address_p): Move earlier in file. (address_eliminator): New structure. (satisfies_memory_constraint_p): New function. (satisfies_address_constraint_p): Likewise. (process_alt_operands, process_address, curr_insn_transform): Use them. Index: gcc/lra-constraints.c =================================================================== --- gcc/lra-constraints.c 2014-05-17 17:49:19.071639652 +0100 +++ gcc/lra-constraints.c 2014-05-18 20:36:17.499181467 +0100 @@ -317,6 +317,118 @@ in_mem_p (int regno) return get_reg_class (regno) == NO_REGS; } +/* Return 1 if ADDR is a valid memory address for mode MODE in address + space AS, and check that each pseudo has the proper kind of hard + reg. */ +static int +valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx addr, addr_space_t as) +{ +#ifdef GO_IF_LEGITIMATE_ADDRESS + lra_assert (ADDR_SPACE_GENERIC_P (as)); + GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); + return 0; + + win: + return 1; +#else + return targetm.addr_space.legitimate_address_p (mode, addr, 0, as); +#endif +} + +namespace { + /* Temporarily eliminates registers in an address (for the lifetime of + the object). */ + class address_eliminator { + public: + address_eliminator (struct address_info *ad); + ~address_eliminator (); + + private: + struct address_info *m_ad; + rtx *m_base_loc; + rtx m_base_reg; + rtx *m_index_loc; + rtx m_index_reg; + }; +} + +address_eliminator::address_eliminator (struct address_info *ad) + : m_ad (ad), + m_base_loc (strip_subreg (ad->base_term)), + m_base_reg (NULL_RTX), + m_index_loc (strip_subreg (ad->index_term)), + m_index_reg (NULL_RTX) +{ + if (m_base_loc != NULL) + { + m_base_reg = *m_base_loc; + lra_eliminate_reg_if_possible (m_base_loc); + if (m_ad->base_term2 != NULL) + *m_ad->base_term2 = *m_ad->base_term; + } + if (m_index_loc != NULL) + { + m_index_reg = *m_index_loc; + lra_eliminate_reg_if_possible (m_index_loc); + } +} + +address_eliminator::~address_eliminator () +{ + if (m_base_loc && *m_base_loc != m_base_reg) + { + *m_base_loc = m_base_reg; + if (m_ad->base_term2 != NULL) + *m_ad->base_term2 = *m_ad->base_term; + } + if (m_index_loc && *m_index_loc != m_index_reg) + *m_index_loc = m_index_reg; +} + +/* Return true if the eliminated form of AD is a legitimate target address. */ +static bool +valid_address_p (struct address_info *ad) +{ + address_eliminator eliminator (ad); + return valid_address_p (ad->mode, *ad->outer, ad->as); +} + +#ifdef EXTRA_CONSTRAINT_STR +/* Return true if the eliminated form of memory reference OP satisfies + extra address constraint CONSTRAINT. */ +static bool +satisfies_memory_constraint_p (rtx op, const char *constraint) +{ + struct address_info ad; + + decompose_mem_address (&ad, op); + address_eliminator eliminator (&ad); + return EXTRA_CONSTRAINT_STR (op, *constraint, constraint); +} + +/* Return true if the eliminated form of address AD satisfies extra + address constraint CONSTRAINT. */ +static bool +satisfies_address_constraint_p (struct address_info *ad, + const char *constraint) +{ + address_eliminator eliminator (ad); + return EXTRA_CONSTRAINT_STR (*ad->outer, *constraint, constraint); +} + +/* Return true if the eliminated form of address OP satisfies extra + address constraint CONSTRAINT. */ +static bool +satisfies_address_constraint_p (rtx op, const char *constraint) +{ + struct address_info ad; + + decompose_lea_address (&ad, &op); + return satisfies_address_constraint_p (&ad, constraint); +} +#endif + /* Initiate equivalences for LRA. As we keep original equivalences before any elimination, we need to make copies otherwise any change in insns might change the equivalences. */ @@ -1941,7 +2053,8 @@ process_alt_operands (int only_alternati #ifdef EXTRA_CONSTRAINT_STR if (EXTRA_MEMORY_CONSTRAINT (c, p)) { - if (EXTRA_CONSTRAINT_STR (op, c, p)) + if (MEM_P (op) + && satisfies_memory_constraint_p (op, p)) win = true; else if (spilled_pseudo_p (op)) win = true; @@ -1960,7 +2073,7 @@ process_alt_operands (int only_alternati } if (EXTRA_ADDRESS_CONSTRAINT (c, p)) { - if (EXTRA_CONSTRAINT_STR (op, c, p)) + if (satisfies_address_constraint_p (op, p)) win = true; /* If we didn't already win, we can reload @@ -2576,60 +2689,6 @@ process_alt_operands (int only_alternati return ok_p; } -/* Return 1 if ADDR is a valid memory address for mode MODE in address - space AS, and check that each pseudo has the proper kind of hard - reg. */ -static int -valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, - rtx addr, addr_space_t as) -{ -#ifdef GO_IF_LEGITIMATE_ADDRESS - lra_assert (ADDR_SPACE_GENERIC_P (as)); - GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); - return 0; - - win: - return 1; -#else - return targetm.addr_space.legitimate_address_p (mode, addr, 0, as); -#endif -} - -/* Return whether address AD is valid. */ - -static bool -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; - rtx *base_term = strip_subreg (ad->base_term); - rtx *index_term = strip_subreg (ad->index_term); - if (base_term != NULL) - { - saved_base_reg = *base_term; - lra_eliminate_reg_if_possible (base_term); - if (ad->base_term2 != NULL) - *ad->base_term2 = *ad->base_term; - } - if (index_term != NULL) - { - saved_index_reg = *index_term; - lra_eliminate_reg_if_possible (index_term); - } - bool ok_p = valid_address_p (ad->mode, *ad->outer, ad->as); - if (saved_base_reg != NULL_RTX) - { - *base_term = saved_base_reg; - if (ad->base_term2 != NULL) - *ad->base_term2 = *ad->base_term; - } - if (saved_index_reg != NULL_RTX) - *index_term = saved_index_reg; - return ok_p; -} - /* Make reload base reg + disp from address AD. Return the new pseudo. */ static rtx base_plus_disp_to_reg (struct address_info *ad) @@ -2832,7 +2891,7 @@ process_address (int nop, rtx *before, r EXTRA_CONSTRAINT_STR for the validation. */ if (constraint[0] != 'p' && EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint) - && EXTRA_CONSTRAINT_STR (op, constraint[0], constraint)) + && satisfies_address_constraint_p (&ad, constraint)) return change_p; #endif @@ -3539,7 +3598,7 @@ curr_insn_transform (void) break; #ifdef EXTRA_CONSTRAINT_STR if (EXTRA_MEMORY_CONSTRAINT (c, constraint) - && EXTRA_CONSTRAINT_STR (tem, c, constraint)) + && satisfies_memory_constraint_p (tem, constraint)) break; #endif }