static rtx *reg_equiv_replacement;
+/* Used for communication between update_equiv_regs and no_equiv. */
+static rtx *reg_equiv_init_insns;
+
static void alloc_qty PROTO((int, enum machine_mode, int, int));
static void validate_equiv_mem_from_store PROTO((rtx, rtx));
static int validate_equiv_mem PROTO((rtx, rtx, rtx));
static int memref_referenced_p PROTO((rtx, rtx));
static int memref_used_between_p PROTO((rtx, rtx, rtx));
static void update_equiv_regs PROTO((void));
+static void no_equiv PROTO((rtx, rtx));
static void block_alloc PROTO((int));
static int qty_sugg_compare PROTO((int, int));
static int qty_sugg_compare_1 PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void
update_equiv_regs ()
{
- rtx *reg_equiv_init_insn = (rtx *) alloca (max_regno * sizeof (rtx));
/* Set when an attempt should be made to replace a register with the
associated reg_equiv_replacement entry at the end of this function. */
char *reg_equiv_replace
rtx insn;
int block, depth;
+ reg_equiv_init_insns = (rtx *) alloca (max_regno * sizeof (rtx));
reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx));
- bzero ((char *) reg_equiv_init_insn, max_regno * sizeof (rtx));
+ bzero ((char *) reg_equiv_init_insns, max_regno * sizeof (rtx));
bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx));
bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx note;
- rtx set = single_set (insn);
+ rtx set;
rtx dest, src;
int regno;
loop_depth--;
}
- /* If this insn contains more (or less) than a single SET, ignore it. */
- if (set == 0)
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_INC)
+ no_equiv (XEXP (note, 0), note);
+
+ set = single_set (insn);
+
+ /* If this insn contains more (or less) than a single SET,
+ only mark all destinations as having no known equivalence. */
+ if (set == 0)
+ {
+ note_stores (PATTERN (insn), no_equiv);
+ continue;
+ }
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ int i;
+
+ for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+ {
+ rtx part = XVECEXP (PATTERN (insn), 0, i);
+ if (part != set)
+ note_stores (part, no_equiv);
+ }
+ }
+
dest = SET_DEST (set);
src = SET_SRC (set);
If one of the regs in the address is marked as reg_equiv_replace,
then we can't add this REG_EQUIV note. The reg_equiv_replace
optimization may move the set of this register immediately before
- insn, which puts it after reg_equiv_init_insn[regno], and hence
+ insn, which puts it after reg_equiv_init_insns[regno], and hence
the mention in the REG_EQUIV note would be to an uninitialized
pseudo. */
-
- if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG
- && (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
+ /* ????? This test isn't good enough; we might see a MEM with a use of
+ a pseudo register before we see its setting insn that will cause
+ reg_equiv_replace for that pseudo to be set.
+ Equivalences to MEMs should be made in another pass, after the
+ reg_equiv_replace information has been gathered. */
+
+ if (GET_CODE (dest) == MEM && GET_CODE (src) == REG
+ && (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
&& REG_BASIC_BLOCK (regno) >= 0
- && reg_equiv_init_insn[regno] != 0
+ && REG_N_SETS (regno) == 1
+ && reg_equiv_init_insns[regno] != 0
+ && reg_equiv_init_insns[regno] != const0_rtx
&& ! find_reg_note (insn, REG_EQUIV, NULL_RTX)
- && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace)
- && validate_equiv_mem (reg_equiv_init_insn[regno], SET_SRC (set),
- dest)
- && ! memref_used_between_p (SET_DEST (set),
- reg_equiv_init_insn[regno], insn))
- REG_NOTES (reg_equiv_init_insn[regno])
- = gen_rtx_EXPR_LIST (REG_EQUIV, dest,
- REG_NOTES (reg_equiv_init_insn[regno]));
+ && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace))
+ {
+ rtx init_insn = XEXP (reg_equiv_init_insns[regno], 0);
+ if (validate_equiv_mem (init_insn, src, dest)
+ && ! memref_used_between_p (dest, init_insn, insn))
+ REG_NOTES (init_insn)
+ = gen_rtx_EXPR_LIST (REG_EQUIV, dest, REG_NOTES (init_insn));
+ }
/* We only handle the case of a pseudo register being set
- once and only if neither the source nor the destination are
- in a register class that's likely to be spilled. */
+ once, or always to the same value. */
+ /* ??? The mn10200 port breaks if we add equivalences for
+ values that need an ADDRESS_REGS register and set them equivalent
+ to a MEM of a pseudo. The actual problem is in the over-conservative
+ handling of INPADDR_ADDRESS / INPUT_ADDRESS / INPUT triples in
+ calculate_needs, but we traditionally work around this problem
+ here by rejecting equivalences when the destination is in a register
+ that's likely spilled. This is fragile, of course, since the
+ preferred class of a pseudo depends on all intructions that set
+ or use it. */
+
if (GET_CODE (dest) != REG
|| (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
- || REG_N_SETS (regno) != 1
- || CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (dest)))
- || (GET_CODE (src) == REG
- && REGNO (src) >= FIRST_PSEUDO_REGISTER
- && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src)))))
- continue;
+ || reg_equiv_init_insns[regno] == const0_rtx
+ || (CLASS_LIKELY_SPILLED_P (reg_preferred_class (regno))
+ && GET_CODE (src) == MEM))
+ {
+ /* This might be seting a SUBREG of a pseudo, a pseudo that is
+ also set somewhere else to a constant. */
+ note_stores (set, no_equiv);
+ continue;
+ }
+ /* Don't handle the equivalence if the source is in a register
+ class that's likely to be spilled. */
+ if (GET_CODE (src) == REG
+ && REGNO (src) >= FIRST_PSEUDO_REGISTER
+ && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src))))
+ {
+ no_equiv (dest, set);
+ continue;
+ }
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
note = NULL;
#endif
+ if (REG_N_SETS (regno) != 1
+ && (! note
+ || ! CONSTANT_P (XEXP (note, 0))
+ || (reg_equiv_replacement[regno]
+ && ! rtx_equal_p (XEXP (note, 0),
+ reg_equiv_replacement[regno]))))
+ {
+ no_equiv (dest, set);
+ continue;
+ }
/* Record this insn as initializing this register. */
- reg_equiv_init_insn[regno] = insn;
+ reg_equiv_init_insns[regno]
+ = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init_insns[regno]);
/* If this register is known to be equal to a constant, record that
it is always equivalent to the constant. */
if (! reg_equiv_replace[regno])
continue;
- equiv_insn = reg_equiv_init_insn[regno];
+ /* reg_equiv_replace[REGNO] gets set only when
+ REG_N_REFS[REGNO] is 2, i.e. the register is set
+ once and used once. (If it were only set, but not used,
+ flow would have deleted the setting insns.) Hence
+ there can only be one insn in reg_equiv_init_insns. */
+ equiv_insn = XEXP (reg_equiv_init_insns[regno], 0);
if (validate_replace_rtx (regno_reg_rtx[regno],
reg_equiv_replacement[regno], insn))
}
}
}
+
+/* Mark REG as having no known equivalence.
+ Some instructions might have been proceessed before and furnished
+ with REG_EQUIV notes for this register; these notes will have to be
+ removed.
+ STORE is the piece of RTL that does the non-constant / conflicting
+ assignment - a SET, CLOBBER or REG_INC note. It is currently not used,
+ but needs to be there because this function is called from note_stores. */
+static void
+no_equiv (reg, store)
+ rtx reg, store;
+{
+ int regno;
+ rtx list;
+
+ if (GET_CODE (reg) != REG)
+ return;
+ regno = REGNO (reg);
+ list = reg_equiv_init_insns[regno];
+ if (list == const0_rtx)
+ return;
+ for (; list; list = XEXP (list, 1))
+ {
+ rtx insn = XEXP (list, 0);
+ remove_note (insn, find_reg_note (insn, REG_EQUIV, NULL_RTX));
+ }
+ reg_equiv_init_insns[regno] = const0_rtx;
+ reg_equiv_replacement[regno] = NULL_RTX;
+}
\f
/* Allocate hard regs to the pseudo regs used only within block number B.
Only the pseudos that die but once can be handled. */
/* Widest width in which each pseudo reg is referred to (via subreg). */
static int *reg_max_ref_width;
-/* Element N is the insn that initialized reg N from its equivalent
+/* Element N is the list of insns that initialized reg N from its equivalent
constant or memory slot. */
static rtx *reg_equiv_init;
So don't mark this insn now. */
if (GET_CODE (x) != MEM
|| rtx_equal_p (SET_SRC (set), x))
- reg_equiv_init[i] = insn;
+ reg_equiv_init[i]
+ = gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv_init[i]);
}
}
}
&& reg_equiv_memory_loc[REGNO (SET_SRC (set))]
&& rtx_equal_p (SET_DEST (set),
reg_equiv_memory_loc[REGNO (SET_SRC (set))]))
- reg_equiv_init[REGNO (SET_SRC (set))] = insn;
+ reg_equiv_init[REGNO (SET_SRC (set))]
+ = gen_rtx_INSN_LIST (VOIDmode, insn,
+ reg_equiv_init[REGNO (SET_SRC (set))]);
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
scan_paradoxical_subregs (PATTERN (insn));
If that insn didn't set the register (i.e., it copied the register to
memory), just delete that insn instead of the equivalencing insn plus
anything now dead. If we call delete_dead_insn on that insn, we may
- delete the insn that actually sets the register if the register die
+ delete the insn that actually sets the register if the register dies
there and that is incorrect. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0
- && GET_CODE (reg_equiv_init[i]) != NOTE)
- {
- if (reg_set_p (regno_reg_rtx[i], PATTERN (reg_equiv_init[i])))
- delete_dead_insn (reg_equiv_init[i]);
- else
- {
- PUT_CODE (reg_equiv_init[i], NOTE);
- NOTE_SOURCE_FILE (reg_equiv_init[i]) = 0;
- NOTE_LINE_NUMBER (reg_equiv_init[i]) = NOTE_INSN_DELETED;
- }
- }
+ {
+ if (reg_renumber[i] < 0 && reg_equiv_init[i] != 0)
+ {
+ rtx list;
+ for (list = reg_equiv_init[i]; list; list = XEXP (list, 1))
+ {
+ rtx equiv_insn = XEXP (list, 0);
+ if (GET_CODE (equiv_insn) == NOTE)
+ continue;
+ if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
+ delete_dead_insn (equiv_insn);
+ else
+ {
+ PUT_CODE (equiv_insn, NOTE);
+ NOTE_SOURCE_FILE (equiv_insn) = 0;
+ NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
+ }
+ }
+ }
+ }
/* Use the reload registers where necessary
by generating move instructions to move the must-be-register