SET_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs);
}
+/* Return true if insn REG is an early clobber operand in alternative
+ NALT. Negative NALT means that we don't know the current insn
+ alternative. So assume the worst. */
+static inline bool
+reg_early_clobber_p (const struct lra_insn_reg *reg, int n_alt)
+{
+ return (reg->early_clobber
+ && (n_alt < 0 || TEST_BIT (reg->early_clobber_alts, n_alt)));
+}
+
/* Process insns of the basic block BB to update pseudo live ranges,
pseudo hard register conflicts, and insn notes. We do it on
backward scan of BB insns. CURR_POINT is the program point where
FOR_BB_INSNS_REVERSE_SAFE (bb, curr_insn, next)
{
bool call_p;
- int dst_regno, src_regno;
+ int n_alt, dst_regno, src_regno;
rtx set;
struct lra_insn_reg *reg;
curr_id = lra_get_insn_recog_data (curr_insn);
curr_static_id = curr_id->insn_static_data;
+ n_alt = curr_id->used_insn_alternative;
if (lra_dump_file != NULL)
- fprintf (lra_dump_file, " Insn %u: point = %d\n",
- INSN_UID (curr_insn), curr_point);
+ fprintf (lra_dump_file, " Insn %u: point = %d, n_alt = %d\n",
+ INSN_UID (curr_insn), curr_point, n_alt);
set = single_set (curr_insn);
/* See which defined values die here. */
for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- if (reg->type == OP_OUT && ! reg->early_clobber && ! reg->subreg_p)
+ if (reg->type == OP_OUT
+ && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
need_curr_point_incr
|= mark_regno_dead (reg->regno, reg->biggest_mode,
curr_point);
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type == OP_OUT && ! reg->early_clobber && ! reg->subreg_p)
+ if (reg->type == OP_OUT
+ && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
make_hard_regno_dead (reg->regno);
if (curr_id->arg_hard_regs != NULL)
/* Mark early clobber outputs dead. */
for (reg = curr_id->regs; reg != NULL; reg = reg->next)
- if (reg->type == OP_OUT && reg->early_clobber && ! reg->subreg_p)
+ if (reg->type == OP_OUT
+ && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
need_curr_point_incr
|= mark_regno_dead (reg->regno, reg->biggest_mode,
curr_point);
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
- if (reg->type == OP_OUT && reg->early_clobber && ! reg->subreg_p)
+ if (reg->type == OP_OUT
+ && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
make_hard_regno_dead (reg->regno);
if (need_curr_point_incr)
/* Pools for insn reg info. */
object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs");
-/* Create LRA insn related info about a reference to REGNO in INSN with
- TYPE (in/out/inout), biggest reference mode MODE, flag that it is
- reference through subreg (SUBREG_P), flag that is early clobbered
- in the insn (EARLY_CLOBBER), and reference to the next insn reg
- info (NEXT). */
+/* Create LRA insn related info about a reference to REGNO in INSN
+ with TYPE (in/out/inout), biggest reference mode MODE, flag that it
+ is reference through subreg (SUBREG_P), flag that is early
+ clobbered in the insn (EARLY_CLOBBER), and reference to the next
+ insn reg info (NEXT). If REGNO can be early clobbered,
+ alternatives in which it can be early clobbered are given by
+ EARLY_CLOBBER_ALTS. */
static struct lra_insn_reg *
new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
machine_mode mode,
- bool subreg_p, bool early_clobber, struct lra_insn_reg *next)
+ bool subreg_p, bool early_clobber,
+ alternative_mask early_clobber_alts,
+ struct lra_insn_reg *next)
{
lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
ir->type = type;
lra_reg_info[regno].biggest_mode = mode;
ir->subreg_p = subreg_p;
ir->early_clobber = early_clobber;
+ ir->early_clobber_alts = early_clobber_alts;
ir->regno = regno;
ir->next = next;
return ir;
static struct lra_operand_data debug_operand_data =
{
NULL, /* alternative */
+ 0, /* early_clobber_alts */
VOIDmode, /* We are not interesting in the operand mode. */
OP_IN,
0, 0, 0, 0
static_data->operand_alternative = op_alt;
for (i = 0; i < nop; i++)
{
+ static_data->operand[i].early_clobber_alts = 0;
static_data->operand[i].early_clobber = false;
static_data->operand[i].is_address = false;
if (static_data->operand[i].constraint[0] == '%')
for (i = 0; i < nop; i++, op_alt++)
{
static_data->operand[i].early_clobber |= op_alt->earlyclobber;
+ if (op_alt->earlyclobber)
+ static_data->operand[i].early_clobber_alts |= (alternative_mask) 1 << j;
static_data->operand[i].is_address |= op_alt->is_address;
}
}
{
if (curr->type != type)
curr->type = OP_INOUT;
- if (curr->early_clobber != early_clobber)
- curr->early_clobber = true;
+ if (early_clobber)
+ {
+ curr->early_clobber = true;
+ curr->early_clobber_alts = ALL_ALTERNATIVES;
+ }
break;
}
if (curr == NULL)
&& regno <= LAST_STACK_REG));
#endif
list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
- early_clobber, list);
+ early_clobber,
+ early_clobber ? ALL_ALTERNATIVES : 0, list);
}
}
return list;
/* Process X of insn UID recursively and add info (operand type is
given by TYPE, flag of that it is early clobber is EARLY_CLOBBER)
- about registers in X to the insn DATA. */
+ about registers in X to the insn DATA. If X can be early clobbered,
+ alternatives in which it can be early clobbered are given by
+ EARLY_CLOBBER_ALTS. */
static void
add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
- enum op_type type, bool early_clobber)
+ enum op_type type, bool early_clobber,
+ alternative_mask early_clobber_alts)
{
int i, j, regno;
bool subreg_p;
if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid))
{
data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p,
- early_clobber, data->regs);
+ early_clobber, early_clobber_alts,
+ data->regs);
return;
}
else
structure. */
data->regs = new_insn_reg (data->insn, regno, type, mode,
subreg_p, early_clobber,
- data->regs);
+ early_clobber_alts, data->regs);
else
{
if (curr->type != type)
curr->type = OP_INOUT;
if (curr->early_clobber != early_clobber)
curr->early_clobber = true;
+ curr->early_clobber_alts |= early_clobber_alts;
}
return;
}
switch (code)
{
case SET:
- add_regs_to_insn_regno_info (data, SET_DEST (x), uid, OP_OUT, false);
- add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false);
+ add_regs_to_insn_regno_info (data, SET_DEST (x), uid, OP_OUT, false, 0);
+ add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false, 0);
break;
case CLOBBER:
/* We treat clobber of non-operand hard registers as early
clobber (the behavior is expected from asm). */
- add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_OUT, true);
+ add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_OUT, true, ALL_ALTERNATIVES);
break;
case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
- add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false);
+ add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0);
break;
case PRE_MODIFY: case POST_MODIFY:
- add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false);
- add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false);
+ add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0);
+ add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false, 0);
break;
default:
if ((code != PARALLEL && code != EXPR_LIST) || type != OP_OUT)
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- add_regs_to_insn_regno_info (data, XEXP (x, i), uid, type, false);
+ add_regs_to_insn_regno_info (data, XEXP (x, i), uid, type, false, 0);
else if (fmt[i] == 'E')
{
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), uid,
- type, false);
+ type, false, 0);
}
}
}
for (i = static_data->n_operands - 1; i >= 0; i--)
add_regs_to_insn_regno_info (data, *data->operand_loc[i], uid,
static_data->operand[i].type,
- static_data->operand[i].early_clobber);
+ static_data->operand[i].early_clobber,
+ static_data->operand[i].early_clobber_alts);
if ((code = GET_CODE (PATTERN (insn))) == CLOBBER || code == USE)
add_regs_to_insn_regno_info (data, XEXP (PATTERN (insn), 0), uid,
- code == USE ? OP_IN : OP_OUT, false);
+ code == USE ? OP_IN : OP_OUT, false, 0);
if (CALL_P (insn))
/* On some targets call insns can refer to pseudos in memory in
CALL_INSN_FUNCTION_USAGE list. Process them in order to
if (((code = GET_CODE (XEXP (link, 0))) == USE || code == CLOBBER)
&& MEM_P (XEXP (XEXP (link, 0), 0)))
add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), uid,
- code == USE ? OP_IN : OP_OUT, false);
+ code == USE ? OP_IN : OP_OUT, false, 0);
if (NONDEBUG_INSN_P (insn))
setup_insn_reg_info (data, freq);
}