RISC-V: Fix epilogue unwind info with fp and single sp adjust.

Message ID 20181117233305.23842-1-jimw@sifive.com
State New
Headers show
Series
  • RISC-V: Fix epilogue unwind info with fp and single sp adjust.
Related show

Commit Message

Jim Wilson Nov. 17, 2018, 11:33 p.m.
Without this patch, compiling a non-leaf function with -g -O0, we get
	addi	s0,sp,16
	.cfi_def_cfa 8, 0
	...
	lw	s0,8(sp)
	.cfi_restore 8
	addi	sp,sp,16
	.cfi_def_cfa_register 2
which clobbers the frame pointer before resetting the cfa to use the stack
pointer, which means there is at least one instruction where we can't unwind.
This was noticed while looking at gdb testsuite failures.  This patch is
patterned after the MIPS port solution, and fixes the problem by emitting
	.cfi_def_cfa 2, 16
when we clobber the frame pointer.

This was tested with a riscv64-linux gcc bootstrap and make check.  There
were no regressions.  This was also tested with a gdb make check, where it
fixed 25 failures in gdb.base/recurse.exp, gdb.base/watchpoint.exp, and
gdb.mi/mi-watch.exp.

	gcc/
	* config/riscv/riscv.c (epilogue_cfa_sp_offset): New.
	(riscv_restore_reg): If restoring HARD_FRAME_POINTER_REGNUM, and
	epilogue_cfa_sp_offset set, then add REG_CFA_DEF_CFA regnote.
	(riscv_expand_epilogue): Initialize epilogue_cfa_sp_offset.  Set it
	to step2 if frame_pointer_needed and step1 is 0.
---
 gcc/config/riscv/riscv.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

-- 
2.17.1

Patch

diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 381a203da9b..47d0b6e849e 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -237,6 +237,11 @@  bool riscv_slow_unaligned_access_p;
 /* Stack alignment to assume/maintain.  */
 unsigned riscv_stack_boundary;
 
+/* If non-zero, this is an offset to be added to SP to redefine the CFA
+   when restoring the FP register from the stack.  Only valid when generating
+   the epilogue.  */
+static int epilogue_cfa_sp_offset;
+
 /* Which tuning parameters to use.  */
 static const struct riscv_tune_info *tune_info;
 
@@ -3627,8 +3632,15 @@  riscv_restore_reg (rtx reg, rtx mem)
   rtx insn = riscv_emit_move (reg, mem);
   rtx dwarf = NULL_RTX;
   dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
-  REG_NOTES (insn) = dwarf;
 
+  if (epilogue_cfa_sp_offset && REGNO (reg) == HARD_FRAME_POINTER_REGNUM)
+    {
+      rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+					 GEN_INT (epilogue_cfa_sp_offset));
+      dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf);
+    }
+
+  REG_NOTES (insn) = dwarf;
   RTX_FRAME_RELATED_P (insn) = 1;
 }
 
@@ -3877,6 +3889,9 @@  riscv_expand_epilogue (int style)
       return;
     }
 
+  /* Reset the epilogue cfa info before starting to emit the epilogue.  */
+  epilogue_cfa_sp_offset = 0;
+
   /* Move past any dynamic stack allocations.  */
   if (cfun->calls_alloca)
     {
@@ -3941,6 +3956,12 @@  riscv_expand_epilogue (int style)
 
       REG_NOTES (insn) = dwarf;
     }
+  else if (frame_pointer_needed)
+    {
+      /* Tell riscv_restore_reg to emit dwarf to redefine CFA when restoring
+	 old value of FP.  */
+      epilogue_cfa_sp_offset = step2;
+    }
 
   if (use_restore_libcall)
     frame->mask = 0; /* Temporarily fib that we need not save GPRs.  */