This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Don't clobber vector registers on catch
- From: gkeating at apple dot com (Geoffrey Keating)
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 25 Jan 2007 12:27:12 -0800 (PST)
- Subject: Don't clobber vector registers on catch
This patch fixes numerous problems in the Darwin save_world machinery.
- It needs to be used for functions that call __builtin_eh_return on
32-bit ppc, even if they are built (as they usually are) without
Altivec enabled.
- On 64-bit ppc, I simplified this by switching Altivec on, so I
didn't have to implement these functions there.
- There was an assert to check that various values matched the numbers
in the save_world code. The values it was checking for didn't
actually match the numbers in the save_world code.
- The values it was checking for were the values actually generated,
which were wrong. GCC was wasting 16 bytes of stack space.
- The RTL was too vague, so EH unwinding didn't work.
- The generated prolog was allocating stack space twice.
- The generated prolog was writing past the bottom of the stack (even
after allocating the stack space twice).
This was sufficiently annoying that I have added three testcases to
make sure it stays working: a low-level one to check that the assembly
looks vaguely right, a C++ one to check that altivec registers get
saved over a regular 'throw', and what I was originally testing, a
testcase that checks that the registers are restored over a signal
frame.
Bootstrapped & tested on powerpc-darwin8, and I also checked the -m64
testcase results.
--
- Geoffrey Keating <geoffk@apple.com>
===File ~/patches/gcc-4940052.patch=========================
2007-01-24 Geoffrey Keating <geoffk@apple.com>
PR 25127
* config/rs6000/rs6000.c (first_altivec_reg_to_save): On Darwin,
save Altivec registers in an eh_return function.
(compute_vrsave_mask): Likewise.
(rs6000_stack_info): Correct AIX/Darwin stack alignment computation
for saving Altivec registers.
(rs6000_emit_prologue): Don't allocate stack twice in
eh_return function. Correct expected value of altivec_save_offset
when using save_world. Describe save of R0 to stack when using
save_world. Describe stack pointer adjustment when using
save_world. Remove duplicated eh_return parameter register saving.
Update sp_offset variable after save_world.
* config/rs6000/t-darwin (LIB2FUNCS_STATIC_EXTRA): Remove
darwin-world.asm.
(LIB2FUNCS_EXTRA): Add darwin-world.asm.
* config/rs6000/darwin.h (SUBTARGET_OVERRIDE_OPTIONS): -m64
implies Altivec.
Index: gcc/testsuite/ChangeLog
2007-01-24 Geoffrey Keating <geoffk@apple.com>
* gcc.target/powerpc/darwin-ehreturn-1.c: New.
* g++.dg/eh/simd-2.C: Also run on Darwin.
* g++.dg/eh/simd-3.C: New.
* g++.dg/eh/simd-4.C: New.
Index: gcc/testsuite/gcc.target/powerpc/darwin-ehreturn-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/darwin-ehreturn-1.c (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/darwin-ehreturn-1.c (revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do compile { target powerpc*-*-darwin* } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-mcpu=G3 -funwind-tables" } */
+/* { dg-final { scan-assembler "bl save_world" } } */
+/* { dg-final { scan-assembler ".byte\t0x6b" } } */
+
+/* Verify that on Darwin, even with -mcpu=G3, __builtin_eh_return
+ saves Altivec registers using save_world, and reports their
+ location in its EH information. */
+
+long offset;
+void *handler;
+
+extern void setup_offset(void);
+
+void foo(void)
+{
+ __builtin_unwind_init ();
+ setup_offset();
+ __builtin_eh_return (offset, handler);
+}
Index: gcc/testsuite/g++.dg/eh/simd-2.C
===================================================================
--- gcc/testsuite/g++.dg/eh/simd-2.C (revision 121137)
+++ gcc/testsuite/g++.dg/eh/simd-2.C (working copy)
@@ -4,6 +4,7 @@
// { dg-options "-O -w" { target { { i?86-*-* x86_64-*-* } && ilp32 } } }
// { dg-options "-O -w" { target powerpc*-*-* } }
// { dg-options "-O -w -maltivec" { target { powerpc*-*-linux* && powerpc_altivec_ok } } }
+// { dg-options "-O -w -maltivec" { target { powerpc*-*-darwin* && powerpc_altivec_ok } } }
// { dg-xfail-if "" { "powerpc-*-eabispe*" "powerpc-ibm-aix*" } { "*" } { "" } }
// { dg-do run }
Index: gcc/testsuite/g++.dg/eh/simd-4.C
===================================================================
--- gcc/testsuite/g++.dg/eh/simd-4.C (revision 0)
+++ gcc/testsuite/g++.dg/eh/simd-4.C (revision 0)
@@ -0,0 +1,68 @@
+/* { dg-do run { target powerpc*-*-darwin* } } */
+/* { dg-options "-fexceptions -fnon-call-exceptions -O -maltivec" } */
+
+#include <cstdlib>
+#include <cstring>
+#include <signal.h>
+
+typedef int __attribute__((vector_size(16))) v;
+
+v vv[32];
+volatile v vt = { 1, 2, 3, 4 };
+
+void clobber_vrs(void) { };
+
+void (*volatile fp)() = clobber_vrs;
+
+void thrower(int sig)
+{
+ v v00 = vv[ 0];
+ v v01 = vv[ 1];
+ v v02 = vv[ 2];
+ v v03 = vv[ 3];
+ v v04 = vv[ 4];
+ v v05 = vv[ 5];
+ v v06 = vv[ 6];
+ v v07 = vv[ 7];
+ v v08 = vv[ 8];
+ v v09 = vv[ 9];
+ v v10 = vv[10];
+ v v11 = vv[11];
+ v v12 = vv[12];
+
+ fp();
+
+ vv[ 0] = v00;
+ vv[ 1] = v01;
+ vv[ 2] = v02;
+ vv[ 3] = v03;
+ vv[ 4] = v04;
+ vv[ 5] = v05;
+ vv[ 6] = v06;
+ vv[ 7] = v07;
+ vv[ 8] = v08;
+ vv[ 9] = v09;
+ vv[10] = v10;
+ vv[11] = v11;
+ vv[12] = v12;
+
+ throw 3;
+}
+
+v v2;
+
+int main(void)
+{
+ v v1 = vt;
+ if (signal (SIGBUS, thrower) == SIG_ERR)
+ abort ();
+ try {
+ *(volatile int *)0 = 0;
+ abort ();
+ } catch (int x) {
+ }
+ v2 = v1;
+ if (memcmp (&v2, (v *)&vt, sizeof (v2)) != 0)
+ abort ();
+ return 0;
+}
Index: gcc/testsuite/g++.dg/eh/simd-3.C
===================================================================
--- gcc/testsuite/g++.dg/eh/simd-3.C (revision 0)
+++ gcc/testsuite/g++.dg/eh/simd-3.C (revision 0)
@@ -0,0 +1,65 @@
+// { dg-options "-O" }
+// { dg-options "-O -maltivec" { target { powerpc*-*-darwin* && powerpc_altivec_ok } } }
+// { dg-do run }
+
+#include <cstdlib>
+#include <cstring>
+
+typedef int __attribute__((vector_size(16))) v;
+
+v vv[32];
+volatile v vt = { 1, 2, 3, 4 };
+
+void clobber_vrs(void) { };
+
+void (*volatile fp)() = clobber_vrs;
+
+void thrower(void)
+{
+ v v00 = vv[ 0];
+ v v01 = vv[ 1];
+ v v02 = vv[ 2];
+ v v03 = vv[ 3];
+ v v04 = vv[ 4];
+ v v05 = vv[ 5];
+ v v06 = vv[ 6];
+ v v07 = vv[ 7];
+ v v08 = vv[ 8];
+ v v09 = vv[ 9];
+ v v10 = vv[10];
+ v v11 = vv[11];
+ v v12 = vv[12];
+
+ fp();
+
+ vv[ 0] = v00;
+ vv[ 1] = v01;
+ vv[ 2] = v02;
+ vv[ 3] = v03;
+ vv[ 4] = v04;
+ vv[ 5] = v05;
+ vv[ 6] = v06;
+ vv[ 7] = v07;
+ vv[ 8] = v08;
+ vv[ 9] = v09;
+ vv[10] = v10;
+ vv[11] = v11;
+ vv[12] = v12;
+
+ throw 3;
+}
+
+v v2;
+
+int main(void)
+{
+ v v1 = vt;
+ try {
+ thrower();
+ } catch (int x) {
+ }
+ v2 = v1;
+ if (memcmp (&v2, (v *)&vt, sizeof (v2)) != 0)
+ abort ();
+ return 0;
+}
Index: gcc/config/rs6000/t-darwin
===================================================================
--- gcc/config/rs6000/t-darwin (revision 121137)
+++ gcc/config/rs6000/t-darwin (working copy)
@@ -1,12 +1,12 @@
LIB2FUNCS_EXTRA = $(srcdir)/config/rs6000/darwin-tramp.asm \
$(srcdir)/config/rs6000/ppc64-fp.c \
$(srcdir)/config/darwin-64.c \
- $(srcdir)/config/rs6000/darwin-ldouble.c
+ $(srcdir)/config/rs6000/darwin-ldouble.c \
+ $(srcdir)/config/rs6000/darwin-world.asm
LIB2FUNCS_STATIC_EXTRA = \
$(srcdir)/config/rs6000/darwin-fpsave.asm \
- $(srcdir)/config/rs6000/darwin-vecsave.asm \
- $(srcdir)/config/rs6000/darwin-world.asm
+ $(srcdir)/config/rs6000/darwin-vecsave.asm
DARWIN_EXTRA_CRT_BUILD_CFLAGS = -mlongcall -mmacosx-version-min=10.4
Index: gcc/config/rs6000/darwin.h
===================================================================
--- gcc/config/rs6000/darwin.h (revision 121137)
+++ gcc/config/rs6000/darwin.h (working copy)
@@ -91,11 +91,19 @@
target_flags |= MASK_POWERPC64; \
warning (0, "-m64 requires PowerPC64 architecture, enabling"); \
} \
- if (flag_mkernel) \
+ if (flag_mkernel) \
{ \
rs6000_default_long_calls = 1; \
target_flags |= MASK_SOFT_FLOAT; \
} \
+ \
+ /* Make -m64 imply -maltivec. Darwin's 64-bit ABI includes \
+ Altivec. */ \
+ if (!flag_mkernel && !flag_apple_kext \
+ && TARGET_64BIT \
+ && ! (target_flags_explicit & MASK_ALTIVEC)) \
+ target_flags |= MASK_ALTIVEC; \
+ \
/* Unless the user (not the configurer) has explicitly overridden \
it with -mcpu=G3 or -mno-altivec, then 10.5+ targets default to \
G4 unless targetting the kernel. */ \
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 121137)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -13020,6 +13020,13 @@
if (! TARGET_ALTIVEC_ABI)
return LAST_ALTIVEC_REGNO + 1;
+ /* On Darwin, the unwind routines are compiled without
+ TARGET_ALTIVEC, and use save_world to save/restore the
+ altivec registers when necessary. */
+ if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
+ && ! TARGET_ALTIVEC)
+ return FIRST_ALTIVEC_REGNO + 20;
+
/* Find lowest numbered live register. */
for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
if (regs_ever_live[i])
@@ -13037,6 +13044,13 @@
{
unsigned int i, mask = 0;
+ /* On Darwin, the unwind routines are compiled without
+ TARGET_ALTIVEC, and use save_world to save/restore the
+ call-saved altivec registers when necessary. */
+ if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
+ && ! TARGET_ALTIVEC)
+ mask |= 0xFFF;
+
/* First, find out if we use _any_ altivec registers. */
for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
if (regs_ever_live[i])
@@ -13381,7 +13395,7 @@
/* Align stack so vector save area is on a quadword boundary. */
if (info_ptr->altivec_size != 0)
info_ptr->altivec_padding_size
- = 16 - (-info_ptr->vrsave_save_offset % 16);
+ = (-info_ptr->vrsave_save_offset) % 16;
else
info_ptr->altivec_padding_size = 0;
@@ -14529,7 +14543,8 @@
|| cfun->machine->ra_need_lr);
/* For V.4, update stack before we do any saving and set back pointer. */
- if (info->push_p
+ if (! WORLD_SAVE_P (info)
+ && info->push_p
&& (DEFAULT_ABI == ABI_V4
|| current_function_calls_eh_return))
{
@@ -14554,11 +14569,13 @@
int i, j, sz;
rtx treg;
rtvec p;
+ rtx reg0;
/* save_world expects lr in r0. */
+ reg0 = gen_rtx_REG (Pmode, 0);
if (info->lr_save_p)
{
- insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
+ insn = emit_move_insn (reg0,
gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -14575,7 +14592,7 @@
&& (!current_function_calls_eh_return
|| info->ehrd_offset == -432)
&& info->vrsave_save_offset == -224
- && info->altivec_save_offset == (-224 -16 -192));
+ && info->altivec_save_offset == -416);
treg = gen_rtx_REG (SImode, 11);
emit_move_insn (treg, GEN_INT (-info->total_size));
@@ -14584,7 +14601,7 @@
in R11. It also clobbers R12, so beware! */
/* Preserve CR2 for save_world prologues */
- sz = 6;
+ sz = 5;
sz += 32 - info->first_gp_reg_save;
sz += 64 - info->first_fp_reg_save;
sz += LAST_ALTIVEC_REGNO - info->first_altivec_reg_save + 1;
@@ -14639,29 +14656,26 @@
RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
}
- /* Prevent any attempt to delete the setting of r0 and treg! */
- RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
- RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, treg);
- RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode, sp_reg_rtx);
+ /* Explain about use of R0. */
+ if (info->lr_save_p)
+ {
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->lr_save_offset
+ + sp_offset));
+ rtx mem = gen_frame_mem (reg_mode, addr);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg0);
+ }
+ /* Explain what happens to the stack pointer. */
+ {
+ rtx newval = gen_rtx_PLUS (Pmode, sp_reg_rtx, treg);
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, sp_reg_rtx, newval);
+ }
insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
- NULL_RTX, NULL_RTX);
-
- if (current_function_calls_eh_return)
- {
- unsigned int i;
- for (i = 0; ; ++i)
- {
- unsigned int regno = EH_RETURN_DATA_REGNO (i);
- if (regno == INVALID_REGNUM)
- break;
- emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
- info->ehrd_offset + sp_offset
- + reg_size * (int) i,
- info->total_size);
- }
- }
+ treg, GEN_INT (-info->total_size));
+ sp_offset = info->total_size;
}
/* Save AltiVec registers if needed. */
@@ -14890,7 +14904,7 @@
/* ??? There's no need to emit actual instructions here, but it's the
easiest way to get the frame unwind information emitted. */
- if (!WORLD_SAVE_P (info) && current_function_calls_eh_return)
+ if (current_function_calls_eh_return)
{
unsigned int i, regno;
============================================================