summaryrefslogtreecommitdiff
path: root/gcc/lra-constraints.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-04-22 10:21:45 +0000
committer <>2015-04-25 21:44:09 +0000
commitf80b5ea1605c9f9408c5aa386ba71c16d918ebbf (patch)
treebb7eafaa81fc4b8c5c215bc08d517fd158db234a /gcc/lra-constraints.c
parentc27a97d04853380f1e80525391b3f0d156ed4c84 (diff)
downloadgcc-tarball-f80b5ea1605c9f9408c5aa386ba71c16d918ebbf.tar.gz
Imported from /home/lorry/working-area/delta_gcc-tarball/gcc-5.1.0.tar.bz2.gcc-5.1.0
Diffstat (limited to 'gcc/lra-constraints.c')
-rw-r--r--gcc/lra-constraints.c1233
1 files changed, 697 insertions, 536 deletions
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index 874696865b..7353e7c2c7 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -1,5 +1,5 @@
/* 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.
@@ -120,14 +120,41 @@
#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 "statistics.h"
+#include "double-int.h"
+#include "real.h"
+#include "fixed-value.h"
+#include "alias.h"
+#include "wide-int.h"
+#include "inchash.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
@@ -138,12 +165,16 @@ static int bb_reload_num;
/* The current insn being processed and corresponding its single set
(NULL otherwise), its data (basic block, the insn data, the insn
static data, and the mode of each operand). */
-static rtx curr_insn;
+static rtx_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];
@@ -247,7 +278,7 @@ static bool
in_class_p (rtx reg, enum reg_class cl, enum reg_class *new_class)
{
enum reg_class rclass, common_class;
- enum machine_mode reg_mode;
+ machine_mode reg_mode;
int class_size, hard_regno, nregs, i, j;
int regno = REGNO (reg);
@@ -317,6 +348,116 @@ in_mem_p (int regno)
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. */
@@ -369,7 +510,11 @@ get_equiv (rtx x)
|| 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)
@@ -381,13 +526,14 @@ get_equiv (rtx x)
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),
+ 0, false, false, true);
}
/* Set up curr_operand_mode. */
@@ -397,7 +543,7 @@ init_curr_operand_mode (void)
int nop = curr_static_id->n_operands;
for (int i = 0; i < nop; i++)
{
- enum machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
+ machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
if (mode == VOIDmode)
{
/* The .md mode for address operands is the mode of the
@@ -446,7 +592,7 @@ init_curr_insn_input_reloads (void)
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,
+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)
{
@@ -516,7 +662,7 @@ ok_for_index_p_nonstrict (rtx 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);
@@ -540,7 +686,7 @@ ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode, addr_space_t as,
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
@@ -625,7 +771,7 @@ operands_match_p (rtx x, rtx y, int y_hard_regno)
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);
@@ -724,11 +870,11 @@ narrow_reload_pseudo_class (rtx reg, enum reg_class cl)
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;
+ 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];
@@ -858,33 +1004,25 @@ reg_class_from_constraints (const char *p)
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;
@@ -901,7 +1039,7 @@ get_op_class (rtx op)
/* 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))
@@ -922,9 +1060,9 @@ emit_spill_move (bool to_p, rtx mem_pseudo, rtx val)
LRA_SUBREG_P (mem_pseudo) = 1;
}
}
- return (to_p
- ? gen_move_insn (mem_pseudo, val)
- : gen_move_insn (val, mem_pseudo));
+ return as_a <rtx_insn *> (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
@@ -936,9 +1074,9 @@ static bool
check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED)
{
int sregno, dregno;
- rtx dest, src, dreg, sreg, old_sreg, new_reg, before, scratch_reg;
+ 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);
@@ -962,8 +1100,6 @@ check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED)
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)
@@ -1022,9 +1158,9 @@ check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED)
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)
@@ -1040,14 +1176,12 @@ check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED)
*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;
@@ -1058,18 +1192,13 @@ check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED)
(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)
@@ -1131,18 +1260,23 @@ static bool no_input_reloads_p, no_output_reloads_p;
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;
+ machine_mode mode;
bool subreg_p, before_p = false;
subreg_p = GET_CODE (*loc) == SUBREG;
@@ -1152,6 +1286,8 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
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");
@@ -1161,7 +1297,8 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
{
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)
{
@@ -1175,6 +1312,8 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
}
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))
@@ -1182,6 +1321,8 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
}
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;
}
@@ -1212,7 +1353,8 @@ process_addr_reg (rtx *loc, rtx *before, rtx *after, enum reg_class cl)
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)
{
@@ -1231,29 +1373,30 @@ insert_move_for_subreg (rtx *before, rtx *after, rtx origreg, rtx newreg)
}
}
-static int valid_address_p (enum machine_mode mode, rtx addr, addr_space_t as);
+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
@@ -1272,7 +1415,7 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode)
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)))
@@ -1287,6 +1430,20 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode)
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
@@ -1306,9 +1463,9 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode)
&& (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. */
@@ -1334,7 +1491,7 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode)
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,
@@ -1377,7 +1534,7 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode)
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
@@ -1395,7 +1552,7 @@ simplify_operand_subreg (int nop, enum machine_mode reg_mode)
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);
@@ -1417,7 +1574,7 @@ static bool
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;
@@ -1490,6 +1647,23 @@ reg_in_class_p (rtx reg, enum reg_class cl)
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;
+
+ // ??? Is this assert right
+ // lra_assert (hard_reg_set_subset_p (set, reg_class_contents[rclass]));
+ 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
@@ -1510,6 +1684,7 @@ process_alt_operands (int only_alternative)
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. */
@@ -1532,7 +1707,7 @@ process_alt_operands (int only_alternative)
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;
@@ -1575,19 +1750,16 @@ process_alt_operands (int only_alternative)
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++)
{
@@ -1620,7 +1792,8 @@ process_alt_operands (int only_alternative)
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)
@@ -1661,6 +1834,7 @@ process_alt_operands (int only_alternative)
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
@@ -1679,17 +1853,15 @@ process_alt_operands (int only_alternative)
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 '#':
@@ -1820,194 +1992,66 @@ process_alt_operands (int only_alternative)
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]);
@@ -2018,7 +2062,6 @@ process_alt_operands (int only_alternative)
IOR_HARD_REG_SET (this_costly_alternative_set,
reg_class_contents[cl]);
}
- reg:
if (mode == BLKmode)
break;
winreg = true;
@@ -2107,6 +2150,7 @@ process_alt_operands (int only_alternative)
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. */
@@ -2281,6 +2325,35 @@ process_alt_operands (int only_alternative)
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
@@ -2594,58 +2667,37 @@ process_alt_operands (int only_alternative)
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 (ad->mode, 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. */
@@ -2787,8 +2839,9 @@ equiv_address_substitution (struct address_info *ad)
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
@@ -2808,20 +2861,21 @@ equiv_address_substitution (struct address_info *ad)
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 *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);
@@ -2830,10 +2884,25 @@ process_address_1 (int nop, rtx *before, rtx *after)
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,
@@ -2847,17 +2916,18 @@ process_address_1 (int nop, rtx *before, rtx *after)
*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:
@@ -2870,6 +2940,8 @@ process_address_1 (int nop, rtx *before, rtx *after)
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))
@@ -2891,8 +2963,8 @@ process_address_1 (int nop, rtx *before, rtx *after)
new_reg = lra_create_new_reg (Pmode, NULL_RTX, cl, "addr");
#ifdef HAVE_lo_sum
{
- rtx insn;
- rtx last = get_last_insn ();
+ rtx_insn *insn;
+ rtx_insn *last = get_last_insn ();
/* addr => lo_sum (new_base, addr), case (2) above. */
insn = emit_insn (gen_rtx_SET
@@ -2950,15 +3022,21 @@ process_address_1 (int nop, rtx *before, rtx *after)
{
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
@@ -2983,6 +3061,32 @@ process_address_1 (int nop, rtx *before, rtx *after)
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;
@@ -3019,15 +3123,24 @@ process_address_1 (int nop, rtx *before, rtx *after)
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 *before, rtx *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;
}
@@ -3049,9 +3162,9 @@ emit_inc (enum reg_class new_rclass, rtx in, rtx value, int inc_amount)
/* 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;
@@ -3174,16 +3287,19 @@ simple_move_p (void)
&& (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];
+ machine_mode mode = curr_operand_mode[nop];
curr_operand_mode[nop] = curr_operand_mode[nop + 1];
curr_operand_mode[nop + 1] = mode;
+ mode = original_subreg_reg_mode[nop];
+ original_subreg_reg_mode[nop] = original_subreg_reg_mode[nop + 1];
+ original_subreg_reg_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;
@@ -3199,9 +3315,15 @@ swap_operands (int nop)
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;
@@ -3209,7 +3331,7 @@ curr_insn_transform (void)
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;
@@ -3268,50 +3390,58 @@ curr_insn_transform (void)
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);
}
@@ -3321,13 +3451,13 @@ curr_insn_transform (void)
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));
@@ -3335,6 +3465,9 @@ curr_insn_transform (void)
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
@@ -3401,7 +3534,7 @@ curr_insn_transform (void)
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
@@ -3426,7 +3559,7 @@ curr_insn_transform (void)
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. */
@@ -3435,14 +3568,14 @@ curr_insn_transform (void)
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
@@ -3454,7 +3587,7 @@ curr_insn_transform (void)
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);
@@ -3542,7 +3675,7 @@ curr_insn_transform (void)
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)
{
@@ -3564,7 +3697,7 @@ curr_insn_transform (void)
*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. */
@@ -3577,13 +3710,10 @@ curr_insn_transform (void)
(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;
@@ -3629,6 +3759,11 @@ curr_insn_transform (void)
&& 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))
@@ -3672,7 +3807,7 @@ curr_insn_transform (void)
}
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;
@@ -3699,6 +3834,8 @@ curr_insn_transform (void)
(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);
}
@@ -3791,6 +3928,26 @@ curr_insn_transform (void)
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)
@@ -3852,6 +4009,35 @@ contains_reg_p (rtx x, bool hard_reg_p, bool spilled_p)
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
@@ -3906,7 +4092,7 @@ loc_equivalence_callback (rtx loc, const_rtx, void *data)
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;
@@ -3947,11 +4133,11 @@ multi_block_pseudo_p (int regno)
/* 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;
}
@@ -3989,7 +4175,7 @@ dead_pseudo_p (rtx x, rtx insn)
/* 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);
@@ -4002,14 +4188,12 @@ insn_rhs_dead_pseudo_p (rtx 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;
}
@@ -4020,14 +4204,15 @@ init_insn_rhs_dead_pseudo_p (int regno)
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;
}
@@ -4038,10 +4223,10 @@ static bool
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;
@@ -4066,7 +4251,11 @@ lra_constraints (bool first_p)
fprintf (lra_dump_file, "\n********** Local #%d: **********\n\n",
lra_constraint_iter);
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. */
@@ -4134,7 +4323,12 @@ lra_constraints (bool first_p)
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;
@@ -4246,7 +4440,7 @@ lra_constraints (bool first_p)
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
@@ -4374,59 +4568,8 @@ add_next_usage_insn (int regno, rtx insn, int reloads_num)
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;
@@ -4436,7 +4579,7 @@ skip_usage_debug_insns (rtx usage_insns)
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
@@ -4449,7 +4592,8 @@ check_secondary_memory_needed_p (enum reg_class inher_cl ATTRIBUTE_UNUSED,
#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
@@ -4496,14 +4640,15 @@ static bitmap_head check_only_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)
@@ -4543,7 +4688,7 @@ inherit_reload_reg (bool def_p, int original_regno,
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);
@@ -4578,13 +4723,13 @@ inherit_reload_reg (bool def_p, int original_regno,
" 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. */
@@ -4597,10 +4742,10 @@ inherit_reload_reg (bool def_p, int 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)
{
@@ -4616,8 +4761,8 @@ inherit_reload_reg (bool def_p, int original_regno,
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,
@@ -4641,7 +4786,10 @@ need_for_call_save_p (int regno)
lra_assert (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0);
return (usage_insns[regno].calls_num < calls_num
&& (overlaps_hard_reg_set_p
- (call_used_reg_set,
+ ((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))));
@@ -4715,7 +4863,7 @@ need_for_split_p (HARD_REG_SET potential_reload_hard_regs, int 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;
@@ -4765,12 +4913,14 @@ choose_split_class (enum reg_class 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;
@@ -4796,7 +4946,7 @@ split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns)
" ((((((((((((((((((((((((((((((((((((((((((((((((\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],
@@ -4829,32 +4979,30 @@ split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns)
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");
}
@@ -4875,8 +5023,8 @@ split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns)
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",
@@ -4886,12 +5034,13 @@ split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns)
}
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)
@@ -4915,9 +5064,9 @@ split_reg (bool before_p, int original_regno, rtx insn, rtx next_usage_insns)
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;
@@ -4947,12 +5096,13 @@ static bitmap_head live_regs;
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;
@@ -5087,10 +5237,10 @@ add_to_inherit (int regno, rtx insns)
/* 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))
@@ -5103,7 +5253,7 @@ get_last_insertion_point (basic_block bb)
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;
@@ -5147,11 +5297,12 @@ static const int max_small_class_regs_num = 2;
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;
@@ -5351,7 +5502,8 @@ inherit_in_ebb (rtx head, rtx tail)
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++;
@@ -5373,16 +5525,21 @@ inherit_in_ebb (rtx head, rtx tail)
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;
@@ -5529,7 +5686,8 @@ inherit_in_ebb (rtx head, rtx tail)
/* 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;
@@ -5575,7 +5733,7 @@ lra_inheritance (void)
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;
}
@@ -5650,7 +5808,8 @@ remove_inheritance_pseudos (bitmap remove_pseudos)
{
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);
@@ -5784,8 +5943,8 @@ remove_inheritance_pseudos (bitmap remove_pseudos)
{
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
@@ -5826,7 +5985,8 @@ undo_optional_reloads (void)
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, &reg_obstack);
@@ -5907,8 +6067,9 @@ undo_optional_reloads (void)
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)
{