207 lines
5.5 KiB
Diff
207 lines
5.5 KiB
Diff
2008-04-14 Alan Modra <amodra@bigpond.net.au>
|
|
|
|
PR target/35907
|
|
* config/rs6000/rs6000.c (rs6000_emit_epilogue): Restore Altivec
|
|
registers using saved backchain as base instead of sp. Restore
|
|
Altivec registers and VRSAVE before increasing sp if they are saved
|
|
below red zone.
|
|
|
|
* gcc.target/powerpc/pr35907.c: New test.
|
|
|
|
--- gcc/config/rs6000/rs6000.c.jj 2008-04-16 09:43:10.000000000 +0200
|
|
+++ gcc/config/rs6000/rs6000.c 2008-04-16 10:05:34.000000000 +0200
|
|
@@ -16380,11 +16380,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))
|
|
{
|
|
@@ -16404,19 +16416,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
|
|
@@ -16430,9 +16477,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;
|
|
|
|
--- gcc/testsuite/gcc.target/powerpc/pr35907.c.jj 2008-04-16 10:04:23.000000000 +0200
|
|
+++ gcc/testsuite/gcc.target/powerpc/pr35907.c 2008-04-16 10:04:58.000000000 +0200
|
|
@@ -0,0 +1,60 @@
|
|
+/* PR target/35907 */
|
|
+/* { dg-do run { target powerpc*-*-* } } */
|
|
+/* { dg-require-effective-target powerpc_altivec_ok } */
|
|
+/* { dg-options "-O2 -maltivec" } */
|
|
+
|
|
+#include "altivec_check.h"
|
|
+
|
|
+#define vector __attribute__((vector_size (16)))
|
|
+union
|
|
+{
|
|
+ vector int k;
|
|
+ int c[16];
|
|
+} u, v, w;
|
|
+vector int m;
|
|
+
|
|
+void __attribute__((noinline))
|
|
+bar (void *i, vector int j)
|
|
+{
|
|
+ asm volatile ("" : : "r" (i), "r" (&j) : "memory");
|
|
+}
|
|
+
|
|
+int __attribute__((noinline))
|
|
+foo (int i, vector int j)
|
|
+{
|
|
+ char *p = __builtin_alloca (64 + i);
|
|
+ m += u.k;
|
|
+ v.k = m;
|
|
+ w.k = j;
|
|
+ if (__builtin_memcmp (&v.c, &w.c, 16) != 0)
|
|
+ __builtin_abort ();
|
|
+ j += u.k;
|
|
+ bar (p, j);
|
|
+ j += u.k;
|
|
+ bar (p, j);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void
|
|
+main1 (void)
|
|
+{
|
|
+ vector int l;
|
|
+ int i;
|
|
+ for (i = 0; i < 4; i++)
|
|
+ u.c[i] = i;
|
|
+ l = u.k;
|
|
+ if (foo (64, l))
|
|
+ __builtin_abort ();
|
|
+ l += u.k;
|
|
+ if (foo (64, l))
|
|
+ __builtin_abort ();
|
|
+}
|
|
+
|
|
+int
|
|
+main ()
|
|
+{
|
|
+ altivec_check ();
|
|
+ main1 ();
|
|
+ exit (0);
|
|
+}
|
|
+
|