Somehow I can't help but think I'm missing something here...
Given:
(set (reg X) (mem Y))
(...)
(set (mem Y) (reg Z))
(...)
(use (reg X))
update_equiv_regs can set an equivalence between (reg X) and (mem Y)
which is clearly wrong as (mem Y) is set to (reg Z).
99.99% of the time this doesn't cause us any problems. However, imagine
if (reg X) is not assigned a hard register. Reload then gleefully
replaces uses of (reg X) with its equivalent memory location. Given the
RTL above that's clearly bad.
It looks like this code is supposed to wipe the problematic equivalence:
/* We only handle the case of a pseudo register being set
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 instructions
that set
or use it. */
if (!REG_P (dest)
|| (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
|| reg_equiv[regno].init_insns == const0_rtx
|| (CLASS_LIKELY_SPILLED_P (reg_preferred_class (regno))
&& MEM_P (src) && ! reg_equiv[regno].is_arg_equivalence))
{
/* This might be setting a SUBREG of a pseudo, a pseudo
that is
also set somewhere else to a constant. */
note_stores (set, no_equiv, NULL);
continue;
}
However, if we look at no_equiv we see the following:
/* Mark REG as having no known equivalence.
Some instructions might have been processed 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 (rtx reg, const_rtx store ATTRIBUTE_UNUSED, void *data
ATTRIBUTE_UNUSED)
{
int regno;
rtx list;
if (!REG_P (reg))
return;
[ ... ]
Thus no_equiv doesn't do anything when passed a MEM.
I haven't tried triggering this problem with the mainline sources...
What am I missing?
jeff