rs6000: Make deallocation of a large frame work (PR77687)
authorSegher Boessenkool <segher@kernel.crashing.org>
Tue, 29 Nov 2016 05:29:47 +0000 (06:29 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Tue, 29 Nov 2016 05:29:47 +0000 (06:29 +0100)
If we use ABI_V4 and we have a big stack frame, we end the epilogue
with a "mr 1,11" (or similar) instruction.  This instruction however
has no dependencies on the earlier restores from stack (done via r11),
so sched2 can end up reordering the insns, which is bad because we
have no red zone so that you then restore from stack that is already
deallocated.

This fixes it by making that restore depend on the memory accesses.

PR target/77687
* config/rs6000/rs6000.c (rs6000_emit_stack_reset): Emit the
stack_restore_tie insn instead of stack_tie, for the SVR4 and
SPE ABIs.
* config/rs6000/rs6000.md (stack_restore_tie): New define_insn.

From-SVN: r242949

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md

index da6c64097007561f412846bf54e1e7f205702966..27f4137134a7de205f216aa9128bc8607f78f933 100644 (file)
@@ -1,3 +1,11 @@
+2016-11-29  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       PR target/77687
+       * config/rs6000/rs6000.c (rs6000_emit_stack_reset): Emit the
+       stack_restore_tie insn instead of stack_tie, for the SVR4 and
+       SPE ABIs.
+       * config/rs6000/rs6000.md (stack_restore_tie): New define_insn.
+
 2016-11-28  Segher Boessenkool  <segher@kernel.crashing.org>
 
        * shrink-wrap.c (init_separate_shrink_wrap): Do not clear
index dfb5dc86b118383eab5bafed5c898c20d3932857..0a6a784a9409202056737928a39db446f64f2941 100644 (file)
@@ -27534,7 +27534,11 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
                         rtx frame_reg_rtx, HOST_WIDE_INT frame_off,
                         unsigned updt_regno)
 {
-  rtx updt_reg_rtx;
+  /* If there is nothing to do, don't do anything.  */
+  if (frame_off == 0 && REGNO (frame_reg_rtx) == updt_regno)
+    return NULL_RTX;
+
+  rtx updt_reg_rtx = gen_rtx_REG (Pmode, updt_regno);
 
   /* This blockage is needed so that sched doesn't decide to move
      the sp change before the register restores.  */
@@ -27542,18 +27546,17 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
       || (TARGET_SPE_ABI
          && info->spe_64bit_regs_used != 0
          && info->first_gp_reg_save != 32))
-    rs6000_emit_stack_tie (frame_reg_rtx, frame_pointer_needed);
+    return emit_insn (gen_stack_restore_tie (updt_reg_rtx, frame_reg_rtx,
+                                            GEN_INT (frame_off)));
 
   /* If we are restoring registers out-of-line, we will be using the
      "exit" variants of the restore routines, which will reset the
      stack for us.  But we do need to point updt_reg into the
      right place for those routines.  */
-  updt_reg_rtx = gen_rtx_REG (Pmode, updt_regno);
-
   if (frame_off != 0)
     return emit_insn (gen_add3_insn (updt_reg_rtx,
                                     frame_reg_rtx, GEN_INT (frame_off)));
-  else if (REGNO (frame_reg_rtx) != updt_regno)
+  else
     return emit_move_insn (updt_reg_rtx, frame_reg_rtx);
 
   return NULL_RTX;
index f3d1d7156e3a7245ebb1b3985b2627885ae2297d..cb982d383cae8890e57af5c5d00ffa009e883d00 100644 (file)
   ""
   [(set_attr "length" "0")])
 
+; Some 32-bit ABIs do not have a red zone, so the stack deallocation has to
+; stay behind all restores from the stack, it cannot be reordered to before
+; one.  See PR77687.  This insn is an add or mr, and a stack_tie on the
+; operands of that.
+(define_insn "stack_restore_tie"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+       (plus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+                (match_operand:SI 2 "reg_or_cint_operand" "O,rI")))
+   (set (mem:BLK (match_dup 0)) (const_int 0))
+   (set (mem:BLK (match_dup 1)) (const_int 0))]
+  "TARGET_32BIT"
+  "@
+   mr %0,%1
+   add%I2 %0,%1,%2"
+  [(set_attr "type" "*,add")])
+
 (define_expand "epilogue"
   [(use (const_int 0))]
   ""