Multiple set insns reload problem.
Jan Hubicka
hubicka@atrey.karlin.mff.cuni.cz
Tue Jan 11 09:57:00 GMT 2000
Hi
In multiple set insns the output reloads are tricky, because the destination address
of one output reload may mention register used as output of insn.
So the separate move insn will put the value to bad destination.
Global.c contains code that probably attempts to avoid it:
/* If INSN has multiple outputs, then any reg that dies here
and is used inside of an output
must conflict with the other outputs.
It is unsafe to use !single_set here since it will ignore an
unused output. Just because an output is unused does not mean
the compiler can assume the side effect will not occur.
Consider if REG appears in the address of an output and we
reload the output. If we allocate REG to the same hard
register as an unused output we could set the hard register
before the output reload insn. */
if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (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);
}
The problem is that pseudo may not conflict with itself, so when one pseudo is used
for both in the address and as output, the colision bit is meaningless.
Second problem is with the clobbers, that produce REG_UNUSED instad of REG_DEAD note.
This problem is easy to fix anyway...
The bug can be easilly trigered by the following testcase:
int a;
main()
{
int *ptr=&a;
asm("":"=r"(ptr):"0"(&a)); /* Hide the constant address behind cse */
asm("movl $0,%0 ; movl $0,%1":"=m,r"(*ptr),"=,c"(ptr));
}
(it clears ptr and writes zero the the address pointed by ptr).
The resulting code is:
main:
#APP
movl $0,%eax ; movl $0,%ecx
#NO_APP
movl %eax, (%ecx) <--- incorrect spill insn
ret
And results in incorrect code storing to NULL pointer.
Any ideas how to fix this?
Honza
More information about the Gcc-bugs
mailing list