static int allocno_compare ();
static void mark_reg_store ();
static void mark_reg_clobber ();
+static void mark_reg_conflicts ();
static void mark_reg_live_nc ();
static void mark_reg_death ();
static void dump_conflicts ();
mark_reg_store (XEXP (link, 0), 0);
#endif
+ /* If INSN has multiple outputs, then any reg that dies here
+ and is used inside of an output
+ must conflict with the other outputs. */
+
+ if (GET_CODE (PATTERN (insn)) == PARALLEL && !single_set (insn))
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ if (REG_NOTE_KIND (link) == REG_DEAD)
+ {
+ int used_in_output = 0;
+ int i;
+ rtx reg = XEXP (link, 0);
+
+ for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ {
+ rtx set = XVECEXP (PATTERN (insn), 0, i);
+ if (GET_CODE (set) == SET
+ && GET_CODE (SET_DEST (set)) != REG
+ && !rtx_equal_p (reg, SET_DEST (set))
+ && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ used_in_output = 1;
+ }
+ if (used_in_output)
+ mark_reg_conflicts (reg);
+ }
+
/* Mark any registers set in INSN and then never used. */
while (n_regs_set > 0)
}
}
}
+
+/* Record that REG has conflicts with all the regs currently live.
+ Do not mark REG itself as live. */
+
+static void
+mark_reg_conflicts (reg)
+ rtx reg;
+{
+ register int regno;
+
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+
+ if (GET_CODE (reg) != REG)
+ return;
+
+ regno = REGNO (reg);
+
+ if (reg_renumber[regno] >= 0)
+ regno = reg_renumber[regno];
+
+ /* Either this is one of the max_allocno pseudo regs not allocated,
+ or it is or has a hardware reg. First handle the pseudo-regs. */
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ if (reg_allocno[regno] >= 0)
+ record_one_conflict (regno);
+ }
+ /* Handle hardware regs (and pseudos allocated to hard regs). */
+ else if (! fixed_regs[regno])
+ {
+ register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (regno < last)
+ {
+ record_one_conflict (regno);
+ regno++;
+ }
+ }
+}
\f
/* Mark REG as being dead (following the insn being scanned now).
Store a 0 in regs_live or allocnos_live for this register. */
/* Record the death of REG in the current insn. If OUTPUT_P is non-zero,
REG is an output that is dying (i.e., it is never used), otherwise it
- is an input (the normal case). */
+ is an input (the normal case).
+ If OUTPUT_P is 1, then we extend the life past the end of this insn. */
static void
wipe_dead_reg (reg, output_p)
{
register int regno = REGNO (reg);
+ /* If this insn has multiple results,
+ and the dead reg is used in one of the results,
+ extend its life to after this insn,
+ so it won't get allocated together with any other result of this insn. */
+ if (GET_CODE (PATTERN (this_insn)) == PARALLEL
+ && !single_set (this_insn))
+ {
+ int i;
+ for (i = XVECLEN (PATTERN (this_insn), 0) - 1; i >= 0; i--)
+ {
+ rtx set = XVECEXP (PATTERN (this_insn), 0, i);
+ if (GET_CODE (set) == SET
+ && GET_CODE (SET_DEST (set)) != REG
+ && !rtx_equal_p (reg, SET_DEST (set))
+ && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ output_p = 1;
+ }
+ }
+
if (regno < FIRST_PSEUDO_REGISTER)
{
mark_life (regno, GET_MODE (reg), 0);