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

Reply via email to