/* Code for RTL transformations to satisfy insn constraints.
- Copyright (C) 2010-2014 Free Software Foundation, Inc.
+ Copyright (C) 2010-2015 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
#include "addresses.h"
#include "target.h"
#include "function.h"
+#include "symtab.h"
+#include "flags.h"
+#include "alias.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
#include "basic-block.h"
#include "except.h"
#include "optabs.h"
#include "df.h"
#include "ira.h"
#include "rtl-error.h"
+#include "params.h"
#include "lra-int.h"
/* Value of LRA_CURR_RELOAD_NUM at the beginning of BB of the current
/* 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_insn *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];
+static machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
+/* Mode of the register substituted by its equivalence with VOIDmode
+ (e.g. constant) and whose subreg is given operand of the current
+ insn. VOIDmode in all other cases. */
+static machine_mode original_subreg_reg_mode[MAX_RECOG_OPERANDS];
\f
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;
+ machine_mode reg_mode;
int class_size, hard_regno, nregs, i, j;
int regno = REGNO (reg);
return get_reg_class (regno) == NO_REGS;
}
+/* Return 1 if ADDR is a valid memory address for mode MODE in address
+ space AS, and check that each pseudo has the proper kind of hard
+ reg. */
+static int
+valid_address_p (machine_mode mode ATTRIBUTE_UNUSED,
+ rtx addr, addr_space_t as)
+{
+#ifdef GO_IF_LEGITIMATE_ADDRESS
+ lra_assert (ADDR_SPACE_GENERIC_P (as));
+ GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
+ return 0;
+
+ win:
+ return 1;
+#else
+ return targetm.addr_space.legitimate_address_p (mode, addr, 0, as);
+#endif
+}
+
+namespace {
+ /* Temporarily eliminates registers in an address (for the lifetime of
+ the object). */
+ class address_eliminator {
+ public:
+ address_eliminator (struct address_info *ad);
+ ~address_eliminator ();
+
+ private:
+ struct address_info *m_ad;
+ rtx *m_base_loc;
+ rtx m_base_reg;
+ rtx *m_index_loc;
+ rtx m_index_reg;
+ };
+}
+
+address_eliminator::address_eliminator (struct address_info *ad)
+ : m_ad (ad),
+ m_base_loc (strip_subreg (ad->base_term)),
+ m_base_reg (NULL_RTX),
+ m_index_loc (strip_subreg (ad->index_term)),
+ m_index_reg (NULL_RTX)
+{
+ if (m_base_loc != NULL)
+ {
+ m_base_reg = *m_base_loc;
+ lra_eliminate_reg_if_possible (m_base_loc);
+ if (m_ad->base_term2 != NULL)
+ *m_ad->base_term2 = *m_ad->base_term;
+ }
+ if (m_index_loc != NULL)
+ {
+ m_index_reg = *m_index_loc;
+ lra_eliminate_reg_if_possible (m_index_loc);
+ }
+}
+
+address_eliminator::~address_eliminator ()
+{
+ if (m_base_loc && *m_base_loc != m_base_reg)
+ {
+ *m_base_loc = m_base_reg;
+ if (m_ad->base_term2 != NULL)
+ *m_ad->base_term2 = *m_ad->base_term;
+ }
+ if (m_index_loc && *m_index_loc != m_index_reg)
+ *m_index_loc = m_index_reg;
+}
+
+/* Return true if the eliminated form of AD is a legitimate target address. */
+static bool
+valid_address_p (struct address_info *ad)
+{
+ address_eliminator eliminator (ad);
+ return valid_address_p (ad->mode, *ad->outer, ad->as);
+}
+
+/* Return true if the eliminated form of memory reference OP satisfies
+ extra memory constraint CONSTRAINT. */
+static bool
+satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
+{
+ struct address_info ad;
+
+ decompose_mem_address (&ad, op);
+ address_eliminator eliminator (&ad);
+ return constraint_satisfied_p (op, constraint);
+}
+
+/* Return true if the eliminated form of address AD satisfies extra
+ address constraint CONSTRAINT. */
+static bool
+satisfies_address_constraint_p (struct address_info *ad,
+ enum constraint_num constraint)
+{
+ address_eliminator eliminator (ad);
+ return constraint_satisfied_p (*ad->outer, constraint);
+}
+
+/* Return true if the eliminated form of address OP satisfies extra
+ address constraint CONSTRAINT. */
+static bool
+satisfies_address_constraint_p (rtx op, enum constraint_num constraint)
+{
+ struct address_info ad;
+
+ decompose_lea_address (&ad, &op);
+ return satisfies_address_constraint_p (&ad, constraint);
+}
+
/* 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. */
|| lra_get_regno_hard_regno (regno) >= 0)
return x;
if ((res = ira_reg_equiv[regno].memory) != NULL_RTX)
- return res;
+ {
+ if (targetm.cannot_substitute_mem_equiv_p (res))
+ return x;
+ return res;
+ }
if ((res = ira_reg_equiv[regno].constant) != NULL_RTX)
return res;
if ((res = ira_reg_equiv[regno].invariant) != NULL_RTX)
return that value after elimination for INSN, otherwise return
X. */
static rtx
-get_equiv_with_elimination (rtx x, rtx insn)
+get_equiv_with_elimination (rtx x, rtx_insn *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);
+ return lra_eliminate_regs_1 (insn, res, GET_MODE (res),
+ false, false, 0, true);
}
/* Set up curr_operand_mode. */
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]);
+ machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
if (mode == VOIDmode)
{
/* The .md mode for address operands is the mode of the
}
/* Create a new pseudo using MODE, RCLASS, ORIGINAL or reuse already
- created input reload pseudo (only if TYPE is not OP_OUT). 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. */
+ 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, const char *title, rtx *result_reg)
+get_reload_reg (enum op_type type, 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;
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));
/* 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,
+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);
REGNO1 + lra_constraint_offset (REGNO1, MODE1)
== REGNO2 + lra_constraint_offset (REGNO2, MODE2) */
int
-lra_constraint_offset (int regno, enum machine_mode mode)
+lra_constraint_offset (int regno, machine_mode mode)
{
lra_assert (regno < FIRST_PSEUDO_REGISTER);
if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (mode) > UNITS_PER_WORD
slow:
+ if (code == REG && REG_P (y))
+ return REGNO (x) == REGNO (y);
+
if (code == REG && GET_CODE (y) == SUBREG && REG_P (SUBREG_REG (y))
&& x == SUBREG_REG (y))
return true;
return false;
case LABEL_REF:
- return XEXP (x, 0) == XEXP (y, 0);
+ return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
matched input operands INS. */
static void
match_reload (signed char out, signed char *ins, enum reg_class goal_class,
- rtx *before, rtx *after)
+ rtx_insn **before, rtx_insn **after)
{
int i, in;
- rtx new_in_reg, new_out_reg, reg, clobber;
- enum machine_mode inmode, outmode;
+ rtx new_in_reg, new_out_reg, reg;
+ 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];
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);
+ rtx_insn *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)
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)
+ enum constraint_num cn = lookup_constraint (p);
+ enum reg_class cl = reg_class_for_constraint (cn);
+ if (cl == NO_REGS)
{
-#ifdef EXTRA_CONSTRAINT_STR
- if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+ if (insn_extra_address_constraint (cn))
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;
+ op_class = reg_class_subunion[op_class][cl];
+ break;
}
while ((p += len), c);
return op_class;
/* 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
+static rtx_insn *
emit_spill_move (bool to_p, rtx mem_pseudo, rtx val)
{
if (GET_MODE (mem_pseudo) != GET_MODE (val))
LRA_SUBREG_P (mem_pseudo) = 1;
}
}
- return (to_p
- ? gen_move_insn (mem_pseudo, val)
- : gen_move_insn (val, mem_pseudo));
+ 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
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;
+ rtx dest, src, dreg, sreg, new_reg, scratch_reg;
+ rtx_insn *before;
enum reg_class dclass, sclass, secondary_class;
- enum machine_mode sreg_mode;
secondary_reload_info sri;
lra_assert (curr_insn_set != NULL_RTX);
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)
sri.icode = CODE_FOR_nothing;
sri.extra_cost = 0;
secondary_class
- = (enum reg_class) targetm.secondary_reload (true, sreg,
+ = (enum reg_class) targetm.secondary_reload (true, src,
(reg_class_t) dclass,
- sreg_mode, &sri);
+ GET_MODE (src), &sri);
/* Check the target hook consistency. */
lra_assert
((secondary_class == NO_REGS && sri.icode == CODE_FOR_nothing)
*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,
+ new_reg = lra_create_new_reg_with_unique_value (GET_MODE (src), 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);
+ lra_emit_move (new_reg, src);
else
{
enum reg_class scratch_class;
(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));
+ src, scratch_reg));
}
before = get_insns ();
end_sequence ();
- lra_process_new_insns (curr_insn, before, NULL_RTX, "Inserting the move");
+ lra_process_new_insns (curr_insn, before, NULL, "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;
- }
+ SET_SRC (curr_insn_set) = new_reg;
else
{
if (lra_dump_file != NULL)
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. */
+/* if CHECK_ONLY_P is false, 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.
+
+ if CHECK_ONLY_P is true, check that the *LOC is a correct address
+ register. Return false if the address register is correct. */
static bool
-process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
+process_addr_reg (rtx *loc, bool check_only_p, rtx_insn **before, rtx_insn **after,
+ enum reg_class cl)
{
int regno;
enum reg_class rclass, new_class;
rtx reg;
rtx new_reg;
- enum machine_mode mode;
- bool before_p = false;
+ machine_mode mode;
+ bool subreg_p, before_p = false;
- loc = strip_subreg (loc);
+ subreg_p = GET_CODE (*loc) == SUBREG;
+ if (subreg_p)
+ loc = &SUBREG_REG (*loc);
reg = *loc;
mode = GET_MODE (reg);
if (! REG_P (reg))
{
+ if (check_only_p)
+ return true;
/* 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");
{
regno = REGNO (reg);
rclass = get_reg_class (regno);
- if ((*loc = get_equiv_with_elimination (reg, curr_insn)) != reg)
+ if (! check_only_p
+ && (*loc = get_equiv_with_elimination (reg, curr_insn)) != reg)
{
if (lra_dump_file != NULL)
{
}
if (*loc != reg || ! in_class_p (reg, cl, &new_class))
{
+ if (check_only_p)
+ return true;
reg = *loc;
if (get_reload_reg (after == NULL ? OP_IN : OP_INOUT,
- mode, reg, cl, "address", &new_reg))
+ mode, reg, cl, subreg_p, "address", &new_reg))
before_p = true;
}
else if (new_class != NO_REGS && rclass != new_class)
{
+ if (check_only_p)
+ return true;
lra_change_class (regno, new_class, " Change to", true);
return false;
}
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)
+insert_move_for_subreg (rtx_insn **before, rtx_insn **after, rtx origreg,
+ rtx newreg)
{
if (before)
{
}
}
+static int valid_address_p (machine_mode mode, rtx addr, addr_space_t as);
+
/* 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. */
+ any change was done. */
static bool
-simplify_operand_subreg (int nop, enum machine_mode reg_mode)
+simplify_operand_subreg (int nop, machine_mode reg_mode)
{
int hard_regno;
- rtx before, after;
- enum machine_mode mode;
+ rtx_insn *before, *after;
+ machine_mode mode, innermode;
rtx reg, new_reg;
rtx operand = *curr_id->operand_loc[nop];
enum reg_class regclass;
enum op_type type;
- before = after = NULL_RTX;
+ before = after = NULL;
if (GET_CODE (operand) != SUBREG)
return false;
mode = GET_MODE (operand);
reg = SUBREG_REG (operand);
+ innermode = GET_MODE (reg);
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
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))
+ if (MEM_P (reg)
+ && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (reg))
+ || MEM_ALIGN (reg) >= GET_MODE_ALIGNMENT (mode)))
+ {
+ rtx subst, old = *curr_id->operand_loc[nop];
+
+ alter_subreg (curr_id->operand_loc[nop], false);
+ subst = *curr_id->operand_loc[nop];
+ lra_assert (MEM_P (subst));
+ if (! valid_address_p (innermode, XEXP (reg, 0),
+ MEM_ADDR_SPACE (reg))
+ || valid_address_p (GET_MODE (subst), XEXP (subst, 0),
+ MEM_ADDR_SPACE (subst)))
+ return true;
+ /* If the address was valid and became invalid, prefer to reload
+ the memory. Typical case is when the index scale should
+ correspond the memory. */
+ *curr_id->operand_loc[nop] = old;
+ }
+ else if (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
{
alter_subreg (curr_id->operand_loc[nop], false);
return true;
}
+ else if (CONSTANT_P (reg))
+ {
+ /* Try to simplify subreg of constant. It is usually result of
+ equivalence substitution. */
+ if (innermode == VOIDmode
+ && (innermode = original_subreg_reg_mode[nop]) == VOIDmode)
+ innermode = curr_static_id->operand[nop].mode;
+ if ((new_reg = simplify_subreg (mode, reg, innermode,
+ SUBREG_BYTE (operand))) != NULL_RTX)
+ {
+ *curr_id->operand_loc[nop] = new_reg;
+ 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
&& (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][innermode]
>= hard_regno_nregs[hard_regno][mode])
- && simplify_subreg_regno (hard_regno, GET_MODE (reg),
+ && simplify_subreg_regno (hard_regno, innermode,
SUBREG_BYTE (operand), mode) < 0
/* Don't reload subreg for matching reload. It is actually
valid subreg in LRA. */
= (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
if (get_reload_reg (curr_static_id->operand[nop].type, reg_mode, reg,
- rclass, "subreg reg", &new_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));
+ || GET_MODE_SIZE (innermode) > GET_MODE_SIZE (mode));
insert_after = (type != OP_IN);
insert_move_for_subreg (insert_before ? &before : NULL,
insert_after ? &after : NULL,
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][innermode]
< hard_regno_nregs[hard_regno][mode])
&& (regclass = lra_get_allocno_class (REGNO (reg)))
&& (type != OP_IN
= (enum reg_class) targetm.preferred_reload_class (reg, ALL_REGS);
if (get_reload_reg (curr_static_id->operand[nop].type, mode, reg,
- rclass, "paradoxical subreg", &new_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);
+ subreg = simplify_gen_subreg (innermode, new_reg, mode, 0);
bitmap_set_bit (&lra_subreg_reload_pseudos, REGNO (new_reg));
insert_before = (type != OP_OUT);
uses_hard_regs_p (rtx x, HARD_REG_SET set)
{
int i, j, x_hard_regno;
- enum machine_mode mode;
+ machine_mode mode;
const char *fmt;
enum rtx_code code;
return in_class_p (reg, cl, NULL);
}
+/* Return true if SET of RCLASS contains no hard regs which can be
+ used in MODE. */
+static bool
+prohibited_class_reg_set_mode_p (enum reg_class rclass,
+ HARD_REG_SET &set,
+ enum machine_mode mode)
+{
+ 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);
+ return (hard_reg_set_subset_p
+ (temp, ira_prohibited_class_mode_regs[rclass][mode]));
+}
+
/* 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
then REJECT is ignored, but otherwise it gets this much counted
against it in addition to the reloading needed. */
int reject;
+ int op_reject;
/* The number of elements in the following array. */
int early_clobbered_regs_num;
/* Numbers of operands which are early clobber registers. */
otherwise NULL. */
rtx operand_reg[MAX_RECOG_OPERANDS];
int hard_regno[MAX_RECOG_OPERANDS];
- enum machine_mode biggest_mode[MAX_RECOG_OPERANDS];
+ machine_mode biggest_mode[MAX_RECOG_OPERANDS];
int reload_nregs, reload_sum;
bool costly_p;
enum reg_class cl;
together, the second alternatives go together, etc.
First loop over alternatives. */
+ alternative_mask preferred = curr_id->preferred_alternatives;
+ if (only_alternative >= 0)
+ preferred &= ALTERNATIVE_BIT (only_alternative);
+
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)
+ if (!TEST_BIT (preferred, nalt))
continue;
-
overall = losers = reject = reload_nregs = reload_sum = 0;
for (nop = 0; nop < n_operands; nop++)
{
bool this_alternative_match_win, this_alternative_win;
bool this_alternative_offmemok;
bool scratch_p;
- enum machine_mode mode;
+ machine_mode mode;
+ enum constraint_num cn;
opalt_num = nalt * n_operands + nop;
if (curr_static_id->operand_alternative[opalt_num].anything_ok)
track. */
lra_assert (*p != 0 && *p != ',');
+ op_reject = 0;
/* 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
c = '\0';
break;
- case '=': case '+': case '?': case '*': case '!':
- case ' ': case '\t':
+ case '&':
+ early_clobber_p = true;
break;
- case '%':
- /* We only support one commutative marker, the first
- one. We already set commutative above. */
+ case '$':
+ op_reject += LRA_MAX_REJECT;
break;
-
- case '&':
- early_clobber_p = true;
+ case '^':
+ op_reject += LRA_LOSER_COST_FACTOR;
break;
case '#':
[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))
+ /* Prefer matching earlyclobber alternative as
+ 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 (lra_dump_file != NULL)
+ fprintf
+ (lra_dump_file,
+ " %d Matching earlyclobber alt:"
+ " reject--\n",
+ nop);
+ reject--;
+ }
+ /* Otherwise we prefer no matching
+ alternatives because it gives more freedom
+ in RA. */
+ else 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
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]);
- }
+ cl = GENERAL_REGS;
goto reg;
default:
- if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+ cn = lookup_constraint (p);
+ switch (get_constraint_type (cn))
{
-#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;
- }
+ case CT_REGISTER:
+ cl = reg_class_for_constraint (cn);
+ if (cl != NO_REGS)
+ goto reg;
+ break;
- if (EXTRA_CONSTRAINT_STR (op, c, p))
+ case CT_CONST_INT:
+ if (CONST_INT_P (op)
+ && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+ win = true;
+ break;
+
+ case CT_MEMORY:
+ if (MEM_P (op)
+ && satisfies_memory_constraint_p (op, cn))
+ 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;
+
+ case CT_ADDRESS:
+ /* If we didn't already win, we can reload the address
+ into a base register. */
+ if (satisfies_address_constraint_p (op, cn))
+ win = true;
+ cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+ ADDRESS, SCRATCH);
+ badop = false;
+ goto reg;
+
+ case CT_FIXED_FORM:
+ if (constraint_satisfied_p (op, cn))
win = true;
-#endif
break;
}
+ break;
- cl = REG_CLASS_FROM_CONSTRAINT (c, p);
+ reg:
this_alternative = reg_class_subunion[this_alternative][cl];
IOR_HARD_REG_SET (this_alternative_set,
reg_class_contents[cl]);
IOR_HARD_REG_SET (this_costly_alternative_set,
reg_class_contents[cl]);
}
- reg:
if (mode == BLKmode)
break;
winreg = true;
int const_to_mem = 0;
bool no_regs_p;
+ reject += op_reject;
/* Never do output reload of stack pointer. It makes
impossible to do elimination when SP is changed in
RTL. */
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 the operand is dying, has a matching constraint,
and satisfies constraints of the matched operand
- which failed to satisfy the own constraints, probably
+ which failed to satisfy the own constraints, most probably
the reload for this operand will be gone. */
if (this_alternative_matches >= 0
&& !curr_alt_win[this_alternative_matches]
goto fail;
}
+ /* Alternative loses if it required class pseudo can not
+ 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
+ && ! hard_reg_set_empty_p (this_alternative_set)
+ /* It is common practice for constraints to use a
+ 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. */
+ && ! HARD_REGNO_MODE_OK (ira_class_hard_regs
+ [this_alternative][0],
+ GET_MODE (*curr_id->operand_loc[nop]))
+ /* The above condition is not enough as the first
+ reg in ira_class_hard_regs can be not aligned for
+ multi-words mode values. */
+ && (prohibited_class_reg_set_mode_p
+ (this_alternative, this_alternative_set,
+ 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",
+ nalt, nop);
+ goto fail;
+ }
+
/* Check strong discouragement of reload of non-constant
into class THIS_ALTERNATIVE. */
if (! CONSTANT_P (op) && ! no_regs_p
if (lra_dump_file != NULL)
fprintf
(lra_dump_file,
- " %d Spill pseudo in memory: reject+=3\n",
+ " %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
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)
+/* Make reload base reg from address AD. */
+static rtx
+base_to_reg (struct address_info *ad)
{
-#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. */
+ enum reg_class cl;
+ int code = -1;
+ rtx new_inner = NULL_RTX;
+ rtx new_reg = NULL_RTX;
+ rtx_insn *insn;
+ rtx_insn *last_insn = get_last_insn();
-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)
+ 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");
+ new_inner = simplify_gen_binary (PLUS, GET_MODE (new_reg), new_reg,
+ ad->disp_term == NULL
+ ? gen_int_mode (0, ad->mode)
+ : *ad->disp_term);
+ if (!valid_address_p (ad->mode, new_inner, ad->as))
+ return NULL_RTX;
+ insn = emit_insn (gen_rtx_SET (new_reg, *ad->base_term));
+ code = recog_memoized (insn);
+ if (code < 0)
{
- *base_term = saved_base_reg;
- if (ad->base_term2 != NULL)
- *ad->base_term2 = *ad->base_term;
+ delete_insns_since (last_insn);
+ return NULL_RTX;
}
- if (saved_index_reg != NULL_RTX)
- *index_term = saved_index_reg;
- return ok_p;
+
+ return new_inner;
}
/* Make reload base reg + disp from address AD. Return the new pseudo. */
return new_reg;
}
+/* Make reload of index part of address AD. Return the new
+ pseudo. */
+static rtx
+index_part_to_reg (struct address_info *ad)
+{
+ rtx new_reg;
+
+ new_reg = lra_create_new_reg (GET_MODE (*ad->index), NULL_RTX,
+ INDEX_REG_CLASS, "index term");
+ expand_mult (GET_MODE (*ad->index), *ad->index_term,
+ GEN_INT (get_index_scale (ad)), new_reg, 1);
+ 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. */
return change_p;
}
-/* Major function to make reloads for an address in operand NOP.
- The supported cases are:
+/* Major function to make reloads for an address in operand NOP or
+ check its correctness (If CHECK_ONLY_P is true). 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
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. */
+ address. Return true for any RTL change.
+
+ The function is a helper function which does not produce all
+ transformations (when CHECK_ONLY_P is false) which can be
+ necessary. It does just basic steps. To do all necessary
+ transformations use function process_address. */
static bool
-process_address (int nop, rtx *before, rtx *after)
+process_address_1 (int nop, bool check_only_p,
+ rtx_insn **before, rtx_insn **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;
+ enum constraint_num cn = lookup_constraint (constraint);
+ bool change_p = false;
- if (constraint[0] == 'p'
- || EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint))
+ if (insn_extra_address_constraint (cn))
decompose_lea_address (&ad, curr_id->operand_loc[nop]);
else if (MEM_P (op))
decompose_mem_address (&ad, op);
decompose_mem_address (&ad, SUBREG_REG (op));
else
return false;
- change_p = equiv_address_substitution (&ad);
+ /* If INDEX_REG_CLASS is assigned to base_term already and isn't to
+ index_term, swap them so to avoid assigning INDEX_REG_CLASS to both
+ when INDEX_REG_CLASS is a single register class. */
+ if (ad.base_term != NULL
+ && ad.index_term != NULL
+ && ira_class_hard_regs_num[INDEX_REG_CLASS] == 1
+ && REG_P (*ad.base_term)
+ && REG_P (*ad.index_term)
+ && in_class_p (*ad.base_term, INDEX_REG_CLASS, NULL)
+ && ! in_class_p (*ad.index_term, INDEX_REG_CLASS, NULL))
+ {
+ std::swap (ad.base, ad.index);
+ std::swap (ad.base_term, ad.index_term);
+ }
+ if (! check_only_p)
+ change_p = equiv_address_substitution (&ad);
if (ad.base_term != NULL
&& (process_addr_reg
- (ad.base_term, before,
+ (ad.base_term, check_only_p, before,
(ad.autoinc_p
&& !(REG_P (*ad.base_term)
&& find_regno_note (curr_insn, REG_DEAD,
*ad.base_term2 = *ad.base_term;
}
if (ad.index_term != NULL
- && process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS))
+ && process_addr_reg (ad.index_term, check_only_p,
+ 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))
+ /* Target hooks sometimes don't treat extra-constraint addresses as
+ legitimate address_operands, so handle them specially. */
+ if (insn_extra_address_constraint (cn)
+ && satisfies_address_constraint_p (&ad, cn))
+ return change_p;
+
+ if (check_only_p)
return change_p;
-#endif
/* There are three cases where the shape of *AD.INNER may now be invalid:
3) the address is a frame address with an invalid offset.
+ 4) the address is a frame address with an invalid base.
+
All these cases involve a non-autoinc address, so there is no
point revalidating other types. */
if (ad.autoinc_p || valid_address_p (&ad))
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 (HAVE_lo_sum)
+ {
+ rtx_insn *insn;
+ rtx_insn *last = get_last_insn ();
+
+ /* addr => lo_sum (new_base, addr), case (2) above. */
+ insn = emit_insn (gen_rtx_SET
+ (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
+ (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);
+ }
+
if (code < 0)
{
/* addr => new_base, case (2) above. */
{
int regno;
enum reg_class cl;
- rtx set, insns, last_insn;
+ rtx set;
+ rtx_insn *insns, *last_insn;
+ /* Try to reload base into register only if the base is invalid
+ for the address but with valid offset, case (4) above. */
+ start_sequence ();
+ new_reg = base_to_reg (&ad);
+
/* 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);
+ if (new_reg == NULL_RTX)
+ 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
delete_insns_since (PREV_INSN (last_insn));
}
}
+ /* Try if target can split displacement into legitimite new disp
+ and offset. If it's the case, we replace the last insn with
+ insns for base + offset => new_reg and set new_reg + new disp
+ to *ad.inner. */
+ last_insn = get_last_insn ();
+ if ((set = single_set (last_insn)) != NULL_RTX
+ && GET_CODE (SET_SRC (set)) == PLUS
+ && REG_P (XEXP (SET_SRC (set), 0))
+ && REGNO (XEXP (SET_SRC (set), 0)) < FIRST_PSEUDO_REGISTER
+ && CONST_INT_P (XEXP (SET_SRC (set), 1)))
+ {
+ rtx addend, disp = XEXP (SET_SRC (set), 1);
+ if (targetm.legitimize_address_displacement (&disp, &addend,
+ ad.mode))
+ {
+ rtx_insn *new_insns;
+ start_sequence ();
+ lra_emit_add (new_reg, XEXP (SET_SRC (set), 0), addend);
+ new_insns = get_insns ();
+ end_sequence ();
+ new_reg = gen_rtx_PLUS (Pmode, new_reg, disp);
+ delete_insns_since (PREV_INSN (last_insn));
+ add_insn (new_insns);
+ insns = get_insns ();
+ }
+ }
end_sequence ();
emit_insn (insns);
*ad.inner = new_reg;
}
- else
+ else if (ad.disp_term != NULL)
{
/* base + scale * index + disp => new base + scale * index,
case (1) above. */
*ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
new_reg, *ad.index);
}
+ else if (get_index_scale (&ad) == 1)
+ {
+ /* The last transformation to one reg will be made in
+ curr_insn_transform function. */
+ end_sequence ();
+ return false;
+ }
+ else
+ {
+ /* base + scale * index => base + new_reg,
+ case (1) above.
+ Index part of address may become invalid. For example, we
+ changed pseudo on the equivalent memory and a subreg of the
+ pseudo onto the memory of different mode for which the scale is
+ prohibitted. */
+ new_reg = index_part_to_reg (&ad);
+ *ad.inner = simplify_gen_binary (PLUS, GET_MODE (new_reg),
+ *ad.base_term, new_reg);
+ }
*before = get_insns ();
end_sequence ();
return true;
}
+/* If CHECK_ONLY_P is false, do address reloads until it is necessary.
+ Use process_address_1 as a helper function. Return true for any
+ RTL changes.
+
+ If CHECK_ONLY_P is true, just check address correctness. Return
+ false if the address correct. */
+static bool
+process_address (int nop, bool check_only_p,
+ rtx_insn **before, rtx_insn **after)
+{
+ bool res = false;
+
+ while (process_address_1 (nop, check_only_p, before, after))
+ {
+ if (check_only_p)
+ return true;
+ res = true;
+ }
+ return res;
+}
+
/* 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.
/* 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_insn *last;
rtx inc;
- rtx add_insn;
+ rtx_insn *add_insn;
int code;
rtx real_in = in == value ? incloc : in;
rtx result;
&& (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);
+ && targetm.register_move_cost (GET_MODE (src), sclass, dclass) == 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;
+ std::swap (curr_operand_mode[nop], curr_operand_mode[nop + 1]);
+ std::swap (original_subreg_reg_mode[nop], original_subreg_reg_mode[nop + 1]);
+ std::swap (*curr_id->operand_loc[nop], *curr_id->operand_loc[nop + 1]);
/* Swap the duplicates too. */
lra_update_dup (curr_id, nop);
lra_update_dup (curr_id, nop + 1);
model can be changed in future. Make commutative operand exchange
if it is chosen.
- Return true if some RTL changes happened during function call. */
+ if CHECK_ONLY_P is false, do RTL changes to satisfy the
+ constraints. Return true if any change happened during function
+ call.
+
+ If CHECK_ONLY_P is true then don't do any transformation. Just
+ check that the insn satisfies all constraints. If the insn does
+ not satisfy any constraint, return true. */
static bool
-curr_insn_transform (void)
+curr_insn_transform (bool check_only_p)
{
int i, j, k;
int n_operands;
int commutative;
signed char goal_alt_matched[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
signed char match_inputs[MAX_RECOG_OPERANDS + 1];
- rtx before, after;
+ rtx_insn *before, *after;
bool alt_p = false;
/* Flag that the insn has been changed through a transformation. */
bool change_p;
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)))
+ if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (curr_insn)))
no_input_reloads_p = true;
- if (reg_set_p (cc0_rtx, PATTERN (curr_insn)))
+ if (HAVE_cc0 && 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;
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);
- }
- }
+ if (! check_only_p)
+ /* 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);
+ original_subreg_reg_mode[i] = VOIDmode;
+ if (subst != old)
+ {
+ subst = copy_rtx (subst);
+ lra_assert (REG_P (old));
+ if (GET_CODE (op) != SUBREG)
+ *curr_id->operand_loc[i] = subst;
+ else
+ {
+ SUBREG_REG (op) = subst;
+ if (GET_MODE (subst) == VOIDmode)
+ original_subreg_reg_mode[i] = GET_MODE (old);
+ }
+ 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;
+ before = after = NULL;
for (i = 0; i < n_operands; i++)
if (! curr_static_id->operand[i].is_operator
- && process_address (i, &before, &after))
+ && process_address (i, check_only_p, &before, &after))
{
+ if (check_only_p)
+ return true;
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
+ if (! check_only_p && 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;
+ reused_alternative_num = check_only_p ? -1 : 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 (check_only_p)
+ return ! alt_p || best_losers != 0;
+
/* 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
if (use_sec_mem_p)
{
rtx new_reg, src, dest, rld;
- enum machine_mode sec_mode, rld_mode;
+ machine_mode sec_mode, rld_mode;
lra_assert (sec_mem_p);
lra_assert (curr_static_id->operand[0].type == OP_OUT
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,
+ lra_process_new_insns (curr_insn, NULL, after,
"Inserting the sec. move");
/* We may have non null BEFORE here (e.g. after address
processing. */
emit_insn (before);
before = get_insns ();
end_sequence ();
- lra_process_new_insns (curr_insn, before, NULL_RTX, "Changing on");
+ lra_process_new_insns (curr_insn, before, NULL, "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,
+ lra_process_new_insns (curr_insn, NULL, after,
"Inserting the sec. move");
}
else
emit_insn (before);
before = get_insns ();
end_sequence ();
- lra_process_new_insns (curr_insn, before, NULL_RTX,
+ lra_process_new_insns (curr_insn, before, NULL,
"Inserting the sec. move");
}
lra_update_insn_regno_info (curr_insn);
char c;
rtx op = *curr_id->operand_loc[i];
rtx subreg = NULL_RTX;
- enum machine_mode mode = curr_operand_mode[i];
+ machine_mode mode = curr_operand_mode[i];
if (GET_CODE (op) == SUBREG)
{
*curr_id->operand_loc[i] = tem;
lra_update_dup (curr_id, i);
- process_address (i, &before, &after);
+ process_address (i, false, &before, &after);
/* If the alternative accepts constant pool refs directly
there will be no reload needed at all. */
(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))
+ enum constraint_num cn = lookup_constraint (constraint);
+ if (insn_extra_memory_constraint (cn)
+ && satisfies_memory_constraint_p (tem, cn))
break;
-#endif
}
if (c == '\0' || c == ',' || c == '#')
continue;
&& regno < new_regno_start
&& ! lra_former_scratch_p (regno)
&& reg_renumber[regno] < 0
+ /* Check that the optional reload pseudo will be able to
+ hold given mode value. */
+ && ! (prohibited_class_reg_set_mode_p
+ (goal_alt[i], reg_class_contents[goal_alt[i]],
+ PSEUDO_REGNO_MODE (regno)))
&& (curr_insn_set == NULL_RTX
|| !((REG_P (SET_SRC (curr_insn_set))
|| MEM_P (SET_SRC (curr_insn_set))
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,
+ else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, FALSE,
"offsetable address", &new_reg))
lra_emit_move (new_reg, *loc);
before = get_insns ();
}
else if (goal_alt_matched[i][0] == -1)
{
- enum machine_mode mode;
+ machine_mode mode;
rtx reg, *loc;
int hard_regno, byte;
enum op_type type = curr_static_id->operand[i].type;
(ira_class_hard_regs[goal_alt[i]][0],
GET_MODE (reg), byte, mode) >= 0)))))
{
+ if (type == OP_OUT)
+ type = OP_INOUT;
loc = &SUBREG_REG (*loc);
mode = GET_MODE (*loc);
}
}
old = *loc;
- if (get_reload_reg (type, mode, old, goal_alt[i], "", &new_reg)
+ 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);
return change_p;
}
+/* Return true if INSN satisfies all constraints. In other words, no
+ reload insns are needed. */
+bool
+lra_constrain_insn (rtx_insn *insn)
+{
+ int saved_new_regno_start = new_regno_start;
+ int saved_new_insn_uid_start = new_insn_uid_start;
+ bool change_p;
+
+ curr_insn = insn;
+ curr_id = lra_get_insn_recog_data (curr_insn);
+ curr_static_id = curr_id->insn_static_data;
+ new_insn_uid_start = get_max_uid ();
+ new_regno_start = max_reg_num ();
+ change_p = curr_insn_transform (true);
+ new_regno_start = saved_new_regno_start;
+ new_insn_uid_start = saved_new_insn_uid_start;
+ return ! change_p;
+}
+
/* Return true if X is in LIST. */
static bool
in_list_p (rtx x, rtx list)
return false;
}
+/* Return true if X contains a symbol reg. */
+static bool
+contains_symbol_ref_p (rtx x)
+{
+ int i, j;
+ const char *fmt;
+ enum rtx_code code;
+
+ code = GET_CODE (x);
+ if (code == SYMBOL_REF)
+ return true;
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (contains_symbol_ref_p (XEXP (x, i)))
+ return true;
+ }
+ else if (fmt[i] == 'E')
+ {
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (contains_symbol_ref_p (XVECEXP (x, i, j)))
+ 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
return NULL_RTX;
rtx subst = (data == NULL
- ? get_equiv (loc) : get_equiv_with_elimination (loc, (rtx) data));
+ ? get_equiv (loc) : get_equiv_with_elimination (loc, (rtx_insn *) data));
if (subst != loc)
return subst;
/* 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
/* Return true if LIST contains a deleted insn. */
static bool
-contains_deleted_insn_p (rtx list)
+contains_deleted_insn_p (rtx_insn_list *list)
{
- for (; list != NULL_RTX; list = XEXP (list, 1))
- if (NOTE_P (XEXP (list, 0))
- && NOTE_KIND (XEXP (list, 0)) == NOTE_INSN_DELETED)
+ for (; list != NULL_RTX; list = list->next ())
+ if (NOTE_P (list->insn ())
+ && NOTE_KIND (list->insn ()) == 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)
+dead_pseudo_p (rtx x, rtx_insn *insn)
{
int i, j;
const char *fmt;
/* Return true if INSN contains a dying pseudo in INSN right hand
side. */
static bool
-insn_rhs_dead_pseudo_p (rtx insn)
+insn_rhs_dead_pseudo_p (rtx_insn *insn)
{
rtx set = single_set (insn);
static bool
init_insn_rhs_dead_pseudo_p (int regno)
{
- rtx insns = ira_reg_equiv[regno].init_insns;
+ rtx_insn_list *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)))
+ for (; insns != NULL_RTX; insns = insns->next ())
+ if (insn_rhs_dead_pseudo_p (insns->insn ()))
return true;
return false;
}
static bool
reverse_equiv_p (int regno)
{
- rtx insns, set;
+ rtx_insn_list *insns = ira_reg_equiv[regno].init_insns;
+ rtx set;
- if ((insns = ira_reg_equiv[regno].init_insns) == NULL_RTX)
+ if (insns == NULL)
return false;
- if (! INSN_P (XEXP (insns, 0))
- || XEXP (insns, 1) != NULL_RTX)
+ if (! INSN_P (insns->insn ())
+ || insns->next () != NULL)
return false;
- if ((set = single_set (XEXP (insns, 0))) == NULL_RTX)
+ if ((set = single_set (insns->insn ())) == NULL_RTX)
return false;
return REG_P (SET_SRC (set)) && (int) REGNO (SET_SRC (set)) == regno;
}
contains_reloaded_insn_p (int regno)
{
rtx set;
- rtx list = ira_reg_equiv[regno].init_insns;
+ rtx_insn_list *list = ira_reg_equiv[regno].init_insns;
- for (; list != NULL_RTX; list = XEXP (list, 1))
- if ((set = single_set (XEXP (list, 0))) == NULL_RTX
+ for (; list != NULL; list = list->next ())
+ if ((set = single_set (list->insn ())) == NULL_RTX
|| ! REG_P (SET_DEST (set))
|| (int) REGNO (SET_DEST (set)) != regno)
return true;
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;
+ if (pic_offset_table_rtx
+ && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
+ lra_risky_transformations_p = true;
+ else
+ 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. */
paradoxical subregs. */
|| (MEM_P (x)
&& (GET_MODE_SIZE (lra_reg_info[i].biggest_mode)
- > GET_MODE_SIZE (GET_MODE (x)))))
+ > GET_MODE_SIZE (GET_MODE (x))))
+ || (pic_offset_table_rtx
+ && ((CONST_POOL_OK_P (PSEUDO_REGNO_MODE (i), x)
+ && (targetm.preferred_reload_class
+ (x, lra_get_allocno_class (i)) == NO_REGS))
+ || contains_symbol_ref_p (x))))
ira_reg_equiv[i].defined_p = false;
if (contains_reg_p (x, false, true))
ira_reg_equiv[i].profitable_p = false;
curr_static_id = curr_id->insn_static_data;
init_curr_insn_input_reloads ();
init_curr_operand_mode ();
- if (curr_insn_transform ())
+ if (curr_insn_transform (false))
changed_p = true;
/* Check non-transformed insns too for equiv change as USE
or CLOBBER don't need reloads but can contain pseudos
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
+static rtx_insn *
skip_usage_debug_insns (rtx usage_insns)
{
rtx insn;
insn != NULL_RTX && GET_CODE (insn) == INSN_LIST;
insn = XEXP (insn, 1))
;
- return insn;
+ return safe_as_a <rtx_insn *> (insn);
}
/* Return true if we need secondary memory moves for insn in
#ifndef SECONDARY_MEMORY_NEEDED
return false;
#else
- rtx insn, set, dest;
+ rtx_insn *insn;
+ rtx set, dest;
enum reg_class cl;
if (inher_cl == ALL_REGS
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)
+ enum reg_class cl, rtx_insn *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;
+ rtx new_reg, usage_insn;
+ rtx_insn *new_insns;
lra_assert (! usage_insns[original_regno].after_p);
if (lra_dump_file != NULL)
transformation will be unprofitable. */
if (lra_dump_file != NULL)
{
- rtx insn = skip_usage_debug_insns (next_usage_insns);
+ rtx_insn *insn = skip_usage_debug_insns (next_usage_insns);
rtx set = single_set (insn);
lra_assert (set != NULL_RTX);
rclass, "inheritance");
start_sequence ();
if (def_p)
- emit_move_insn (original_reg, new_reg);
+ lra_emit_move (original_reg, new_reg);
else
- emit_move_insn (new_reg, original_reg);
+ lra_emit_move (new_reg, original_reg);
new_insns = get_insns ();
end_sequence ();
if (NEXT_INSN (new_insns) != NULL_RTX)
" 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);
+ dump_rtl_slim (lra_dump_file, new_insns, NULL, -1, 0);
fprintf (lra_dump_file,
" >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
}
return false;
}
- substitute_pseudo (&insn, original_regno, new_reg);
+ lra_substitute_pseudo_within_insn (insn, original_regno, new_reg);
lra_update_insn_regno_info (insn);
if (! def_p)
/* We now have a new usage insn for original regno. */
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,
+ lra_process_new_insns (insn, NULL, new_insns,
"Add original<-inheritance");
else
- lra_process_new_insns (insn, new_insns, NULL_RTX,
+ lra_process_new_insns (insn, new_insns, NULL,
"Add inheritance<-original");
while (next_usage_insns != NULL_RTX)
{
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);
+ lra_substitute_pseudo (&usage_insn, original_regno, new_reg);
+ lra_update_insn_regno_info (as_a <rtx_insn *> (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);
+ dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (usage_insn));
}
}
if (lra_dump_file != NULL)
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,
+ ((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])
|| HARD_REGNO_CALL_PART_CLOBBERED (reg_renumber[regno],
PSEUDO_REGNO_MODE (regno))));
static enum reg_class
choose_split_class (enum reg_class allocno_class,
int hard_regno ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
+ machine_mode mode ATTRIBUTE_UNUSED)
{
#ifndef SECONDARY_MEMORY_NEEDED
return allocno_class;
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)
+split_reg (bool before_p, int original_regno, rtx_insn *insn,
+ rtx next_usage_insns)
{
enum reg_class rclass;
rtx original_reg;
int hard_regno, nregs;
- rtx new_reg, save, restore, usage_insn;
+ rtx new_reg, usage_insn;
+ rtx_insn *restore, *save;
bool after_p;
bool call_save_p;
" ((((((((((((((((((((((((((((((((((((((((((((((((\n");
if (call_save_p)
{
- enum machine_mode mode = GET_MODE (original_reg);
+ machine_mode mode = GET_MODE (original_reg);
mode = HARD_REGNO_CALLER_SAVE_MODE (hard_regno,
hard_regno_nregs[hard_regno][mode],
reg_renumber[REGNO (new_reg)] = hard_regno;
}
save = emit_spill_move (true, new_reg, original_reg);
- if (NEXT_INSN (save) != NULL_RTX)
+ if (NEXT_INSN (save) != NULL_RTX && !call_save_p)
{
- 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);
+ " Rejecting split %d->%d resulting in > 2 save insns:\n",
+ original_regno, REGNO (new_reg));
+ dump_rtl_slim (lra_dump_file, save, NULL, -1, 0);
fprintf (lra_dump_file,
" ))))))))))))))))))))))))))))))))))))))))))))))))\n");
}
return false;
}
restore = emit_spill_move (false, new_reg, original_reg);
- if (NEXT_INSN (restore) != NULL_RTX)
+ if (NEXT_INSN (restore) != NULL_RTX && !call_save_p)
{
- 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);
+ "resulting in > 2 restore insns:\n",
+ original_regno, REGNO (new_reg));
+ dump_rtl_slim (lra_dump_file, restore, NULL, -1, 0);
fprintf (lra_dump_file,
" ))))))))))))))))))))))))))))))))))))))))))))))))\n");
}
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);
+ lra_substitute_pseudo (&usage_insn, original_regno, new_reg);
+ lra_update_insn_regno_info (as_a <rtx_insn *> (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);
+ dump_insn_slim (lra_dump_file, as_a <rtx_insn *> (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,
+ lra_process_new_insns (as_a <rtx_insn *> (usage_insn),
+ after_p ? NULL : restore,
+ after_p ? restore : NULL,
call_save_p
? "Add reg<-save" : "Add reg<-split");
- lra_process_new_insns (insn, before_p ? save : NULL_RTX,
- before_p ? NULL_RTX : save,
+ lra_process_new_insns (insn, before_p ? save : NULL,
+ before_p ? NULL : save,
call_save_p
? "Add save<-reg" : "Add split<-reg");
if (nregs > 1)
uid before starting INSN processing. Return true if we succeed in
such transformation. */
static bool
-split_if_necessary (int regno, enum machine_mode mode,
+split_if_necessary (int regno, machine_mode mode,
HARD_REG_SET potential_reload_hard_regs,
- bool before_p, rtx insn, int max_uid)
+ bool before_p, rtx_insn *insn, int max_uid)
{
bool res = false;
int i, nregs = 1;
inheritance/split transformation. The function removes dead moves
too. */
static void
-update_ebb_live_info (rtx head, rtx tail)
+update_ebb_live_info (rtx_insn *head, rtx_insn *tail)
{
unsigned int j;
int i, regno;
bool live_p;
- rtx prev_insn, set;
+ rtx_insn *prev_insn;
+ rtx set;
bool remove_p;
basic_block last_bb, prev_bb, curr_bb;
bitmap_iterator bi;
/* Return the last non-debug insn in basic block BB, or the block begin
note if none. */
-static rtx
+static rtx_insn *
get_last_insertion_point (basic_block bb)
{
- rtx insn;
+ rtx_insn *insn;
FOR_BB_INSNS_REVERSE (bb, insn)
if (NONDEBUG_INSN_P (insn) || NOTE_INSN_BASIC_BLOCK_P (insn))
static void
get_live_on_other_edges (basic_block from, basic_block to, bitmap res)
{
- rtx last;
+ rtx_insn *last;
struct lra_insn_reg *reg;
edge e;
edge_iterator ei;
splitting even more but it is to expensive and the current approach
works well enough. */
static bool
-inherit_in_ebb (rtx head, rtx tail)
+inherit_in_ebb (rtx_insn *head, rtx_insn *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;
+ rtx_insn *prev_insn, *last_insn;
+ rtx next_usage_insns, set;
enum reg_class cl;
struct lra_insn_reg *reg;
basic_block last_processed_bb, curr_bb = NULL;
change_p = true;
if (CALL_P (curr_insn))
{
- rtx cheap, pat, dest, restore;
+ rtx cheap, pat, dest;
+ rtx_insn *restore;
int regno, hard_regno;
calls_num++;
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);
+ /* For multiple return values dest is PARALLEL.
+ Currently we handle only single return value case. */
+ if (REG_P (dest))
+ {
+ 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;
|| reg_renumber[src_regno] >= 0)
{
bool before_p;
- rtx use_insn = curr_insn;
+ rtx_insn *use_insn = curr_insn;
before_p = (JUMP_P (curr_insn)
|| (CALL_P (curr_insn) && reg->type == OP_IN));
/* 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)
+#define EBB_PROBABILITY_CUTOFF \
+ ((REG_BR_PROB_BASE * LRA_INHERITANCE_EBB_PROBABILITY_CUTOFF) / 100)
/* Current number of inheritance/split iteration. */
int lra_inheritance_iter;
e = find_fallthru_edge (bb->succs);
if (! e)
break;
- if (e->probability <= EBB_PROBABILITY_CUTOFF)
+ if (e->probability < EBB_PROBABILITY_CUTOFF)
break;
bb = bb->next_bb;
}
{
basic_block bb;
int regno, sregno, prev_sregno, dregno, restore_regno;
- rtx set, prev_set, prev_insn;
+ rtx set, prev_set;
+ rtx_insn *prev_insn;
bool change_p, done_p;
change_p = ! bitmap_empty_p (remove_pseudos);
SUBREG_REG (SET_SRC (set)) = SET_SRC (prev_set);
else
SET_SRC (set) = SET_SRC (prev_set);
+ /* As we are finishing with processing the insn
+ here, check the destination too as it might
+ inheritance pseudo for another pseudo. */
+ if (bitmap_bit_p (remove_pseudos, dregno)
+ && bitmap_bit_p (&lra_inheritance_pseudos, dregno)
+ && (restore_regno
+ = lra_reg_info[dregno].restore_regno) >= 0)
+ {
+ if (GET_CODE (SET_DEST (set)) == SUBREG)
+ SUBREG_REG (SET_DEST (set))
+ = regno_reg_rtx[restore_regno];
+ else
+ SET_DEST (set) = regno_reg_rtx[restore_regno];
+ }
lra_push_insn_and_update_insn_regno_info (curr_insn);
lra_set_used_insn_alternative_by_uid
(INSN_UID (curr_insn), -1);
{
if (change_p && bitmap_bit_p (remove_pseudos, regno))
{
- substitute_pseudo (&curr_insn, regno,
- regno_reg_rtx[restore_regno]);
+ lra_substitute_pseudo_within_insn (
+ curr_insn, regno, regno_reg_rtx[restore_regno]);
restored_regs_p = true;
}
else
bool change_p, keep_p;
unsigned int regno, uid;
bitmap_iterator bi, bi2;
- rtx insn, set, src, dest;
+ rtx_insn *insn;
+ rtx set, src, dest;
bitmap_head removed_optional_reload_pseudos, insn_bitmap;
bitmap_initialize (&removed_optional_reload_pseudos, ®_obstack);
we remove the inheritance pseudo and the optional
reload. */
}
- substitute_pseudo (&insn, regno,
- regno_reg_rtx[lra_reg_info[regno].restore_regno]);
+ lra_substitute_pseudo_within_insn (
+ insn, regno,
+ regno_reg_rtx[lra_reg_info[regno].restore_regno]);
lra_update_insn_regno_info (insn);
if (lra_dump_file != NULL)
{