On 7/15/26 2:19 PM, Matt Turner wrote:
ira_setup_eliminable_regset calls df_set_regs_ever_live for the hard frame
pointer when it decides frame_pointer_needed.  LRA can reach that decision
later instead, in setup_can_eliminate, when it finds the frame pointer to
stack pointer elimination is not possible after all, but it does not mark the
register live there.

A target whose prologue decides which registers to save from
df_regs_ever_live_p then sets up the frame pointer without saving the caller's
value.  On alpha this miscompiles pge while bootstrapping the Modula-2 front
end (PR117184): alpha_compute_frame_layout leaves $15 out of the save mask, so
alpha_expand_prologue emits the "mov $30,$15" that clobbers it but no matching
store, while alpha_expand_epilogue restores the register whenever
frame_pointer_needed, from an fp_offset that stayed 0 -- the return address
slot.  The caller gets its call-saved $15 back as a code address, which shows
up much later as a NULL dereference, and the Modula-2 runtime turns the
resulting SIGSEGV into an unhandled exception:

   terminate called after throwing an instance of 'unsigned int'

The testcase needs the VLA to reach the caller by inlining: a caller with its
own VLA has cfun->calls_alloca set, so IRA already knows a frame pointer is
needed and marks $15 live itself.

Do what IRA does, so the two paths agree.

gcc/
        * lra-eliminations.cc (setup_can_eliminate): Mark the hard frame
        pointer live when setting frame_pointer_needed.

gcc/testsuite/
        * gcc.target/alpha/frame-pointer-save-1.c: New test.
The patch looks good for me.  You can commit it.  Thank you for fixing this.

Reply via email to