On 7/8/2026 9:22 AM, Jin Ma wrote:
Hi, Jeff

You're right that regrename's check_new_reg_p should already prevent
this, and that the right fix is to chase down why df_regs_ever_live_p
isn't working here.  I believe I've found the root cause.

The RISC-V stack_tie pattern is a length-0 "ghost" insn:

   (define_insn "stack_tie<mode>"
     [(set (mem:BLK (scratch))
           (unspec:BLK [(match_operand:X 0 "register_operand" "r")
                        (match_operand:X 1 "register_operand" "r")]
                       UNSPEC_TIE))]
     "" ""
     [(set_attr "type" "ghost") (set_attr "length" "0")])

It emits no code, but at the RTL level it is a real SET that
references its register operands.  The RISC-V backend's
riscv_emit_stack_tie helper hardcodes hard_frame_pointer_rtx
(s0) as the second operand.

In the prologue, every call site guards the tie with
"if (frame_pointer_needed)", and the surrounding comment explains
why: the tie exists only to order stack adjustments WRT frame
pointer setup.  When there is no frame pointer, sp is the CFA and
no such ordering barrier is needed.
Just for the record stack ties also help with FP/SP aliasing in the epilogue path.  Essentially it's possible to have a register restore using FP.  Occasionally the scheduler will move this kind of load past an SP adjustment.  99.99% of the time nothing bad happens.  But if you get an interrupt in the window between the SP adjustment and that FP relative load, then the stack can get clobbered  and the restore gets the wrong data.  This is touched on in the need_barrier_p initialization in the epilogue code.



But three call sites in riscv_expand_epilogue omit that guard:

   - calls_alloca path
If calls_alloca is set, then isn't frame_pointer_required set?  And that should have triggered save/restore of the frame pointer.  So is this really a problem.?

   - "if (known_gt (step1, 0))" (almost every function with a frame)
   - "if (need_barrier_p)" (any non-empty frame)
These are the more worrisome IMHO.  The latter is the source of the stack tie in the testcase you provided.



Proposed fix: add the frame_pointer_needed guard to the three
epilogue stack_tie call sites, mirroring what the prologue already
does.  This keeps the tie's anti-load ordering for frame-pointer
functions while avoiding the spurious s0 reference for
non-frame-pointer functions, where sp is the CFA and the barrier
isn't needed.

Do you have any further comments on this?
I think you're on the right track.  We may want to think about verifying that if we emit the stack tie that the frame pointer is saved/restored if that can be reasonably done.

jeff

Reply via email to