https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120165
--- Comment #10 from Mikael Pettersson <mikpelinux at gmail dot com> ---
Comparing the output from reload and LRA shows where LRA goes wrong:
> gcc/xgcc -Bgcc -O2 -S -o pr120156.s-reload /tmp/pr120165.c
> gcc/xgcc -Bgcc -O2 -mlra -S -o pr120156.s-lra /tmp/pr120165.c
> diff -u pr120156.s-{reload,lra}
...
@@ -57,10 +57,9 @@
movem.l (%sp)+,#3084
rts
.L11:
- addq.l #4,%a0
move.l %a0,20(%sp)
- subq.l #4,%a0
move.l (%a0)+,-(%sp)
+ move.l %a0,20(%sp)
jsr target
addq.l #4,%sp
add.l %d0,%d3
...
(There are two other hunks in the diff, but they are benign as far as I can
tell.)
This is the
result += target (__builtin_va_arg (ap, int));
statement (case 's').
Register %a0 contains the working copy of the va_list ap, whose home location
is at 20(%sp).
Reload prepares the call by updating 20(%sp) to the next value of ap (after
va_arg (ap, int)), then fetches that arg (va_arg (ap, int)) and pushes it as
outgoing argument to target.
LRA first writes the non-updated ap to its home location (this is redundant),
then fetches the arg and pushes it (move.l (%a0)+,-(%sp)), and then attempts to
save the updated ap on the stack before target will clobber it. But at this
point %sp has already been decremented by the outgoing argument push, so the
store writes to the 32-bit word below ap's home location, which is the return
address.
Two errors then follow:
- when target returns and we loop over the format string, ap hasn't been
updated
- when function_under_test returns, it will jump to ap+4 which is a location on
the stack, and crash (this bit was confirmed with gdb on the machine)
It seems like something isn't updating elimination offsets correctly when using
LRA.