On 7/8/2026 7:38 AM, Jin Ma wrote:
The regrename pass runs after prologue/epilogue generation and may
rename temporaries to callee-saved registers that the prologue did
not save. This corrupts the caller's register values on return or
exception unwind.
The IRA callee-save cost hooks added by r15-8547-gb191e8bdecf changed
the cost model so that IRA leaves more callee-saved registers unused.
The epilogue's stack_tie references s0 (hard frame pointer), which
makes df_regs_ever_live_p(s0) true after the prologue is generated.
regrename's check_new_reg_p relies on df_regs_ever_live_p as a proxy
for "saved by prologue", so it treats s0 as available even though it
was not saved.
Fix by checking frame.mask/frame.fmask/frame.vmask in
HARD_REGNO_RENAME_OK instead.
gcc/ChangeLog:
* config/riscv/riscv.cc (riscv_hard_regno_rename_ok): Reject
callee-saved registers not present in frame.mask, frame.fmask,
or frame.vmask.
gcc/testsuite/ChangeLog:
* g++.target/riscv/regrename-unwind.C: New test.
This sounds like it might be papering over a bug in regrename. In
theory regrename should never rename to a callee saved register which
wasn't already used (and thus saved/restored in the prologue/epilogue).
for (i = nregs - 1; i >= 0; --i)
if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i)
|| fixed_regs[new_reg + i]
|| global_regs[new_reg + i]
/* Can't use regs which aren't saved by the prologue. */
|| (! df_regs_ever_live_p (new_reg + i)
&& ! crtl->abi->clobbers_full_reg_p (new_reg + i))
#ifdef LEAF_REGISTERS
/* We can't use a non-leaf register if we're in a
leaf function. */
|| (crtl->is_leaf
&& !LEAF_REGISTERS[new_reg + i])
#endif
|| ! HARD_REGNO_RENAME_OK (reg + i, new_reg + i))
return false;
Note df_regs_ever_live test, that should be preventing this problem. So
I think you're going to need to chase down why that's not working properly.
jeff