re PR target/35907 (64-bit power6 glibc miscompilation)
authorAlan Modra <amodra@bigpond.net.au>
Thu, 17 Apr 2008 12:27:31 +0000 (12:27 +0000)
committerAlan Modra <amodra@gcc.gnu.org>
Thu, 17 Apr 2008 12:27:31 +0000 (21:57 +0930)
PR target/35907
* config/rs6000/rs6000.c (rs6000_emit_epilogue): Restore vr and vrsave
regs before frame pop when needed.  If use_backchain_to_restore_sp
then load backchain into a temp reg to restore vr and vrsave.  Add
code to restore vr after frame pop if possible.

From-SVN: r134387

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

index 4a3a4d0bd5303283b7053a63e682d988dceea98a..d1b9a4ca76a7491bb790cbb6b027ebbf06ec18de 100644 (file)
@@ -1,3 +1,11 @@
+2008-04-17  Alan Modra  <amodra@bigpond.net.au>
+
+       PR target/35907
+       * config/rs6000/rs6000.c (rs6000_emit_epilogue): Restore vr and vrsave
+       regs before frame pop when needed.  If use_backchain_to_restore_sp
+       then load backchain into a temp reg to restore vr and vrsave.  Add
+       code to restore vr after frame pop if possible.
+
 2008-04-17  Richard Guenther  <rguenther@suse.de>
 
        * tree-vn.c (expressions_equal_p): Do not check type
index 0d868944218d6ba31c4f91a537ac1c2ed26862f1..024c140b27454b462e16ecb550eb4cb33979736a 100644 (file)
@@ -16370,11 +16370,23 @@ rs6000_emit_epilogue (int sibcall)
   if (info->push_p)
     sp_offset = info->total_size;
 
-  /* Restore AltiVec registers if needed.  */
-  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+  /* Restore AltiVec registers if we must do so before adjusting the
+     stack.  */
+  if (TARGET_ALTIVEC_ABI
+      && info->altivec_size != 0
+      && DEFAULT_ABI != ABI_V4
+      && info->altivec_save_offset < (TARGET_32BIT ? -220 : -288))
     {
       int i;
 
+      if (use_backchain_to_restore_sp)
+       {
+         frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+         emit_move_insn (frame_reg_rtx,
+                         gen_rtx_MEM (Pmode, sp_reg_rtx));
+         sp_offset = 0;
+       }
+
       for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
          {
@@ -16394,19 +16406,54 @@ rs6000_emit_epilogue (int sibcall)
          }
     }
 
+  /* Restore VRSAVE if we must do so before adjusting the stack.  */
+  if (TARGET_ALTIVEC
+      && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0
+      && DEFAULT_ABI != ABI_V4
+      && info->vrsave_save_offset < (TARGET_32BIT ? -220 : -288))
+    {
+      rtx addr, mem, reg;
+
+      if (use_backchain_to_restore_sp
+         && frame_reg_rtx == sp_reg_rtx)
+       {
+         frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+         emit_move_insn (frame_reg_rtx,
+                         gen_rtx_MEM (Pmode, sp_reg_rtx));
+         sp_offset = 0;
+       }
+
+      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                          GEN_INT (info->vrsave_save_offset + sp_offset));
+      mem = gen_frame_mem (SImode, addr);
+      reg = gen_rtx_REG (SImode, 12);
+      emit_move_insn (reg, mem);
+
+      emit_insn (generate_set_vrsave (reg, info, 1));
+    }
+
   /* If we have a frame pointer, a call to alloca,  or a large stack
      frame, restore the old stack pointer using the backchain.  Otherwise,
      we know what size to update it with.  */
   if (use_backchain_to_restore_sp)
     {
-      /* Under V.4, don't reset the stack pointer until after we're done
-        loading the saved registers.  */
-      if (DEFAULT_ABI == ABI_V4)
-       frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+      if (frame_reg_rtx != sp_reg_rtx)
+       {
+         emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+         frame_reg_rtx = sp_reg_rtx;
+       }
+      else
+       {
+         /* Under V.4, don't reset the stack pointer until after we're done
+            loading the saved registers.  */
+         if (DEFAULT_ABI == ABI_V4)
+           frame_reg_rtx = gen_rtx_REG (Pmode, 11);
 
-      emit_move_insn (frame_reg_rtx,
-                     gen_rtx_MEM (Pmode, sp_reg_rtx));
-      sp_offset = 0;
+         emit_move_insn (frame_reg_rtx,
+                         gen_rtx_MEM (Pmode, sp_reg_rtx));
+         sp_offset = 0;
+       }
     }
   else if (info->push_p
           && DEFAULT_ABI != ABI_V4
@@ -16420,9 +16467,39 @@ rs6000_emit_epilogue (int sibcall)
       sp_offset = 0;
     }
 
-  /* Restore VRSAVE if needed.  */
-  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && info->vrsave_mask != 0)
+  /* Restore AltiVec registers if we have not done so already.  */
+  if (TARGET_ALTIVEC_ABI
+      && info->altivec_size != 0
+      && (DEFAULT_ABI == ABI_V4
+         || info->altivec_save_offset >= (TARGET_32BIT ? -220 : -288)))
+    {
+      int i;
+
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+       if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+         {
+           rtx addr, areg, mem;
+
+           areg = gen_rtx_REG (Pmode, 0);
+           emit_move_insn
+             (areg, GEN_INT (info->altivec_save_offset
+                             + sp_offset
+                             + 16 * (i - info->first_altivec_reg_save)));
+
+           /* AltiVec addressing mode is [reg+reg].  */
+           addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+           mem = gen_frame_mem (V4SImode, addr);
+
+           emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
+         }
+    }
+
+  /* Restore VRSAVE if we have not done so already.  */
+  if (TARGET_ALTIVEC
+      && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0
+      && (DEFAULT_ABI == ABI_V4
+         || info->vrsave_save_offset >= (TARGET_32BIT ? -220 : -288)))
     {
       rtx addr, mem, reg;