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.

Reply via email to