/* 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 "output.h"
#include "addresses.h"
#include "target.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
-#include "input.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 "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
static lra_insn_recog_data_t curr_id;
static struct lra_static_insn_data *curr_static_id;
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
|| 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)
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. */
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;
rtx_insn **before, rtx_insn **after)
{
int i, in;
- rtx new_in_reg, new_out_reg, reg, clobber;
+ 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)
LRA_SUBREG_P (mem_pseudo) = 1;
}
}
- return as_a <rtx_insn *> (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, scratch_reg;
+ rtx dest, src, dreg, sreg, new_reg, scratch_reg;
rtx_insn *before;
enum reg_class dclass, sclass, secondary_class;
- 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, "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_insn **before, rtx_insn **after,
+process_addr_reg (rtx *loc, bool check_only_p, rtx_insn **before, rtx_insn **after,
enum reg_class cl)
{
int regno;
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, subreg_p, "address", &new_reg))
}
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;
}
/* 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, machine_mode reg_mode)
{
int hard_regno;
rtx_insn *before, *after;
- machine_mode mode;
+ machine_mode mode, innermode;
rtx reg, new_reg;
rtx operand = *curr_id->operand_loc[nop];
enum reg_class regclass;
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
alter_subreg (curr_id->operand_loc[nop], false);
subst = *curr_id->operand_loc[nop];
lra_assert (MEM_P (subst));
- if (! valid_address_p (GET_MODE (reg), XEXP (reg, 0),
+ 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)))
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. */
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
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);
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. */
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
early_clobber_p = true;
break;
+ case '$':
+ op_reject += LRA_MAX_REJECT;
+ break;
+ case '^':
+ op_reject += LRA_LOSER_COST_FACTOR;
+ break;
+
case '#':
/* Ignore rest of this alternative. */
c = '\0';
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;
}
+ /* 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
: *ad->disp_term);
if (!valid_address_p (ad->mode, new_inner, ad->as))
return NULL_RTX;
- insn = emit_insn (gen_rtx_SET (ad->mode, new_reg, *ad->base_term));
+ insn = emit_insn (gen_rtx_SET (new_reg, *ad->base_term));
code = recog_memoized (insn);
if (code < 0)
{
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
address. Return true for any RTL change.
The function is a helper function which does not produce all
- transformations which can be necessary. It does just basic steps.
- To do all necessary transformations use function
- process_address. */
+ 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_1 (int nop, rtx_insn **before, rtx_insn **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;
enum constraint_num cn = lookup_constraint (constraint);
- bool change_p;
+ bool change_p = false;
if (insn_extra_address_constraint (cn))
decompose_lea_address (&ad, curr_id->operand_loc[nop]);
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;
/* Target hooks sometimes don't treat extra-constraint addresses as
&& satisfies_address_constraint_p (&ad, cn))
return change_p;
+ if (check_only_p)
+ return change_p;
+
/* There are three cases where the shape of *AD.INNER may now be invalid:
1) the original address was valid, but either elimination or
rtx addr = *ad.inner;
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "addr");
-#ifdef 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
- (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. */
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;
return true;
}
-/* 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 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, rtx_insn **before, rtx_insn **after)
+process_address (int nop, bool check_only_p,
+ rtx_insn **before, rtx_insn **after)
{
bool res = false;
- while (process_address_1 (nop, before, after))
- res = true;
+ while (process_address_1 (nop, check_only_p, before, after))
+ {
+ if (check_only_p)
+ return true;
+ res = true;
+ }
return res;
}
&& (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)
{
- 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;
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;
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);
}
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
*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. */
&& 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))
(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);
}
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 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;
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
" 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
- ((flag_use_caller_save &&
+ ((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,
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" : "");
+ " 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" : "");
+ "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");
{
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));
|| 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;
}