RISC-V: Don't clobber retval when __builtin_eh_return called.
authorJim Wilson <jimw@sifive.com>
Mon, 4 Jun 2018 23:44:43 +0000 (23:44 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Mon, 4 Jun 2018 23:44:43 +0000 (16:44 -0700)
gcc/
* config/riscv/riscv-protos.h (riscv_expand_epilogue): Change bool arg
to int.
* config/riscv/riscv.c (riscv_for_each_saved_reg): New args epilogue
and maybe_eh_return.  Change regno to unsigned int.  Use new args to
handle EH_RETURN_DATA_REGNO registers properly.
(riscv_expand_prologue): Pass new args to riscv_for_each_saved_reg.
(riscv_expand_epilogue): Update comment.  Change argument name and
type.  Update code to use new name and type.  Pass new args to
riscv_for_each_saved_reg.  Only use EH_RETURN_STACKADJ_RTX when
EXCEPTION_RETURN.
* config/riscv/riscv.md (NORMAL_RETURN): New.
(SIBCALL_RETURN, EXCEPTION_RETURN): New.
(epilogue, sibcall_epilogue): Update riscv_expand_epilogue arg.
(eh_return): Call gen_eh_return_internal and emit barrier.
(eh_return_internal): Call riscv_expand_epilogue.

From-SVN: r261176

gcc/ChangeLog
gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv.c
gcc/config/riscv/riscv.md

index 074e1492afc0a3c2050a4ff3dd0ea53a1f04e4ec..ebf9dc43ee6a46da7435a62561950c304647d395 100644 (file)
@@ -1,3 +1,21 @@
+2018-06-04  Jim Wilson  <jimw@sifive.com>
+
+       * config/riscv/riscv-protos.h (riscv_expand_epilogue): Change bool arg
+       to int.
+       * config/riscv/riscv.c (riscv_for_each_saved_reg): New args epilogue
+       and maybe_eh_return.  Change regno to unsigned int.  Use new args to
+       handle EH_RETURN_DATA_REGNO registers properly.
+       (riscv_expand_prologue): Pass new args to riscv_for_each_saved_reg.
+       (riscv_expand_epilogue): Update comment.  Change argument name and
+       type.  Update code to use new name and type.  Pass new args to
+       riscv_for_each_saved_reg.  Only use EH_RETURN_STACKADJ_RTX when
+       EXCEPTION_RETURN.
+       * config/riscv/riscv.md (NORMAL_RETURN): New.
+       (SIBCALL_RETURN, EXCEPTION_RETURN): New.
+       (epilogue, sibcall_epilogue): Update riscv_expand_epilogue arg.
+       (eh_return): Call gen_eh_return_internal and emit barrier.
+       (eh_return_internal): Call riscv_expand_epilogue.
+
 2018-06-04  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gimple-ssa-store-merging.c (struct merged_store_group): Move up
index a194b192a2b60c6937843a934eb17b74fa83d550..f158ed007dd78c7012882398f372a9d8970723cf 100644 (file)
@@ -66,7 +66,7 @@ extern bool riscv_expand_block_move (rtx, rtx, rtx);
 extern rtx riscv_return_addr (int, rtx);
 extern HOST_WIDE_INT riscv_initial_elimination_offset (int, int);
 extern void riscv_expand_prologue (void);
-extern void riscv_expand_epilogue (bool);
+extern void riscv_expand_epilogue (int);
 extern bool riscv_epilogue_uses (unsigned int);
 extern bool riscv_can_use_return_insn (void);
 extern rtx riscv_function_value (const_tree, const_tree, enum machine_mode);
index 6e389fa0102524e05baf15b2ac90109e08f9c7ee..c418dc1ec2e18296cd8df54c88f5f65d930c4a5b 100644 (file)
@@ -3502,23 +3502,45 @@ riscv_save_restore_reg (machine_mode mode, int regno,
    of the frame.  */
 
 static void
-riscv_for_each_saved_reg (HOST_WIDE_INT sp_offset, riscv_save_restore_fn fn)
+riscv_for_each_saved_reg (HOST_WIDE_INT sp_offset, riscv_save_restore_fn fn,
+                         bool epilogue, bool maybe_eh_return)
 {
   HOST_WIDE_INT offset;
 
   /* Save the link register and s-registers. */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
-  for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+  for (unsigned int regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
     if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
       {
-       riscv_save_restore_reg (word_mode, regno, offset, fn);
+       bool handle_reg = TRUE;
+
+       /* If this is a normal return in a function that calls the eh_return
+          builtin, then do not restore the eh return data registers as that
+          would clobber the return value.  But we do still need to save them
+          in the prologue, and restore them for an exception return, so we
+          need special handling here.  */
+       if (epilogue && !maybe_eh_return && crtl->calls_eh_return)
+         {
+           unsigned int i, regnum;
+
+           for (i = 0; (regnum = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM;
+                i++)
+             if (regno == regnum)
+               {
+                 handle_reg = FALSE;
+                 break;
+               }
+         }
+
+       if (handle_reg)
+         riscv_save_restore_reg (word_mode, regno, offset, fn);
        offset -= UNITS_PER_WORD;
       }
 
   /* This loop must iterate over the same space as its companion in
      riscv_compute_frame_info.  */
   offset = cfun->machine->frame.fp_sp_offset - sp_offset;
-  for (int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
+  for (unsigned int regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
     if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
       {
        machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode;
@@ -3694,7 +3716,7 @@ riscv_expand_prologue (void)
                            GEN_INT (-step1));
       RTX_FRAME_RELATED_P (emit_insn (insn)) = 1;
       size -= step1;
-      riscv_for_each_saved_reg (size, riscv_save_reg);
+      riscv_for_each_saved_reg (size, riscv_save_reg, false, false);
     }
 
   frame->mask = mask; /* Undo the above fib.  */
@@ -3756,11 +3778,11 @@ riscv_adjust_libcall_cfi_epilogue ()
   return dwarf;
 }
 
-/* Expand an "epilogue" or "sibcall_epilogue" pattern; SIBCALL_P
-   says which.  */
+/* Expand an "epilogue", "sibcall_epilogue", or "eh_return_internal" pattern;
+   style says which.  */
 
 void
-riscv_expand_epilogue (bool sibcall_p)
+riscv_expand_epilogue (int style)
 {
   /* Split the frame into two.  STEP1 is the amount of stack we should
      deallocate before restoring the registers.  STEP2 is the amount we
@@ -3771,7 +3793,8 @@ riscv_expand_epilogue (bool sibcall_p)
   unsigned mask = frame->mask;
   HOST_WIDE_INT step1 = frame->total_size;
   HOST_WIDE_INT step2 = 0;
-  bool use_restore_libcall = !sibcall_p && riscv_use_save_libcall (frame);
+  bool use_restore_libcall = ((style == NORMAL_RETURN)
+                             && riscv_use_save_libcall (frame));
   rtx ra = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
   rtx insn;
 
@@ -3781,14 +3804,14 @@ riscv_expand_epilogue (bool sibcall_p)
 
   if (cfun->machine->naked_p)
     {
-      gcc_assert (!sibcall_p);
+      gcc_assert (style == NORMAL_RETURN);
 
       emit_jump_insn (gen_return ());
 
       return;
     }
 
-  if (!sibcall_p && riscv_can_use_return_insn ())
+  if ((style == NORMAL_RETURN) && riscv_can_use_return_insn ())
     {
       emit_jump_insn (gen_return ());
       return;
@@ -3863,7 +3886,8 @@ riscv_expand_epilogue (bool sibcall_p)
     frame->mask = 0; /* Temporarily fib that we need not save GPRs.  */
 
   /* Restore the registers.  */
-  riscv_for_each_saved_reg (frame->total_size - step2, riscv_restore_reg);
+  riscv_for_each_saved_reg (frame->total_size - step2, riscv_restore_reg,
+                           true, style == EXCEPTION_RETURN);
 
   if (use_restore_libcall)
     {
@@ -3902,14 +3926,14 @@ riscv_expand_epilogue (bool sibcall_p)
     }
 
   /* Add in the __builtin_eh_return stack adjustment. */
-  if (crtl->calls_eh_return)
+  if ((style == EXCEPTION_RETURN) && crtl->calls_eh_return)
     emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx,
                              EH_RETURN_STACKADJ_RTX));
 
   /* Return from interrupt.  */
   if (cfun->machine->interrupt_handler_p)
     emit_insn (gen_riscv_mret ());
-  else if (!sibcall_p)
+  else if (style != SIBCALL_RETURN)
     emit_jump_insn (gen_simple_return_internal (ra));
 }
 
index fa681971c4c4ff042386c63d9f3bebee02316b7a..b9faf00d076eb625f30876831ce961a595beb7a0 100644 (file)
    (S0_REGNUM                  8)
    (S1_REGNUM                  9)
    (S2_REGNUM                  18)
+
+   (NORMAL_RETURN              0)
+   (SIBCALL_RETURN             1)
+   (EXCEPTION_RETURN           2)
 ])
 
 (include "predicates.md")
   [(const_int 2)]
   ""
 {
-  riscv_expand_epilogue (false);
+  riscv_expand_epilogue (NORMAL_RETURN);
   DONE;
 })
 
   [(const_int 2)]
   ""
 {
-  riscv_expand_epilogue (true);
+  riscv_expand_epilogue (SIBCALL_RETURN);
   DONE;
 })
 
     emit_insn (gen_eh_set_lr_di (operands[0]));
   else
     emit_insn (gen_eh_set_lr_si (operands[0]));
+
+  emit_jump_insn (gen_eh_return_internal ());
+  emit_barrier ();
   DONE;
 })
 
   DONE;
 })
 
+(define_insn_and_split "eh_return_internal"
+  [(eh_return)]
+  ""
+  "#"
+  "epilogue_completed"
+  [(const_int 0)]
+  "riscv_expand_epilogue (EXCEPTION_RETURN); DONE;")
+
 ;;
 ;;  ....................
 ;;