The svr4 ABI requires that r1 (SP) always be valid, so it must be restored at
the end of the epilogue, after the last register restore read from the stack
frame.  Unfortunately, in some cases, the PPC port is scheduling the epilogue
set of r1 before some register restores.  If you take an interrupt in between
the r1 set and a register restore, and the interrupt handler uses the process
stack, the interrupt handler may overwrite saved registers before they can be
restored.  This causes difficult to debug failures.

I can reproduce the failure with -O2 -fno-omit-frame-pointer.  I don't know if
the problem can be triggered with other optimization options.

The PPC port tries to prevent the r1 set from being moved before register
restores by emitting a stack_tie instruction.  This uses a BLKmode read from
the stack frame, which in theory should conflict with the register reads and
the set of r1.  But this fails because of how reg_base_value works in alias.c.

The PPC port is using a temp register r11 in the epilogue.  In my testcase, r11
is set in the function body to the address of a variable in data.  The code
that sets reg_base_value, in init_alias_analysis in alias.c, deliberately
ignores instructions in the prologue and epilogue.  Thus it sees only one store
to r11, and decides that r11 must hold a data variable address everywhere in
the function.  When we check stack reads (using r11) against the stack_tie insn
(using r1), alias analysis decides that they can't conflict because r1 points
to the stack and r11 points to data.  Thus incorrect insn scheduling occurs.

This seems to be a flaw in alias analysis.  If we aren't going to count
prologue/epilogue insns when computing reg_base_value, then we should not use
reg_base_value when disambiguating insns in the prologue/epilogue. 
Unfortunately, the interface to alias is passing in only MEMs, not insns, so we
can't easily tell when we have a prologue/epilogue MEM.

A possible simple way to solve the problem is to use a stricter stack_tie insn.
 I noticed that the ARM port has one that uses (mem:BLK (scratch)).  If I hack
this into the rs6000 port, then this problem goes away.  Testing for this is
one of the first things that write_dependence_p does, so this prevents any
possible reg_base_value confusion.

This only fails if I get a symbol address into r11, and r11 is only set once,
so it is a bit tricky to reproduce with small examples.  I do have a testcase
that works with gcc mainline which I will attach.


-- 
           Summary: bad epilogue scheduling leads to stack corruption
           Product: gcc
           Version: 4.5.0
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: target
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: wilson at gcc dot gnu dot org
GCC target triplet: powerpc-eabi


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42953

Reply via email to