From: Jin Ma Date: Wed, 15 Jul 2026 14:26:18 +0000 (+0800) Subject: RISC-V: Avoid unused frame-pointer references in stack ties X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2db2cf62f1ad2788365b1898aefdba2fa76aab87;p=thirdparty%2Fgcc.git RISC-V: Avoid unused frame-pointer references in stack ties Epilogue stack ties referenced s0 without a frame pointer, making the unsaved register ever live. Regrename could then select it and corrupt callee-saved state during exception unwinding. The simpler fix of allowing equal operands in the existing pattern is unsafe: copy propagation can fold stack_tie (sp, t3) used by stack probing into stack_tie (sp, sp). This removes t3 = sp while CFI still names t3 as the CFA. Keep the two-register pattern distinct and add an SP-only form for epilogue barriers. gcc/ChangeLog: * config/riscv/riscv-sr.cc (riscv_sr_match_epilogue): Accept SP-only stack ties. * config/riscv/riscv.cc (riscv_emit_stack_tie): Use parameterized generators and emit SP-only ties. (riscv_expand_epilogue): Use SP ties without a frame pointer. * config/riscv/riscv.md (@stack_tie): Use a parameterized name. (@stack_tie_sp): New pattern. gcc/testsuite/ChangeLog: * g++.target/riscv/stack-tie-unwind.C: New test. * gcc.target/riscv/stack-tie-no-fp.c: New test. Signed-off-by: Jin Ma --- diff --git a/gcc/config/riscv/riscv-sr.cc b/gcc/config/riscv/riscv-sr.cc index e1b2dafc30b..84dc9504d05 100644 --- a/gcc/config/riscv/riscv-sr.cc +++ b/gcc/config/riscv/riscv-sr.cc @@ -144,7 +144,7 @@ riscv_sr_match_epilogue (void) standard epilogue (of the form we expect to handle) consists of the following instructions: - 1. A stack_tiesi or stack_tiedi (for RV32 and RV64 respectively), + 1. A stack tie instruction, 2. An optional use instruction for the register holding the return value. This will be missing in functions with no return value, @@ -154,7 +154,9 @@ riscv_sr_match_epilogue (void) 4. A jump instruction of type gpr_restore_return. */ start = insn; if (INSN_CODE (insn) != CODE_FOR_stack_tiesi - && INSN_CODE (insn) != CODE_FOR_stack_tiedi) + && INSN_CODE (insn) != CODE_FOR_stack_tiedi + && INSN_CODE (insn) != CODE_FOR_stack_tie_spsi + && INSN_CODE (insn) != CODE_FOR_stack_tie_spdi) return NULL; insn = NEXT_INSN (insn); diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index d813f03b549..83f552c5e46 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -9876,10 +9876,17 @@ riscv_adjust_multi_push_cfi_prologue (int saved_size) static void riscv_emit_stack_tie (rtx reg) { - if (Pmode == SImode) - emit_insn (gen_stack_tiesi (stack_pointer_rtx, reg)); + /* A frame-pointer tie requires a saved frame pointer. */ + if (REG_P (reg) + && REGNO (reg) == HARD_FRAME_POINTER_REGNUM) + gcc_assert (frame_pointer_needed + && (cfun->machine->frame.mask + & (1U << HARD_FRAME_POINTER_REGNUM))); + + if (rtx_equal_p (reg, stack_pointer_rtx)) + emit_insn (gen_stack_tie_sp (Pmode, reg)); else - emit_insn (gen_stack_tiedi (stack_pointer_rtx, reg)); + emit_insn (gen_stack_tie (Pmode, stack_pointer_rtx, reg)); } /*zcmp multi push and pop code_for_push_pop function ptr array */ @@ -10508,6 +10515,11 @@ riscv_expand_epilogue (int style) unsigned th_int_mask = 0; rtx insn; + /* Avoid referencing an unused frame pointer. */ + rtx stack_tie_reg = frame_pointer_needed + ? hard_frame_pointer_rtx + : stack_pointer_rtx; + /* We need to add memory barrier to prevent read from deallocated stack. */ bool need_barrier_p = known_ne (get_frame_size () + cfun->machine->frame.arg_pointer_offset, 0); @@ -10628,7 +10640,7 @@ riscv_expand_epilogue (int style) if (known_gt (step1, 0)) { /* Emit a barrier to prevent loads from a deallocated stack. */ - riscv_emit_stack_tie (hard_frame_pointer_rtx); + riscv_emit_stack_tie (stack_tie_reg); need_barrier_p = false; /* Restore the scalable frame which is assigned in prologue. */ @@ -10729,7 +10741,7 @@ riscv_expand_epilogue (int style) frame->mask = mask; /* Undo the above fib. */ if (need_barrier_p) - riscv_emit_stack_tie (hard_frame_pointer_rtx); + riscv_emit_stack_tie (stack_tie_reg); /* Deallocate the final bit of the frame. */ if (step2.to_constant () > 0) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 9140a0ce6fe..6f66f983d87 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -4471,7 +4471,7 @@ "mnret" [(set_attr "type" "ret")]) -(define_insn "stack_tie" +(define_insn "@stack_tie" [(set (mem:BLK (scratch)) (unspec:BLK [(match_operand:X 0 "register_operand" "r") (match_operand:X 1 "register_operand" "r")] @@ -4482,6 +4482,17 @@ (set_attr "length" "0")] ) +;; Keep stack loads before an SP adjustment without a second register. +(define_insn "@stack_tie_sp" + [(set (mem:BLK (scratch)) + (unspec:BLK [(match_operand:X 0 "register_operand" "r")] + UNSPEC_TIE))] + "rtx_equal_p (operands[0], stack_pointer_rtx)" + "" + [(set_attr "type" "ghost") + (set_attr "length" "0")] +) + (define_expand "save_stack_nonlocal" [(set (match_operand 0 "memory_operand") (match_operand 1 "register_operand"))] diff --git a/gcc/testsuite/g++.target/riscv/stack-tie-unwind.C b/gcc/testsuite/g++.target/riscv/stack-tie-unwind.C new file mode 100644 index 00000000000..f9d99d5d71b --- /dev/null +++ b/gcc/testsuite/g++.target/riscv/stack-tie-unwind.C @@ -0,0 +1,41 @@ +// { dg-do run } +// { dg-options "-O2 -frename-registers -fprofile-generate -fomit-frame-pointer" } +// { dg-require-profiling "-fprofile-generate" } +// { dg-require-effective-target exceptions_enabled } +// { dg-final { cleanup-coverage-files } } + +/* Verify that regrename cannot use an unsaved frame pointer. */ + +extern "C" void abort (void); + +struct MyException {}; +struct Data { + int nr; + Data() : nr(66) {} +}; + +Data __attribute__((noinline,noclone)) +getData (int i) +{ + if (i) + throw MyException (); + Data data; + data.nr = i; + return data; +} + +int +main (int, char **) +{ + Data data; + try + { + data = getData (1); + } + catch (MyException &) + { + if (data.nr != 66) + abort (); + } + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/stack-tie-no-fp.c b/gcc/testsuite/gcc.target/riscv/stack-tie-no-fp.c new file mode 100644 index 00000000000..a1333b92776 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/stack-tie-no-fp.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fomit-frame-pointer -fdump-rtl-pro_and_epilogue" } */ + +/* Keep the epilogue stack tie without a frame pointer. */ + +int +foo (int x) +{ + volatile int data[8]; + data[0] = x; + return data[0]; +} + +/* { dg-final { scan-rtl-dump "UNSPEC_TIE" "pro_and_epilogue" } } */