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,
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);
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 */
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);
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. */
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)
"mnret"
[(set_attr "type" "ret")])
-(define_insn "stack_tie<mode>"
+(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")]
(set_attr "length" "0")]
)
+;; Keep stack loads before an SP adjustment without a second register.
+(define_insn "@stack_tie_sp<mode>"
+ [(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"))]
--- /dev/null
+// { 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;
+}
--- /dev/null
+/* { 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" } } */