OSDN Git Service

PR target/35907
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 0d86894..024c140 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;