/* Code for RTL transformations to satisfy insn constraints.
- Copyright (C) 2010-2018 Free Software Foundation, Inc.
+ Copyright (C) 2010-2020 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
#include "expr.h"
#include "cfgrtl.h"
#include "rtl-error.h"
-#include "params.h"
#include "lra.h"
#include "lra-int.h"
#include "print-rtl.h"
+#include "function-abi.h"
+#include "rtl-iter.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
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.
+ class to be narrowed to CL if it is currently a superset of CL and
+ if either:
+
+ - ALLOW_ALL_RELOAD_CLASS_CHANGES_P is true or
+ - the instruction we're processing is not a reload move.
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)
+in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class,
+ bool allow_all_reload_class_changes_p = false)
{
enum reg_class rclass, common_class;
machine_mode reg_mode;
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
+ || (!allow_all_reload_class_changes_p
+ && 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)))
if (m_base_loc != NULL)
{
m_base_reg = *m_base_loc;
- lra_eliminate_reg_if_possible (m_base_loc);
+ /* If we have non-legitimate address which is decomposed not in
+ the way we expected, don't do elimination here. In such case
+ the address will be reloaded and elimination will be done in
+ reload insn finally. */
+ if (REG_P (m_base_reg))
+ lra_eliminate_reg_if_possible (m_base_loc);
if (m_ad->base_term2 != NULL)
*m_ad->base_term2 = *m_ad->base_term;
}
if (m_index_loc != NULL)
{
m_index_reg = *m_index_loc;
- lra_eliminate_reg_if_possible (m_index_loc);
+ if (REG_P (m_index_reg))
+ lra_eliminate_reg_if_possible (m_index_loc);
}
}
*m_index_loc = m_index_reg;
}
-/* Return true if the eliminated form of AD is a legitimate target address. */
+/* Return true if the eliminated form of AD is a legitimate target address.
+ If OP is a MEM, AD is the address within OP, otherwise OP should be
+ ignored. CONSTRAINT is one constraint that the operand may need
+ to meet. */
static bool
-valid_address_p (struct address_info *ad)
+valid_address_p (rtx op, struct address_info *ad,
+ enum constraint_num constraint)
{
address_eliminator eliminator (ad);
+
+ /* Allow a memory OP if it matches CONSTRAINT, even if CONSTRAINT is more
+ forgiving than "m".
+ Need to extract memory from op for special memory constraint,
+ i.e. bcst_mem_operand in i386 backend. */
+ if (MEM_P (extract_mem_from_operand (op))
+ && (insn_extra_memory_constraint (constraint)
+ || insn_extra_special_memory_constraint (constraint))
+ && constraint_satisfied_p (op, constraint))
+ return true;
+
return valid_address_p (ad->mode, *ad->outer, ad->as);
}
+/* For special_memory_operand, it could be false for MEM_P (op),
+ i.e. bcst_mem_operand in i386 backend.
+ Extract and return real memory operand or op. */
+rtx
+extract_mem_from_operand (rtx op)
+{
+ for (rtx x = op;; x = XEXP (x, 0))
+ {
+ if (MEM_P (x))
+ return x;
+ if (GET_RTX_LENGTH (GET_CODE (x)) != 1
+ || GET_RTX_FORMAT (GET_CODE (x))[0] != 'e')
+ break;
+ }
+ return op;
+}
+
/* Return true if the eliminated form of memory reference OP satisfies
extra (special) memory constraint CONSTRAINT. */
static bool
satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
{
struct address_info ad;
+ rtx mem = extract_mem_from_operand (op);
+ if (!MEM_P (mem))
+ return false;
- decompose_mem_address (&ad, op);
+ decompose_mem_address (&ad, mem);
address_eliminator eliminator (&ad);
return constraint_satisfied_p (op, constraint);
}
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. */
+/* The canonical form of an rtx inside a MEM is not necessarily the same as the
+ canonical form of the rtx outside the MEM. Fix this up in the case that
+ we're reloading an address (and therefore pulling it outside a MEM). */
+static rtx
+canonicalize_reload_addr (rtx addr)
+{
+ subrtx_var_iterator::array_type array;
+ FOR_EACH_SUBRTX_VAR (iter, array, addr, NONCONST)
+ {
+ rtx x = *iter;
+ if (GET_CODE (x) == MULT && CONST_INT_P (XEXP (x, 1)))
+ {
+ const HOST_WIDE_INT ci = INTVAL (XEXP (x, 1));
+ const int pwr2 = exact_log2 (ci);
+ if (pwr2 > 0)
+ {
+ /* Rewrite this to use a shift instead, which is canonical when
+ outside of a MEM. */
+ PUT_CODE (x, ASHIFT);
+ XEXP (x, 1) = GEN_INT (pwr2);
+ }
+ }
+ }
+
+ return addr;
+}
+
+/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse an existing
+ reload pseudo. Don't reuse an existing reload pseudo if IN_SUBREG_P
+ is true and the reused pseudo should be wrapped up in a SUBREG.
+ The result pseudo is returned through RESULT_REG. Return TRUE if we
+ created a new pseudo, FALSE if we reused an existing reload pseudo.
+ Use TITLE to describe new registers for debug purposes. */
static bool
get_reload_reg (enum op_type type, machine_mode mode, rtx original,
enum reg_class rclass, bool in_subreg_p,
if (type == OP_OUT)
{
+ /* Output reload registers tend to start out with a conservative
+ choice of register class. Usually this is ALL_REGS, although
+ a target might narrow it (for performance reasons) through
+ targetm.preferred_reload_class. It's therefore quite common
+ for a reload instruction to require a more restrictive class
+ than the class that was originally assigned to the reload register.
+
+ In these situations, it's more efficient to refine the choice
+ of register class rather than create a second reload register.
+ This also helps to avoid cycling for registers that are only
+ used by reload instructions. */
+ if (REG_P (original)
+ && (int) REGNO (original) >= new_regno_start
+ && INSN_UID (curr_insn) >= new_insn_uid_start
+ && in_class_p (original, rclass, &new_class, true))
+ {
+ unsigned int regno = REGNO (original);
+ if (lra_dump_file != NULL)
+ {
+ fprintf (lra_dump_file, " Reuse r%d for output ", 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");
+ *result_reg = original;
+ return false;
+ }
*result_reg
= lra_create_new_reg_with_unique_value (mode, original, rclass, title);
return true;
}
\f
-
-/* 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, 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);
-}
-
-\f
-
/* The page contains major code to choose the current insn alternative
and generate reloads for it. */
operand ("a"). "b" must then be copied into a new register
so that it doesn't clobber the current value of "a".
- We can not use the same value if the output pseudo is
+ We cannot use the same value if the output pseudo is
early clobbered or the input pseudo is mentioned in the
output, e.g. as an address part in memory, because
output reload will actually extend the pseudo liveness.
curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = true;
curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = new_in_reg;
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]));
+ if (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;
- }
+ else
+ {
+ lra_assert
+ (GET_MODE (new_out_reg) == GET_MODE (*curr_id->operand_loc[in]));
+ *curr_id->operand_loc[in] = new_out_reg;
+ }
lra_update_dups (curr_id, ins);
if (out < 0)
return;
narrow_reload_pseudo_class (out_rtx, goal_class);
if (find_reg_note (curr_insn, REG_UNUSED, out_rtx) == NULL_RTX)
{
+ reg = SUBREG_P (out_rtx) ? SUBREG_REG (out_rtx) : out_rtx;
start_sequence ();
+ /* If we had strict_low_part, use it also in reload to keep other
+ parts unchanged but do it only for regs as strict_low_part
+ has no sense for memory and probably there is no insn pattern
+ to match the reload insn in memory case. */
+ if (out >= 0 && curr_static_id->operand[out].strict_low && REG_P (reg))
+ out_rtx = gen_rtx_STRICT_LOW_PART (VOIDmode, out_rtx);
lra_emit_move (out_rtx, copy_rtx (new_out_reg));
emit_insn (*after);
*after = get_insns ();
static bool
simplify_operand_subreg (int nop, machine_mode reg_mode)
{
- int hard_regno;
+ int hard_regno, inner_hard_regno;
rtx_insn *before, *after;
machine_mode mode, innermode;
rtx reg, new_reg;
alter_subreg (curr_id->operand_loc[nop], false);
rtx subst = *curr_id->operand_loc[nop];
lra_assert (MEM_P (subst));
-
+ const bool addr_is_valid = valid_address_p (GET_MODE (subst),
+ XEXP (subst, 0),
+ MEM_ADDR_SPACE (subst));
if (!addr_was_valid
- || valid_address_p (GET_MODE (subst), XEXP (subst, 0),
- MEM_ADDR_SPACE (subst))
+ || addr_is_valid
|| ((get_constraint_type (lookup_constraint
(curr_static_id->operand[nop].constraint))
!= CT_SPECIAL_MEMORY)
data into a register when the inner is narrower than outer or
missing important data from memory when the inner is wider than
outer. This rule only applies to modes that are no wider than
- a word. */
- if (!(maybe_ne (GET_MODE_PRECISION (mode),
- GET_MODE_PRECISION (innermode))
- && known_le (GET_MODE_SIZE (mode), UNITS_PER_WORD)
- && known_le (GET_MODE_SIZE (innermode), UNITS_PER_WORD)
- && WORD_REGISTER_OPERATIONS)
+ a word.
+
+ If valid memory becomes invalid after subreg elimination
+ and address might be different we still have to reload
+ memory.
+ */
+ if ((! addr_was_valid
+ || addr_is_valid
+ || known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (innermode)))
+ && !(maybe_ne (GET_MODE_PRECISION (mode),
+ GET_MODE_PRECISION (innermode))
+ && known_le (GET_MODE_SIZE (mode), UNITS_PER_WORD)
+ && known_le (GET_MODE_SIZE (innermode), UNITS_PER_WORD)
+ && WORD_REGISTER_OPERATIONS)
&& (!(MEM_ALIGN (subst) < GET_MODE_ALIGNMENT (mode)
&& targetm.slow_unaligned_access (mode, MEM_ALIGN (subst)))
|| (MEM_ALIGN (reg) < GET_MODE_ALIGNMENT (innermode)
enum reg_class rclass
= (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
if (get_reload_reg (curr_static_id->operand[nop].type, innermode,
- reg, rclass, TRUE, "slow mem", &new_reg))
+ reg, rclass, TRUE, "slow/invalid mem", &new_reg))
{
bool insert_before, insert_after;
bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
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, "slow mem", &new_reg))
+ rclass, TRUE, "slow/invalid mem", &new_reg))
{
bool insert_before, insert_after;
bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
}
*curr_id->operand_loc[nop] = new_reg;
lra_process_new_insns (curr_insn, before, after,
- "Inserting slow mem reload");
+ "Inserting slow/invalid mem reload");
return true;
}
for the new uses. */
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, innermode)
- < 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)
- || overlaps_hard_reg_set_p (lra_no_alloc_regs,
- mode, hard_regno)))
+ && paradoxical_subreg_p (operand)
+ && (inner_hard_regno = lra_get_regno_hard_regno (REGNO (reg))) >= 0
+ && ((hard_regno
+ = simplify_subreg_regno (inner_hard_regno, innermode,
+ SUBREG_BYTE (operand), mode)) < 0
+ || ((hard_regno_nregs (inner_hard_regno, innermode)
+ < 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)
+ || overlaps_hard_reg_set_p (lra_no_alloc_regs,
+ mode, hard_regno)))))
{
/* The class will be defined later in curr_insn_transform. */
enum reg_class rclass
return false;
code = GET_CODE (x);
mode = GET_MODE (x);
+
if (code == SUBREG)
{
+ /* For all SUBREGs we want to check whether the full multi-register
+ overlaps the set. For normal SUBREGs this means 'get_hard_regno' of
+ the inner register, for paradoxical SUBREGs this means the
+ 'get_hard_regno' of the full SUBREG and for complete SUBREGs either is
+ fine. Use the wider mode for all cases. */
+ rtx subreg = SUBREG_REG (x);
mode = wider_subreg_mode (x);
- x = SUBREG_REG (x);
- code = GET_CODE (x);
+ if (mode == GET_MODE (subreg))
+ {
+ x = subreg;
+ code = GET_CODE (x);
+ }
}
- if (REG_P (x))
+ if (REG_P (x) || SUBREG_P (x))
{
x_hard_regno = get_hard_regno (x, true);
return (x_hard_regno >= 0
HARD_REG_SET temp;
lra_assert (hard_reg_set_subset_p (reg_class_contents[rclass], set));
- COPY_HARD_REG_SET (temp, set);
- AND_COMPL_HARD_REG_SET (temp, lra_no_alloc_regs);
+ temp = set & ~lra_no_alloc_regs;
return (hard_reg_set_subset_p
(temp, ira_prohibited_class_mode_regs[rclass][mode]));
}
alternative. */
static unsigned int curr_small_class_check = 0;
-/* Update number of used inputs of class OP_CLASS for operand NOP.
- Return true if we have more such class operands than the number of
- available regs. */
+/* Update number of used inputs of class OP_CLASS for operand NOP
+ of alternative NALT. Return true if we have more such class operands
+ than the number of available regs. */
static bool
-update_and_check_small_class_inputs (int nop, enum reg_class op_class)
+update_and_check_small_class_inputs (int nop, int nalt,
+ enum reg_class op_class)
{
static unsigned int small_class_check[LIM_REG_CLASSES];
static int small_class_input_nums[LIM_REG_CLASSES];
&& hard_reg_set_intersect_p (reg_class_contents[op_class],
ira_no_alloc_regs)
&& (curr_static_id->operand[nop].type != OP_OUT
- || curr_static_id->operand[nop].early_clobber))
+ || TEST_BIT (curr_static_id->operand[nop].early_clobber_alts, nalt)))
{
if (small_class_check[op_class] == curr_small_class_check)
small_class_input_nums[op_class]++;
/* 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
+ we cannot choose the alternative or find how to reload the
operands. */
static bool
process_alt_operands (int only_alternative)
if (!TEST_BIT (preferred, nalt))
continue;
+ bool matching_early_clobber[MAX_RECOG_OPERANDS];
curr_small_class_check++;
overall = losers = addr_losers = 0;
static_reject = reject = reload_nregs = reload_sum = 0;
fprintf (lra_dump_file,
" Staticly defined alt reject+=%d\n", inc);
static_reject += inc;
+ matching_early_clobber[nop] = 0;
}
reject += static_reject;
early_clobbered_regs_num = 0;
/* 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
+ if (!TEST_BIT (curr_static_id->operand[m]
+ .early_clobber_alts, nalt)
|| operand_reg[nop] == NULL_RTX
|| (find_regno_note (curr_insn, REG_DEAD,
REGNO (op))
}
else
{
- /* Operands don't match. Both operands must
- allow a reload register, otherwise we
- cannot make them match. */
+ /* If the operands do not match and one
+ operand is INOUT, we can not match them.
+ Try other possibilities, e.g. other
+ alternatives or commutative operand
+ exchange. */
+ if (curr_static_id->operand[nop].type == OP_INOUT
+ || curr_static_id->operand[m].type == OP_INOUT)
+ break;
+ /* Operands don't match. If the operands are
+ different user defined explicit hard
+ registers, then we cannot make them match
+ when one is early clobber operand. */
+ if ((REG_P (*curr_id->operand_loc[nop])
+ || SUBREG_P (*curr_id->operand_loc[nop]))
+ && (REG_P (*curr_id->operand_loc[m])
+ || SUBREG_P (*curr_id->operand_loc[m])))
+ {
+ rtx nop_reg = *curr_id->operand_loc[nop];
+ if (SUBREG_P (nop_reg))
+ nop_reg = SUBREG_REG (nop_reg);
+ rtx m_reg = *curr_id->operand_loc[m];
+ if (SUBREG_P (m_reg))
+ m_reg = SUBREG_REG (m_reg);
+
+ if (REG_P (nop_reg)
+ && HARD_REGISTER_P (nop_reg)
+ && REG_USERVAR_P (nop_reg)
+ && REG_P (m_reg)
+ && HARD_REGISTER_P (m_reg)
+ && REG_USERVAR_P (m_reg))
+ {
+ int i;
+
+ for (i = 0; i < early_clobbered_regs_num; i++)
+ if (m == early_clobbered_nops[i])
+ break;
+ if (i < early_clobbered_regs_num
+ || early_clobber_p)
+ break;
+ }
+ }
+ /* 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
it results in less hard regs required for
the insn than a non-matching earlyclobber
alternative. */
- if (curr_static_id->operand[m].early_clobber)
+ if (TEST_BIT (curr_static_id->operand[m]
+ .early_clobber_alts, nalt))
{
if (lra_dump_file != NULL)
fprintf
" %d Matching earlyclobber alt:"
" reject--\n",
nop);
- reject--;
+ if (!matching_early_clobber[m])
+ {
+ reject--;
+ matching_early_clobber[m] = 1;
+ }
}
/* Otherwise we prefer no matching
alternatives because it gives more freedom
reloads. */
badop = false;
this_alternative = curr_alt[m];
- COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]);
+ this_alternative_set = curr_alt_set[m];
winreg = this_alternative != NO_REGS;
break;
}
break;
case CT_SPECIAL_MEMORY:
- if (MEM_P (op)
- && satisfies_memory_constraint_p (op, cn))
+ if (satisfies_memory_constraint_p (op, cn))
win = true;
else if (spilled_pseudo_p (op))
win = true;
break;
reg:
+ if (mode == BLKmode)
+ break;
this_alternative = reg_class_subunion[this_alternative][cl];
- IOR_HARD_REG_SET (this_alternative_set,
- reg_class_contents[cl]);
+ 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]);
+ this_costly_alternative_set |= reg_class_contents[cl];
}
- if (mode == BLKmode)
- break;
winreg = true;
if (REG_P (op))
{
while ((p += len), c);
scratch_p = (operand_reg[nop] != NULL_RTX
- && lra_former_scratch_p (REGNO (operand_reg[nop])));
+ && ira_former_scratch_p (REGNO (operand_reg[nop])));
/* Record which operands fit this alternative. */
if (win)
{
if (this_alternative != NO_REGS)
{
- HARD_REG_SET available_regs;
-
- COPY_HARD_REG_SET (available_regs,
- reg_class_contents[this_alternative]);
- AND_COMPL_HARD_REG_SET
- (available_regs,
- ira_prohibited_class_mode_regs[this_alternative][mode]);
- AND_COMPL_HARD_REG_SET (available_regs, lra_no_alloc_regs);
+ HARD_REG_SET available_regs
+ = (reg_class_contents[this_alternative]
+ & ~((ira_prohibited_class_mode_regs
+ [this_alternative][mode])
+ | lra_no_alloc_regs));
if (hard_reg_set_empty_p (available_regs))
{
/* There are no hard regs holding a value of given
goto fail;
}
- /* Alternative loses if it required class pseudo can not
+ /* Alternative loses if it required class pseudo cannot
hold value of required mode. Such insns can be
described by insn definitions with mode iterators. */
if (GET_MODE (*curr_id->operand_loc[nop]) != VOIDmode
class which does not have actually enough regs to
hold the value (e.g. x86 AREG for mode requiring
more one general reg). Therefore we have 2
- conditions to check that the reload pseudo can
- not hold the mode value. */
+ conditions to check that the reload pseudo cannot
+ hold the mode value. */
&& (!targetm.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: reload pseudo for op %d "
- " can not hold the mode value -- refuse\n",
+ "cannot hold the mode value -- refuse\n",
nalt, nop);
goto fail;
}
&& (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 (offmemok && REG_P (op))
+ {
+ if (lra_dump_file != NULL)
+ fprintf
+ (lra_dump_file,
+ " %d Spill pseudo into memory: reject+=3\n",
+ nop);
+ reject += 3;
+ }
+ else
+ {
+ 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)
(GET_MODE (op), this_alternative, cl)))))
losers++;
- /* 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 (MEM_P (op) && offmemok)
addr_losers++;
- else if (curr_static_id->operand[nop].type == OP_INOUT)
+ else
{
- if (lra_dump_file != NULL)
- fprintf
- (lra_dump_file,
- " %d Input/Output reload: reject+=%d\n",
- nop, LRA_LOSER_COST_FACTOR);
- reject += LRA_LOSER_COST_FACTOR;
+ /* 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 (curr_static_id->operand[nop].type == OP_INOUT)
+ {
+ if (lra_dump_file != NULL)
+ fprintf
+ (lra_dump_file,
+ " %d Input/Output reload: reject+=%d\n",
+ nop, LRA_LOSER_COST_FACTOR);
+ reject += LRA_LOSER_COST_FACTOR;
+ }
}
}
goto fail;
}
- if (update_and_check_small_class_inputs (nop, this_alternative))
+ if (update_and_check_small_class_inputs (nop, nalt,
+ this_alternative))
{
if (lra_dump_file != NULL)
fprintf (lra_dump_file,
goto fail;
}
curr_alt[nop] = this_alternative;
- COPY_HARD_REG_SET (curr_alt_set[nop], this_alternative_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;
if (first_conflict_j < 0)
first_conflict_j = j;
last_conflict_j = j;
+ /* Both the earlyclobber operand and conflicting operand
+ cannot both be user defined hard registers. */
+ if (HARD_REGISTER_P (operand_reg[i])
+ && REG_USERVAR_P (operand_reg[i])
+ && operand_reg[j] != NULL_RTX
+ && HARD_REGISTER_P (operand_reg[j])
+ && REG_USERVAR_P (operand_reg[j]))
+ fatal_insn ("unable to generate reloads for "
+ "impossible constraints:", curr_insn);
}
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]))
+
+ /* If an earlyclobber operand conflicts with another non-matching
+ operand (ie, they have been assigned the same hard register),
+ then it is better to reload the other operand, as there may
+ exist yet another operand with a matching constraint associated
+ with the earlyclobber operand. However, if one of the operands
+ is an explicit use of a hard register, then we must reload the
+ other non-hard register operand. */
+ if (HARD_REGISTER_P (operand_reg[i])
+ || (first_conflict_j == last_conflict_j
+ && operand_reg[last_conflict_j] != NULL_RTX
+ && !curr_alt_match_win[last_conflict_j]
+ && !HARD_REGISTER_P (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
{
}
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);
+ }
+ /* Early clobber was already reflected in REJECT. */
+ if (!matching_early_clobber[i])
+ {
+ lra_assert (reject > 0);
reject--;
- overall += LRA_LOSER_COST_FACTOR - 1;
+ matching_early_clobber[i] = 1;
}
+ 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",
rtx new_reg;
HOST_WIDE_INT scale;
rtx op = *curr_id->operand_loc[nop];
+ rtx mem = extract_mem_from_operand (op);
const char *constraint = curr_static_id->operand[nop].constraint;
enum constraint_num cn = lookup_constraint (constraint);
bool change_p = false;
- if (MEM_P (op)
- && GET_MODE (op) == BLKmode
- && GET_CODE (XEXP (op, 0)) == SCRATCH)
+ if (MEM_P (mem)
+ && GET_MODE (mem) == BLKmode
+ && GET_CODE (XEXP (mem, 0)) == SCRATCH)
return false;
if (insn_extra_address_constraint (cn)
&& curr_static_id->operand[nop].is_address)
decompose_lea_address (&ad, curr_id->operand_loc[nop]);
/* Do not attempt to decompose arbitrary addresses generated by combine
- for asm operands with loose constraints, e.g 'X'. */
- else if (MEM_P (op)
+ for asm operands with loose constraints, e.g 'X'.
+ Need to extract memory from op for special memory constraint,
+ i.e. bcst_mem_operand in i386 backend. */
+ else if (MEM_P (mem)
&& !(INSN_CODE (curr_insn) < 0
&& get_constraint_type (cn) == CT_FIXED_FORM
&& constraint_satisfied_p (op, cn)))
- decompose_mem_address (&ad, op);
+ decompose_mem_address (&ad, mem);
else if (GET_CODE (op) == SUBREG
&& MEM_P (SUBREG_REG (op)))
decompose_mem_address (&ad, SUBREG_REG (op));
All these cases involve a non-autoinc address, so there is no
point revalidating other types. */
- if (ad.autoinc_p || valid_address_p (&ad))
+ if (ad.autoinc_p || valid_address_p (op, &ad, cn))
return change_p;
/* Any index existed before LRA started, so we can assume that the
if (code >= 0)
{
*ad.inner = gen_rtx_LO_SUM (Pmode, new_reg, addr);
- if (! valid_address_p (ad.mode, *ad.outer, ad.as))
+ if (!valid_address_p (op, &ad, cn))
{
/* Try to put lo_sum into register. */
insn = emit_insn (gen_rtx_SET
if (code >= 0)
{
*ad.inner = new_reg;
- if (! valid_address_p (ad.mode, *ad.outer, ad.as))
+ if (!valid_address_p (op, &ad, cn))
{
*ad.inner = addr;
code = -1;
&& CONSTANT_P (XEXP (SET_SRC (set), 1)))
{
*ad.inner = SET_SRC (set);
- if (valid_address_p (ad.mode, *ad.outer, ad.as))
+ if (valid_address_p (op, &ad, cn))
{
*ad.base_term = XEXP (SET_SRC (set), 0);
*ad.disp_term = XEXP (SET_SRC (set), 1);
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))
+ /* 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 (CALL_P (curr_insn))
no_output_reloads_p = true;
if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (curr_insn)))
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. Don't generate use
- pattern here as we could use the insn SP offset. */
- lra_set_insn_deleted (curr_insn);
+ lra_asm_error_p = true;
+ if (! JUMP_P (curr_insn))
+ {
+ /* Avoid further trouble with this insn. Don't generate use
+ pattern here as we could use the insn SP offset. */
+ lra_set_insn_deleted (curr_insn);
+ }
+ else
+ {
+ lra_invalidate_insn_data (curr_insn);
+ ira_nullify_asm_goto (curr_insn);
+ lra_update_insn_regno_info (curr_insn);
+ }
return true;
}
if (sec_mode != rld_mode)
{
/* If the target says specifically to use another mode for
- secondary memory moves we can not reuse the original
+ secondary memory moves we cannot reuse the original
insn. */
after = emit_spill_move (false, new_reg, dest);
lra_process_new_insns (curr_insn, NULL, after,
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)
- && lra_former_scratch_p (REGNO (op)))
+ && ira_former_scratch_operand_p (curr_insn, i)
+ && ira_former_scratch_p (REGNO (op)))
{
int regno = REGNO (op);
lra_change_class (regno, NO_REGS, " Change to", true);
&& goal_alt[i] != NO_REGS && REG_P (op)
&& (regno = REGNO (op)) >= FIRST_PSEUDO_REGISTER
&& regno < new_regno_start
- && ! lra_former_scratch_p (regno)
+ && ! ira_former_scratch_p (regno)
&& reg_renumber[regno] < 0
/* Check that the optional reload pseudo will be able to
hold given mode value. */
|| MEM_P (SET_DEST (curr_insn_set))
|| GET_CODE (SET_DEST (curr_insn_set)) == SUBREG))))
optional_p = true;
+ else if (goal_alt_matched[i][0] != -1
+ && curr_static_id->operand[i].type == OP_OUT
+ && (curr_static_id->operand_alternative
+ [goal_alt_number * n_operands + i].earlyclobber)
+ && REG_P (op))
+ {
+ for (j = 0; goal_alt_matched[i][j] != -1; j++)
+ {
+ rtx op2 = *curr_id->operand_loc[goal_alt_matched[i][j]];
+
+ if (REG_P (op2) && REGNO (op) != REGNO (op2))
+ break;
+ }
+ if (goal_alt_matched[i][j] != -1)
+ {
+ /* Generate reloads for different output and matched
+ input registers. This is the easiest way to avoid
+ creation of non-existing register conflicts in
+ lra-lives.c. */
+ match_reload (i, goal_alt_matched[i], outputs, goal_alt[i], &before,
+ &after, TRUE);
+ outputs[n_outputs++] = i;
+ outputs[n_outputs] = -1;
+ }
+ continue;
+ }
else
continue;
}
{
rtx addr = *loc;
enum rtx_code code = GET_CODE (addr);
-
+ bool align_p = false;
+
if (code == AND && CONST_INT_P (XEXP (addr, 1)))
- /* (and ... (const_int -X)) is used to align to X bytes. */
- addr = XEXP (*loc, 0);
+ {
+ /* (and ... (const_int -X)) is used to align to X bytes. */
+ align_p = true;
+ addr = XEXP (*loc, 0);
+ }
+ else
+ addr = canonicalize_reload_addr (addr);
+
lra_emit_move (new_reg, addr);
- if (addr != *loc)
+ if (align_p)
emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg), new_reg, XEXP (*loc, 1)));
}
before = get_insns ();
regno = lra_get_regno_hard_regno (regno);
if (regno < 0)
return false;
- COMPL_HARD_REG_SET (alloc_regs, lra_no_alloc_regs);
+ alloc_regs = ~lra_no_alloc_regs;
return overlaps_hard_reg_set_p (alloc_regs, GET_MODE (x), regno);
}
else
/* The current iteration number of this LRA pass. */
int lra_constraint_iter;
-/* 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;
+/* True if we should during assignment sub-pass check assignment
+ correctness for all pseudos and spill some of them to correct
+ conflicts. It can be necessary when we substitute equiv which
+ needs checking register allocation correctness because the
+ equivalent value contains allocatable hard registers, or when we
+ restore multi-register pseudo, or when we change the insn code and
+ its operand became INOUT operand when it was IN one before. */
+bool check_and_force_assignment_correctness_p;
/* Return true if REGNO is referenced in more than one block. */
static bool
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;
+ 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. */
changed_p = false;
if (pic_offset_table_rtx
&& REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
- lra_risky_transformations_p = true;
- else
+ check_and_force_assignment_correctness_p = true;
+ else if (first_p)
/* On the first iteration we should check IRA assignment
correctness. In rare cases, the assignments can be wrong as
- early clobbers operands are ignored in IRA. */
- lra_risky_transformations_p = first_p;
+ early clobbers operands are ignored in IRA or usages of
+ paradoxical sub-registers are not taken into account by
+ IRA. */
+ check_and_force_assignment_correctness_p = true;
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. */
{
bool pseudo_p = contains_reg_p (x, false, false);
- /* After RTL transformation, we can not guarantee that
+ /* After RTL transformation, we cannot guarantee that
pseudo in the substitution was not reloaded which might
make equivalence invalid. For example, in reverse
equiv of p0
|| (! 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
+ init insn, we cannot remove the equiv init
insns and the init insns might write into
const memory in this case. */
|| contains_reloaded_insn_p (i)))
}
if (new_insns_num > MAX_RELOAD_INSNS_NUMBER)
internal_error
- ("Max. number of generated reload insns per insn is achieved (%d)\n",
+ ("maximum number of generated reload insns per insn achieved (%d)",
MAX_RELOAD_INSNS_NUMBER);
new_insns_num++;
if (DEBUG_INSN_P (curr_insn))
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
+ cannot be changed. Such insns might be not in
init_insns because we don't update equiv data
during insn transformations.
dump_insn_slim (lra_dump_file, curr_insn);
}
if (contains_reg_p (x, true, false))
- lra_risky_transformations_p = true;
+ check_and_force_assignment_correctness_p = true;
lra_set_insn_deleted (curr_insn);
continue;
}
/* Number of calls passed so far in current EBB. */
static int calls_num;
+/* Index ID is the CALLS_NUM associated the last call we saw with
+ ABI identifier ID. */
+static int last_call_for_abi[NUM_ABI_IDS];
+
+/* Which registers have been fully or partially clobbered by a call
+ since they were last used. */
+static HARD_REG_SET full_and_partial_call_clobbers;
+
/* Current reload pseudo check for validity of elements in
USAGE_INSNS. */
static int curr_usage_insns_check;
usage_insns[regno].reloads_num = reloads_num;
usage_insns[regno].calls_num = calls_num;
usage_insns[regno].after_p = after_p;
+ if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
+ remove_from_hard_reg_set (&full_and_partial_call_clobbers,
+ PSEUDO_REGNO_MODE (regno),
+ reg_renumber[regno]);
}
/* The function is used to form list REGNO usages which consists of
(inheritance/split pseudos and original registers). */
static bitmap_head check_only_regs;
-/* Reload pseudos can not be involded in invariant inheritance in the
+/* Reload pseudos cannot be involded in invariant inheritance in the
current EBB. */
static bitmap_head invalid_invariant_regs;
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
- ((flag_ipa_ra &&
- ! hard_reg_set_empty_p (lra_reg_info[regno].actual_call_used_reg_set))
- ? lra_reg_info[regno].actual_call_used_reg_set
- : call_used_reg_set,
- PSEUDO_REGNO_MODE (regno), reg_renumber[regno])
- || (targetm.hard_regno_call_part_clobbered
- (reg_renumber[regno], PSEUDO_REGNO_MODE (regno)))));
+ if (usage_insns[regno].calls_num < calls_num)
+ {
+ unsigned int abis = 0;
+ for (unsigned int i = 0; i < NUM_ABI_IDS; ++i)
+ if (last_call_for_abi[i] > usage_insns[regno].calls_num)
+ abis |= 1 << i;
+ gcc_assert (abis);
+ if (call_clobbered_in_region_p (abis, full_and_partial_call_clobbers,
+ PSEUDO_REGNO_MODE (regno),
+ reg_renumber[regno]))
+ return true;
+ }
+ return false;
}
/* Global registers occurring in the current EBB. */
/* 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
+ situation when check_and_force_assignment_correctness_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)
+ || !TEST_HARD_REG_BIT (full_and_partial_call_clobbers, regno))
/* 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
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. If TO is not NULL, we don't use
- usage_insns, we put restore insns after TO insn.
+ usage_insns, we put restore insns after TO insn. It is a case when
+ we call it from lra_split_hard_reg_for, outside the inheritance
+ pass.
The transformations look like:
&& mode == PSEUDO_REGNO_MODE (original_regno))
lra_copy_reg_equiv (new_regno, original_regno);
lra_reg_info[new_regno].restore_rtx = regno_reg_rtx[original_regno];
- bitmap_set_bit (&check_only_regs, new_regno);
- bitmap_set_bit (&check_only_regs, original_regno);
bitmap_set_bit (&lra_split_regs, new_regno);
if (to != NULL)
{
+ lra_assert (next_usage_insns == NULL);
usage_insn = to;
after_p = TRUE;
}
else
{
+ /* We need check_only_regs only inside the inheritance pass. */
+ bitmap_set_bit (&check_only_regs, new_regno);
+ bitmap_set_bit (&check_only_regs, original_regno);
after_p = usage_insns[original_regno].after_p;
for (;;)
{
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;
+ check_and_force_assignment_correctness_p = true;
if (lra_dump_file != NULL)
fprintf (lra_dump_file,
" ))))))))))))))))))))))))))))))))))))))))))))))))\n");
struct lra_insn_reg *reg;
for (reg = id->regs; reg != NULL; reg = reg->next)
- if (reg->regno <= FIRST_PSEUDO_REGISTER)
+ if (reg->regno < FIRST_PSEUDO_REGISTER)
SET_HARD_REG_BIT (ignore, reg->regno);
for (reg = static_id->hard_regs; reg != NULL; reg = reg->next)
SET_HARD_REG_BIT (ignore, reg->regno);
|| TEST_HARD_REG_BIT (ignore, hard_regno))
continue;
for (insn = from; insn != NEXT_INSN (to); insn = NEXT_INSN (insn))
- if (bitmap_bit_p (&lra_reg_info[hard_regno].insn_bitmap,
- INSN_UID (insn)))
- break;
+ {
+ struct lra_static_insn_data *static_id;
+ struct lra_insn_reg *reg;
+
+ if (!INSN_P (insn))
+ continue;
+ if (bitmap_bit_p (&lra_reg_info[hard_regno].insn_bitmap,
+ INSN_UID (insn)))
+ break;
+ static_id = lra_get_insn_recog_data (insn)->insn_static_data;
+ for (reg = static_id->hard_regs; reg != NULL; reg = reg->next)
+ if (reg->regno == hard_regno)
+ break;
+ if (reg != NULL)
+ break;
+ }
if (insn != NEXT_INSN (to))
continue;
if (split_reg (TRUE, hard_regno, from, NULL, to))
enum rtx_code code;
int i, j;
+ if (side_effects_p (x))
+ return false;
+
code = GET_CODE (x);
mode = GET_MODE (x);
if (code == SUBREG)
curr_usage_insns_check++;
clear_invariants ();
reloads_num = calls_num = 0;
+ for (unsigned int i = 0; i < NUM_ABI_IDS; ++i)
+ last_call_for_abi[i] = 0;
+ CLEAR_HARD_REG_SET (full_and_partial_call_clobbers);
bitmap_clear (&check_only_regs);
bitmap_clear (&invalid_invariant_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);
+ live_hard_regs = eliminable_regset | 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)
{
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]);
+ potential_reload_hard_regs |= reg_class_contents[cl];
}
else if (src_regno < 0
&& dst_regno >= lra_constraint_new_regno_start
if (process_invariant_for_inheritance (SET_DEST (curr_set), SET_SRC (curr_set)))
change_p = true;
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]);
+ potential_reload_hard_regs |= reg_class_contents[cl];
}
else if (src_regno >= lra_constraint_new_regno_start
&& dst_regno < lra_constraint_new_regno_start
/* 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]);
+ potential_reload_hard_regs |= reg_class_contents[cl];
}
else if (INSN_P (curr_insn))
{
/* Don't do inheritance if the pseudo is also
used in the insn. */
if (r == NULL)
- /* We can not do inheritance right now
+ /* We cannot 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
+ /* We cannot process one reg twice here because of
usage_insns invalidation. */
if ((dst_regno < FIRST_PSEUDO_REGISTER
|| reg_renumber[dst_regno] >= 0)
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);
+ live_hard_regs &= ~s;
+ potential_reload_hard_regs &= ~s;
}
/* We should invalidate potential inheritance or
splitting for the current insn usages to the next
int regno, hard_regno;
calls_num++;
+ function_abi callee_abi = insn_callee_abi (curr_insn);
+ last_call_for_abi[callee_abi.id ()] = calls_num;
+ full_and_partial_call_clobbers
+ |= callee_abi.full_and_partial_reg_clobbers ();
if ((cheap = find_reg_note (curr_insn,
REG_RETURNED, NULL_RTX)) != NULL_RTX
&& ((cheap = XEXP (cheap, 0)), true)
/* 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))
+ && callee_abi.clobbers_reg_p (GET_MODE (cheap), hard_regno))
{
/* Restore the pseudo from the call result as
REG_RETURNED note says that the pseudo value is
/* We don't need to save/restore of the pseudo from
this call. */
usage_insns[regno].calls_num = calls_num;
+ remove_from_hard_reg_set
+ (&full_and_partial_call_clobbers,
+ GET_MODE (cheap), hard_regno);
bitmap_set_bit (&check_only_regs, regno);
}
}
before_p, curr_insn, max_uid))
{
if (reg->subreg_p)
- lra_risky_transformations_p = true;
+ check_and_force_assignment_correctness_p = true;
change_p = true;
/* Invalidate. */
usage_insns[src_regno].check = 0;
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]);
+ potential_reload_hard_regs |= reg_class_contents[cl];
}
}
if (NONDEBUG_INSN_P (curr_insn))
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 * LRA_INHERITANCE_EBB_PROBABILITY_CUTOFF) / 100)
+ ((REG_BR_PROB_BASE * param_lra_inheritance_ebb_probability_cutoff) / 100)
/* Current number of inheritance/split iteration. */
int lra_inheritance_iter;
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 (&invalid_invariant_regs);
- bitmap_clear (&check_only_regs);
+ bitmap_release (&ebb_global_regs);
+ bitmap_release (&temp_bitmap);
+ bitmap_release (&live_regs);
+ bitmap_release (&invalid_invariant_regs);
+ bitmap_release (&check_only_regs);
free (usage_insns);
timevar_pop (TV_LRA_INHERITANCE);
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
+ /* We cannot 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. */
{
/* reload pseudo <- invariant inheritance pseudo */
start_sequence ();
- /* We can not just change the source. It might be
+ /* We cannot just change the source. It might be
an insn different from the move. */
emit_insn (lra_reg_info[sregno].restore_rtx);
rtx_insn *new_insns = get_insns ();