diff options
author | Ben Cheng <bccheng@google.com> | 2014-03-25 22:37:19 -0700 |
---|---|---|
committer | Ben Cheng <bccheng@google.com> | 2014-03-25 22:37:19 -0700 |
commit | 1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch) | |
tree | c607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/lra-constraints.c | |
parent | 283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff) | |
download | toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2 toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip |
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/lra-constraints.c')
-rw-r--r-- | gcc-4.9/gcc/lra-constraints.c | 5909 |
1 files changed, 5909 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/lra-constraints.c b/gcc-4.9/gcc/lra-constraints.c new file mode 100644 index 000000000..ba4d489e9 --- /dev/null +++ b/gcc-4.9/gcc/lra-constraints.c @@ -0,0 +1,5909 @@ +/* Code for RTL transformations to satisfy insn constraints. + Copyright (C) 2010-2014 Free Software Foundation, Inc. + Contributed by Vladimir Makarov <vmakarov@redhat.com>. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + + +/* This file contains code for 3 passes: constraint pass, + inheritance/split pass, and pass for undoing failed inheritance and + split. + + The major goal of constraint pass is to transform RTL to satisfy + insn and address constraints by: + o choosing insn alternatives; + o generating *reload insns* (or reloads in brief) and *reload + pseudos* which will get necessary hard registers later; + o substituting pseudos with equivalent values and removing the + instructions that initialized those pseudos. + + The constraint pass has biggest and most complicated code in LRA. + There are a lot of important details like: + o reuse of input reload pseudos to simplify reload pseudo + allocations; + o some heuristics to choose insn alternative to improve the + inheritance; + o early clobbers etc. + + The pass is mimicking former reload pass in alternative choosing + because the reload pass is oriented to current machine description + model. It might be changed if the machine description model is + changed. + + There is special code for preventing all LRA and this pass cycling + in case of bugs. + + On the first iteration of the pass we process every instruction and + choose an alternative for each one. On subsequent iterations we try + to avoid reprocessing instructions if we can be sure that the old + choice is still valid. + + The inheritance/spilt pass is to transform code to achieve + ineheritance and live range splitting. It is done on backward + traversal of EBBs. + + The inheritance optimization goal is to reuse values in hard + registers. There is analogous optimization in old reload pass. The + inheritance is achieved by following transformation: + + reload_p1 <- p reload_p1 <- p + ... new_p <- reload_p1 + ... => ... + reload_p2 <- p reload_p2 <- new_p + + where p is spilled and not changed between the insns. Reload_p1 is + also called *original pseudo* and new_p is called *inheritance + pseudo*. + + The subsequent assignment pass will try to assign the same (or + another if it is not possible) hard register to new_p as to + reload_p1 or reload_p2. + + If the assignment pass fails to assign a hard register to new_p, + this file will undo the inheritance and restore the original code. + This is because implementing the above sequence with a spilled + new_p would make the code much worse. The inheritance is done in + EBB scope. The above is just a simplified example to get an idea + of the inheritance as the inheritance is also done for non-reload + insns. + + Splitting (transformation) is also done in EBB scope on the same + pass as the inheritance: + + r <- ... or ... <- r r <- ... or ... <- r + ... s <- r (new insn -- save) + ... => + ... r <- s (new insn -- restore) + ... <- r ... <- r + + The *split pseudo* s is assigned to the hard register of the + original pseudo or hard register r. + + Splitting is done: + o In EBBs with high register pressure for global pseudos (living + in at least 2 BBs) and assigned to hard registers when there + are more one reloads needing the hard registers; + o for pseudos needing save/restore code around calls. + + If the split pseudo still has the same hard register as the + original pseudo after the subsequent assignment pass or the + original pseudo was split, the opposite transformation is done on + the same pass for undoing inheritance. */ + +#undef REG_OK_STRICT + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "hard-reg-set.h" +#include "rtl.h" +#include "tm_p.h" +#include "regs.h" +#include "insn-config.h" +#include "insn-codes.h" +#include "recog.h" +#include "output.h" +#include "addresses.h" +#include "target.h" +#include "function.h" +#include "expr.h" +#include "basic-block.h" +#include "except.h" +#include "optabs.h" +#include "df.h" +#include "ira.h" +#include "rtl-error.h" +#include "lra-int.h" + +/* Value of LRA_CURR_RELOAD_NUM at the beginning of BB of the current + insn. Remember that LRA_CURR_RELOAD_NUM is the number of emitted + reload insns. */ +static int bb_reload_num; + +/* The current insn being processed and corresponding its single set + (NULL otherwise), its data (basic block, the insn data, the insn + static data, and the mode of each operand). */ +static rtx curr_insn; +static rtx curr_insn_set; +static basic_block curr_bb; +static lra_insn_recog_data_t curr_id; +static struct lra_static_insn_data *curr_static_id; +static enum machine_mode curr_operand_mode[MAX_RECOG_OPERANDS]; + + + +/* Start numbers for new registers and insns at the current constraints + pass start. */ +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 +get_try_hard_regno (int regno) +{ + int hard_regno; + enum reg_class rclass; + + if ((hard_regno = regno) >= FIRST_PSEUDO_REGISTER) + hard_regno = lra_get_regno_hard_regno (regno); + if (hard_regno >= 0) + return hard_regno; + rclass = lra_get_allocno_class (regno); + if (rclass == NO_REGS) + return -1; + return ira_class_hard_regs[rclass][0]; +} + +/* Return final hard regno (plus offset) which will be after + elimination. We do this for matching constraints because the final + hard regno could have a different class. */ +static int +get_final_hard_regno (int hard_regno, int offset) +{ + if (hard_regno < 0) + return hard_regno; + hard_regno = lra_get_elimination_hard_regno (hard_regno); + return hard_regno + offset; +} + +/* Return hard regno of X after removing subreg and making + elimination. If X is not a register or subreg of register, return + -1. For pseudo use its assignment. */ +static int +get_hard_regno (rtx x) +{ + rtx reg; + int offset, hard_regno; + + reg = x; + if (GET_CODE (x) == SUBREG) + reg = SUBREG_REG (x); + if (! REG_P (reg)) + return -1; + if ((hard_regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER) + hard_regno = lra_get_regno_hard_regno (hard_regno); + if (hard_regno < 0) + return -1; + offset = 0; + if (GET_CODE (x) == SUBREG) + offset += subreg_regno_offset (hard_regno, GET_MODE (reg), + SUBREG_BYTE (x), GET_MODE (x)); + return get_final_hard_regno (hard_regno, offset); +} + +/* If REGNO is a hard register or has been allocated a hard register, + return the class of that register. If REGNO is a reload pseudo + created by the current constraints pass, return its allocno class. + Return NO_REGS otherwise. */ +static enum reg_class +get_reg_class (int regno) +{ + int hard_regno; + + if ((hard_regno = regno) >= FIRST_PSEUDO_REGISTER) + hard_regno = lra_get_regno_hard_regno (regno); + if (hard_regno >= 0) + { + hard_regno = get_final_hard_regno (hard_regno, 0); + return REGNO_REG_CLASS (hard_regno); + } + if (regno >= new_regno_start) + return lra_get_allocno_class (regno); + return NO_REGS; +} + +/* Return true if REG satisfies (or will satisfy) reg class constraint + CL. Use elimination first if REG is a hard register. If REG is a + reload pseudo created by this constraints pass, assume that it will + be allocated a hard register from its allocno class, but allow that + class to be narrowed to CL if it is currently a superset of CL. + + If NEW_CLASS is nonnull, set *NEW_CLASS to the new allocno class of + REGNO (reg), or NO_REGS if no change in its class was needed. */ +static bool +in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class) +{ + enum reg_class rclass, common_class; + enum machine_mode reg_mode; + int class_size, hard_regno, nregs, i, j; + int regno = REGNO (reg); + + if (new_class != NULL) + *new_class = NO_REGS; + if (regno < FIRST_PSEUDO_REGISTER) + { + rtx final_reg = reg; + rtx *final_loc = &final_reg; + + lra_eliminate_reg_if_possible (final_loc); + return TEST_HARD_REG_BIT (reg_class_contents[cl], REGNO (*final_loc)); + } + reg_mode = GET_MODE (reg); + rclass = get_reg_class (regno); + if (regno < new_regno_start + /* Do not allow the constraints for reload instructions to + influence the classes of new pseudos. These reloads are + typically moves that have many alternatives, and restricting + reload pseudos for one alternative may lead to situations + where other reload pseudos are no longer allocatable. */ + || (INSN_UID (curr_insn) >= new_insn_uid_start + && curr_insn_set != NULL + && ((OBJECT_P (SET_SRC (curr_insn_set)) + && ! CONSTANT_P (SET_SRC (curr_insn_set))) + || (GET_CODE (SET_SRC (curr_insn_set)) == SUBREG + && OBJECT_P (SUBREG_REG (SET_SRC (curr_insn_set))) + && ! CONSTANT_P (SUBREG_REG (SET_SRC (curr_insn_set))))))) + /* When we don't know what class will be used finally for reload + pseudos, we use ALL_REGS. */ + return ((regno >= new_regno_start && rclass == ALL_REGS) + || (rclass != NO_REGS && ira_class_subset_p[rclass][cl] + && ! hard_reg_set_subset_p (reg_class_contents[cl], + lra_no_alloc_regs))); + else + { + common_class = ira_reg_class_subset[rclass][cl]; + if (new_class != NULL) + *new_class = common_class; + if (hard_reg_set_subset_p (reg_class_contents[common_class], + lra_no_alloc_regs)) + return false; + /* Check that there are enough allocatable regs. */ + class_size = ira_class_hard_regs_num[common_class]; + for (i = 0; i < class_size; i++) + { + hard_regno = ira_class_hard_regs[common_class][i]; + nregs = hard_regno_nregs[hard_regno][reg_mode]; + if (nregs == 1) + return true; + for (j = 0; j < nregs; j++) + if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j) + || ! TEST_HARD_REG_BIT (reg_class_contents[common_class], + hard_regno + j)) + break; + if (j >= nregs) + return true; + } + return false; + } +} + +/* Return true if REGNO satisfies a memory constraint. */ +static bool +in_mem_p (int regno) +{ + return get_reg_class (regno) == NO_REGS; +} + +/* 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. */ +void +lra_init_equiv (void) +{ + ira_expand_reg_equiv (); + for (int i = FIRST_PSEUDO_REGISTER; i < max_reg_num (); i++) + { + rtx res; + + if ((res = ira_reg_equiv[i].memory) != NULL_RTX) + ira_reg_equiv[i].memory = copy_rtx (res); + if ((res = ira_reg_equiv[i].invariant) != NULL_RTX) + ira_reg_equiv[i].invariant = copy_rtx (res); + } +} + +static rtx loc_equivalence_callback (rtx, const_rtx, void *); + +/* Update equivalence for REGNO. We need to this as the equivalence + might contain other pseudos which are changed by their + equivalences. */ +static void +update_equiv (int regno) +{ + rtx x; + + if ((x = ira_reg_equiv[regno].memory) != NULL_RTX) + ira_reg_equiv[regno].memory + = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback, + NULL_RTX); + if ((x = ira_reg_equiv[regno].invariant) != NULL_RTX) + ira_reg_equiv[regno].invariant + = simplify_replace_fn_rtx (x, NULL_RTX, loc_equivalence_callback, + NULL_RTX); +} + +/* If we have decided to substitute X with another value, return that + value, otherwise return X. */ +static rtx +get_equiv (rtx x) +{ + int regno; + rtx res; + + if (! REG_P (x) || (regno = REGNO (x)) < FIRST_PSEUDO_REGISTER + || ! ira_reg_equiv[regno].defined_p + || ! ira_reg_equiv[regno].profitable_p + || lra_get_regno_hard_regno (regno) >= 0) + return x; + if ((res = ira_reg_equiv[regno].memory) != NULL_RTX) + return res; + if ((res = ira_reg_equiv[regno].constant) != NULL_RTX) + return res; + if ((res = ira_reg_equiv[regno].invariant) != NULL_RTX) + return res; + gcc_unreachable (); +} + +/* If we have decided to substitute X with the equivalent value, + return that value after elimination for INSN, otherwise return + X. */ +static rtx +get_equiv_with_elimination (rtx x, rtx insn) +{ + rtx res = get_equiv (x); + + if (x == res || CONSTANT_P (res)) + return res; + return lra_eliminate_regs_1 (insn, res, GET_MODE (res), false, false, true); +} + +/* Set up curr_operand_mode. */ +static void +init_curr_operand_mode (void) +{ + int nop = curr_static_id->n_operands; + for (int i = 0; i < nop; i++) + { + enum machine_mode mode = GET_MODE (*curr_id->operand_loc[i]); + if (mode == VOIDmode) + { + /* The .md mode for address operands is the mode of the + addressed value rather than the mode of the address itself. */ + if (curr_id->icode >= 0 && curr_static_id->operand[i].is_address) + mode = Pmode; + else + mode = curr_static_id->operand[i].mode; + } + curr_operand_mode[i] = mode; + } +} + + + +/* The page contains code to reuse input reloads. */ + +/* Structure describes input reload of the current insns. */ +struct input_reload +{ + /* Reloaded value. */ + rtx input; + /* Reload pseudo used. */ + rtx reg; +}; + +/* The number of elements in the following array. */ +static int curr_insn_input_reloads_num; +/* Array containing info about input reloads. It is used to find the + same input reload and reuse the reload pseudo in this case. */ +static struct input_reload curr_insn_input_reloads[LRA_MAX_INSN_RELOADS]; + +/* Initiate data concerning reuse of input reloads for the current + insn. */ +static void +init_curr_insn_input_reloads (void) +{ + curr_insn_input_reloads_num = 0; +} + +/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse already + created input reload pseudo (only if TYPE is not OP_OUT). Don't + reuse pseudo if IN_SUBREG_P is true and the reused pseudo should be + wrapped up in SUBREG. The result pseudo is returned through + RESULT_REG. Return TRUE if we created a new pseudo, FALSE if we + reused the already created input reload pseudo. Use TITLE to + describe new registers for debug purposes. */ +static bool +get_reload_reg (enum op_type type, enum machine_mode mode, rtx original, + enum reg_class rclass, bool in_subreg_p, + const char *title, rtx *result_reg) +{ + int i, regno; + enum reg_class new_class; + + if (type == OP_OUT) + { + *result_reg + = lra_create_new_reg_with_unique_value (mode, original, rclass, title); + return true; + } + /* Prevent reuse value of expression with side effects, + e.g. volatile memory. */ + if (! side_effects_p (original)) + for (i = 0; i < curr_insn_input_reloads_num; i++) + if (rtx_equal_p (curr_insn_input_reloads[i].input, original) + && in_class_p (curr_insn_input_reloads[i].reg, rclass, &new_class)) + { + rtx reg = curr_insn_input_reloads[i].reg; + regno = REGNO (reg); + /* If input is equal to original and both are VOIDmode, + GET_MODE (reg) might be still different from mode. + Ensure we don't return *result_reg with wrong mode. */ + if (GET_MODE (reg) != mode) + { + if (in_subreg_p) + continue; + if (GET_MODE_SIZE (GET_MODE (reg)) < GET_MODE_SIZE (mode)) + continue; + reg = lowpart_subreg (mode, reg, GET_MODE (reg)); + if (reg == NULL_RTX || GET_CODE (reg) != SUBREG) + continue; + } + *result_reg = reg; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Reuse r%d for reload ", regno); + dump_value_slim (lra_dump_file, original, 1); + } + if (new_class != lra_get_allocno_class (regno)) + lra_change_class (regno, new_class, ", change to", false); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n"); + return false; + } + *result_reg = lra_create_new_reg (mode, original, rclass, title); + lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS); + curr_insn_input_reloads[curr_insn_input_reloads_num].input = original; + curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = *result_reg; + return true; +} + + + +/* The page contains code to extract memory address parts. */ + +/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudos. */ +static inline bool +ok_for_index_p_nonstrict (rtx reg) +{ + unsigned regno = REGNO (reg); + + return regno >= FIRST_PSEUDO_REGISTER || REGNO_OK_FOR_INDEX_P (regno); +} + +/* A version of regno_ok_for_base_p for use here, when all pseudos + should count as OK. Arguments as for regno_ok_for_base_p. */ +static inline bool +ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as, + enum rtx_code outer_code, enum rtx_code index_code) +{ + unsigned regno = REGNO (reg); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + return ok_for_base_p_1 (regno, mode, as, outer_code, index_code); +} + + + +/* The page contains major code to choose the current insn alternative + and generate reloads for it. */ + +/* Return the offset from REGNO of the least significant register + in (reg:MODE REGNO). + + This function is used to tell whether two registers satisfy + a matching constraint. (reg:MODE1 REGNO1) matches (reg:MODE2 REGNO2) if: + + REGNO1 + lra_constraint_offset (REGNO1, MODE1) + == REGNO2 + lra_constraint_offset (REGNO2, MODE2) */ +int +lra_constraint_offset (int regno, enum machine_mode mode) +{ + lra_assert (regno < FIRST_PSEUDO_REGISTER); + if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (mode) > UNITS_PER_WORD + && SCALAR_INT_MODE_P (mode)) + return hard_regno_nregs[regno][mode] - 1; + return 0; +} + +/* Like rtx_equal_p except that it allows a REG and a SUBREG to match + if they are the same hard reg, and has special hacks for + auto-increment and auto-decrement. This is specifically intended for + process_alt_operands to use in determining whether two operands + match. X is the operand whose number is the lower of the two. + + It is supposed that X is the output operand and Y is the input + operand. Y_HARD_REGNO is the final hard regno of register Y or + register in subreg Y as we know it now. Otherwise, it is a + negative value. */ +static bool +operands_match_p (rtx x, rtx y, int y_hard_regno) +{ + int i; + RTX_CODE code = GET_CODE (x); + const char *fmt; + + if (x == y) + return true; + if ((code == REG || (code == SUBREG && REG_P (SUBREG_REG (x)))) + && (REG_P (y) || (GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))))) + { + int j; + + i = get_hard_regno (x); + if (i < 0) + goto slow; + + if ((j = y_hard_regno) < 0) + goto slow; + + i += lra_constraint_offset (i, GET_MODE (x)); + j += lra_constraint_offset (j, GET_MODE (y)); + + return i == j; + } + + /* If two operands must match, because they are really a single + operand of an assembler insn, then two post-increments are invalid + because the assembler insn would increment only once. On the + other hand, a post-increment matches ordinary indexing if the + post-increment is the output operand. */ + if (code == POST_DEC || code == POST_INC || code == POST_MODIFY) + return operands_match_p (XEXP (x, 0), y, y_hard_regno); + + /* Two pre-increments are invalid because the assembler insn would + increment only once. On the other hand, a pre-increment matches + ordinary indexing if the pre-increment is the input operand. */ + if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC + || GET_CODE (y) == PRE_MODIFY) + return operands_match_p (x, XEXP (y, 0), -1); + + slow: + + if (code == REG && GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y)) + && x == SUBREG_REG (y)) + return true; + if (GET_CODE (y) == REG && code == SUBREG && REG_P (SUBREG_REG (x)) + && SUBREG_REG (x) == y) + return true; + + /* Now we have disposed of all the cases in which different rtx + codes can match. */ + if (code != GET_CODE (y)) + return false; + + /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ + if (GET_MODE (x) != GET_MODE (y)) + return false; + + switch (code) + { + CASE_CONST_UNIQUE: + return false; + + case LABEL_REF: + return XEXP (x, 0) == XEXP (y, 0); + case SYMBOL_REF: + return XSTR (x, 0) == XSTR (y, 0); + + default: + break; + } + + /* Compare the elements. If any pair of corresponding elements fail + to match, return false for the whole things. */ + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + int val, j; + switch (fmt[i]) + { + case 'w': + if (XWINT (x, i) != XWINT (y, i)) + return false; + break; + + case 'i': + if (XINT (x, i) != XINT (y, i)) + return false; + break; + + case 'e': + val = operands_match_p (XEXP (x, i), XEXP (y, i), -1); + if (val == 0) + return false; + break; + + case '0': + break; + + case 'E': + if (XVECLEN (x, i) != XVECLEN (y, i)) + return false; + for (j = XVECLEN (x, i) - 1; j >= 0; --j) + { + val = operands_match_p (XVECEXP (x, i, j), XVECEXP (y, i, j), -1); + if (val == 0) + return false; + } + break; + + /* It is believed that rtx's at this level will never + contain anything but integers and other rtx's, except for + within LABEL_REFs and SYMBOL_REFs. */ + default: + gcc_unreachable (); + } + } + return true; +} + +/* True if X is a constant that can be forced into the constant pool. + MODE is the mode of the operand, or VOIDmode if not known. */ +#define CONST_POOL_OK_P(MODE, X) \ + ((MODE) != VOIDmode \ + && CONSTANT_P (X) \ + && GET_CODE (X) != HIGH \ + && !targetm.cannot_force_const_mem (MODE, X)) + +/* True if C is a non-empty register class that has too few registers + to be safely used as a reload target class. */ +#define SMALL_REGISTER_CLASS_P(C) \ + (ira_class_hard_regs_num [(C)] == 1 \ + || (ira_class_hard_regs_num [(C)] >= 1 \ + && targetm.class_likely_spilled_p (C))) + +/* If REG is a reload pseudo, try to make its class satisfying CL. */ +static void +narrow_reload_pseudo_class (rtx reg, enum reg_class cl) +{ + enum reg_class rclass; + + /* Do not make more accurate class from reloads generated. They are + mostly moves with a lot of constraints. Making more accurate + class may results in very narrow class and impossibility of find + registers for several reloads of one insn. */ + if (INSN_UID (curr_insn) >= new_insn_uid_start) + return; + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (! REG_P (reg) || (int) REGNO (reg) < new_regno_start) + return; + if (in_class_p (reg, cl, &rclass) && rclass != cl) + lra_change_class (REGNO (reg), rclass, " Change to", true); +} + +/* Generate reloads for matching OUT and INS (array of input operand + numbers with end marker -1) with reg class GOAL_CLASS. Add input + and output reloads correspondingly to the lists *BEFORE and *AFTER. + OUT might be negative. In this case we generate input reloads for + matched input operands INS. */ +static void +match_reload (signed char out, signed char *ins, enum reg_class goal_class, + rtx *before, rtx *after) +{ + int i, in; + rtx new_in_reg, new_out_reg, reg, clobber; + enum machine_mode inmode, outmode; + rtx in_rtx = *curr_id->operand_loc[ins[0]]; + rtx out_rtx = out < 0 ? in_rtx : *curr_id->operand_loc[out]; + + inmode = curr_operand_mode[ins[0]]; + outmode = out < 0 ? inmode : curr_operand_mode[out]; + push_to_sequence (*before); + if (inmode != outmode) + { + if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode)) + { + reg = new_in_reg + = lra_create_new_reg_with_unique_value (inmode, in_rtx, + goal_class, ""); + if (SCALAR_INT_MODE_P (inmode)) + new_out_reg = gen_lowpart_SUBREG (outmode, reg); + else + new_out_reg = gen_rtx_SUBREG (outmode, reg, 0); + LRA_SUBREG_P (new_out_reg) = 1; + /* If the input reg is dying here, we can use the same hard + register for REG and IN_RTX. We do it only for original + pseudos as reload pseudos can die although original + pseudos still live where reload pseudos dies. */ + if (REG_P (in_rtx) && (int) REGNO (in_rtx) < lra_new_regno_start + && find_regno_note (curr_insn, REG_DEAD, REGNO (in_rtx))) + lra_assign_reg_val (REGNO (in_rtx), REGNO (reg)); + } + else + { + reg = new_out_reg + = lra_create_new_reg_with_unique_value (outmode, out_rtx, + goal_class, ""); + if (SCALAR_INT_MODE_P (outmode)) + new_in_reg = gen_lowpart_SUBREG (inmode, reg); + else + new_in_reg = gen_rtx_SUBREG (inmode, reg, 0); + /* NEW_IN_REG is non-paradoxical subreg. We don't want + NEW_OUT_REG living above. We add clobber clause for + this. This is just a temporary clobber. We can remove + it at the end of LRA work. */ + clobber = emit_clobber (new_out_reg); + LRA_TEMP_CLOBBER_P (PATTERN (clobber)) = 1; + LRA_SUBREG_P (new_in_reg) = 1; + if (GET_CODE (in_rtx) == SUBREG) + { + rtx subreg_reg = SUBREG_REG (in_rtx); + + /* If SUBREG_REG is dying here and sub-registers IN_RTX + and NEW_IN_REG are similar, we can use the same hard + register for REG and SUBREG_REG. */ + if (REG_P (subreg_reg) + && (int) REGNO (subreg_reg) < lra_new_regno_start + && GET_MODE (subreg_reg) == outmode + && SUBREG_BYTE (in_rtx) == SUBREG_BYTE (new_in_reg) + && find_regno_note (curr_insn, REG_DEAD, REGNO (subreg_reg))) + lra_assign_reg_val (REGNO (subreg_reg), REGNO (reg)); + } + } + } + else + { + /* Pseudos have values -- see comments for lra_reg_info. + Different pseudos with the same value do not conflict even if + they live in the same place. When we create a pseudo we + assign value of original pseudo (if any) from which we + created the new pseudo. If we create the pseudo from the + input pseudo, the new pseudo will no conflict with the input + pseudo which is wrong when the input pseudo lives after the + insn and as the new pseudo value is changed by the insn + output. Therefore we create the new pseudo from the output. + + We cannot reuse the current output register because we might + have a situation like "a <- a op b", where the constraints + force the second input operand ("b") to match the output + operand ("a"). "b" must then be copied into a new register + so that it doesn't clobber the current value of "a". */ + + new_in_reg = new_out_reg + = lra_create_new_reg_with_unique_value (outmode, out_rtx, + goal_class, ""); + } + /* In operand can be got from transformations before processing insn + constraints. One example of such transformations is subreg + reloading (see function simplify_operand_subreg). The new + pseudos created by the transformations might have inaccurate + class (ALL_REGS) and we should make their classes more + accurate. */ + narrow_reload_pseudo_class (in_rtx, goal_class); + lra_emit_move (copy_rtx (new_in_reg), in_rtx); + *before = get_insns (); + end_sequence (); + for (i = 0; (in = ins[i]) >= 0; i++) + { + lra_assert + (GET_MODE (*curr_id->operand_loc[in]) == VOIDmode + || GET_MODE (new_in_reg) == GET_MODE (*curr_id->operand_loc[in])); + *curr_id->operand_loc[in] = new_in_reg; + } + lra_update_dups (curr_id, ins); + if (out < 0) + return; + /* See a comment for the input operand above. */ + narrow_reload_pseudo_class (out_rtx, goal_class); + if (find_reg_note (curr_insn, REG_UNUSED, out_rtx) == NULL_RTX) + { + start_sequence (); + lra_emit_move (out_rtx, copy_rtx (new_out_reg)); + emit_insn (*after); + *after = get_insns (); + end_sequence (); + } + *curr_id->operand_loc[out] = new_out_reg; + lra_update_dup (curr_id, out); +} + +/* Return register class which is union of all reg classes in insn + constraint alternative string starting with P. */ +static enum reg_class +reg_class_from_constraints (const char *p) +{ + int c, len; + enum reg_class op_class = NO_REGS; + + do + switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) + { + case '#': + case ',': + return op_class; + + case 'p': + op_class = (reg_class_subunion + [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH)]); + break; + + case 'g': + case 'r': + op_class = reg_class_subunion[op_class][GENERAL_REGS]; + break; + + default: + if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) + { +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + op_class + = (reg_class_subunion + [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH)]); +#endif + break; + } + + op_class + = reg_class_subunion[op_class][REG_CLASS_FROM_CONSTRAINT (c, p)]; + break; + } + while ((p += len), c); + return op_class; +} + +/* If OP is a register, return the class of the register as per + get_reg_class, otherwise return NO_REGS. */ +static inline enum reg_class +get_op_class (rtx op) +{ + return REG_P (op) ? get_reg_class (REGNO (op)) : NO_REGS; +} + +/* Return generated insn mem_pseudo:=val if TO_P or val:=mem_pseudo + otherwise. If modes of MEM_PSEUDO and VAL are different, use + SUBREG for VAL to make them equal. */ +static rtx +emit_spill_move (bool to_p, rtx mem_pseudo, rtx val) +{ + if (GET_MODE (mem_pseudo) != GET_MODE (val)) + { + /* Usually size of mem_pseudo is greater than val size but in + rare cases it can be less as it can be defined by target + dependent macro HARD_REGNO_CALLER_SAVE_MODE. */ + if (! MEM_P (val)) + { + val = gen_rtx_SUBREG (GET_MODE (mem_pseudo), + GET_CODE (val) == SUBREG ? SUBREG_REG (val) : val, + 0); + LRA_SUBREG_P (val) = 1; + } + else + { + mem_pseudo = gen_lowpart_SUBREG (GET_MODE (val), mem_pseudo); + LRA_SUBREG_P (mem_pseudo) = 1; + } + } + return (to_p + ? gen_move_insn (mem_pseudo, val) + : gen_move_insn (val, mem_pseudo)); +} + +/* Process a special case insn (register move), return true if we + don't need to process it anymore. INSN should be a single set + insn. Set up that RTL was changed through CHANGE_P and macro + SECONDARY_MEMORY_NEEDED says to use secondary memory through + SEC_MEM_P. */ +static bool +check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED) +{ + int sregno, dregno; + rtx dest, src, dreg, sreg, old_sreg, new_reg, before, scratch_reg; + enum reg_class dclass, sclass, secondary_class; + enum machine_mode sreg_mode; + secondary_reload_info sri; + + lra_assert (curr_insn_set != NULL_RTX); + dreg = dest = SET_DEST (curr_insn_set); + sreg = src = SET_SRC (curr_insn_set); + if (GET_CODE (dest) == SUBREG) + dreg = SUBREG_REG (dest); + if (GET_CODE (src) == SUBREG) + sreg = SUBREG_REG (src); + if (! (REG_P (dreg) || MEM_P (dreg)) || ! (REG_P (sreg) || MEM_P (sreg))) + return false; + sclass = dclass = NO_REGS; + if (REG_P (dreg)) + dclass = get_reg_class (REGNO (dreg)); + if (dclass == ALL_REGS) + /* ALL_REGS is used for new pseudos created by transformations + like reload of SUBREG_REG (see function + simplify_operand_subreg). We don't know their class yet. We + should figure out the class from processing the insn + constraints not in this fast path function. Even if ALL_REGS + were a right class for the pseudo, secondary_... hooks usually + are not define for ALL_REGS. */ + return false; + sreg_mode = GET_MODE (sreg); + old_sreg = sreg; + if (REG_P (sreg)) + sclass = get_reg_class (REGNO (sreg)); + if (sclass == ALL_REGS) + /* See comments above. */ + return false; + if (sclass == NO_REGS && dclass == NO_REGS) + return false; +#ifdef SECONDARY_MEMORY_NEEDED + if (SECONDARY_MEMORY_NEEDED (sclass, dclass, GET_MODE (src)) +#ifdef SECONDARY_MEMORY_NEEDED_MODE + && ((sclass != NO_REGS && dclass != NO_REGS) + || GET_MODE (src) != SECONDARY_MEMORY_NEEDED_MODE (GET_MODE (src))) +#endif + ) + { + *sec_mem_p = true; + return false; + } +#endif + if (! REG_P (dreg) || ! REG_P (sreg)) + return false; + sri.prev_sri = NULL; + sri.icode = CODE_FOR_nothing; + sri.extra_cost = 0; + secondary_class = NO_REGS; + /* Set up hard register for a reload pseudo for hook + secondary_reload because some targets just ignore unassigned + pseudos in the hook. */ + if (dclass != NO_REGS && lra_get_regno_hard_regno (REGNO (dreg)) < 0) + { + dregno = REGNO (dreg); + reg_renumber[dregno] = ira_class_hard_regs[dclass][0]; + } + else + dregno = -1; + if (sclass != NO_REGS && lra_get_regno_hard_regno (REGNO (sreg)) < 0) + { + sregno = REGNO (sreg); + reg_renumber[sregno] = ira_class_hard_regs[sclass][0]; + } + else + sregno = -1; + if (sclass != NO_REGS) + secondary_class + = (enum reg_class) targetm.secondary_reload (false, dest, + (reg_class_t) sclass, + GET_MODE (src), &sri); + if (sclass == NO_REGS + || ((secondary_class != NO_REGS || sri.icode != CODE_FOR_nothing) + && dclass != NO_REGS)) + { + enum reg_class old_sclass = secondary_class; + secondary_reload_info old_sri = sri; + + sri.prev_sri = NULL; + sri.icode = CODE_FOR_nothing; + sri.extra_cost = 0; + secondary_class + = (enum reg_class) targetm.secondary_reload (true, sreg, + (reg_class_t) dclass, + sreg_mode, &sri); + /* Check the target hook consistency. */ + lra_assert + ((secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing) + || (old_sclass == NO_REGS && old_sri.icode == CODE_FOR_nothing) + || (secondary_class == old_sclass && sri.icode == old_sri.icode)); + } + if (sregno >= 0) + reg_renumber [sregno] = -1; + if (dregno >= 0) + reg_renumber [dregno] = -1; + if (secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing) + return false; + *change_p = true; + new_reg = NULL_RTX; + if (secondary_class != NO_REGS) + new_reg = lra_create_new_reg_with_unique_value (sreg_mode, NULL_RTX, + secondary_class, + "secondary"); + start_sequence (); + if (old_sreg != sreg) + sreg = copy_rtx (sreg); + if (sri.icode == CODE_FOR_nothing) + lra_emit_move (new_reg, sreg); + else + { + enum reg_class scratch_class; + + scratch_class = (reg_class_from_constraints + (insn_data[sri.icode].operand[2].constraint)); + scratch_reg = (lra_create_new_reg_with_unique_value + (insn_data[sri.icode].operand[2].mode, NULL_RTX, + scratch_class, "scratch")); + emit_insn (GEN_FCN (sri.icode) (new_reg != NULL_RTX ? new_reg : dest, + sreg, scratch_reg)); + } + before = get_insns (); + end_sequence (); + lra_process_new_insns (curr_insn, before, NULL_RTX, "Inserting the move"); + if (new_reg != NULL_RTX) + { + if (GET_CODE (src) == SUBREG) + SUBREG_REG (src) = new_reg; + else + SET_SRC (curr_insn_set) = new_reg; + } + else + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, "Deleting move %u\n", INSN_UID (curr_insn)); + dump_insn_slim (lra_dump_file, curr_insn); + } + lra_set_insn_deleted (curr_insn); + return true; + } + return false; +} + +/* The following data describe the result of process_alt_operands. + The data are used in curr_insn_transform to generate reloads. */ + +/* The chosen reg classes which should be used for the corresponding + operands. */ +static enum reg_class goal_alt[MAX_RECOG_OPERANDS]; +/* True if the operand should be the same as another operand and that + other operand does not need a reload. */ +static bool goal_alt_match_win[MAX_RECOG_OPERANDS]; +/* True if the operand does not need a reload. */ +static bool goal_alt_win[MAX_RECOG_OPERANDS]; +/* True if the operand can be offsetable memory. */ +static bool goal_alt_offmemok[MAX_RECOG_OPERANDS]; +/* The number of an operand to which given operand can be matched to. */ +static int goal_alt_matches[MAX_RECOG_OPERANDS]; +/* The number of elements in the following array. */ +static int goal_alt_dont_inherit_ops_num; +/* Numbers of operands whose reload pseudos should not be inherited. */ +static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; +/* True if the insn commutative operands should be swapped. */ +static bool goal_alt_swapped; +/* The chosen insn alternative. */ +static int goal_alt_number; + +/* The following five variables are used to choose the best insn + alternative. They reflect final characteristics of the best + alternative. */ + +/* Number of necessary reloads and overall cost reflecting the + previous value and other unpleasantness of the best alternative. */ +static int best_losers, best_overall; +/* Overall number hard registers used for reloads. For example, on + some targets we need 2 general registers to reload DFmode and only + one floating point register. */ +static int best_reload_nregs; +/* Overall number reflecting distances of previous reloading the same + value. The distances are counted from the current BB start. It is + used to improve inheritance chances. */ +static int best_reload_sum; + +/* True if the current insn should have no correspondingly input or + output reloads. */ +static bool no_input_reloads_p, no_output_reloads_p; + +/* True if we swapped the commutative operands in the current + insn. */ +static int curr_swapped; + +/* Arrange for address element *LOC to be a register of class CL. + Add any input reloads to list BEFORE. AFTER is nonnull if *LOC is an + automodified value; handle that case by adding the required output + reloads to list AFTER. Return true if the RTL was changed. */ +static bool +process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl) +{ + int regno; + enum reg_class rclass, new_class; + rtx reg; + rtx new_reg; + enum machine_mode mode; + bool subreg_p, before_p = false; + + subreg_p = GET_CODE (*loc) == SUBREG; + if (subreg_p) + loc = &SUBREG_REG (*loc); + reg = *loc; + mode = GET_MODE (reg); + if (! REG_P (reg)) + { + /* Always reload memory in an address even if the target supports + such addresses. */ + new_reg = lra_create_new_reg_with_unique_value (mode, reg, cl, "address"); + before_p = true; + } + else + { + regno = REGNO (reg); + rclass = get_reg_class (regno); + if ((*loc = get_equiv_with_elimination (reg, curr_insn)) != reg) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + "Changing pseudo %d in address of insn %u on equiv ", + REGNO (reg), INSN_UID (curr_insn)); + dump_value_slim (lra_dump_file, *loc, 1); + fprintf (lra_dump_file, "\n"); + } + *loc = copy_rtx (*loc); + } + if (*loc != reg || ! in_class_p (reg, cl, &new_class)) + { + reg = *loc; + if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT, + mode, reg, cl, subreg_p, "address", &new_reg)) + before_p = true; + } + else if (new_class != NO_REGS && rclass != new_class) + { + lra_change_class (regno, new_class, " Change to", true); + return false; + } + else + return false; + } + if (before_p) + { + push_to_sequence (*before); + lra_emit_move (new_reg, reg); + *before = get_insns (); + end_sequence (); + } + *loc = new_reg; + if (after != NULL) + { + start_sequence (); + lra_emit_move (reg, new_reg); + emit_insn (*after); + *after = get_insns (); + end_sequence (); + } + return true; +} + +/* Insert move insn in simplify_operand_subreg. BEFORE returns + the insn to be inserted before curr insn. AFTER returns the + the insn to be inserted after curr insn. ORIGREG and NEWREG + are the original reg and new reg for reload. */ +static void +insert_move_for_subreg (rtx *before, rtx *after, rtx origreg, rtx newreg) +{ + if (before) + { + push_to_sequence (*before); + lra_emit_move (newreg, origreg); + *before = get_insns (); + end_sequence (); + } + if (after) + { + start_sequence (); + lra_emit_move (origreg, newreg); + emit_insn (*after); + *after = get_insns (); + end_sequence (); + } +} + +/* Make reloads for subreg in operand NOP with internal subreg mode + REG_MODE, add new reloads for further processing. Return true if + any reload was generated. */ +static bool +simplify_operand_subreg (int nop, enum machine_mode reg_mode) +{ + int hard_regno; + rtx before, after; + enum machine_mode mode; + rtx reg, new_reg; + rtx operand = *curr_id->operand_loc[nop]; + enum reg_class regclass; + enum op_type type; + + before = after = NULL_RTX; + + if (GET_CODE (operand) != SUBREG) + return false; + + mode = GET_MODE (operand); + reg = SUBREG_REG (operand); + type = curr_static_id->operand[nop].type; + /* If we change address for paradoxical subreg of memory, the + address might violate the necessary alignment or the access might + be slow. So take this into consideration. We should not worry + about access beyond allocated memory for paradoxical memory + subregs as we don't substitute such equiv memory (see processing + equivalences in function lra_constraints) and because for spilled + pseudos we allocate stack memory enough for the biggest + corresponding paradoxical subreg. */ + if ((MEM_P (reg) + && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (reg)) + || MEM_ALIGN (reg) >= GET_MODE_ALIGNMENT (mode))) + || (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)) + { + alter_subreg (curr_id->operand_loc[nop], false); + return true; + } + /* Put constant into memory when we have mixed modes. It generates + a better code in most cases as it does not need a secondary + reload memory. It also prevents LRA looping when LRA is using + secondary reload memory again and again. */ + if (CONSTANT_P (reg) && CONST_POOL_OK_P (reg_mode, reg) + && SCALAR_INT_MODE_P (reg_mode) != SCALAR_INT_MODE_P (mode)) + { + SUBREG_REG (operand) = force_const_mem (reg_mode, reg); + alter_subreg (curr_id->operand_loc[nop], false); + return true; + } + /* Force a reload of the SUBREG_REG if this is a constant or PLUS or + if there may be a problem accessing OPERAND in the outer + mode. */ + if ((REG_P (reg) + && REGNO (reg) >= FIRST_PSEUDO_REGISTER + && (hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0 + /* Don't reload paradoxical subregs because we could be looping + having repeatedly final regno out of hard regs range. */ + && (hard_regno_nregs[hard_regno][GET_MODE (reg)] + >= hard_regno_nregs[hard_regno][mode]) + && simplify_subreg_regno (hard_regno, GET_MODE (reg), + SUBREG_BYTE (operand), mode) < 0 + /* Don't reload subreg for matching reload. It is actually + valid subreg in LRA. */ + && ! LRA_SUBREG_P (operand)) + || CONSTANT_P (reg) || GET_CODE (reg) == PLUS || MEM_P (reg)) + { + enum reg_class rclass; + + if (REG_P (reg)) + /* There is a big probability that we will get the same class + for the new pseudo and we will get the same insn which + means infinite looping. So spill the new pseudo. */ + rclass = NO_REGS; + else + /* The class will be defined later in curr_insn_transform. */ + rclass + = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); + + if (get_reload_reg (curr_static_id->operand[nop].type, reg_mode, reg, + rclass, TRUE, "subreg reg", &new_reg)) + { + bool insert_before, insert_after; + bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg)); + + insert_before = (type != OP_OUT + || GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode)); + insert_after = (type != OP_IN); + insert_move_for_subreg (insert_before ? &before : NULL, + insert_after ? &after : NULL, + reg, new_reg); + } + SUBREG_REG (operand) = new_reg; + lra_process_new_insns (curr_insn, before, after, + "Inserting subreg reload"); + return true; + } + /* Force a reload for a paradoxical subreg. For paradoxical subreg, + IRA allocates hardreg to the inner pseudo reg according to its mode + instead of the outermode, so the size of the hardreg may not be enough + to contain the outermode operand, in that case we may need to insert + reload for the reg. For the following two types of paradoxical subreg, + we need to insert reload: + 1. If the op_type is OP_IN, and the hardreg could not be paired with + other hardreg to contain the outermode operand + (checked by in_hard_reg_set_p), we need to insert the reload. + 2. If the op_type is OP_OUT or OP_INOUT. + + Here is a paradoxical subreg example showing how the reload is generated: + + (insn 5 4 7 2 (set (reg:TI 106 [ __comp ]) + (subreg:TI (reg:DI 107 [ __comp ]) 0)) {*movti_internal_rex64} + + In IRA, reg107 is allocated to a DImode hardreg. We use x86-64 as example + here, if reg107 is assigned to hardreg R15, because R15 is the last + hardreg, compiler cannot find another hardreg to pair with R15 to + contain TImode data. So we insert a TImode reload reg180 for it. + After reload is inserted: + + (insn 283 0 0 (set (subreg:DI (reg:TI 180 [orig:107 __comp ] [107]) 0) + (reg:DI 107 [ __comp ])) -1 + (insn 5 4 7 2 (set (reg:TI 106 [ __comp ]) + (subreg:TI (reg:TI 180 [orig:107 __comp ] [107]) 0)) {*movti_internal_rex64} + + Two reload hard registers will be allocated to reg180 to save TImode data + in LRA_assign. */ + else if (REG_P (reg) + && REGNO (reg) >= FIRST_PSEUDO_REGISTER + && (hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0 + && (hard_regno_nregs[hard_regno][GET_MODE (reg)] + < hard_regno_nregs[hard_regno][mode]) + && (regclass = lra_get_allocno_class (REGNO (reg))) + && (type != OP_IN + || !in_hard_reg_set_p (reg_class_contents[regclass], + mode, hard_regno))) + { + /* The class will be defined later in curr_insn_transform. */ + enum reg_class rclass + = (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS); + + if (get_reload_reg (curr_static_id->operand[nop].type, mode, reg, + rclass, TRUE, "paradoxical subreg", &new_reg)) + { + rtx subreg; + bool insert_before, insert_after; + + PUT_MODE (new_reg, mode); + subreg = simplify_gen_subreg (GET_MODE (reg), new_reg, mode, 0); + bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg)); + + insert_before = (type != OP_OUT); + insert_after = (type != OP_IN); + insert_move_for_subreg (insert_before ? &before : NULL, + insert_after ? &after : NULL, + reg, subreg); + } + SUBREG_REG (operand) = new_reg; + lra_process_new_insns (curr_insn, before, after, + "Inserting paradoxical subreg reload"); + return true; + } + return false; +} + +/* Return TRUE if X refers for a hard register from SET. */ +static bool +uses_hard_regs_p (rtx x, HARD_REG_SET set) +{ + int i, j, x_hard_regno; + enum machine_mode mode; + const char *fmt; + enum rtx_code code; + + if (x == NULL_RTX) + return false; + code = GET_CODE (x); + mode = GET_MODE (x); + if (code == SUBREG) + { + x = SUBREG_REG (x); + code = GET_CODE (x); + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode)) + mode = GET_MODE (x); + } + + if (REG_P (x)) + { + x_hard_regno = get_hard_regno (x); + return (x_hard_regno >= 0 + && overlaps_hard_reg_set_p (set, mode, x_hard_regno)); + } + if (MEM_P (x)) + { + struct address_info ad; + + 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--) + { + if (fmt[i] == 'e') + { + if (uses_hard_regs_p (XEXP (x, i), set)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (uses_hard_regs_p (XVECEXP (x, i, j), set)) + return true; + } + } + return false; +} + +/* Return true if OP is a spilled pseudo. */ +static inline bool +spilled_pseudo_p (rtx op) +{ + return (REG_P (op) + && REGNO (op) >= FIRST_PSEUDO_REGISTER && in_mem_p (REGNO (op))); +} + +/* Return true if X is a general constant. */ +static inline bool +general_constant_p (rtx x) +{ + return CONSTANT_P (x) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (x)); +} + +static bool +reg_in_class_p (rtx reg, enum reg_class cl) +{ + if (cl == NO_REGS) + return get_reg_class (REGNO (reg)) == NO_REGS; + return in_class_p (reg, cl, NULL); +} + +/* Major function to choose the current insn alternative and what + operands should be reloaded and how. If ONLY_ALTERNATIVE is not + negative we should consider only this alternative. Return false if + we can not choose the alternative or find how to reload the + operands. */ +static bool +process_alt_operands (int only_alternative) +{ + bool ok_p = false; + int nop, overall, nalt; + int n_alternatives = curr_static_id->n_alternatives; + int n_operands = curr_static_id->n_operands; + /* LOSERS counts the operands that don't fit this alternative and + would require loading. */ + int losers; + /* REJECT is a count of how undesirable this alternative says it is + if any reloading is required. If the alternative matches exactly + then REJECT is ignored, but otherwise it gets this much counted + against it in addition to the reloading needed. */ + int reject; + /* The number of elements in the following array. */ + int early_clobbered_regs_num; + /* Numbers of operands which are early clobber registers. */ + int early_clobbered_nops[MAX_RECOG_OPERANDS]; + enum reg_class curr_alt[MAX_RECOG_OPERANDS]; + HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS]; + bool curr_alt_match_win[MAX_RECOG_OPERANDS]; + bool curr_alt_win[MAX_RECOG_OPERANDS]; + bool curr_alt_offmemok[MAX_RECOG_OPERANDS]; + int curr_alt_matches[MAX_RECOG_OPERANDS]; + /* The number of elements in the following array. */ + int curr_alt_dont_inherit_ops_num; + /* Numbers of operands whose reload pseudos should not be inherited. */ + int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS]; + rtx op; + /* The register when the operand is a subreg of register, otherwise the + operand itself. */ + rtx no_subreg_reg_operand[MAX_RECOG_OPERANDS]; + /* The register if the operand is a register or subreg of register, + otherwise NULL. */ + rtx operand_reg[MAX_RECOG_OPERANDS]; + int hard_regno[MAX_RECOG_OPERANDS]; + enum machine_mode biggest_mode[MAX_RECOG_OPERANDS]; + int reload_nregs, reload_sum; + bool costly_p; + enum reg_class cl; + + /* Calculate some data common for all alternatives to speed up the + function. */ + for (nop = 0; nop < n_operands; nop++) + { + rtx reg; + + op = no_subreg_reg_operand[nop] = *curr_id->operand_loc[nop]; + /* The real hard regno of the operand after the allocation. */ + hard_regno[nop] = get_hard_regno (op); + + operand_reg[nop] = reg = op; + biggest_mode[nop] = GET_MODE (op); + if (GET_CODE (op) == SUBREG) + { + operand_reg[nop] = reg = SUBREG_REG (op); + if (GET_MODE_SIZE (biggest_mode[nop]) + < GET_MODE_SIZE (GET_MODE (reg))) + biggest_mode[nop] = GET_MODE (reg); + } + if (! REG_P (reg)) + operand_reg[nop] = NULL_RTX; + else if (REGNO (reg) >= FIRST_PSEUDO_REGISTER + || ((int) REGNO (reg) + == lra_get_elimination_hard_regno (REGNO (reg)))) + no_subreg_reg_operand[nop] = reg; + else + operand_reg[nop] = no_subreg_reg_operand[nop] + /* Just use natural mode for elimination result. It should + be enough for extra constraints hooks. */ + = regno_reg_rtx[hard_regno[nop]]; + } + + /* The constraints are made of several alternatives. Each operand's + constraint looks like foo,bar,... with commas separating the + alternatives. The first alternatives for all operands go + together, the second alternatives go together, etc. + + First loop over alternatives. */ + for (nalt = 0; nalt < n_alternatives; nalt++) + { + /* Loop over operands for one constraint alternative. */ +#if HAVE_ATTR_enabled + if (curr_id->alternative_enabled_p != NULL + && ! curr_id->alternative_enabled_p[nalt]) + continue; +#endif + + if (only_alternative >= 0 && nalt != only_alternative) + continue; + + + overall = losers = reject = reload_nregs = reload_sum = 0; + for (nop = 0; nop < n_operands; nop++) + { + int inc = (curr_static_id + ->operand_alternative[nalt * n_operands + nop].reject); + if (lra_dump_file != NULL && inc != 0) + fprintf (lra_dump_file, + " Staticly defined alt reject+=%d\n", inc); + reject += inc; + } + early_clobbered_regs_num = 0; + + for (nop = 0; nop < n_operands; nop++) + { + const char *p; + char *end; + int len, c, m, i, opalt_num, this_alternative_matches; + bool win, did_match, offmemok, early_clobber_p; + /* false => this operand can be reloaded somehow for this + alternative. */ + bool badop; + /* true => this operand can be reloaded if the alternative + allows regs. */ + bool winreg; + /* True if a constant forced into memory would be OK for + this operand. */ + bool constmemok; + enum reg_class this_alternative, this_costly_alternative; + HARD_REG_SET this_alternative_set, this_costly_alternative_set; + bool this_alternative_match_win, this_alternative_win; + bool this_alternative_offmemok; + bool scratch_p; + enum machine_mode mode; + + opalt_num = nalt * n_operands + nop; + if (curr_static_id->operand_alternative[opalt_num].anything_ok) + { + /* Fast track for no constraints at all. */ + curr_alt[nop] = NO_REGS; + CLEAR_HARD_REG_SET (curr_alt_set[nop]); + curr_alt_win[nop] = true; + curr_alt_match_win[nop] = false; + curr_alt_offmemok[nop] = false; + curr_alt_matches[nop] = -1; + continue; + } + + op = no_subreg_reg_operand[nop]; + mode = curr_operand_mode[nop]; + + win = did_match = winreg = offmemok = constmemok = false; + badop = true; + + early_clobber_p = false; + p = curr_static_id->operand_alternative[opalt_num].constraint; + + this_costly_alternative = this_alternative = NO_REGS; + /* We update set of possible hard regs besides its class + because reg class might be inaccurate. For example, + union of LO_REGS (l), HI_REGS(h), and STACK_REG(k) in ARM + is translated in HI_REGS because classes are merged by + pairs and there is no accurate intermediate class. */ + CLEAR_HARD_REG_SET (this_alternative_set); + CLEAR_HARD_REG_SET (this_costly_alternative_set); + this_alternative_win = false; + this_alternative_match_win = false; + this_alternative_offmemok = false; + this_alternative_matches = -1; + + /* An empty constraint should be excluded by the fast + track. */ + lra_assert (*p != 0 && *p != ','); + + /* Scan this alternative's specs for this operand; set WIN + if the operand fits any letter in this alternative. + Otherwise, clear BADOP if this operand could fit some + letter after reloads, or set WINREG if this operand could + fit after reloads provided the constraint allows some + registers. */ + costly_p = false; + do + { + switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c) + { + case '\0': + len = 0; + break; + case ',': + c = '\0'; + break; + + case '=': case '+': case '?': case '*': case '!': + case ' ': case '\t': + break; + + case '%': + /* We only support one commutative marker, the first + one. We already set commutative above. */ + break; + + case '&': + early_clobber_p = true; + break; + + case '#': + /* Ignore rest of this alternative. */ + c = '\0'; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int m_hregno; + bool match_p; + + m = strtoul (p, &end, 10); + p = end; + len = 0; + lra_assert (nop > m); + + this_alternative_matches = m; + m_hregno = get_hard_regno (*curr_id->operand_loc[m]); + /* We are supposed to match a previous operand. + If we do, we win if that one did. If we do + not, count both of the operands as losers. + (This is too conservative, since most of the + time only a single reload insn will be needed + to make the two operands win. As a result, + this alternative may be rejected when it is + actually desirable.) */ + match_p = false; + if (operands_match_p (*curr_id->operand_loc[nop], + *curr_id->operand_loc[m], m_hregno)) + { + /* We should reject matching of an early + clobber operand if the matching operand is + not dying in the insn. */ + if (! curr_static_id->operand[m].early_clobber + || operand_reg[nop] == NULL_RTX + || (find_regno_note (curr_insn, REG_DEAD, + REGNO (op)) + || REGNO (op) == REGNO (operand_reg[m]))) + match_p = true; + } + if (match_p) + { + /* If we are matching a non-offsettable + address where an offsettable address was + expected, then we must reject this + combination, because we can't reload + it. */ + if (curr_alt_offmemok[m] + && MEM_P (*curr_id->operand_loc[m]) + && curr_alt[m] == NO_REGS && ! curr_alt_win[m]) + continue; + } + else + { + /* Operands don't match. Both operands must + allow a reload register, otherwise we + cannot make them match. */ + if (curr_alt[m] == NO_REGS) + break; + /* Retroactively mark the operand we had to + match as a loser, if it wasn't already and + it wasn't matched to a register constraint + (e.g it might be matched by memory). */ + if (curr_alt_win[m] + && (operand_reg[m] == NULL_RTX + || hard_regno[m] < 0)) + { + losers++; + reload_nregs + += (ira_reg_class_max_nregs[curr_alt[m]] + [GET_MODE (*curr_id->operand_loc[m])]); + } + + /* We prefer no matching alternatives because + it gives more freedom in RA. */ + if (operand_reg[nop] == NULL_RTX + || (find_regno_note (curr_insn, REG_DEAD, + REGNO (operand_reg[nop])) + == NULL_RTX)) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Matching alt: reject+=2\n", + nop); + reject += 2; + } + } + /* If we have to reload this operand and some + previous operand also had to match the same + thing as this operand, we don't know how to do + that. */ + if (!match_p || !curr_alt_win[m]) + { + for (i = 0; i < nop; i++) + if (curr_alt_matches[i] == m) + break; + if (i < nop) + break; + } + else + did_match = true; + + /* This can be fixed with reloads if the operand + we are supposed to match can be fixed with + reloads. */ + badop = false; + this_alternative = curr_alt[m]; + COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]); + winreg = this_alternative != NO_REGS; + break; + } + + case 'p': + cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH); + this_alternative = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + win = true; + badop = false; + break; + + case TARGET_MEM_CONSTRAINT: + if (MEM_P (op) || spilled_pseudo_p (op)) + win = true; + /* We can put constant or pseudo value into memory + to satisfy the constraint. */ + if (CONST_POOL_OK_P (mode, op) || REG_P (op)) + badop = false; + constmemok = true; + break; + + case '<': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_DEC + || GET_CODE (XEXP (op, 0)) == POST_DEC)) + win = true; + break; + + case '>': + if (MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_INC + || GET_CODE (XEXP (op, 0)) == POST_INC)) + win = true; + break; + + /* Memory op whose address is not offsettable. */ + case 'V': + if (MEM_P (op) + && ! offsettable_nonstrict_memref_p (op)) + win = true; + break; + + /* Memory operand whose address is offsettable. */ + case 'o': + if ((MEM_P (op) + && offsettable_nonstrict_memref_p (op)) + || spilled_pseudo_p (op)) + win = true; + /* We can put constant or pseudo value into memory + or make memory address offsetable to satisfy the + constraint. */ + if (CONST_POOL_OK_P (mode, op) || MEM_P (op) || REG_P (op)) + badop = false; + constmemok = true; + offmemok = true; + break; + + case 'E': + case 'F': + if (GET_CODE (op) == CONST_DOUBLE + || (GET_CODE (op) == CONST_VECTOR + && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT))) + win = true; + break; + + case 'G': + case 'H': + if (CONST_DOUBLE_AS_FLOAT_P (op) + && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) + win = true; + break; + + case 's': + if (CONST_SCALAR_INT_P (op)) + break; + + case 'i': + if (general_constant_p (op)) + win = true; + break; + + case 'n': + if (CONST_SCALAR_INT_P (op)) + win = true; + break; + + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + if (CONST_INT_P (op) + && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) + win = true; + break; + + case 'X': + /* This constraint should be excluded by the fast + track. */ + gcc_unreachable (); + break; + + case 'g': + if (MEM_P (op) + || general_constant_p (op) + || spilled_pseudo_p (op)) + win = true; + /* Drop through into 'r' case. */ + + case 'r': + this_alternative + = reg_class_subunion[this_alternative][GENERAL_REGS]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[GENERAL_REGS]); + if (costly_p) + { + this_costly_alternative + = (reg_class_subunion + [this_costly_alternative][GENERAL_REGS]); + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[GENERAL_REGS]); + } + goto reg; + + default: + if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS) + { +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_MEMORY_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + else if (spilled_pseudo_p (op)) + win = true; + + /* If we didn't already win, we can reload + constants via force_const_mem or put the + pseudo value into memory, or make other + memory by reloading the address like for + 'o'. */ + if (CONST_POOL_OK_P (mode, op) + || MEM_P (op) || REG_P (op)) + badop = false; + constmemok = true; + offmemok = true; + break; + } + if (EXTRA_ADDRESS_CONSTRAINT (c, p)) + { + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; + + /* If we didn't already win, we can reload + the address into a base register. */ + cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, + ADDRESS, SCRATCH); + this_alternative + = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = (reg_class_subunion + [this_costly_alternative][cl]); + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + badop = false; + break; + } + + if (EXTRA_CONSTRAINT_STR (op, c, p)) + win = true; +#endif + break; + } + + cl = REG_CLASS_FROM_CONSTRAINT (c, p); + this_alternative = reg_class_subunion[this_alternative][cl]; + IOR_HARD_REG_SET (this_alternative_set, + reg_class_contents[cl]); + if (costly_p) + { + this_costly_alternative + = reg_class_subunion[this_costly_alternative][cl]; + IOR_HARD_REG_SET (this_costly_alternative_set, + reg_class_contents[cl]); + } + reg: + if (mode == BLKmode) + break; + winreg = true; + if (REG_P (op)) + { + if (hard_regno[nop] >= 0 + && in_hard_reg_set_p (this_alternative_set, + mode, hard_regno[nop])) + win = true; + else if (hard_regno[nop] < 0 + && in_class_p (op, this_alternative, NULL)) + win = true; + } + break; + } + if (c != ' ' && c != '\t') + costly_p = c == '*'; + } + while ((p += len), c); + + scratch_p = (operand_reg[nop] != NULL_RTX + && lra_former_scratch_p (REGNO (operand_reg[nop]))); + /* Record which operands fit this alternative. */ + if (win) + { + this_alternative_win = true; + if (operand_reg[nop] != NULL_RTX) + { + if (hard_regno[nop] >= 0) + { + if (in_hard_reg_set_p (this_costly_alternative_set, + mode, hard_regno[nop])) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " %d Costly set: reject++\n", + nop); + reject++; + } + } + else + { + /* Prefer won reg to spilled pseudo under other + equal conditions for possibe inheritance. */ + if (! scratch_p) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Non pseudo reload: reject++\n", + nop); + reject++; + } + if (in_class_p (operand_reg[nop], + this_costly_alternative, NULL)) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Non pseudo costly reload:" + " reject++\n", + nop); + reject++; + } + } + /* We simulate the behaviour of old reload here. + Although scratches need hard registers and it + might result in spilling other pseudos, no reload + insns are generated for the scratches. So it + might cost something but probably less than old + reload pass believes. */ + if (scratch_p) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " %d Scratch win: reject+=2\n", + nop); + reject += 2; + } + } + } + else if (did_match) + this_alternative_match_win = true; + else + { + int const_to_mem = 0; + bool no_regs_p; + + /* Never do output reload of stack pointer. It makes + impossible to do elimination when SP is changed in + RTL. */ + if (op == stack_pointer_rtx && ! frame_pointer_needed + && curr_static_id->operand[nop].type != OP_IN) + goto fail; + + /* If this alternative asks for a specific reg class, see if there + is at least one allocatable register in that class. */ + no_regs_p + = (this_alternative == NO_REGS + || (hard_reg_set_subset_p + (reg_class_contents[this_alternative], + lra_no_alloc_regs))); + + /* For asms, verify that the class for this alternative is possible + for the mode that is specified. */ + if (!no_regs_p && INSN_CODE (curr_insn) < 0) + { + int i; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (HARD_REGNO_MODE_OK (i, mode) + && in_hard_reg_set_p (reg_class_contents[this_alternative], + mode, i)) + break; + if (i == FIRST_PSEUDO_REGISTER) + winreg = false; + } + + /* If this operand accepts a register, and if the + register class has at least one allocatable register, + then this operand can be reloaded. */ + if (winreg && !no_regs_p) + badop = false; + + if (badop) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " alt=%d: Bad operand -- refuse\n", + nalt); + goto fail; + } + + /* If not assigned pseudo has a class which a subset of + required reg class, it is a less costly alternative + as the pseudo still can get a hard reg of necessary + class. */ + if (! no_regs_p && REG_P (op) && hard_regno[nop] < 0 + && (cl = get_reg_class (REGNO (op))) != NO_REGS + && ira_class_subset_p[this_alternative][cl]) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Super set class reg: reject-=3\n", nop); + reject -= 3; + } + + this_alternative_offmemok = offmemok; + if (this_costly_alternative != NO_REGS) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " %d Costly loser: reject++\n", nop); + reject++; + } + /* If the operand is dying, has a matching constraint, + and satisfies constraints of the matched operand + which failed to satisfy the own constraints, probably + the reload for this operand will be gone. */ + if (this_alternative_matches >= 0 + && !curr_alt_win[this_alternative_matches] + && REG_P (op) + && find_regno_note (curr_insn, REG_DEAD, REGNO (op)) + && (hard_regno[nop] >= 0 + ? in_hard_reg_set_p (this_alternative_set, + mode, hard_regno[nop]) + : in_class_p (op, this_alternative, NULL))) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Dying matched operand reload: reject++\n", + nop); + reject++; + } + else + { + /* Strict_low_part requires to reload the register + not the sub-register. In this case we should + check that a final reload hard reg can hold the + value mode. */ + if (curr_static_id->operand[nop].strict_low + && REG_P (op) + && hard_regno[nop] < 0 + && GET_CODE (*curr_id->operand_loc[nop]) == SUBREG + && ira_class_hard_regs_num[this_alternative] > 0 + && ! HARD_REGNO_MODE_OK (ira_class_hard_regs + [this_alternative][0], + GET_MODE + (*curr_id->operand_loc[nop]))) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " alt=%d: Strict low subreg reload -- refuse\n", + nalt); + goto fail; + } + losers++; + } + if (operand_reg[nop] != NULL_RTX + /* Output operands and matched input operands are + not inherited. The following conditions do not + exactly describe the previous statement but they + are pretty close. */ + && curr_static_id->operand[nop].type != OP_OUT + && (this_alternative_matches < 0 + || curr_static_id->operand[nop].type != OP_IN)) + { + int last_reload = (lra_reg_info[ORIGINAL_REGNO + (operand_reg[nop])] + .last_reload); + + /* The value of reload_sum has sense only if we + process insns in their order. It happens only on + the first constraints sub-pass when we do most of + reload work. */ + if (lra_constraint_iter == 1 && last_reload > bb_reload_num) + reload_sum += last_reload - bb_reload_num; + } + /* If this is a constant that is reloaded into the + desired class by copying it to memory first, count + that as another reload. This is consistent with + other code and is required to avoid choosing another + alternative when the constant is moved into memory. + Note that the test here is precisely the same as in + the code below that calls force_const_mem. */ + if (CONST_POOL_OK_P (mode, op) + && ((targetm.preferred_reload_class + (op, this_alternative) == NO_REGS) + || no_input_reloads_p)) + { + const_to_mem = 1; + if (! no_regs_p) + losers++; + } + + /* Alternative loses if it requires a type of reload not + permitted for this insn. We can always reload + objects with a REG_UNUSED note. */ + if ((curr_static_id->operand[nop].type != OP_IN + && no_output_reloads_p + && ! find_reg_note (curr_insn, REG_UNUSED, op)) + || (curr_static_id->operand[nop].type != OP_OUT + && no_input_reloads_p && ! const_to_mem) + || (this_alternative_matches >= 0 + && (no_input_reloads_p + || (no_output_reloads_p + && (curr_static_id->operand + [this_alternative_matches].type != OP_IN) + && ! find_reg_note (curr_insn, REG_UNUSED, + no_subreg_reg_operand + [this_alternative_matches]))))) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " alt=%d: No input/otput reload -- refuse\n", + nalt); + goto fail; + } + + /* Check strong discouragement of reload of non-constant + into class THIS_ALTERNATIVE. */ + if (! CONSTANT_P (op) && ! no_regs_p + && (targetm.preferred_reload_class + (op, this_alternative) == NO_REGS + || (curr_static_id->operand[nop].type == OP_OUT + && (targetm.preferred_output_reload_class + (op, this_alternative) == NO_REGS)))) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " %d Non-prefered reload: reject+=%d\n", + nop, LRA_MAX_REJECT); + reject += LRA_MAX_REJECT; + } + + if (! (MEM_P (op) && offmemok) + && ! (const_to_mem && constmemok)) + { + /* We prefer to reload pseudos over reloading other + things, since such reloads may be able to be + eliminated later. So bump REJECT in other cases. + Don't do this in the case where we are forcing a + constant into memory and it will then win since + we don't want to have a different alternative + match then. */ + if (! (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Non-pseudo reload: reject+=2\n", + nop); + reject += 2; + } + + if (! no_regs_p) + reload_nregs + += ira_reg_class_max_nregs[this_alternative][mode]; + + if (SMALL_REGISTER_CLASS_P (this_alternative)) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Small class reload: reject+=%d\n", + nop, LRA_LOSER_COST_FACTOR / 2); + reject += LRA_LOSER_COST_FACTOR / 2; + } + } + + /* We are trying to spill pseudo into memory. It is + usually more costly than moving to a hard register + although it might takes the same number of + reloads. */ + if (no_regs_p && REG_P (op) && hard_regno[nop] >= 0) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Spill pseudo into memory: reject+=3\n", + nop); + reject += 3; + if (VECTOR_MODE_P (mode)) + { + /* Spilling vectors into memory is usually more + costly as they contain big values. */ + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Spill vector pseudo: reject+=2\n", + nop); + reject += 2; + } + } + +#ifdef SECONDARY_MEMORY_NEEDED + /* If reload requires moving value through secondary + memory, it will need one more insn at least. */ + if (this_alternative != NO_REGS + && REG_P (op) && (cl = get_reg_class (REGNO (op))) != NO_REGS + && ((curr_static_id->operand[nop].type != OP_OUT + && SECONDARY_MEMORY_NEEDED (cl, this_alternative, + GET_MODE (op))) + || (curr_static_id->operand[nop].type != OP_IN + && SECONDARY_MEMORY_NEEDED (this_alternative, cl, + GET_MODE (op))))) + losers++; +#endif + /* Input reloads can be inherited more often than output + reloads can be removed, so penalize output + reloads. */ + if (!REG_P (op) || curr_static_id->operand[nop].type != OP_IN) + { + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Non input pseudo reload: reject++\n", + nop); + reject++; + } + } + + if (early_clobber_p && ! scratch_p) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " %d Early clobber: reject++\n", nop); + reject++; + } + /* ??? We check early clobbers after processing all operands + (see loop below) and there we update the costs more. + Should we update the cost (may be approximately) here + because of early clobber register reloads or it is a rare + or non-important thing to be worth to do it. */ + overall = losers * LRA_LOSER_COST_FACTOR + reject; + if ((best_losers == 0 || losers != 0) && best_overall < overall) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " alt=%d,overall=%d,losers=%d -- refuse\n", + nalt, overall, losers); + goto fail; + } + + curr_alt[nop] = this_alternative; + COPY_HARD_REG_SET (curr_alt_set[nop], this_alternative_set); + curr_alt_win[nop] = this_alternative_win; + curr_alt_match_win[nop] = this_alternative_match_win; + curr_alt_offmemok[nop] = this_alternative_offmemok; + curr_alt_matches[nop] = this_alternative_matches; + + if (this_alternative_matches >= 0 + && !did_match && !this_alternative_win) + curr_alt_win[this_alternative_matches] = false; + + if (early_clobber_p && operand_reg[nop] != NULL_RTX) + early_clobbered_nops[early_clobbered_regs_num++] = nop; + } + if (curr_insn_set != NULL_RTX && n_operands == 2 + /* Prevent processing non-move insns. */ + && (GET_CODE (SET_SRC (curr_insn_set)) == SUBREG + || SET_SRC (curr_insn_set) == no_subreg_reg_operand[1]) + && ((! curr_alt_win[0] && ! curr_alt_win[1] + && REG_P (no_subreg_reg_operand[0]) + && REG_P (no_subreg_reg_operand[1]) + && (reg_in_class_p (no_subreg_reg_operand[0], curr_alt[1]) + || reg_in_class_p (no_subreg_reg_operand[1], curr_alt[0]))) + || (! curr_alt_win[0] && curr_alt_win[1] + && REG_P (no_subreg_reg_operand[1]) + && reg_in_class_p (no_subreg_reg_operand[1], curr_alt[0])) + || (curr_alt_win[0] && ! curr_alt_win[1] + && REG_P (no_subreg_reg_operand[0]) + && reg_in_class_p (no_subreg_reg_operand[0], curr_alt[1]) + && (! CONST_POOL_OK_P (curr_operand_mode[1], + no_subreg_reg_operand[1]) + || (targetm.preferred_reload_class + (no_subreg_reg_operand[1], + (enum reg_class) curr_alt[1]) != NO_REGS)) + /* If it is a result of recent elimination in move + insn we can transform it into an add still by + using this alternative. */ + && GET_CODE (no_subreg_reg_operand[1]) != PLUS))) + { + /* We have a move insn and a new reload insn will be similar + to the current insn. We should avoid such situation as it + results in LRA cycling. */ + overall += LRA_MAX_REJECT; + } + ok_p = true; + curr_alt_dont_inherit_ops_num = 0; + for (nop = 0; nop < early_clobbered_regs_num; nop++) + { + int i, j, clobbered_hard_regno, first_conflict_j, last_conflict_j; + HARD_REG_SET temp_set; + + i = early_clobbered_nops[nop]; + if ((! curr_alt_win[i] && ! curr_alt_match_win[i]) + || hard_regno[i] < 0) + continue; + lra_assert (operand_reg[i] != NULL_RTX); + clobbered_hard_regno = hard_regno[i]; + CLEAR_HARD_REG_SET (temp_set); + add_to_hard_reg_set (&temp_set, biggest_mode[i], clobbered_hard_regno); + first_conflict_j = last_conflict_j = -1; + for (j = 0; j < n_operands; j++) + if (j == i + /* We don't want process insides of match_operator and + match_parallel because otherwise we would process + their operands once again generating a wrong + code. */ + || curr_static_id->operand[j].is_operator) + continue; + else if ((curr_alt_matches[j] == i && curr_alt_match_win[j]) + || (curr_alt_matches[i] == j && curr_alt_match_win[i])) + continue; + /* If we don't reload j-th operand, check conflicts. */ + else if ((curr_alt_win[j] || curr_alt_match_win[j]) + && uses_hard_regs_p (*curr_id->operand_loc[j], temp_set)) + { + if (first_conflict_j < 0) + first_conflict_j = j; + last_conflict_j = j; + } + if (last_conflict_j < 0) + continue; + /* If earlyclobber operand conflicts with another + non-matching operand which is actually the same register + as the earlyclobber operand, it is better to reload the + another operand as an operand matching the earlyclobber + operand can be also the same. */ + if (first_conflict_j == last_conflict_j + && operand_reg[last_conflict_j] + != NULL_RTX && ! curr_alt_match_win[last_conflict_j] + && REGNO (operand_reg[i]) == REGNO (operand_reg[last_conflict_j])) + { + curr_alt_win[last_conflict_j] = false; + curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] + = last_conflict_j; + losers++; + /* Early clobber was already reflected in REJECT. */ + lra_assert (reject > 0); + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Conflict early clobber reload: reject--\n", + i); + reject--; + overall += LRA_LOSER_COST_FACTOR - 1; + } + else + { + /* We need to reload early clobbered register and the + matched registers. */ + for (j = 0; j < n_operands; j++) + if (curr_alt_matches[j] == i) + { + curr_alt_match_win[j] = false; + losers++; + overall += LRA_LOSER_COST_FACTOR; + } + if (! curr_alt_match_win[i]) + curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i; + else + { + /* Remember pseudos used for match reloads are never + inherited. */ + lra_assert (curr_alt_matches[i] >= 0); + curr_alt_win[curr_alt_matches[i]] = false; + } + curr_alt_win[i] = curr_alt_match_win[i] = false; + losers++; + /* Early clobber was already reflected in REJECT. */ + lra_assert (reject > 0); + if (lra_dump_file != NULL) + fprintf + (lra_dump_file, + " %d Matched conflict early clobber reloads:" + "reject--\n", + i); + reject--; + overall += LRA_LOSER_COST_FACTOR - 1; + } + } + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " alt=%d,overall=%d,losers=%d,rld_nregs=%d\n", + nalt, overall, losers, reload_nregs); + + /* If this alternative can be made to work by reloading, and it + needs less reloading than the others checked so far, record + it as the chosen goal for reloading. */ + if ((best_losers != 0 && losers == 0) + || (((best_losers == 0 && losers == 0) + || (best_losers != 0 && losers != 0)) + && (best_overall > overall + || (best_overall == overall + /* If the cost of the reloads is the same, + prefer alternative which requires minimal + number of reload regs. */ + && (reload_nregs < best_reload_nregs + || (reload_nregs == best_reload_nregs + && (best_reload_sum < reload_sum + || (best_reload_sum == reload_sum + && nalt < goal_alt_number)))))))) + { + for (nop = 0; nop < n_operands; nop++) + { + goal_alt_win[nop] = curr_alt_win[nop]; + goal_alt_match_win[nop] = curr_alt_match_win[nop]; + goal_alt_matches[nop] = curr_alt_matches[nop]; + goal_alt[nop] = curr_alt[nop]; + goal_alt_offmemok[nop] = curr_alt_offmemok[nop]; + } + goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num; + for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++) + goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop]; + goal_alt_swapped = curr_swapped; + best_overall = overall; + best_losers = losers; + best_reload_nregs = reload_nregs; + best_reload_sum = reload_sum; + goal_alt_number = nalt; + } + if (losers == 0) + /* Everything is satisfied. Do not process alternatives + anymore. */ + break; + fail: + ; + } + 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) +{ + enum reg_class cl; + rtx new_reg; + + 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 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_info *ad) +{ + return (!ad->autoinc_p + && ad->segment == NULL + && ad->base == ad->base_term + && ad->disp == ad->disp_term); +} + +/* Make equiv substitution in address AD. Return true if a substitution + was made. */ +static bool +equiv_address_substitution (struct address_info *ad) +{ + rtx base_reg, new_base_reg, index_reg, new_index_reg, *base_term, *index_term; + HOST_WIDE_INT disp, scale; + bool change_p; + + base_term = strip_subreg (ad->base_term); + if (base_term == NULL) + base_reg = new_base_reg = NULL_RTX; + else + { + base_reg = *base_term; + new_base_reg = get_equiv_with_elimination (base_reg, curr_insn); + } + index_term = strip_subreg (ad->index_term); + if (index_term == NULL) + index_reg = new_index_reg = NULL_RTX; + else + { + index_reg = *index_term; + new_index_reg = get_equiv_with_elimination (index_reg, curr_insn); + } + if (base_reg == new_base_reg && index_reg == new_index_reg) + return false; + disp = 0; + change_p = false; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, "Changing address in insn %d ", + INSN_UID (curr_insn)); + dump_value_slim (lra_dump_file, *ad->outer, 1); + } + if (base_reg != new_base_reg) + { + if (REG_P (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)) + { + disp += INTVAL (XEXP (new_base_reg, 1)); + *base_term = XEXP (new_base_reg, 0); + change_p = true; + } + if (ad->base_term2 != NULL) + *ad->base_term2 = *ad->base_term; + } + if (index_reg != new_index_reg) + { + if (REG_P (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) + && (scale = get_index_scale (ad))) + { + disp += INTVAL (XEXP (new_index_reg, 1)) * scale; + *index_term = XEXP (new_index_reg, 0); + change_p = true; + } + } + if (disp != 0) + { + if (ad->disp != NULL) + *ad->disp = plus_constant (GET_MODE (*ad->inner), *ad->disp, disp); + else + { + *ad->inner = plus_constant (GET_MODE (*ad->inner), *ad->inner, disp); + update_address (ad); + } + change_p = true; + } + if (lra_dump_file != NULL) + { + if (! change_p) + fprintf (lra_dump_file, " -- no change\n"); + else + { + fprintf (lra_dump_file, " on equiv "); + dump_value_slim (lra_dump_file, *ad->outer, 1); + fprintf (lra_dump_file, "\n"); + } + } + return change_p; +} + +/* Major function to make reloads for an address in operand NOP. + The supported cases are: + + 1) an address that existed before LRA started, at which point it + must have been valid. These addresses are subject to elimination + and may have become invalid due to the elimination offset being out + of range. + + 2) an address created by forcing a constant to memory + (force_const_to_mem). The initial form of these addresses might + not be valid, and it is this function's job to make them valid. + + 3) a frame address formed from a register and a (possibly zero) + constant offset. As above, these addresses might not be valid and + this function must make them so. + + Add reloads to the lists *BEFORE and *AFTER. We might need to add + reloads to *AFTER because of inc/dec, {pre, post} modify in the + address. Return true for any RTL change. */ +static bool +process_address (int nop, rtx *before, rtx *after) +{ + 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; + + if (constraint[0] == 'p' + || EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint)) + decompose_lea_address (&ad, curr_id->operand_loc[nop]); + else if (MEM_P (op)) + decompose_mem_address (&ad, op); + else if (GET_CODE (op) == SUBREG + && MEM_P (SUBREG_REG (op))) + decompose_mem_address (&ad, SUBREG_REG (op)); + else + return false; + change_p = equiv_address_substitution (&ad); + if (ad.base_term != NULL + && (process_addr_reg + (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 (ad.mode, ad.as, ad.base_outer_code, + get_index_code (&ad))))) + { + change_p = true; + if (ad.base_term2 != NULL) + *ad.base_term2 = *ad.base_term; + } + if (ad.index_term != NULL + && process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS)) + change_p = true; + +#ifdef EXTRA_CONSTRAINT_STR + /* Target hooks sometimes reject extra constraint addresses -- use + EXTRA_CONSTRAINT_STR for the validation. */ + if (constraint[0] != 'p' + && EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint) + && EXTRA_CONSTRAINT_STR (op, constraint[0], constraint)) + return change_p; +#endif + + /* 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 was applied and that made + the address invalid. + + 2) the address is an invalid symbolic address created by + force_const_to_mem. + + 3) the address is a frame address with an invalid offset. + + All these cases involve a non-autoinc address, so there is no + point revalidating other types. */ + if (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); + lra_assert (ad.disp == ad.disp_term); + if (ad.base == NULL) + { + if (ad.index == NULL) + { + int code = -1; + enum reg_class cl = base_reg_class (ad.mode, ad.as, + SCRATCH, SCRATCH); + rtx addr = *ad.inner; + + new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "addr"); +#ifdef HAVE_lo_sum + { + rtx insn; + rtx last = get_last_insn (); + + /* addr => lo_sum (new_base, addr), case (2) above. */ + insn = emit_insn (gen_rtx_SET + (VOIDmode, new_reg, + gen_rtx_HIGH (Pmode, copy_rtx (addr)))); + code = recog_memoized (insn); + if (code >= 0) + { + *ad.inner = gen_rtx_LO_SUM (Pmode, new_reg, addr); + if (! valid_address_p (ad.mode, *ad.outer, ad.as)) + { + /* Try to put lo_sum into register. */ + insn = emit_insn (gen_rtx_SET + (VOIDmode, new_reg, + gen_rtx_LO_SUM (Pmode, new_reg, addr))); + code = recog_memoized (insn); + if (code >= 0) + { + *ad.inner = new_reg; + if (! valid_address_p (ad.mode, *ad.outer, ad.as)) + { + *ad.inner = addr; + code = -1; + } + } + + } + } + if (code < 0) + delete_insns_since (last); + } +#endif + if (code < 0) + { + /* addr => new_base, case (2) above. */ + lra_emit_move (new_reg, addr); + *ad.inner = new_reg; + } + } + else + { + /* index * scale + disp => new base + index * scale, + case (1) above. */ + 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); + *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg), + new_reg, *ad.index); + } + } + else if (ad.index == NULL) + { + int regno; + enum reg_class cl; + rtx set, insns, last_insn; + /* base + disp => new base, cases (1) and (3) above. */ + /* Another option would be to reload the displacement into an + index register. However, postreload has code to optimize + address reloads that have the same base and different + displacements, so reloading into an index register would + not necessarily be a win. */ + start_sequence (); + new_reg = base_plus_disp_to_reg (&ad); + insns = get_insns (); + last_insn = get_last_insn (); + /* If we generated at least two insns, try last insn source as + an address. If we succeed, we generate one less insn. */ + if (last_insn != insns && (set = single_set (last_insn)) != NULL_RTX + && GET_CODE (SET_SRC (set)) == PLUS + && REG_P (XEXP (SET_SRC (set), 0)) + && CONSTANT_P (XEXP (SET_SRC (set), 1))) + { + *ad.inner = SET_SRC (set); + if (valid_address_p (ad.mode, *ad.outer, ad.as)) + { + *ad.base_term = XEXP (SET_SRC (set), 0); + *ad.disp_term = XEXP (SET_SRC (set), 1); + cl = base_reg_class (ad.mode, ad.as, ad.base_outer_code, + get_index_code (&ad)); + regno = REGNO (*ad.base_term); + if (regno >= FIRST_PSEUDO_REGISTER + && cl != lra_get_allocno_class (regno)) + lra_change_class (regno, cl, " Change to", true); + new_reg = SET_SRC (set); + delete_insns_since (PREV_INSN (last_insn)); + } + } + end_sequence (); + emit_insn (insns); + *ad.inner = new_reg; + } + else + { + /* base + scale * index + disp => new base + scale * index, + case (1) above. */ + 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 (); + return true; +} + +/* Emit insns to reload VALUE into a new register. VALUE is an + auto-increment or auto-decrement RTX whose operand is a register or + memory location; so reloading involves incrementing that location. + IN is either identical to VALUE, or some cheaper place to reload + value being incremented/decremented from. + + INC_AMOUNT is the number to increment or decrement by (always + positive and ignored for POST_MODIFY/PRE_MODIFY). + + Return pseudo containing the result. */ +static rtx +emit_inc (enum reg_class new_rclass, rtx in, rtx value, int inc_amount) +{ + /* REG or MEM to be copied and incremented. */ + rtx incloc = XEXP (value, 0); + /* Nonzero if increment after copying. */ + int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC + || GET_CODE (value) == POST_MODIFY); + rtx last; + rtx inc; + rtx add_insn; + int code; + rtx real_in = in == value ? incloc : in; + rtx result; + bool plus_p = true; + + if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY) + { + lra_assert (GET_CODE (XEXP (value, 1)) == PLUS + || GET_CODE (XEXP (value, 1)) == MINUS); + lra_assert (rtx_equal_p (XEXP (XEXP (value, 1), 0), XEXP (value, 0))); + plus_p = GET_CODE (XEXP (value, 1)) == PLUS; + inc = XEXP (XEXP (value, 1), 1); + } + else + { + if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC) + inc_amount = -inc_amount; + + inc = GEN_INT (inc_amount); + } + + if (! post && REG_P (incloc)) + result = incloc; + else + result = lra_create_new_reg (GET_MODE (value), value, new_rclass, + "INC/DEC result"); + + if (real_in != result) + { + /* First copy the location to the result register. */ + lra_assert (REG_P (result)); + emit_insn (gen_move_insn (result, real_in)); + } + + /* We suppose that there are insns to add/sub with the constant + increment permitted in {PRE/POST)_{DEC/INC/MODIFY}. At least the + old reload worked with this assumption. If the assumption + becomes wrong, we should use approach in function + base_plus_disp_to_reg. */ + if (in == value) + { + /* See if we can directly increment INCLOC. */ + last = get_last_insn (); + add_insn = emit_insn (plus_p + ? gen_add2_insn (incloc, inc) + : gen_sub2_insn (incloc, inc)); + + code = recog_memoized (add_insn); + if (code >= 0) + { + if (! post && result != incloc) + emit_insn (gen_move_insn (result, incloc)); + return result; + } + delete_insns_since (last); + } + + /* If couldn't do the increment directly, must increment in RESULT. + The way we do this depends on whether this is pre- or + post-increment. For pre-increment, copy INCLOC to the reload + register, increment it there, then save back. */ + if (! post) + { + if (real_in != result) + emit_insn (gen_move_insn (result, real_in)); + if (plus_p) + emit_insn (gen_add2_insn (result, inc)); + else + emit_insn (gen_sub2_insn (result, inc)); + if (result != incloc) + emit_insn (gen_move_insn (incloc, result)); + } + else + { + /* Post-increment. + + Because this might be a jump insn or a compare, and because + RESULT may not be available after the insn in an input + reload, we must do the incrementing before the insn being + reloaded for. + + We have already copied IN to RESULT. Increment the copy in + RESULT, save that back, then decrement RESULT so it has + the original value. */ + if (plus_p) + emit_insn (gen_add2_insn (result, inc)); + else + emit_insn (gen_sub2_insn (result, inc)); + emit_insn (gen_move_insn (incloc, result)); + /* Restore non-modified value for the result. We prefer this + way because it does not require an additional hard + register. */ + if (plus_p) + { + if (CONST_INT_P (inc)) + emit_insn (gen_add2_insn (result, + gen_int_mode (-INTVAL (inc), + GET_MODE (result)))); + else + emit_insn (gen_sub2_insn (result, inc)); + } + else + emit_insn (gen_add2_insn (result, inc)); + } + return result; +} + +/* Return true if the current move insn does not need processing as we + already know that it satisfies its constraints. */ +static bool +simple_move_p (void) +{ + rtx dest, src; + enum reg_class dclass, sclass; + + lra_assert (curr_insn_set != NULL_RTX); + dest = SET_DEST (curr_insn_set); + src = SET_SRC (curr_insn_set); + return ((dclass = get_op_class (dest)) != NO_REGS + && (sclass = get_op_class (src)) != NO_REGS + /* The backend guarantees that register moves of cost 2 + never need reloads. */ + && targetm.register_move_cost (GET_MODE (src), dclass, sclass) == 2); + } + +/* Swap operands NOP and NOP + 1. */ +static inline void +swap_operands (int nop) +{ + enum machine_mode mode = curr_operand_mode[nop]; + curr_operand_mode[nop] = curr_operand_mode[nop + 1]; + curr_operand_mode[nop + 1] = mode; + rtx x = *curr_id->operand_loc[nop]; + *curr_id->operand_loc[nop] = *curr_id->operand_loc[nop + 1]; + *curr_id->operand_loc[nop + 1] = x; + /* Swap the duplicates too. */ + lra_update_dup (curr_id, nop); + lra_update_dup (curr_id, nop + 1); +} + +/* Main entry point of the constraint code: search the body of the + current insn to choose the best alternative. It is mimicking insn + alternative cost calculation model of former reload pass. That is + because machine descriptions were written to use this model. This + model can be changed in future. Make commutative operand exchange + if it is chosen. + + Return true if some RTL changes happened during function call. */ +static bool +curr_insn_transform (void) +{ + int i, j, k; + int n_operands; + int n_alternatives; + int commutative; + signed char goal_alt_matched[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS]; + signed char match_inputs[MAX_RECOG_OPERANDS + 1]; + rtx before, after; + bool alt_p = false; + /* Flag that the insn has been changed through a transformation. */ + bool change_p; + bool sec_mem_p; +#ifdef SECONDARY_MEMORY_NEEDED + bool use_sec_mem_p; +#endif + int max_regno_before; + int reused_alternative_num; + + curr_insn_set = single_set (curr_insn); + if (curr_insn_set != NULL_RTX && simple_move_p ()) + return false; + + no_input_reloads_p = no_output_reloads_p = false; + goal_alt_number = -1; + change_p = sec_mem_p = false; + /* JUMP_INSNs and CALL_INSNs are not allowed to have any output + reloads; neither are insns that SET cc0. Insns that use CC0 are + not allowed to have any input reloads. */ + if (JUMP_P (curr_insn) || CALL_P (curr_insn)) + no_output_reloads_p = true; + +#ifdef HAVE_cc0 + if (reg_referenced_p (cc0_rtx, PATTERN (curr_insn))) + no_input_reloads_p = true; + if (reg_set_p (cc0_rtx, PATTERN (curr_insn))) + no_output_reloads_p = true; +#endif + + n_operands = curr_static_id->n_operands; + n_alternatives = curr_static_id->n_alternatives; + + /* Just return "no reloads" if insn has no operands with + constraints. */ + if (n_operands == 0 || n_alternatives == 0) + return false; + + max_regno_before = max_reg_num (); + + for (i = 0; i < n_operands; i++) + { + goal_alt_matched[i][0] = -1; + goal_alt_matches[i] = -1; + } + + commutative = curr_static_id->commutative; + + /* Now see what we need for pseudos that didn't get hard regs or got + the wrong kind of hard reg. For this, we must consider all the + operands together against the register constraints. */ + + best_losers = best_overall = INT_MAX; + best_reload_sum = 0; + + curr_swapped = false; + goal_alt_swapped = false; + + /* Make equivalence substitution and memory subreg elimination + before address processing because an address legitimacy can + depend on memory mode. */ + for (i = 0; i < n_operands; i++) + { + rtx op = *curr_id->operand_loc[i]; + rtx subst, old = op; + bool op_change_p = false; + + if (GET_CODE (old) == SUBREG) + old = SUBREG_REG (old); + subst = get_equiv_with_elimination (old, curr_insn); + if (subst != old) + { + subst = copy_rtx (subst); + lra_assert (REG_P (old)); + if (GET_CODE (op) == SUBREG) + SUBREG_REG (op) = subst; + else + *curr_id->operand_loc[i] = subst; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + "Changing pseudo %d in operand %i of insn %u on equiv ", + REGNO (old), i, INSN_UID (curr_insn)); + dump_value_slim (lra_dump_file, subst, 1); + fprintf (lra_dump_file, "\n"); + } + op_change_p = change_p = true; + } + if (simplify_operand_subreg (i, GET_MODE (old)) || op_change_p) + { + change_p = true; + lra_update_dup (curr_id, i); + } + } + + /* Reload address registers and displacements. We do it before + finding an alternative because of memory constraints. */ + before = after = NULL_RTX; + for (i = 0; i < n_operands; i++) + if (! curr_static_id->operand[i].is_operator + && process_address (i, &before, &after)) + { + change_p = true; + lra_update_dup (curr_id, i); + } + + if (change_p) + /* If we've changed the instruction then any alternative that + we chose previously may no longer be valid. */ + lra_set_used_insn_alternative (curr_insn, -1); + + if (curr_insn_set != NULL_RTX + && check_and_process_move (&change_p, &sec_mem_p)) + return change_p; + + try_swapped: + + reused_alternative_num = curr_id->used_insn_alternative; + if (lra_dump_file != NULL && reused_alternative_num >= 0) + fprintf (lra_dump_file, "Reusing alternative %d for insn #%u\n", + reused_alternative_num, INSN_UID (curr_insn)); + + if (process_alt_operands (reused_alternative_num)) + alt_p = true; + + /* If insn is commutative (it's safe to exchange a certain pair of + operands) then we need to try each alternative twice, the second + time matching those two operands as if we had exchanged them. To + do this, really exchange them in operands. + + If we have just tried the alternatives the second time, return + operands to normal and drop through. */ + + if (reused_alternative_num < 0 && commutative >= 0) + { + curr_swapped = !curr_swapped; + if (curr_swapped) + { + swap_operands (commutative); + goto try_swapped; + } + else + swap_operands (commutative); + } + + if (! alt_p && ! sec_mem_p) + { + /* No alternative works with reloads?? */ + if (INSN_CODE (curr_insn) >= 0) + fatal_insn ("unable to generate reloads for:", curr_insn); + error_for_asm (curr_insn, + "inconsistent operand constraints in an %<asm%>"); + /* Avoid further trouble with this insn. */ + PATTERN (curr_insn) = gen_rtx_USE (VOIDmode, const0_rtx); + lra_invalidate_insn_data (curr_insn); + return true; + } + + /* If the best alternative is with operands 1 and 2 swapped, swap + them. Update the operand numbers of any reloads already + pushed. */ + + if (goal_alt_swapped) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Commutative operand exchange in insn %u\n", + INSN_UID (curr_insn)); + + /* Swap the duplicates too. */ + swap_operands (commutative); + change_p = true; + } + +#ifdef SECONDARY_MEMORY_NEEDED + /* Some target macros SECONDARY_MEMORY_NEEDED (e.g. x86) are defined + too conservatively. So we use the secondary memory only if there + is no any alternative without reloads. */ + use_sec_mem_p = false; + if (! alt_p) + use_sec_mem_p = true; + else if (sec_mem_p) + { + for (i = 0; i < n_operands; i++) + if (! goal_alt_win[i] && ! goal_alt_match_win[i]) + break; + use_sec_mem_p = i < n_operands; + } + + if (use_sec_mem_p) + { + rtx new_reg, src, dest, rld; + enum machine_mode sec_mode, rld_mode; + + lra_assert (sec_mem_p); + lra_assert (curr_static_id->operand[0].type == OP_OUT + && curr_static_id->operand[1].type == OP_IN); + dest = *curr_id->operand_loc[0]; + src = *curr_id->operand_loc[1]; + rld = (GET_MODE_SIZE (GET_MODE (dest)) <= GET_MODE_SIZE (GET_MODE (src)) + ? dest : src); + rld_mode = GET_MODE (rld); +#ifdef SECONDARY_MEMORY_NEEDED_MODE + sec_mode = SECONDARY_MEMORY_NEEDED_MODE (rld_mode); +#else + sec_mode = rld_mode; +#endif + new_reg = lra_create_new_reg (sec_mode, NULL_RTX, + NO_REGS, "secondary"); + /* If the mode is changed, it should be wider. */ + lra_assert (GET_MODE_SIZE (sec_mode) >= GET_MODE_SIZE (rld_mode)); + if (sec_mode != rld_mode) + { + /* If the target says specifically to use another mode for + secondary memory moves we can not reuse the original + insn. */ + after = emit_spill_move (false, new_reg, dest); + lra_process_new_insns (curr_insn, NULL_RTX, after, + "Inserting the sec. move"); + /* We may have non null BEFORE here (e.g. after address + processing. */ + push_to_sequence (before); + before = emit_spill_move (true, new_reg, src); + emit_insn (before); + before = get_insns (); + end_sequence (); + lra_process_new_insns (curr_insn, before, NULL_RTX, "Changing on"); + lra_set_insn_deleted (curr_insn); + } + else if (dest == rld) + { + *curr_id->operand_loc[0] = new_reg; + after = emit_spill_move (false, new_reg, dest); + lra_process_new_insns (curr_insn, NULL_RTX, after, + "Inserting the sec. move"); + } + else + { + *curr_id->operand_loc[1] = new_reg; + /* See comments above. */ + push_to_sequence (before); + before = emit_spill_move (true, new_reg, src); + emit_insn (before); + before = get_insns (); + end_sequence (); + lra_process_new_insns (curr_insn, before, NULL_RTX, + "Inserting the sec. move"); + } + lra_update_insn_regno_info (curr_insn); + return true; + } +#endif + + lra_assert (goal_alt_number >= 0); + lra_set_used_insn_alternative (curr_insn, goal_alt_number); + + if (lra_dump_file != NULL) + { + const char *p; + + fprintf (lra_dump_file, " Choosing alt %d in insn %u:", + goal_alt_number, INSN_UID (curr_insn)); + for (i = 0; i < n_operands; i++) + { + p = (curr_static_id->operand_alternative + [goal_alt_number * n_operands + i].constraint); + if (*p == '\0') + continue; + fprintf (lra_dump_file, " (%d) ", i); + for (; *p != '\0' && *p != ',' && *p != '#'; p++) + fputc (*p, lra_dump_file); + } + if (INSN_CODE (curr_insn) >= 0 + && (p = get_insn_name (INSN_CODE (curr_insn))) != NULL) + fprintf (lra_dump_file, " {%s}", p); + if (curr_id->sp_offset != 0) + fprintf (lra_dump_file, " (sp_off=%" HOST_WIDE_INT_PRINT "d)", + curr_id->sp_offset); + fprintf (lra_dump_file, "\n"); + } + + /* Right now, for any pair of operands I and J that are required to + match, with J < I, goal_alt_matches[I] is J. Add I to + goal_alt_matched[J]. */ + + for (i = 0; i < n_operands; i++) + if ((j = goal_alt_matches[i]) >= 0) + { + for (k = 0; goal_alt_matched[j][k] >= 0; k++) + ; + /* We allow matching one output operand and several input + operands. */ + lra_assert (k == 0 + || (curr_static_id->operand[j].type == OP_OUT + && curr_static_id->operand[i].type == OP_IN + && (curr_static_id->operand + [goal_alt_matched[j][0]].type == OP_IN))); + goal_alt_matched[j][k] = i; + goal_alt_matched[j][k + 1] = -1; + } + + for (i = 0; i < n_operands; i++) + goal_alt_win[i] |= goal_alt_match_win[i]; + + /* Any constants that aren't allowed and can't be reloaded into + registers are here changed into memory references. */ + for (i = 0; i < n_operands; i++) + if (goal_alt_win[i]) + { + int regno; + enum reg_class new_class; + rtx reg = *curr_id->operand_loc[i]; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + + if (REG_P (reg) && (regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER) + { + bool ok_p = in_class_p (reg, goal_alt[i], &new_class); + + if (new_class != NO_REGS && get_reg_class (regno) != new_class) + { + lra_assert (ok_p); + lra_change_class (regno, new_class, " Change to", true); + } + } + } + else + { + const char *constraint; + char c; + rtx op = *curr_id->operand_loc[i]; + rtx subreg = NULL_RTX; + enum machine_mode mode = curr_operand_mode[i]; + + if (GET_CODE (op) == SUBREG) + { + subreg = op; + op = SUBREG_REG (op); + mode = GET_MODE (op); + } + + if (CONST_POOL_OK_P (mode, op) + && ((targetm.preferred_reload_class + (op, (enum reg_class) goal_alt[i]) == NO_REGS) + || no_input_reloads_p)) + { + rtx tem = force_const_mem (mode, op); + + change_p = true; + if (subreg != NULL_RTX) + tem = gen_rtx_SUBREG (mode, tem, SUBREG_BYTE (subreg)); + + *curr_id->operand_loc[i] = tem; + lra_update_dup (curr_id, i); + process_address (i, &before, &after); + + /* If the alternative accepts constant pool refs directly + there will be no reload needed at all. */ + if (subreg != NULL_RTX) + continue; + /* Skip alternatives before the one requested. */ + constraint = (curr_static_id->operand_alternative + [goal_alt_number * n_operands + i].constraint); + for (; + (c = *constraint) && c != ',' && c != '#'; + constraint += CONSTRAINT_LEN (c, constraint)) + { + if (c == TARGET_MEM_CONSTRAINT || c == 'o') + break; +#ifdef EXTRA_CONSTRAINT_STR + if (EXTRA_MEMORY_CONSTRAINT (c, constraint) + && EXTRA_CONSTRAINT_STR (tem, c, constraint)) + break; +#endif + } + if (c == '\0' || c == ',' || c == '#') + continue; + + goal_alt_win[i] = true; + } + } + + for (i = 0; i < n_operands; i++) + { + int regno; + bool optional_p = false; + rtx old, new_reg; + rtx op = *curr_id->operand_loc[i]; + + if (goal_alt_win[i]) + { + if (goal_alt[i] == NO_REGS + && REG_P (op) + /* When we assign NO_REGS it means that we will not + assign a hard register to the scratch pseudo by + assigment pass and the scratch pseudo will be + spilled. Spilled scratch pseudos are transformed + back to scratches at the LRA end. */ + && lra_former_scratch_operand_p (curr_insn, i)) + { + int regno = REGNO (op); + lra_change_class (regno, NO_REGS, " Change to", true); + if (lra_get_regno_hard_regno (regno) >= 0) + /* We don't have to mark all insn affected by the + spilled pseudo as there is only one such insn, the + current one. */ + reg_renumber[regno] = -1; + } + /* We can do an optional reload. If the pseudo got a hard + reg, we might improve the code through inheritance. If + it does not get a hard register we coalesce memory/memory + moves later. Ignore move insns to avoid cycling. */ + if (! lra_simple_p + && lra_undo_inheritance_iter < LRA_MAX_INHERITANCE_PASSES + && goal_alt[i] != NO_REGS && REG_P (op) + && (regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER + && regno < new_regno_start + && ! lra_former_scratch_p (regno) + && reg_renumber[regno] < 0 + && (curr_insn_set == NULL_RTX + || !((REG_P (SET_SRC (curr_insn_set)) + || MEM_P (SET_SRC (curr_insn_set)) + || GET_CODE (SET_SRC (curr_insn_set)) == SUBREG) + && (REG_P (SET_DEST (curr_insn_set)) + || MEM_P (SET_DEST (curr_insn_set)) + || GET_CODE (SET_DEST (curr_insn_set)) == SUBREG)))) + optional_p = true; + else + continue; + } + + /* Operands that match previous ones have already been handled. */ + if (goal_alt_matches[i] >= 0) + continue; + + /* We should not have an operand with a non-offsettable address + appearing where an offsettable address will do. It also may + be a case when the address should be special in other words + not a general one (e.g. it needs no index reg). */ + if (goal_alt_matched[i][0] == -1 && goal_alt_offmemok[i] && MEM_P (op)) + { + enum reg_class rclass; + rtx *loc = &XEXP (op, 0); + enum rtx_code code = GET_CODE (*loc); + + push_to_sequence (before); + rclass = base_reg_class (GET_MODE (op), MEM_ADDR_SPACE (op), + MEM, SCRATCH); + if (GET_RTX_CLASS (code) == RTX_AUTOINC) + new_reg = emit_inc (rclass, *loc, *loc, + /* This value does not matter for MODIFY. */ + GET_MODE_SIZE (GET_MODE (op))); + else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, FALSE, + "offsetable address", &new_reg)) + lra_emit_move (new_reg, *loc); + before = get_insns (); + end_sequence (); + *loc = new_reg; + lra_update_dup (curr_id, i); + } + else if (goal_alt_matched[i][0] == -1) + { + enum machine_mode mode; + rtx reg, *loc; + int hard_regno, byte; + enum op_type type = curr_static_id->operand[i].type; + + loc = curr_id->operand_loc[i]; + mode = curr_operand_mode[i]; + if (GET_CODE (*loc) == SUBREG) + { + reg = SUBREG_REG (*loc); + byte = SUBREG_BYTE (*loc); + if (REG_P (reg) + /* Strict_low_part requires reload the register not + the sub-register. */ + && (curr_static_id->operand[i].strict_low + || (GET_MODE_SIZE (mode) + <= GET_MODE_SIZE (GET_MODE (reg)) + && (hard_regno + = get_try_hard_regno (REGNO (reg))) >= 0 + && (simplify_subreg_regno + (hard_regno, + GET_MODE (reg), byte, mode) < 0) + && (goal_alt[i] == NO_REGS + || (simplify_subreg_regno + (ira_class_hard_regs[goal_alt[i]][0], + GET_MODE (reg), byte, mode) >= 0))))) + { + loc = &SUBREG_REG (*loc); + mode = GET_MODE (*loc); + } + } + old = *loc; + if (get_reload_reg (type, mode, old, goal_alt[i], + loc != curr_id->operand_loc[i], "", &new_reg) + && type != OP_OUT) + { + push_to_sequence (before); + lra_emit_move (new_reg, old); + before = get_insns (); + end_sequence (); + } + *loc = new_reg; + if (type != OP_IN + && find_reg_note (curr_insn, REG_UNUSED, old) == NULL_RTX) + { + start_sequence (); + lra_emit_move (type == OP_INOUT ? copy_rtx (old) : old, new_reg); + emit_insn (after); + after = get_insns (); + end_sequence (); + *loc = new_reg; + } + for (j = 0; j < goal_alt_dont_inherit_ops_num; j++) + if (goal_alt_dont_inherit_ops[j] == i) + { + lra_set_regno_unique_value (REGNO (new_reg)); + break; + } + lra_update_dup (curr_id, i); + } + else if (curr_static_id->operand[i].type == OP_IN + && (curr_static_id->operand[goal_alt_matched[i][0]].type + == OP_OUT)) + { + /* generate reloads for input and matched outputs. */ + match_inputs[0] = i; + match_inputs[1] = -1; + match_reload (goal_alt_matched[i][0], match_inputs, + goal_alt[i], &before, &after); + } + else if (curr_static_id->operand[i].type == OP_OUT + && (curr_static_id->operand[goal_alt_matched[i][0]].type + == OP_IN)) + /* Generate reloads for output and matched inputs. */ + match_reload (i, goal_alt_matched[i], goal_alt[i], &before, &after); + else if (curr_static_id->operand[i].type == OP_IN + && (curr_static_id->operand[goal_alt_matched[i][0]].type + == OP_IN)) + { + /* Generate reloads for matched inputs. */ + match_inputs[0] = i; + for (j = 0; (k = goal_alt_matched[i][j]) >= 0; j++) + match_inputs[j + 1] = k; + match_inputs[j + 1] = -1; + match_reload (-1, match_inputs, goal_alt[i], &before, &after); + } + else + /* We must generate code in any case when function + process_alt_operands decides that it is possible. */ + gcc_unreachable (); + if (optional_p) + { + lra_assert (REG_P (op)); + regno = REGNO (op); + op = *curr_id->operand_loc[i]; /* Substitution. */ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + gcc_assert (REG_P (op) && (int) REGNO (op) >= new_regno_start); + bitmap_set_bit (&lra_optional_reload_pseudos, REGNO (op)); + lra_reg_info[REGNO (op)].restore_regno = regno; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " Making reload reg %d for reg %d optional\n", + REGNO (op), regno); + } + } + if (before != NULL_RTX || after != NULL_RTX + || max_regno_before != max_reg_num ()) + change_p = true; + if (change_p) + { + lra_update_operator_dups (curr_id); + /* Something changes -- process the insn. */ + lra_update_insn_regno_info (curr_insn); + } + lra_process_new_insns (curr_insn, before, after, "Inserting insn reload"); + return change_p; +} + +/* Return true if X is in LIST. */ +static bool +in_list_p (rtx x, rtx list) +{ + for (; list != NULL_RTX; list = XEXP (list, 1)) + if (XEXP (list, 0) == x) + return true; + return false; +} + +/* Return true if X contains an allocatable hard register (if + HARD_REG_P) or a (spilled if SPILLED_P) pseudo. */ +static bool +contains_reg_p (rtx x, bool hard_reg_p, bool spilled_p) +{ + int i, j; + const char *fmt; + enum rtx_code code; + + code = GET_CODE (x); + if (REG_P (x)) + { + int regno = REGNO (x); + HARD_REG_SET alloc_regs; + + if (hard_reg_p) + { + if (regno >= FIRST_PSEUDO_REGISTER) + regno = lra_get_regno_hard_regno (regno); + if (regno < 0) + return false; + COMPL_HARD_REG_SET (alloc_regs, lra_no_alloc_regs); + return overlaps_hard_reg_set_p (alloc_regs, GET_MODE (x), regno); + } + else + { + if (regno < FIRST_PSEUDO_REGISTER) + return false; + if (! spilled_p) + return true; + return lra_get_regno_hard_regno (regno) < 0; + } + } + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (contains_reg_p (XEXP (x, i), hard_reg_p, spilled_p)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (contains_reg_p (XVECEXP (x, i, j), hard_reg_p, spilled_p)) + return true; + } + } + return false; +} + +/* Process all regs in location *LOC and change them on equivalent + substitution. Return true if any change was done. */ +static bool +loc_equivalence_change_p (rtx *loc) +{ + rtx subst, reg, x = *loc; + bool result = false; + enum rtx_code code = GET_CODE (x); + const char *fmt; + int i, j; + + if (code == SUBREG) + { + reg = SUBREG_REG (x); + if ((subst = get_equiv_with_elimination (reg, curr_insn)) != reg + && GET_MODE (subst) == VOIDmode) + { + /* We cannot reload debug location. Simplify subreg here + while we know the inner mode. */ + *loc = simplify_gen_subreg (GET_MODE (x), subst, + GET_MODE (reg), SUBREG_BYTE (x)); + return true; + } + } + if (code == REG && (subst = get_equiv_with_elimination (x, curr_insn)) != x) + { + *loc = subst; + return true; + } + + /* Scan all the operand sub-expressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + result = loc_equivalence_change_p (&XEXP (x, i)) || result; + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + result + = loc_equivalence_change_p (&XVECEXP (x, i, j)) || result; + } + return result; +} + +/* Similar to loc_equivalence_change_p, but for use as + simplify_replace_fn_rtx callback. DATA is insn for which the + elimination is done. If it null we don't do the elimination. */ +static rtx +loc_equivalence_callback (rtx loc, const_rtx, void *data) +{ + if (!REG_P (loc)) + return NULL_RTX; + + rtx subst = (data == NULL + ? get_equiv (loc) : get_equiv_with_elimination (loc, (rtx) data)); + if (subst != loc) + return subst; + + return NULL_RTX; +} + +/* Maximum number of generated reload insns per an insn. It is for + preventing this pass cycling in a bug case. */ +#define MAX_RELOAD_INSNS_NUMBER LRA_MAX_INSN_RELOADS + +/* The current iteration number of this LRA pass. */ +int lra_constraint_iter; + +/* The current iteration number of this LRA pass after the last spill + pass. */ +int lra_constraint_iter_after_spill; + +/* True if we substituted equiv which needs checking register + allocation correctness because the equivalent value contains + allocatable hard registers or when we restore multi-register + pseudo. */ +bool lra_risky_transformations_p; + +/* Return true if REGNO is referenced in more than one block. */ +static bool +multi_block_pseudo_p (int regno) +{ + basic_block bb = NULL; + unsigned int uid; + bitmap_iterator bi; + + if (regno < FIRST_PSEUDO_REGISTER) + return false; + + EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi) + if (bb == NULL) + bb = BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn); + else if (BLOCK_FOR_INSN (lra_insn_recog_data[uid]->insn) != bb) + return true; + return false; +} + +/* Return true if LIST contains a deleted insn. */ +static bool +contains_deleted_insn_p (rtx list) +{ + for (; list != NULL_RTX; list = XEXP (list, 1)) + if (NOTE_P (XEXP (list, 0)) + && NOTE_KIND (XEXP (list, 0)) == NOTE_INSN_DELETED) + return true; + return false; +} + +/* Return true if X contains a pseudo dying in INSN. */ +static bool +dead_pseudo_p (rtx x, rtx insn) +{ + int i, j; + const char *fmt; + enum rtx_code code; + + if (REG_P (x)) + return (insn != NULL_RTX + && find_regno_note (insn, REG_DEAD, REGNO (x)) != NULL_RTX); + code = GET_CODE (x); + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (dead_pseudo_p (XEXP (x, i), insn)) + return true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (dead_pseudo_p (XVECEXP (x, i, j), insn)) + return true; + } + } + return false; +} + +/* Return true if INSN contains a dying pseudo in INSN right hand + side. */ +static bool +insn_rhs_dead_pseudo_p (rtx insn) +{ + rtx set = single_set (insn); + + gcc_assert (set != NULL); + return dead_pseudo_p (SET_SRC (set), insn); +} + +/* Return true if any init insn of REGNO contains a dying pseudo in + insn right hand side. */ +static bool +init_insn_rhs_dead_pseudo_p (int regno) +{ + rtx insns = ira_reg_equiv[regno].init_insns; + + if (insns == NULL) + return false; + if (INSN_P (insns)) + return insn_rhs_dead_pseudo_p (insns); + for (; insns != NULL_RTX; insns = XEXP (insns, 1)) + if (insn_rhs_dead_pseudo_p (XEXP (insns, 0))) + return true; + return false; +} + +/* Return TRUE if REGNO has a reverse equivalence. The equivalence is + reverse only if we have one init insn with given REGNO as a + source. */ +static bool +reverse_equiv_p (int regno) +{ + rtx insns, set; + + if ((insns = ira_reg_equiv[regno].init_insns) == NULL_RTX) + return false; + if (! INSN_P (XEXP (insns, 0)) + || XEXP (insns, 1) != NULL_RTX) + return false; + if ((set = single_set (XEXP (insns, 0))) == NULL_RTX) + return false; + return REG_P (SET_SRC (set)) && (int) REGNO (SET_SRC (set)) == regno; +} + +/* Return TRUE if REGNO was reloaded in an equivalence init insn. We + call this function only for non-reverse equivalence. */ +static bool +contains_reloaded_insn_p (int regno) +{ + rtx set; + rtx list = ira_reg_equiv[regno].init_insns; + + for (; list != NULL_RTX; list = XEXP (list, 1)) + if ((set = single_set (XEXP (list, 0))) == NULL_RTX + || ! REG_P (SET_DEST (set)) + || (int) REGNO (SET_DEST (set)) != regno) + return true; + return false; +} + +/* Entry function of LRA constraint pass. Return true if the + constraint pass did change the code. */ +bool +lra_constraints (bool first_p) +{ + bool changed_p; + int i, hard_regno, new_insns_num; + unsigned int min_len, new_min_len, uid; + rtx set, x, reg, dest_reg; + basic_block last_bb; + bitmap_head equiv_insn_bitmap; + bitmap_iterator bi; + + lra_constraint_iter++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n********** Local #%d: **********\n\n", + lra_constraint_iter); + lra_constraint_iter_after_spill++; + if (lra_constraint_iter_after_spill > LRA_MAX_CONSTRAINT_ITERATION_NUMBER) + internal_error + ("Maximum number of LRA constraint passes is achieved (%d)\n", + LRA_MAX_CONSTRAINT_ITERATION_NUMBER); + changed_p = false; + lra_risky_transformations_p = false; + new_insn_uid_start = get_max_uid (); + new_regno_start = first_p ? lra_constraint_new_regno_start : max_reg_num (); + /* Mark used hard regs for target stack size calulations. */ + for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++) + if (lra_reg_info[i].nrefs != 0 + && (hard_regno = lra_get_regno_hard_regno (i)) >= 0) + { + int j, nregs; + + nregs = hard_regno_nregs[hard_regno][lra_reg_info[i].biggest_mode]; + for (j = 0; j < nregs; j++) + df_set_regs_ever_live (hard_regno + j, true); + } + /* Do elimination before the equivalence processing as we can spill + some pseudos during elimination. */ + lra_eliminate (false, first_p); + bitmap_initialize (&equiv_insn_bitmap, ®_obstack); + for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++) + if (lra_reg_info[i].nrefs != 0) + { + ira_reg_equiv[i].profitable_p = true; + reg = regno_reg_rtx[i]; + if (lra_get_regno_hard_regno (i) < 0 && (x = get_equiv (reg)) != reg) + { + bool pseudo_p = contains_reg_p (x, false, false); + + /* After RTL transformation, we can not guarantee that + pseudo in the substitution was not reloaded which might + make equivalence invalid. For example, in reverse + equiv of p0 + + p0 <- ... + ... + equiv_mem <- p0 + + the memory address register was reloaded before the 2nd + insn. */ + if ((! first_p && pseudo_p) + /* We don't use DF for compilation speed sake. So it + is problematic to update live info when we use an + equivalence containing pseudos in more than one + BB. */ + || (pseudo_p && multi_block_pseudo_p (i)) + /* If an init insn was deleted for some reason, cancel + the equiv. We could update the equiv insns after + transformations including an equiv insn deletion + but it is not worthy as such cases are extremely + rare. */ + || contains_deleted_insn_p (ira_reg_equiv[i].init_insns) + /* If it is not a reverse equivalence, we check that a + pseudo in rhs of the init insn is not dying in the + insn. Otherwise, the live info at the beginning of + the corresponding BB might be wrong after we + removed the insn. When the equiv can be a + constant, the right hand side of the init insn can + be a pseudo. */ + || (! reverse_equiv_p (i) + && (init_insn_rhs_dead_pseudo_p (i) + /* If we reloaded the pseudo in an equivalence + init insn, we can not remove the equiv init + insns and the init insns might write into + const memory in this case. */ + || contains_reloaded_insn_p (i))) + /* Prevent access beyond equivalent memory for + paradoxical subregs. */ + || (MEM_P (x) + && (GET_MODE_SIZE (lra_reg_info[i].biggest_mode) + > GET_MODE_SIZE (GET_MODE (x))))) + ira_reg_equiv[i].defined_p = false; + if (contains_reg_p (x, false, true)) + ira_reg_equiv[i].profitable_p = false; + if (get_equiv (reg) != reg) + bitmap_ior_into (&equiv_insn_bitmap, &lra_reg_info[i].insn_bitmap); + } + } + for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++) + update_equiv (i); + /* We should add all insns containing pseudos which should be + substituted by their equivalences. */ + EXECUTE_IF_SET_IN_BITMAP (&equiv_insn_bitmap, 0, uid, bi) + lra_push_insn_by_uid (uid); + min_len = lra_insn_stack_length (); + new_insns_num = 0; + last_bb = NULL; + changed_p = false; + while ((new_min_len = lra_insn_stack_length ()) != 0) + { + curr_insn = lra_pop_insn (); + --new_min_len; + curr_bb = BLOCK_FOR_INSN (curr_insn); + if (curr_bb != last_bb) + { + last_bb = curr_bb; + bb_reload_num = lra_curr_reload_num; + } + if (min_len > new_min_len) + { + min_len = new_min_len; + new_insns_num = 0; + } + if (new_insns_num > MAX_RELOAD_INSNS_NUMBER) + internal_error + ("Max. number of generated reload insns per insn is achieved (%d)\n", + MAX_RELOAD_INSNS_NUMBER); + new_insns_num++; + if (DEBUG_INSN_P (curr_insn)) + { + /* We need to check equivalence in debug insn and change + pseudo to the equivalent value if necessary. */ + curr_id = lra_get_insn_recog_data (curr_insn); + if (bitmap_bit_p (&equiv_insn_bitmap, INSN_UID (curr_insn))) + { + rtx old = *curr_id->operand_loc[0]; + *curr_id->operand_loc[0] + = simplify_replace_fn_rtx (old, NULL_RTX, + loc_equivalence_callback, curr_insn); + if (old != *curr_id->operand_loc[0]) + { + lra_update_insn_regno_info (curr_insn); + changed_p = true; + } + } + } + else if (INSN_P (curr_insn)) + { + if ((set = single_set (curr_insn)) != NULL_RTX) + { + dest_reg = SET_DEST (set); + /* The equivalence pseudo could be set up as SUBREG in a + case when it is a call restore insn in a mode + different from the pseudo mode. */ + if (GET_CODE (dest_reg) == SUBREG) + dest_reg = SUBREG_REG (dest_reg); + if ((REG_P (dest_reg) + && (x = get_equiv (dest_reg)) != dest_reg + /* Remove insns which set up a pseudo whose value + can not be changed. Such insns might be not in + init_insns because we don't update equiv data + during insn transformations. + + As an example, let suppose that a pseudo got + hard register and on the 1st pass was not + changed to equivalent constant. We generate an + additional insn setting up the pseudo because of + secondary memory movement. Then the pseudo is + spilled and we use the equiv constant. In this + case we should remove the additional insn and + this insn is not init_insns list. */ + && (! MEM_P (x) || MEM_READONLY_P (x) + /* Check that this is actually an insn setting + up the equivalence. */ + || in_list_p (curr_insn, + ira_reg_equiv + [REGNO (dest_reg)].init_insns))) + || (((x = get_equiv (SET_SRC (set))) != SET_SRC (set)) + && in_list_p (curr_insn, + ira_reg_equiv + [REGNO (SET_SRC (set))].init_insns))) + { + /* This is equiv init insn of pseudo which did not get a + hard register -- remove the insn. */ + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Removing equiv init insn %i (freq=%d)\n", + INSN_UID (curr_insn), + REG_FREQ_FROM_BB (BLOCK_FOR_INSN (curr_insn))); + dump_insn_slim (lra_dump_file, curr_insn); + } + if (contains_reg_p (x, true, false)) + lra_risky_transformations_p = true; + lra_set_insn_deleted (curr_insn); + continue; + } + } + curr_id = lra_get_insn_recog_data (curr_insn); + curr_static_id = curr_id->insn_static_data; + init_curr_insn_input_reloads (); + init_curr_operand_mode (); + if (curr_insn_transform ()) + changed_p = true; + /* Check non-transformed insns too for equiv change as USE + or CLOBBER don't need reloads but can contain pseudos + being changed on their equivalences. */ + else if (bitmap_bit_p (&equiv_insn_bitmap, INSN_UID (curr_insn)) + && loc_equivalence_change_p (&PATTERN (curr_insn))) + { + lra_update_insn_regno_info (curr_insn); + changed_p = true; + } + } + } + bitmap_clear (&equiv_insn_bitmap); + /* If we used a new hard regno, changed_p should be true because the + hard reg is assigned to a new pseudo. */ +#ifdef ENABLE_CHECKING + if (! changed_p) + { + for (i = FIRST_PSEUDO_REGISTER; i < new_regno_start; i++) + if (lra_reg_info[i].nrefs != 0 + && (hard_regno = lra_get_regno_hard_regno (i)) >= 0) + { + int j, nregs = hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (i)]; + + for (j = 0; j < nregs; j++) + lra_assert (df_regs_ever_live_p (hard_regno + j)); + } + } +#endif + return changed_p; +} + +/* Initiate the LRA constraint pass. It is done once per + function. */ +void +lra_constraints_init (void) +{ +} + +/* Finalize the LRA constraint pass. It is done once per + function. */ +void +lra_constraints_finish (void) +{ +} + + + +/* This page contains code to do inheritance/split + transformations. */ + +/* Number of reloads passed so far in current EBB. */ +static int reloads_num; + +/* Number of calls passed so far in current EBB. */ +static int calls_num; + +/* Current reload pseudo check for validity of elements in + USAGE_INSNS. */ +static int curr_usage_insns_check; + +/* Info about last usage of registers in EBB to do inheritance/split + transformation. Inheritance transformation is done from a spilled + pseudo and split transformations from a hard register or a pseudo + assigned to a hard register. */ +struct usage_insns +{ + /* If the value is equal to CURR_USAGE_INSNS_CHECK, then the member + value INSNS is valid. The insns is chain of optional debug insns + and a finishing non-debug insn using the corresponding reg. The + value is also used to mark the registers which are set up in the + current insn. The negated insn uid is used for this. */ + int check; + /* Value of global reloads_num at the last insn in INSNS. */ + int reloads_num; + /* Value of global reloads_nums at the last insn in INSNS. */ + int calls_num; + /* It can be true only for splitting. And it means that the restore + insn should be put after insn given by the following member. */ + bool after_p; + /* Next insns in the current EBB which use the original reg and the + original reg value is not changed between the current insn and + the next insns. In order words, e.g. for inheritance, if we need + to use the original reg value again in the next insns we can try + to use the value in a hard register from a reload insn of the + current insn. */ + rtx insns; +}; + +/* Map: regno -> corresponding pseudo usage insns. */ +static struct usage_insns *usage_insns; + +static void +setup_next_usage_insn (int regno, rtx insn, int reloads_num, bool after_p) +{ + usage_insns[regno].check = curr_usage_insns_check; + usage_insns[regno].insns = insn; + usage_insns[regno].reloads_num = reloads_num; + usage_insns[regno].calls_num = calls_num; + usage_insns[regno].after_p = after_p; +} + +/* The function is used to form list REGNO usages which consists of + optional debug insns finished by a non-debug insn using REGNO. + RELOADS_NUM is current number of reload insns processed so far. */ +static void +add_next_usage_insn (int regno, rtx insn, int reloads_num) +{ + rtx next_usage_insns; + + if (usage_insns[regno].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[regno].insns) != NULL_RTX + && DEBUG_INSN_P (insn)) + { + /* Check that we did not add the debug insn yet. */ + if (next_usage_insns != insn + && (GET_CODE (next_usage_insns) != INSN_LIST + || XEXP (next_usage_insns, 0) != insn)) + usage_insns[regno].insns = gen_rtx_INSN_LIST (VOIDmode, insn, + next_usage_insns); + } + else if (NONDEBUG_INSN_P (insn)) + setup_next_usage_insn (regno, insn, reloads_num, false); + else + usage_insns[regno].check = 0; +} + +/* Replace all references to register OLD_REGNO in *LOC with pseudo + register NEW_REG. Return true if any change was made. */ +static bool +substitute_pseudo (rtx *loc, int old_regno, rtx new_reg) +{ + rtx x = *loc; + bool result = false; + enum rtx_code code; + const char *fmt; + int i, j; + + if (x == NULL_RTX) + return false; + + code = GET_CODE (x); + if (code == REG && (int) REGNO (x) == old_regno) + { + enum machine_mode mode = GET_MODE (*loc); + enum machine_mode inner_mode = GET_MODE (new_reg); + + if (mode != inner_mode) + { + if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (inner_mode) + || ! SCALAR_INT_MODE_P (inner_mode)) + new_reg = gen_rtx_SUBREG (mode, new_reg, 0); + else + new_reg = gen_lowpart_SUBREG (mode, new_reg); + } + *loc = new_reg; + return true; + } + + /* Scan all the operand sub-expressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + { + if (substitute_pseudo (&XEXP (x, i), old_regno, new_reg)) + result = true; + } + else if (fmt[i] == 'E') + { + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (substitute_pseudo (&XVECEXP (x, i, j), old_regno, new_reg)) + result = true; + } + } + return result; +} + +/* Return first non-debug insn in list USAGE_INSNS. */ +static rtx +skip_usage_debug_insns (rtx usage_insns) +{ + rtx insn; + + /* Skip debug insns. */ + for (insn = usage_insns; + insn != NULL_RTX && GET_CODE (insn) == INSN_LIST; + insn = XEXP (insn, 1)) + ; + return insn; +} + +/* Return true if we need secondary memory moves for insn in + USAGE_INSNS after inserting inherited pseudo of class INHER_CL + into the insn. */ +static bool +check_secondary_memory_needed_p (enum reg_class inher_cl ATTRIBUTE_UNUSED, + rtx usage_insns ATTRIBUTE_UNUSED) +{ +#ifndef SECONDARY_MEMORY_NEEDED + return false; +#else + rtx insn, set, dest; + enum reg_class cl; + + if (inher_cl == ALL_REGS + || (insn = skip_usage_debug_insns (usage_insns)) == NULL_RTX) + return false; + lra_assert (INSN_P (insn)); + if ((set = single_set (insn)) == NULL_RTX || ! REG_P (SET_DEST (set))) + return false; + dest = SET_DEST (set); + if (! REG_P (dest)) + return false; + lra_assert (inher_cl != NO_REGS); + cl = get_reg_class (REGNO (dest)); + return (cl != NO_REGS && cl != ALL_REGS + && SECONDARY_MEMORY_NEEDED (inher_cl, cl, GET_MODE (dest))); +#endif +} + +/* Registers involved in inheritance/split in the current EBB + (inheritance/split pseudos and original registers). */ +static bitmap_head check_only_regs; + +/* Do inheritance transformations for insn INSN, which defines (if + DEF_P) or uses ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which + instruction in the EBB next uses ORIGINAL_REGNO; it has the same + form as the "insns" field of usage_insns. Return true if we + succeed in such transformation. + + The transformations look like: + + p <- ... i <- ... + ... p <- i (new insn) + ... => + <- ... p ... <- ... i ... + or + ... i <- p (new insn) + <- ... p ... <- ... i ... + ... => + <- ... p ... <- ... i ... + where p is a spilled original pseudo and i is a new inheritance pseudo. + + + The inheritance pseudo has the smallest class of two classes CL and + class of ORIGINAL REGNO. */ +static bool +inherit_reload_reg (bool def_p, int original_regno, + enum reg_class cl, rtx insn, rtx next_usage_insns) +{ + if (optimize_function_for_size_p (cfun)) + return false; + + enum reg_class rclass = lra_get_allocno_class (original_regno); + rtx original_reg = regno_reg_rtx[original_regno]; + rtx new_reg, new_insns, usage_insn; + + lra_assert (! usage_insns[original_regno].after_p); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); + if (! ira_reg_classes_intersect_p[cl][rclass]) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting inheritance for %d " + "because of disjoint classes %s and %s\n", + original_regno, reg_class_names[cl], + reg_class_names[rclass]); + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + return false; + } + if ((ira_class_subset_p[cl][rclass] && cl != rclass) + /* We don't use a subset of two classes because it can be + NO_REGS. This transformation is still profitable in most + cases even if the classes are not intersected as register + move is probably cheaper than a memory load. */ + || ira_class_hard_regs_num[cl] < ira_class_hard_regs_num[rclass]) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Use smallest class of %s and %s\n", + reg_class_names[cl], reg_class_names[rclass]); + + rclass = cl; + } + if (check_secondary_memory_needed_p (rclass, next_usage_insns)) + { + /* Reject inheritance resulting in secondary memory moves. + Otherwise, there is a danger in LRA cycling. Also such + transformation will be unprofitable. */ + if (lra_dump_file != NULL) + { + rtx insn = skip_usage_debug_insns (next_usage_insns); + rtx set = single_set (insn); + + lra_assert (set != NULL_RTX); + + rtx dest = SET_DEST (set); + + lra_assert (REG_P (dest)); + fprintf (lra_dump_file, + " Rejecting inheritance for insn %d(%s)<-%d(%s) " + "as secondary mem is needed\n", + REGNO (dest), reg_class_names[get_reg_class (REGNO (dest))], + original_regno, reg_class_names[rclass]); + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + return false; + } + new_reg = lra_create_new_reg (GET_MODE (original_reg), original_reg, + rclass, "inheritance"); + start_sequence (); + if (def_p) + lra_emit_move (original_reg, new_reg); + else + lra_emit_move (new_reg, original_reg); + new_insns = get_insns (); + end_sequence (); + if (NEXT_INSN (new_insns) != NULL_RTX) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting inheritance %d->%d " + "as it results in 2 or more insns:\n", + original_regno, REGNO (new_reg)); + dump_rtl_slim (lra_dump_file, new_insns, NULL_RTX, -1, 0); + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + } + return false; + } + substitute_pseudo (&insn, original_regno, new_reg); + lra_update_insn_regno_info (insn); + if (! def_p) + /* We now have a new usage insn for original regno. */ + setup_next_usage_insn (original_regno, new_insns, reloads_num, false); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Original reg change %d->%d (bb%d):\n", + original_regno, REGNO (new_reg), BLOCK_FOR_INSN (insn)->index); + lra_reg_info[REGNO (new_reg)].restore_regno = original_regno; + bitmap_set_bit (&check_only_regs, REGNO (new_reg)); + bitmap_set_bit (&check_only_regs, original_regno); + bitmap_set_bit (&lra_inheritance_pseudos, REGNO (new_reg)); + if (def_p) + lra_process_new_insns (insn, NULL_RTX, new_insns, + "Add original<-inheritance"); + else + lra_process_new_insns (insn, new_insns, NULL_RTX, + "Add inheritance<-original"); + while (next_usage_insns != NULL_RTX) + { + if (GET_CODE (next_usage_insns) != INSN_LIST) + { + usage_insn = next_usage_insns; + lra_assert (NONDEBUG_INSN_P (usage_insn)); + next_usage_insns = NULL; + } + else + { + usage_insn = XEXP (next_usage_insns, 0); + lra_assert (DEBUG_INSN_P (usage_insn)); + next_usage_insns = XEXP (next_usage_insns, 1); + } + substitute_pseudo (&usage_insn, original_regno, new_reg); + lra_update_insn_regno_info (usage_insn); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Inheritance reuse change %d->%d (bb%d):\n", + original_regno, REGNO (new_reg), + BLOCK_FOR_INSN (usage_insn)->index); + dump_insn_slim (lra_dump_file, usage_insn); + } + } + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + return true; +} + +/* Return true if we need a caller save/restore for pseudo REGNO which + was assigned to a hard register. */ +static inline bool +need_for_call_save_p (int regno) +{ + lra_assert (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0); + return (usage_insns[regno].calls_num < calls_num + && (overlaps_hard_reg_set_p + (call_used_reg_set, + PSEUDO_REGNO_MODE (regno), reg_renumber[regno]) + || HARD_REGNO_CALL_PART_CLOBBERED (reg_renumber[regno], + PSEUDO_REGNO_MODE (regno)))); +} + +/* Global registers occurring in the current EBB. */ +static bitmap_head ebb_global_regs; + +/* Return true if we need a split for hard register REGNO or pseudo + REGNO which was assigned to a hard register. + POTENTIAL_RELOAD_HARD_REGS contains hard registers which might be + used for reloads since the EBB end. It is an approximation of the + used hard registers in the split range. The exact value would + require expensive calculations. If we were aggressive with + splitting because of the approximation, the split pseudo will save + the same hard register assignment and will be removed in the undo + pass. We still need the approximation because too aggressive + splitting would result in too inaccurate cost calculation in the + assignment pass because of too many generated moves which will be + probably removed in the undo pass. */ +static inline bool +need_for_split_p (HARD_REG_SET potential_reload_hard_regs, int regno) +{ + int hard_regno = regno < FIRST_PSEUDO_REGISTER ? regno : reg_renumber[regno]; + + lra_assert (hard_regno >= 0); + return ((TEST_HARD_REG_BIT (potential_reload_hard_regs, hard_regno) + /* Don't split eliminable hard registers, otherwise we can + split hard registers like hard frame pointer, which + lives on BB start/end according to DF-infrastructure, + when there is a pseudo assigned to the register and + living in the same BB. */ + && (regno >= FIRST_PSEUDO_REGISTER + || ! TEST_HARD_REG_BIT (eliminable_regset, hard_regno)) + && ! TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno) + /* Don't split call clobbered hard regs living through + calls, otherwise we might have a check problem in the + assign sub-pass as in the most cases (exception is a + situation when lra_risky_transformations_p value is + true) the assign pass assumes that all pseudos living + through calls are assigned to call saved hard regs. */ + && (regno >= FIRST_PSEUDO_REGISTER + || ! TEST_HARD_REG_BIT (call_used_reg_set, regno) + || usage_insns[regno].calls_num == calls_num) + /* We need at least 2 reloads to make pseudo splitting + profitable. We should provide hard regno splitting in + any case to solve 1st insn scheduling problem when + moving hard register definition up might result in + impossibility to find hard register for reload pseudo of + small register class. */ + && (usage_insns[regno].reloads_num + + (regno < FIRST_PSEUDO_REGISTER ? 0 : 3) < reloads_num) + && (regno < FIRST_PSEUDO_REGISTER + /* For short living pseudos, spilling + inheritance can + be considered a substitution for splitting. + Therefore we do not splitting for local pseudos. It + decreases also aggressiveness of splitting. The + minimal number of references is chosen taking into + account that for 2 references splitting has no sense + as we can just spill the pseudo. */ + || (regno >= FIRST_PSEUDO_REGISTER + && lra_reg_info[regno].nrefs > 3 + && bitmap_bit_p (&ebb_global_regs, regno)))) + || (regno >= FIRST_PSEUDO_REGISTER && need_for_call_save_p (regno))); +} + +/* Return class for the split pseudo created from original pseudo with + ALLOCNO_CLASS and MODE which got a hard register HARD_REGNO. We + choose subclass of ALLOCNO_CLASS which contains HARD_REGNO and + results in no secondary memory movements. */ +static enum reg_class +choose_split_class (enum reg_class allocno_class, + int hard_regno ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ +#ifndef SECONDARY_MEMORY_NEEDED + return allocno_class; +#else + int i; + enum reg_class cl, best_cl = NO_REGS; + enum reg_class hard_reg_class ATTRIBUTE_UNUSED + = REGNO_REG_CLASS (hard_regno); + + if (! SECONDARY_MEMORY_NEEDED (allocno_class, allocno_class, mode) + && TEST_HARD_REG_BIT (reg_class_contents[allocno_class], hard_regno)) + return allocno_class; + for (i = 0; + (cl = reg_class_subclasses[allocno_class][i]) != LIM_REG_CLASSES; + i++) + if (! SECONDARY_MEMORY_NEEDED (cl, hard_reg_class, mode) + && ! SECONDARY_MEMORY_NEEDED (hard_reg_class, cl, mode) + && TEST_HARD_REG_BIT (reg_class_contents[cl], hard_regno) + && (best_cl == NO_REGS + || ira_class_hard_regs_num[best_cl] < ira_class_hard_regs_num[cl])) + best_cl = cl; + return best_cl; +#endif +} + +/* Do split transformations for insn INSN, which defines or uses + ORIGINAL_REGNO. NEXT_USAGE_INSNS specifies which instruction in + the EBB next uses ORIGINAL_REGNO; it has the same form as the + "insns" field of usage_insns. + + The transformations look like: + + p <- ... p <- ... + ... s <- p (new insn -- save) + ... => + ... p <- s (new insn -- restore) + <- ... p ... <- ... p ... + or + <- ... p ... <- ... p ... + ... s <- p (new insn -- save) + ... => + ... p <- s (new insn -- restore) + <- ... p ... <- ... p ... + + where p is an original pseudo got a hard register or a hard + register and s is a new split pseudo. The save is put before INSN + if BEFORE_P is true. Return true if we succeed in such + transformation. */ +static bool +split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns) +{ + enum reg_class rclass; + rtx original_reg; + int hard_regno, nregs; + rtx new_reg, save, restore, usage_insn; + bool after_p; + bool call_save_p; + + if (original_regno < FIRST_PSEUDO_REGISTER) + { + rclass = ira_allocno_class_translate[REGNO_REG_CLASS (original_regno)]; + hard_regno = original_regno; + call_save_p = false; + nregs = 1; + } + else + { + hard_regno = reg_renumber[original_regno]; + nregs = hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (original_regno)]; + rclass = lra_get_allocno_class (original_regno); + original_reg = regno_reg_rtx[original_regno]; + call_save_p = need_for_call_save_p (original_regno); + } + original_reg = regno_reg_rtx[original_regno]; + lra_assert (hard_regno >= 0); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " ((((((((((((((((((((((((((((((((((((((((((((((((\n"); + if (call_save_p) + { + enum machine_mode mode = GET_MODE (original_reg); + + mode = HARD_REGNO_CALLER_SAVE_MODE (hard_regno, + hard_regno_nregs[hard_regno][mode], + mode); + new_reg = lra_create_new_reg (mode, NULL_RTX, NO_REGS, "save"); + } + else + { + rclass = choose_split_class (rclass, hard_regno, + GET_MODE (original_reg)); + if (rclass == NO_REGS) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting split of %d(%s): " + "no good reg class for %d(%s)\n", + original_regno, + reg_class_names[lra_get_allocno_class (original_regno)], + hard_regno, + reg_class_names[REGNO_REG_CLASS (hard_regno)]); + fprintf + (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + } + return false; + } + new_reg = lra_create_new_reg (GET_MODE (original_reg), original_reg, + rclass, "split"); + reg_renumber[REGNO (new_reg)] = hard_regno; + } + save = emit_spill_move (true, new_reg, original_reg); + if (NEXT_INSN (save) != NULL_RTX) + { + lra_assert (! call_save_p); + if (lra_dump_file != NULL) + { + fprintf + (lra_dump_file, + " Rejecting split %d->%d resulting in > 2 %s save insns:\n", + original_regno, REGNO (new_reg), call_save_p ? "call" : ""); + dump_rtl_slim (lra_dump_file, save, NULL_RTX, -1, 0); + fprintf (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + } + return false; + } + restore = emit_spill_move (false, new_reg, original_reg); + if (NEXT_INSN (restore) != NULL_RTX) + { + lra_assert (! call_save_p); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Rejecting split %d->%d " + "resulting in > 2 %s restore insns:\n", + original_regno, REGNO (new_reg), call_save_p ? "call" : ""); + dump_rtl_slim (lra_dump_file, restore, NULL_RTX, -1, 0); + fprintf (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + } + return false; + } + after_p = usage_insns[original_regno].after_p; + lra_reg_info[REGNO (new_reg)].restore_regno = original_regno; + bitmap_set_bit (&check_only_regs, REGNO (new_reg)); + bitmap_set_bit (&check_only_regs, original_regno); + bitmap_set_bit (&lra_split_regs, REGNO (new_reg)); + for (;;) + { + if (GET_CODE (next_usage_insns) != INSN_LIST) + { + usage_insn = next_usage_insns; + break; + } + usage_insn = XEXP (next_usage_insns, 0); + lra_assert (DEBUG_INSN_P (usage_insn)); + next_usage_insns = XEXP (next_usage_insns, 1); + substitute_pseudo (&usage_insn, original_regno, new_reg); + lra_update_insn_regno_info (usage_insn); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Split reuse change %d->%d:\n", + original_regno, REGNO (new_reg)); + dump_insn_slim (lra_dump_file, usage_insn); + } + } + lra_assert (NOTE_P (usage_insn) || NONDEBUG_INSN_P (usage_insn)); + lra_assert (usage_insn != insn || (after_p && before_p)); + lra_process_new_insns (usage_insn, after_p ? NULL_RTX : restore, + after_p ? restore : NULL_RTX, + call_save_p + ? "Add reg<-save" : "Add reg<-split"); + lra_process_new_insns (insn, before_p ? save : NULL_RTX, + before_p ? NULL_RTX : save, + call_save_p + ? "Add save<-reg" : "Add split<-reg"); + if (nregs > 1) + /* If we are trying to split multi-register. We should check + conflicts on the next assignment sub-pass. IRA can allocate on + sub-register levels, LRA do this on pseudos level right now and + this discrepancy may create allocation conflicts after + splitting. */ + lra_risky_transformations_p = true; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); + return true; +} + +/* Recognize that we need a split transformation for insn INSN, which + defines or uses REGNO in its insn biggest MODE (we use it only if + REGNO is a hard register). POTENTIAL_RELOAD_HARD_REGS contains + hard registers which might be used for reloads since the EBB end. + Put the save before INSN if BEFORE_P is true. MAX_UID is maximla + uid before starting INSN processing. Return true if we succeed in + such transformation. */ +static bool +split_if_necessary (int regno, enum machine_mode mode, + HARD_REG_SET potential_reload_hard_regs, + bool before_p, rtx insn, int max_uid) +{ + bool res = false; + int i, nregs = 1; + rtx next_usage_insns; + + if (regno < FIRST_PSEUDO_REGISTER) + nregs = hard_regno_nregs[regno][mode]; + for (i = 0; i < nregs; i++) + if (usage_insns[regno + i].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[regno + i].insns) != NULL_RTX + /* To avoid processing the register twice or more. */ + && ((GET_CODE (next_usage_insns) != INSN_LIST + && INSN_UID (next_usage_insns) < max_uid) + || (GET_CODE (next_usage_insns) == INSN_LIST + && (INSN_UID (XEXP (next_usage_insns, 0)) < max_uid))) + && need_for_split_p (potential_reload_hard_regs, regno + i) + && split_reg (before_p, regno + i, insn, next_usage_insns)) + res = true; + return res; +} + +/* Check only registers living at the current program point in the + current EBB. */ +static bitmap_head live_regs; + +/* Update live info in EBB given by its HEAD and TAIL insns after + inheritance/split transformation. The function removes dead moves + too. */ +static void +update_ebb_live_info (rtx head, rtx tail) +{ + unsigned int j; + int i, regno; + bool live_p; + rtx prev_insn, set; + bool remove_p; + basic_block last_bb, prev_bb, curr_bb; + bitmap_iterator bi; + struct lra_insn_reg *reg; + edge e; + edge_iterator ei; + + last_bb = BLOCK_FOR_INSN (tail); + prev_bb = NULL; + for (curr_insn = tail; + curr_insn != PREV_INSN (head); + curr_insn = prev_insn) + { + prev_insn = PREV_INSN (curr_insn); + /* We need to process empty blocks too. They contain + NOTE_INSN_BASIC_BLOCK referring for the basic block. */ + if (NOTE_P (curr_insn) && NOTE_KIND (curr_insn) != NOTE_INSN_BASIC_BLOCK) + continue; + curr_bb = BLOCK_FOR_INSN (curr_insn); + if (curr_bb != prev_bb) + { + if (prev_bb != NULL) + { + /* Update df_get_live_in (prev_bb): */ + EXECUTE_IF_SET_IN_BITMAP (&check_only_regs, 0, j, bi) + if (bitmap_bit_p (&live_regs, j)) + bitmap_set_bit (df_get_live_in (prev_bb), j); + else + bitmap_clear_bit (df_get_live_in (prev_bb), j); + } + if (curr_bb != last_bb) + { + /* Update df_get_live_out (curr_bb): */ + EXECUTE_IF_SET_IN_BITMAP (&check_only_regs, 0, j, bi) + { + live_p = bitmap_bit_p (&live_regs, j); + if (! live_p) + FOR_EACH_EDGE (e, ei, curr_bb->succs) + if (bitmap_bit_p (df_get_live_in (e->dest), j)) + { + live_p = true; + break; + } + if (live_p) + bitmap_set_bit (df_get_live_out (curr_bb), j); + else + bitmap_clear_bit (df_get_live_out (curr_bb), j); + } + } + prev_bb = curr_bb; + bitmap_and (&live_regs, &check_only_regs, df_get_live_out (curr_bb)); + } + if (! NONDEBUG_INSN_P (curr_insn)) + continue; + curr_id = lra_get_insn_recog_data (curr_insn); + curr_static_id = curr_id->insn_static_data; + remove_p = false; + if ((set = single_set (curr_insn)) != NULL_RTX && REG_P (SET_DEST (set)) + && (regno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER + && bitmap_bit_p (&check_only_regs, regno) + && ! bitmap_bit_p (&live_regs, regno)) + remove_p = true; + /* See which defined values die here. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && ! reg->subreg_p) + bitmap_clear_bit (&live_regs, reg->regno); + for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) + if (reg->type == OP_OUT && ! reg->subreg_p) + bitmap_clear_bit (&live_regs, reg->regno); + /* Mark each used value as live. */ + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type != OP_OUT + && bitmap_bit_p (&check_only_regs, reg->regno)) + bitmap_set_bit (&live_regs, reg->regno); + for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next) + if (reg->type != OP_OUT + && bitmap_bit_p (&check_only_regs, reg->regno)) + bitmap_set_bit (&live_regs, reg->regno); + if (curr_id->arg_hard_regs != NULL) + /* Make argument hard registers live. */ + for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++) + if (bitmap_bit_p (&check_only_regs, regno)) + bitmap_set_bit (&live_regs, regno); + /* It is quite important to remove dead move insns because it + means removing dead store. We don't need to process them for + constraints. */ + if (remove_p) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Removing dead insn:\n "); + dump_insn_slim (lra_dump_file, curr_insn); + } + lra_set_insn_deleted (curr_insn); + } + } +} + +/* The structure describes info to do an inheritance for the current + insn. We need to collect such info first before doing the + transformations because the transformations change the insn + internal representation. */ +struct to_inherit +{ + /* Original regno. */ + int regno; + /* Subsequent insns which can inherit original reg value. */ + rtx insns; +}; + +/* Array containing all info for doing inheritance from the current + insn. */ +static struct to_inherit to_inherit[LRA_MAX_INSN_RELOADS]; + +/* Number elements in the previous array. */ +static int to_inherit_num; + +/* Add inheritance info REGNO and INSNS. Their meaning is described in + structure to_inherit. */ +static void +add_to_inherit (int regno, rtx insns) +{ + int i; + + for (i = 0; i < to_inherit_num; i++) + if (to_inherit[i].regno == regno) + return; + lra_assert (to_inherit_num < LRA_MAX_INSN_RELOADS); + to_inherit[to_inherit_num].regno = regno; + to_inherit[to_inherit_num++].insns = insns; +} + +/* Return the last non-debug insn in basic block BB, or the block begin + note if none. */ +static rtx +get_last_insertion_point (basic_block bb) +{ + rtx insn; + + FOR_BB_INSNS_REVERSE (bb, insn) + if (NONDEBUG_INSN_P (insn) || NOTE_INSN_BASIC_BLOCK_P (insn)) + return insn; + gcc_unreachable (); +} + +/* Set up RES by registers living on edges FROM except the edge (FROM, + TO) or by registers set up in a jump insn in BB FROM. */ +static void +get_live_on_other_edges (basic_block from, basic_block to, bitmap res) +{ + rtx last; + struct lra_insn_reg *reg; + edge e; + edge_iterator ei; + + lra_assert (to != NULL); + bitmap_clear (res); + FOR_EACH_EDGE (e, ei, from->succs) + if (e->dest != to) + bitmap_ior_into (res, df_get_live_in (e->dest)); + last = get_last_insertion_point (from); + if (! JUMP_P (last)) + return; + curr_id = lra_get_insn_recog_data (last); + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + if (reg->type != OP_IN) + bitmap_set_bit (res, reg->regno); +} + +/* Used as a temporary results of some bitmap calculations. */ +static bitmap_head temp_bitmap; + +/* We split for reloads of small class of hard regs. The following + defines how many hard regs the class should have to be qualified as + small. The code is mostly oriented to x86/x86-64 architecture + where some insns need to use only specific register or pair of + registers and these register can live in RTL explicitly, e.g. for + parameter passing. */ +static const int max_small_class_regs_num = 2; + +/* Do inheritance/split transformations in EBB starting with HEAD and + finishing on TAIL. We process EBB insns in the reverse order. + Return true if we did any inheritance/split transformation in the + EBB. + + We should avoid excessive splitting which results in worse code + because of inaccurate cost calculations for spilling new split + pseudos in such case. To achieve this we do splitting only if + register pressure is high in given basic block and there are reload + pseudos requiring hard registers. We could do more register + pressure calculations at any given program point to avoid necessary + splitting even more but it is to expensive and the current approach + works well enough. */ +static bool +inherit_in_ebb (rtx head, rtx tail) +{ + int i, src_regno, dst_regno, nregs; + bool change_p, succ_p, update_reloads_num_p; + rtx prev_insn, next_usage_insns, set, last_insn; + enum reg_class cl; + struct lra_insn_reg *reg; + basic_block last_processed_bb, curr_bb = NULL; + HARD_REG_SET potential_reload_hard_regs, live_hard_regs; + bitmap to_process; + unsigned int j; + bitmap_iterator bi; + bool head_p, after_p; + + change_p = false; + curr_usage_insns_check++; + reloads_num = calls_num = 0; + bitmap_clear (&check_only_regs); + last_processed_bb = NULL; + CLEAR_HARD_REG_SET (potential_reload_hard_regs); + COPY_HARD_REG_SET (live_hard_regs, eliminable_regset); + IOR_HARD_REG_SET (live_hard_regs, lra_no_alloc_regs); + /* We don't process new insns generated in the loop. */ + for (curr_insn = tail; curr_insn != PREV_INSN (head); curr_insn = prev_insn) + { + prev_insn = PREV_INSN (curr_insn); + if (BLOCK_FOR_INSN (curr_insn) != NULL) + curr_bb = BLOCK_FOR_INSN (curr_insn); + if (last_processed_bb != curr_bb) + { + /* We are at the end of BB. Add qualified living + pseudos for potential splitting. */ + to_process = df_get_live_out (curr_bb); + if (last_processed_bb != NULL) + { + /* We are somewhere in the middle of EBB. */ + get_live_on_other_edges (curr_bb, last_processed_bb, + &temp_bitmap); + to_process = &temp_bitmap; + } + last_processed_bb = curr_bb; + last_insn = get_last_insertion_point (curr_bb); + after_p = (! JUMP_P (last_insn) + && (! CALL_P (last_insn) + || (find_reg_note (last_insn, + REG_NORETURN, NULL_RTX) == NULL_RTX + && ! SIBLING_CALL_P (last_insn)))); + CLEAR_HARD_REG_SET (potential_reload_hard_regs); + EXECUTE_IF_SET_IN_BITMAP (to_process, 0, j, bi) + { + if ((int) j >= lra_constraint_new_regno_start) + break; + if (j < FIRST_PSEUDO_REGISTER || reg_renumber[j] >= 0) + { + if (j < FIRST_PSEUDO_REGISTER) + SET_HARD_REG_BIT (live_hard_regs, j); + else + add_to_hard_reg_set (&live_hard_regs, + PSEUDO_REGNO_MODE (j), + reg_renumber[j]); + setup_next_usage_insn (j, last_insn, reloads_num, after_p); + } + } + } + src_regno = dst_regno = -1; + if (NONDEBUG_INSN_P (curr_insn) + && (set = single_set (curr_insn)) != NULL_RTX + && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))) + { + src_regno = REGNO (SET_SRC (set)); + dst_regno = REGNO (SET_DEST (set)); + } + update_reloads_num_p = true; + if (src_regno < lra_constraint_new_regno_start + && src_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[src_regno] < 0 + && dst_regno >= lra_constraint_new_regno_start + && (cl = lra_get_allocno_class (dst_regno)) != NO_REGS) + { + /* 'reload_pseudo <- original_pseudo'. */ + if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num) + reloads_num++; + update_reloads_num_p = false; + succ_p = false; + if (usage_insns[src_regno].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[src_regno].insns) != NULL_RTX) + succ_p = inherit_reload_reg (false, src_regno, cl, + curr_insn, next_usage_insns); + if (succ_p) + change_p = true; + else + setup_next_usage_insn (src_regno, curr_insn, reloads_num, false); + if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs)) + IOR_HARD_REG_SET (potential_reload_hard_regs, + reg_class_contents[cl]); + } + else if (src_regno >= lra_constraint_new_regno_start + && dst_regno < lra_constraint_new_regno_start + && dst_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[dst_regno] < 0 + && (cl = lra_get_allocno_class (src_regno)) != NO_REGS + && usage_insns[dst_regno].check == curr_usage_insns_check + && (next_usage_insns + = usage_insns[dst_regno].insns) != NULL_RTX) + { + if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num) + reloads_num++; + update_reloads_num_p = false; + /* 'original_pseudo <- reload_pseudo'. */ + if (! JUMP_P (curr_insn) + && inherit_reload_reg (true, dst_regno, cl, + curr_insn, next_usage_insns)) + change_p = true; + /* Invalidate. */ + usage_insns[dst_regno].check = 0; + if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs)) + IOR_HARD_REG_SET (potential_reload_hard_regs, + reg_class_contents[cl]); + } + else if (INSN_P (curr_insn)) + { + int iter; + int max_uid = get_max_uid (); + + curr_id = lra_get_insn_recog_data (curr_insn); + curr_static_id = curr_id->insn_static_data; + to_inherit_num = 0; + /* Process insn definitions. */ + for (iter = 0; iter < 2; iter++) + for (reg = iter == 0 ? curr_id->regs : curr_static_id->hard_regs; + reg != NULL; + reg = reg->next) + if (reg->type != OP_IN + && (dst_regno = reg->regno) < lra_constraint_new_regno_start) + { + if (dst_regno >= FIRST_PSEUDO_REGISTER && reg->type == OP_OUT + && reg_renumber[dst_regno] < 0 && ! reg->subreg_p + && usage_insns[dst_regno].check == curr_usage_insns_check + && (next_usage_insns + = usage_insns[dst_regno].insns) != NULL_RTX) + { + struct lra_insn_reg *r; + + for (r = curr_id->regs; r != NULL; r = r->next) + if (r->type != OP_OUT && r->regno == dst_regno) + break; + /* Don't do inheritance if the pseudo is also + used in the insn. */ + if (r == NULL) + /* We can not do inheritance right now + because the current insn reg info (chain + regs) can change after that. */ + add_to_inherit (dst_regno, next_usage_insns); + } + /* We can not process one reg twice here because of + usage_insns invalidation. */ + if ((dst_regno < FIRST_PSEUDO_REGISTER + || reg_renumber[dst_regno] >= 0) + && ! reg->subreg_p && reg->type != OP_IN) + { + HARD_REG_SET s; + + if (split_if_necessary (dst_regno, reg->biggest_mode, + potential_reload_hard_regs, + false, curr_insn, max_uid)) + change_p = true; + CLEAR_HARD_REG_SET (s); + if (dst_regno < FIRST_PSEUDO_REGISTER) + add_to_hard_reg_set (&s, reg->biggest_mode, dst_regno); + else + add_to_hard_reg_set (&s, PSEUDO_REGNO_MODE (dst_regno), + reg_renumber[dst_regno]); + AND_COMPL_HARD_REG_SET (live_hard_regs, s); + } + /* We should invalidate potential inheritance or + splitting for the current insn usages to the next + usage insns (see code below) as the output pseudo + prevents this. */ + if ((dst_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[dst_regno] < 0) + || (reg->type == OP_OUT && ! reg->subreg_p + && (dst_regno < FIRST_PSEUDO_REGISTER + || reg_renumber[dst_regno] >= 0))) + { + /* Invalidate and mark definitions. */ + if (dst_regno >= FIRST_PSEUDO_REGISTER) + usage_insns[dst_regno].check = -(int) INSN_UID (curr_insn); + else + { + nregs = hard_regno_nregs[dst_regno][reg->biggest_mode]; + for (i = 0; i < nregs; i++) + usage_insns[dst_regno + i].check + = -(int) INSN_UID (curr_insn); + } + } + } + if (! JUMP_P (curr_insn)) + for (i = 0; i < to_inherit_num; i++) + if (inherit_reload_reg (true, to_inherit[i].regno, + ALL_REGS, curr_insn, + to_inherit[i].insns)) + change_p = true; + if (CALL_P (curr_insn)) + { + rtx cheap, pat, dest, restore; + int regno, hard_regno; + + calls_num++; + if ((cheap = find_reg_note (curr_insn, + REG_RETURNED, NULL_RTX)) != NULL_RTX + && ((cheap = XEXP (cheap, 0)), true) + && (regno = REGNO (cheap)) >= FIRST_PSEUDO_REGISTER + && (hard_regno = reg_renumber[regno]) >= 0 + /* If there are pending saves/restores, the + optimization is not worth. */ + && usage_insns[regno].calls_num == calls_num - 1 + && TEST_HARD_REG_BIT (call_used_reg_set, hard_regno)) + { + /* Restore the pseudo from the call result as + REG_RETURNED note says that the pseudo value is + in the call result and the pseudo is an argument + of the call. */ + pat = PATTERN (curr_insn); + if (GET_CODE (pat) == PARALLEL) + pat = XVECEXP (pat, 0, 0); + dest = SET_DEST (pat); + start_sequence (); + emit_move_insn (cheap, copy_rtx (dest)); + restore = get_insns (); + end_sequence (); + lra_process_new_insns (curr_insn, NULL, restore, + "Inserting call parameter restore"); + /* We don't need to save/restore of the pseudo from + this call. */ + usage_insns[regno].calls_num = calls_num; + bitmap_set_bit (&check_only_regs, regno); + } + } + to_inherit_num = 0; + /* Process insn usages. */ + for (iter = 0; iter < 2; iter++) + for (reg = iter == 0 ? curr_id->regs : curr_static_id->hard_regs; + reg != NULL; + reg = reg->next) + if ((reg->type != OP_OUT + || (reg->type == OP_OUT && reg->subreg_p)) + && (src_regno = reg->regno) < lra_constraint_new_regno_start) + { + if (src_regno >= FIRST_PSEUDO_REGISTER + && reg_renumber[src_regno] < 0 && reg->type == OP_IN) + { + if (usage_insns[src_regno].check == curr_usage_insns_check + && (next_usage_insns + = usage_insns[src_regno].insns) != NULL_RTX + && NONDEBUG_INSN_P (curr_insn)) + add_to_inherit (src_regno, next_usage_insns); + else if (usage_insns[src_regno].check + != -(int) INSN_UID (curr_insn)) + /* Add usages but only if the reg is not set up + in the same insn. */ + add_next_usage_insn (src_regno, curr_insn, reloads_num); + } + else if (src_regno < FIRST_PSEUDO_REGISTER + || reg_renumber[src_regno] >= 0) + { + bool before_p; + rtx use_insn = curr_insn; + + before_p = (JUMP_P (curr_insn) + || (CALL_P (curr_insn) && reg->type == OP_IN)); + if (NONDEBUG_INSN_P (curr_insn) + && (! JUMP_P (curr_insn) || reg->type == OP_IN) + && split_if_necessary (src_regno, reg->biggest_mode, + potential_reload_hard_regs, + before_p, curr_insn, max_uid)) + { + if (reg->subreg_p) + lra_risky_transformations_p = true; + change_p = true; + /* Invalidate. */ + usage_insns[src_regno].check = 0; + if (before_p) + use_insn = PREV_INSN (curr_insn); + } + if (NONDEBUG_INSN_P (curr_insn)) + { + if (src_regno < FIRST_PSEUDO_REGISTER) + add_to_hard_reg_set (&live_hard_regs, + reg->biggest_mode, src_regno); + else + add_to_hard_reg_set (&live_hard_regs, + PSEUDO_REGNO_MODE (src_regno), + reg_renumber[src_regno]); + } + add_next_usage_insn (src_regno, use_insn, reloads_num); + } + } + /* Process call args. */ + if (curr_id->arg_hard_regs != NULL) + for (i = 0; (src_regno = curr_id->arg_hard_regs[i]) >= 0; i++) + if (src_regno < FIRST_PSEUDO_REGISTER) + { + SET_HARD_REG_BIT (live_hard_regs, src_regno); + add_next_usage_insn (src_regno, curr_insn, reloads_num); + } + for (i = 0; i < to_inherit_num; i++) + { + src_regno = to_inherit[i].regno; + if (inherit_reload_reg (false, src_regno, ALL_REGS, + curr_insn, to_inherit[i].insns)) + change_p = true; + else + setup_next_usage_insn (src_regno, curr_insn, reloads_num, false); + } + } + if (update_reloads_num_p + && NONDEBUG_INSN_P (curr_insn) + && (set = single_set (curr_insn)) != NULL_RTX) + { + int regno = -1; + if ((REG_P (SET_DEST (set)) + && (regno = REGNO (SET_DEST (set))) >= lra_constraint_new_regno_start + && reg_renumber[regno] < 0 + && (cl = lra_get_allocno_class (regno)) != NO_REGS) + || (REG_P (SET_SRC (set)) + && (regno = REGNO (SET_SRC (set))) >= lra_constraint_new_regno_start + && reg_renumber[regno] < 0 + && (cl = lra_get_allocno_class (regno)) != NO_REGS)) + { + if (ira_class_hard_regs_num[cl] <= max_small_class_regs_num) + reloads_num++; + if (hard_reg_set_subset_p (reg_class_contents[cl], live_hard_regs)) + IOR_HARD_REG_SET (potential_reload_hard_regs, + reg_class_contents[cl]); + } + } + /* We reached the start of the current basic block. */ + if (prev_insn == NULL_RTX || prev_insn == PREV_INSN (head) + || BLOCK_FOR_INSN (prev_insn) != curr_bb) + { + /* We reached the beginning of the current block -- do + rest of spliting in the current BB. */ + to_process = df_get_live_in (curr_bb); + if (BLOCK_FOR_INSN (head) != curr_bb) + { + /* We are somewhere in the middle of EBB. */ + get_live_on_other_edges (EDGE_PRED (curr_bb, 0)->src, + curr_bb, &temp_bitmap); + to_process = &temp_bitmap; + } + head_p = true; + EXECUTE_IF_SET_IN_BITMAP (to_process, 0, j, bi) + { + if ((int) j >= lra_constraint_new_regno_start) + break; + if (((int) j < FIRST_PSEUDO_REGISTER || reg_renumber[j] >= 0) + && usage_insns[j].check == curr_usage_insns_check + && (next_usage_insns = usage_insns[j].insns) != NULL_RTX) + { + if (need_for_split_p (potential_reload_hard_regs, j)) + { + if (lra_dump_file != NULL && head_p) + { + fprintf (lra_dump_file, + " ----------------------------------\n"); + head_p = false; + } + if (split_reg (false, j, bb_note (curr_bb), + next_usage_insns)) + change_p = true; + } + usage_insns[j].check = 0; + } + } + } + } + return change_p; +} + +/* This value affects EBB forming. If probability of edge from EBB to + a BB is not greater than the following value, we don't add the BB + to EBB. */ +#define EBB_PROBABILITY_CUTOFF ((REG_BR_PROB_BASE * 50) / 100) + +/* Current number of inheritance/split iteration. */ +int lra_inheritance_iter; + +/* Entry function for inheritance/split pass. */ +void +lra_inheritance (void) +{ + int i; + basic_block bb, start_bb; + edge e; + + lra_inheritance_iter++; + if (lra_inheritance_iter > LRA_MAX_INHERITANCE_PASSES) + return; + timevar_push (TV_LRA_INHERITANCE); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n********** Inheritance #%d: **********\n\n", + lra_inheritance_iter); + curr_usage_insns_check = 0; + usage_insns = XNEWVEC (struct usage_insns, lra_constraint_new_regno_start); + for (i = 0; i < lra_constraint_new_regno_start; i++) + usage_insns[i].check = 0; + bitmap_initialize (&check_only_regs, ®_obstack); + bitmap_initialize (&live_regs, ®_obstack); + bitmap_initialize (&temp_bitmap, ®_obstack); + bitmap_initialize (&ebb_global_regs, ®_obstack); + FOR_EACH_BB_FN (bb, cfun) + { + start_bb = bb; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "EBB"); + /* Form a EBB starting with BB. */ + bitmap_clear (&ebb_global_regs); + bitmap_ior_into (&ebb_global_regs, df_get_live_in (bb)); + for (;;) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " %d", bb->index); + if (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun) + || LABEL_P (BB_HEAD (bb->next_bb))) + break; + e = find_fallthru_edge (bb->succs); + if (! e) + break; + if (e->probability <= EBB_PROBABILITY_CUTOFF) + break; + bb = bb->next_bb; + } + bitmap_ior_into (&ebb_global_regs, df_get_live_out (bb)); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "\n"); + if (inherit_in_ebb (BB_HEAD (start_bb), BB_END (bb))) + /* Remember that the EBB head and tail can change in + inherit_in_ebb. */ + update_ebb_live_info (BB_HEAD (start_bb), BB_END (bb)); + } + bitmap_clear (&ebb_global_regs); + bitmap_clear (&temp_bitmap); + bitmap_clear (&live_regs); + bitmap_clear (&check_only_regs); + free (usage_insns); + + timevar_pop (TV_LRA_INHERITANCE); +} + + + +/* This page contains code to undo failed inheritance/split + transformations. */ + +/* Current number of iteration undoing inheritance/split. */ +int lra_undo_inheritance_iter; + +/* Fix BB live info LIVE after removing pseudos created on pass doing + inheritance/split which are REMOVED_PSEUDOS. */ +static void +fix_bb_live_info (bitmap live, bitmap removed_pseudos) +{ + unsigned int regno; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (removed_pseudos, 0, regno, bi) + if (bitmap_clear_bit (live, regno)) + bitmap_set_bit (live, lra_reg_info[regno].restore_regno); +} + +/* Return regno of the (subreg of) REG. Otherwise, return a negative + number. */ +static int +get_regno (rtx reg) +{ + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (REG_P (reg)) + return REGNO (reg); + return -1; +} + +/* Remove inheritance/split pseudos which are in REMOVE_PSEUDOS and + return true if we did any change. The undo transformations for + inheritance looks like + i <- i2 + p <- i => p <- i2 + or removing + p <- i, i <- p, and i <- i3 + where p is original pseudo from which inheritance pseudo i was + created, i and i3 are removed inheritance pseudos, i2 is another + not removed inheritance pseudo. All split pseudos or other + occurrences of removed inheritance pseudos are changed on the + corresponding original pseudos. + + The function also schedules insns changed and created during + inheritance/split pass for processing by the subsequent constraint + pass. */ +static bool +remove_inheritance_pseudos (bitmap remove_pseudos) +{ + basic_block bb; + int regno, sregno, prev_sregno, dregno, restore_regno; + rtx set, prev_set, prev_insn; + bool change_p, done_p; + + change_p = ! bitmap_empty_p (remove_pseudos); + /* We can not finish the function right away if CHANGE_P is true + because we need to marks insns affected by previous + inheritance/split pass for processing by the subsequent + constraint pass. */ + FOR_EACH_BB_FN (bb, cfun) + { + fix_bb_live_info (df_get_live_in (bb), remove_pseudos); + fix_bb_live_info (df_get_live_out (bb), remove_pseudos); + FOR_BB_INSNS_REVERSE (bb, curr_insn) + { + if (! INSN_P (curr_insn)) + continue; + done_p = false; + sregno = dregno = -1; + if (change_p && NONDEBUG_INSN_P (curr_insn) + && (set = single_set (curr_insn)) != NULL_RTX) + { + dregno = get_regno (SET_DEST (set)); + sregno = get_regno (SET_SRC (set)); + } + + if (sregno >= 0 && dregno >= 0) + { + if ((bitmap_bit_p (remove_pseudos, sregno) + && (lra_reg_info[sregno].restore_regno == dregno + || (bitmap_bit_p (remove_pseudos, dregno) + && (lra_reg_info[sregno].restore_regno + == lra_reg_info[dregno].restore_regno)))) + || (bitmap_bit_p (remove_pseudos, dregno) + && lra_reg_info[dregno].restore_regno == sregno)) + /* One of the following cases: + original <- removed inheritance pseudo + removed inherit pseudo <- another removed inherit pseudo + removed inherit pseudo <- original pseudo + Or + removed_split_pseudo <- original_reg + original_reg <- removed_split_pseudo */ + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Removing %s:\n", + bitmap_bit_p (&lra_split_regs, sregno) + || bitmap_bit_p (&lra_split_regs, dregno) + ? "split" : "inheritance"); + dump_insn_slim (lra_dump_file, curr_insn); + } + lra_set_insn_deleted (curr_insn); + done_p = true; + } + else if (bitmap_bit_p (remove_pseudos, sregno) + && bitmap_bit_p (&lra_inheritance_pseudos, sregno)) + { + /* Search the following pattern: + inherit_or_split_pseudo1 <- inherit_or_split_pseudo2 + original_pseudo <- inherit_or_split_pseudo1 + where the 2nd insn is the current insn and + inherit_or_split_pseudo2 is not removed. If it is found, + change the current insn onto: + original_pseudo <- inherit_or_split_pseudo2. */ + for (prev_insn = PREV_INSN (curr_insn); + prev_insn != NULL_RTX && ! NONDEBUG_INSN_P (prev_insn); + prev_insn = PREV_INSN (prev_insn)) + ; + if (prev_insn != NULL_RTX && BLOCK_FOR_INSN (prev_insn) == bb + && (prev_set = single_set (prev_insn)) != NULL_RTX + /* There should be no subregs in insn we are + searching because only the original reg might + be in subreg when we changed the mode of + load/store for splitting. */ + && REG_P (SET_DEST (prev_set)) + && REG_P (SET_SRC (prev_set)) + && (int) REGNO (SET_DEST (prev_set)) == sregno + && ((prev_sregno = REGNO (SET_SRC (prev_set))) + >= FIRST_PSEUDO_REGISTER) + /* As we consider chain of inheritance or + splitting described in above comment we should + check that sregno and prev_sregno were + inheritance/split pseudos created from the + same original regno. */ + && (lra_reg_info[sregno].restore_regno + == lra_reg_info[prev_sregno].restore_regno) + && ! bitmap_bit_p (remove_pseudos, prev_sregno)) + { + lra_assert (GET_MODE (SET_SRC (prev_set)) + == GET_MODE (regno_reg_rtx[sregno])); + if (GET_CODE (SET_SRC (set)) == SUBREG) + SUBREG_REG (SET_SRC (set)) = SET_SRC (prev_set); + else + SET_SRC (set) = SET_SRC (prev_set); + lra_push_insn_and_update_insn_regno_info (curr_insn); + lra_set_used_insn_alternative_by_uid + (INSN_UID (curr_insn), -1); + done_p = true; + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Change reload insn:\n"); + dump_insn_slim (lra_dump_file, curr_insn); + } + } + } + } + if (! done_p) + { + struct lra_insn_reg *reg; + bool restored_regs_p = false; + bool kept_regs_p = false; + + curr_id = lra_get_insn_recog_data (curr_insn); + for (reg = curr_id->regs; reg != NULL; reg = reg->next) + { + regno = reg->regno; + restore_regno = lra_reg_info[regno].restore_regno; + if (restore_regno >= 0) + { + if (change_p && bitmap_bit_p (remove_pseudos, regno)) + { + substitute_pseudo (&curr_insn, regno, + regno_reg_rtx[restore_regno]); + restored_regs_p = true; + } + else + kept_regs_p = true; + } + } + if (NONDEBUG_INSN_P (curr_insn) && kept_regs_p) + { + /* The instruction has changed since the previous + constraints pass. */ + lra_push_insn_and_update_insn_regno_info (curr_insn); + lra_set_used_insn_alternative_by_uid + (INSN_UID (curr_insn), -1); + } + else if (restored_regs_p) + /* The instruction has been restored to the form that + it had during the previous constraints pass. */ + lra_update_insn_regno_info (curr_insn); + if (restored_regs_p && lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Insn after restoring regs:\n"); + dump_insn_slim (lra_dump_file, curr_insn); + } + } + } + } + return change_p; +} + +/* If optional reload pseudos failed to get a hard register or was not + inherited, it is better to remove optional reloads. We do this + transformation after undoing inheritance to figure out necessity to + remove optional reloads easier. Return true if we do any + change. */ +static bool +undo_optional_reloads (void) +{ + bool change_p, keep_p; + unsigned int regno, uid; + bitmap_iterator bi, bi2; + rtx insn, set, src, dest; + bitmap_head removed_optional_reload_pseudos, insn_bitmap; + + bitmap_initialize (&removed_optional_reload_pseudos, ®_obstack); + bitmap_copy (&removed_optional_reload_pseudos, &lra_optional_reload_pseudos); + EXECUTE_IF_SET_IN_BITMAP (&lra_optional_reload_pseudos, 0, regno, bi) + { + keep_p = false; + /* Keep optional reloads from previous subpasses. */ + if (lra_reg_info[regno].restore_regno < 0 + /* If the original pseudo changed its allocation, just + removing the optional pseudo is dangerous as the original + pseudo will have longer live range. */ + || reg_renumber[lra_reg_info[regno].restore_regno] >= 0) + keep_p = true; + else if (reg_renumber[regno] >= 0) + EXECUTE_IF_SET_IN_BITMAP (&lra_reg_info[regno].insn_bitmap, 0, uid, bi2) + { + insn = lra_insn_recog_data[uid]->insn; + if ((set = single_set (insn)) == NULL_RTX) + continue; + src = SET_SRC (set); + dest = SET_DEST (set); + if (! REG_P (src) || ! REG_P (dest)) + continue; + if (REGNO (dest) == regno + /* Ignore insn for optional reloads itself. */ + && lra_reg_info[regno].restore_regno != (int) REGNO (src) + /* Check only inheritance on last inheritance pass. */ + && (int) REGNO (src) >= new_regno_start + /* Check that the optional reload was inherited. */ + && bitmap_bit_p (&lra_inheritance_pseudos, REGNO (src))) + { + keep_p = true; + break; + } + } + if (keep_p) + { + bitmap_clear_bit (&removed_optional_reload_pseudos, regno); + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "Keep optional reload reg %d\n", regno); + } + } + change_p = ! bitmap_empty_p (&removed_optional_reload_pseudos); + bitmap_initialize (&insn_bitmap, ®_obstack); + EXECUTE_IF_SET_IN_BITMAP (&removed_optional_reload_pseudos, 0, regno, bi) + { + if (lra_dump_file != NULL) + fprintf (lra_dump_file, "Remove optional reload reg %d\n", regno); + bitmap_copy (&insn_bitmap, &lra_reg_info[regno].insn_bitmap); + EXECUTE_IF_SET_IN_BITMAP (&insn_bitmap, 0, uid, bi2) + { + insn = lra_insn_recog_data[uid]->insn; + if ((set = single_set (insn)) != NULL_RTX) + { + src = SET_SRC (set); + dest = SET_DEST (set); + if (REG_P (src) && REG_P (dest) + && ((REGNO (src) == regno + && (lra_reg_info[regno].restore_regno + == (int) REGNO (dest))) + || (REGNO (dest) == regno + && (lra_reg_info[regno].restore_regno + == (int) REGNO (src))))) + { + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, " Deleting move %u\n", + INSN_UID (insn)); + dump_insn_slim (lra_dump_file, insn); + } + lra_set_insn_deleted (insn); + continue; + } + /* We should not worry about generation memory-memory + moves here as if the corresponding inheritance did + not work (inheritance pseudo did not get a hard reg), + we remove the inheritance pseudo and the optional + reload. */ + } + substitute_pseudo (&insn, regno, + regno_reg_rtx[lra_reg_info[regno].restore_regno]); + lra_update_insn_regno_info (insn); + if (lra_dump_file != NULL) + { + fprintf (lra_dump_file, + " Restoring original insn:\n"); + dump_insn_slim (lra_dump_file, insn); + } + } + } + /* Clear restore_regnos. */ + EXECUTE_IF_SET_IN_BITMAP (&lra_optional_reload_pseudos, 0, regno, bi) + lra_reg_info[regno].restore_regno = -1; + bitmap_clear (&insn_bitmap); + bitmap_clear (&removed_optional_reload_pseudos); + return change_p; +} + +/* Entry function for undoing inheritance/split transformation. Return true + if we did any RTL change in this pass. */ +bool +lra_undo_inheritance (void) +{ + unsigned int regno; + int restore_regno, hard_regno; + int n_all_inherit, n_inherit, n_all_split, n_split; + bitmap_head remove_pseudos; + bitmap_iterator bi; + bool change_p; + + lra_undo_inheritance_iter++; + if (lra_undo_inheritance_iter > LRA_MAX_INHERITANCE_PASSES) + return false; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, + "\n********** Undoing inheritance #%d: **********\n\n", + lra_undo_inheritance_iter); + bitmap_initialize (&remove_pseudos, ®_obstack); + n_inherit = n_all_inherit = 0; + EXECUTE_IF_SET_IN_BITMAP (&lra_inheritance_pseudos, 0, regno, bi) + if (lra_reg_info[regno].restore_regno >= 0) + { + n_all_inherit++; + if (reg_renumber[regno] < 0 + /* If the original pseudo changed its allocation, just + removing inheritance is dangerous as for changing + allocation we used shorter live-ranges. */ + && reg_renumber[lra_reg_info[regno].restore_regno] < 0) + bitmap_set_bit (&remove_pseudos, regno); + else + n_inherit++; + } + if (lra_dump_file != NULL && n_all_inherit != 0) + fprintf (lra_dump_file, "Inherit %d out of %d (%.2f%%)\n", + n_inherit, n_all_inherit, + (double) n_inherit / n_all_inherit * 100); + n_split = n_all_split = 0; + EXECUTE_IF_SET_IN_BITMAP (&lra_split_regs, 0, regno, bi) + if ((restore_regno = lra_reg_info[regno].restore_regno) >= 0) + { + n_all_split++; + hard_regno = (restore_regno >= FIRST_PSEUDO_REGISTER + ? reg_renumber[restore_regno] : restore_regno); + if (hard_regno < 0 || reg_renumber[regno] == hard_regno) + bitmap_set_bit (&remove_pseudos, regno); + else + { + n_split++; + if (lra_dump_file != NULL) + fprintf (lra_dump_file, " Keep split r%d (orig=r%d)\n", + regno, restore_regno); + } + } + if (lra_dump_file != NULL && n_all_split != 0) + fprintf (lra_dump_file, "Split %d out of %d (%.2f%%)\n", + n_split, n_all_split, + (double) n_split / n_all_split * 100); + change_p = remove_inheritance_pseudos (&remove_pseudos); + bitmap_clear (&remove_pseudos); + /* Clear restore_regnos. */ + EXECUTE_IF_SET_IN_BITMAP (&lra_inheritance_pseudos, 0, regno, bi) + lra_reg_info[regno].restore_regno = -1; + EXECUTE_IF_SET_IN_BITMAP (&lra_split_regs, 0, regno, bi) + lra_reg_info[regno].restore_regno = -1; + change_p = undo_optional_reloads () || change_p; + return change_p; +} |