aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/lra-constraints.c
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/lra-constraints.c
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_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.c5909
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, &reg_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, &reg_obstack);
+ bitmap_initialize (&live_regs, &reg_obstack);
+ bitmap_initialize (&temp_bitmap, &reg_obstack);
+ bitmap_initialize (&ebb_global_regs, &reg_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, &reg_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, &reg_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, &reg_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;
+}