summaryrefslogtreecommitdiff
path: root/gcc/config/arm
diff options
context:
space:
mode:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2007-03-07 13:04:15 +0000
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2007-03-07 13:04:15 +0000
commit89cd00700887cf6cc5d244d8175c6a4b82491aa2 (patch)
tree519234808030de5a62518b53c312f9e9c19e836a /gcc/config/arm
parent80fbffcbb859e9758c1d5b1b8d09311673b34e05 (diff)
downloadgcc-89cd00700887cf6cc5d244d8175c6a4b82491aa2.tar.gz
gcc:
2007-03-07 Paul Brook <paul@codesourcery.com> * config/arm/libunwind.S: Add .arch/.object_arch for armv4 builds. gcc: 2007-03-07 Joseph Myers <joseph@codesourcery.com> * config/arm/unwind-arm.c (struct wmmxd_regs, struct wmmxc_regs): New. (phase1_vrs): Use them. (DEMAND_SAVE_WMMXD, DEMAND_SAVE_WMMXC): New. (__gnu_Unwind_Save_WMMXD, __gnu_Unwind_Restore_WMMXD, __gnu_Unwind_Save_WMMXC, __gnu_Unwind_Restore_WMMXC): Declare. (restore_non_core_regs): Call __gnu_Unwind_Restore_WMMXD and __gnu_Unwind_Restore_WMMXC if required. (_Unwind_VRS_Pop): Implement iWMMXt support. * config/arm/libunwind.S (gnu_Unwind_Restore_WMMXD, gnu_Unwind_Save_WMMXD, gnu_Unwind_Restore_WMMXC, gnu_Unwind_Save_WMMXC): Define. gcc/testsuite: 2007-03-07 Joseph Myers <joseph@codesourcery.com> * g++.dg/eh/arm-iwmmxt-unwind.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122658 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/arm')
-rw-r--r--gcc/config/arm/libunwind.S72
-rw-r--r--gcc/config/arm/unwind-arm.c98
2 files changed, 169 insertions, 1 deletions
diff --git a/gcc/config/arm/libunwind.S b/gcc/config/arm/libunwind.S
index ef3f89aafcb..23284710467 100644
--- a/gcc/config/arm/libunwind.S
+++ b/gcc/config/arm/libunwind.S
@@ -41,6 +41,18 @@
EQUIV SYM (\name), SYM (__\name)
.endm
+#if (__ARM_ARCH__ == 4)
+/* Some coprocessors require armv5. We know this code will never be run on
+ other cpus. Tell gas to allow armv5, but only mark the objects as armv4.
+ */
+.arch armv5t
+#ifdef __ARM_ARCH_4T__
+.object_arch armv4t
+#else
+.object_arch armv4
+#endif
+#endif
+
/* r0 points to a 16-word block. Upload these values to the actual core
state. */
ARM_FUNC_START restore_core_regs
@@ -119,6 +131,66 @@ ARM_FUNC_START gnu_Unwind_Save_VFP_D_16_to_31
stcl p11,cr0,[r0],{0x20} /* vstm r0, {d16-d31} */
RET
+ARM_FUNC_START gnu_Unwind_Restore_WMMXD
+ /* Use the generic coprocessor form so that gas doesn't complain
+ on non-iWMMXt targets. */
+ ldcl p1, cr0, [r0], #8 /* wldrd wr0, [r0], #8 */
+ ldcl p1, cr1, [r0], #8 /* wldrd wr1, [r0], #8 */
+ ldcl p1, cr2, [r0], #8 /* wldrd wr2, [r0], #8 */
+ ldcl p1, cr3, [r0], #8 /* wldrd wr3, [r0], #8 */
+ ldcl p1, cr4, [r0], #8 /* wldrd wr4, [r0], #8 */
+ ldcl p1, cr5, [r0], #8 /* wldrd wr5, [r0], #8 */
+ ldcl p1, cr6, [r0], #8 /* wldrd wr6, [r0], #8 */
+ ldcl p1, cr7, [r0], #8 /* wldrd wr7, [r0], #8 */
+ ldcl p1, cr8, [r0], #8 /* wldrd wr8, [r0], #8 */
+ ldcl p1, cr9, [r0], #8 /* wldrd wr9, [r0], #8 */
+ ldcl p1, cr10, [r0], #8 /* wldrd wr10, [r0], #8 */
+ ldcl p1, cr11, [r0], #8 /* wldrd wr11, [r0], #8 */
+ ldcl p1, cr12, [r0], #8 /* wldrd wr12, [r0], #8 */
+ ldcl p1, cr13, [r0], #8 /* wldrd wr13, [r0], #8 */
+ ldcl p1, cr14, [r0], #8 /* wldrd wr14, [r0], #8 */
+ ldcl p1, cr15, [r0], #8 /* wldrd wr15, [r0], #8 */
+ RET
+
+ARM_FUNC_START gnu_Unwind_Save_WMMXD
+ /* Use the generic coprocessor form so that gas doesn't complain
+ on non-iWMMXt targets. */
+ stcl p1, cr0, [r0], #8 /* wstrd wr0, [r0], #8 */
+ stcl p1, cr1, [r0], #8 /* wstrd wr1, [r0], #8 */
+ stcl p1, cr2, [r0], #8 /* wstrd wr2, [r0], #8 */
+ stcl p1, cr3, [r0], #8 /* wstrd wr3, [r0], #8 */
+ stcl p1, cr4, [r0], #8 /* wstrd wr4, [r0], #8 */
+ stcl p1, cr5, [r0], #8 /* wstrd wr5, [r0], #8 */
+ stcl p1, cr6, [r0], #8 /* wstrd wr6, [r0], #8 */
+ stcl p1, cr7, [r0], #8 /* wstrd wr7, [r0], #8 */
+ stcl p1, cr8, [r0], #8 /* wstrd wr8, [r0], #8 */
+ stcl p1, cr9, [r0], #8 /* wstrd wr9, [r0], #8 */
+ stcl p1, cr10, [r0], #8 /* wstrd wr10, [r0], #8 */
+ stcl p1, cr11, [r0], #8 /* wstrd wr11, [r0], #8 */
+ stcl p1, cr12, [r0], #8 /* wstrd wr12, [r0], #8 */
+ stcl p1, cr13, [r0], #8 /* wstrd wr13, [r0], #8 */
+ stcl p1, cr14, [r0], #8 /* wstrd wr14, [r0], #8 */
+ stcl p1, cr15, [r0], #8 /* wstrd wr15, [r0], #8 */
+ RET
+
+ARM_FUNC_START gnu_Unwind_Restore_WMMXC
+ /* Use the generic coprocessor form so that gas doesn't complain
+ on non-iWMMXt targets. */
+ ldc2 p1, cr8, [r0], #4 /* wldrw wcgr0, [r0], #4 */
+ ldc2 p1, cr9, [r0], #4 /* wldrw wcgr1, [r0], #4 */
+ ldc2 p1, cr10, [r0], #4 /* wldrw wcgr2, [r0], #4 */
+ ldc2 p1, cr11, [r0], #4 /* wldrw wcgr3, [r0], #4 */
+ RET
+
+ARM_FUNC_START gnu_Unwind_Save_WMMXC
+ /* Use the generic coprocessor form so that gas doesn't complain
+ on non-iWMMXt targets. */
+ stc2 p1, cr8, [r0], #4 /* wstrw wcgr0, [r0], #4 */
+ stc2 p1, cr9, [r0], #4 /* wstrw wcgr1, [r0], #4 */
+ stc2 p1, cr10, [r0], #4 /* wstrw wcgr2, [r0], #4 */
+ stc2 p1, cr11, [r0], #4 /* wstrw wcgr3, [r0], #4 */
+ RET
+
/* Wrappers to save core registers, then call the real routine. */
.macro UNWIND_WRAPPER name nargs
diff --git a/gcc/config/arm/unwind-arm.c b/gcc/config/arm/unwind-arm.c
index 4b75b0fe665..60f61d526f4 100644
--- a/gcc/config/arm/unwind-arm.c
+++ b/gcc/config/arm/unwind-arm.c
@@ -91,6 +91,16 @@ struct fpa_regs
struct fpa_reg f[8];
};
+struct wmmxd_regs
+{
+ _uw64 wd[16];
+};
+
+struct wmmxc_regs
+{
+ _uw wc[4];
+};
+
/* Unwind descriptors. */
typedef struct
@@ -123,12 +133,18 @@ typedef struct
struct vfp_regs vfp;
struct vfpv3_regs vfp_regs_16_to_31;
struct fpa_regs fpa;
+ struct wmmxd_regs wmmxd;
+ struct wmmxc_regs wmmxc;
} phase1_vrs;
#define DEMAND_SAVE_VFP 1 /* VFP state has been saved if not set */
#define DEMAND_SAVE_VFP_D 2 /* VFP state is for FLDMD/FSTMD if set */
#define DEMAND_SAVE_VFP_V3 4 /* VFPv3 state for regs 16 .. 31 has
been saved if not set */
+#define DEMAND_SAVE_WMMXD 8 /* iWMMXt data registers have been
+ saved if not set. */
+#define DEMAND_SAVE_WMMXC 16 /* iWMMXt control registers have been
+ saved if not set. */
/* This must match the structure created by the assembly wrappers. */
typedef struct
@@ -157,6 +173,10 @@ void __attribute__((noreturn)) restore_core_regs (struct core_regs *);
/* Routines for FLDMX/FSTMX format... */
void __gnu_Unwind_Save_VFP (struct vfp_regs * p);
void __gnu_Unwind_Restore_VFP (struct vfp_regs * p);
+void __gnu_Unwind_Save_WMMXD (struct wmmxd_regs * p);
+void __gnu_Unwind_Restore_WMMXD (struct wmmxd_regs * p);
+void __gnu_Unwind_Save_WMMXC (struct wmmxc_regs * p);
+void __gnu_Unwind_Restore_WMMXC (struct wmmxc_regs * p);
/* ...and those for FLDMD/FSTMD format... */
void __gnu_Unwind_Save_VFP_D (struct vfp_regs * p);
@@ -181,6 +201,11 @@ restore_non_core_regs (phase1_vrs * vrs)
if ((vrs->demand_save_flags & DEMAND_SAVE_VFP_V3) == 0)
__gnu_Unwind_Restore_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31);
+
+ if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXD) == 0)
+ __gnu_Unwind_Restore_WMMXD (&vrs->wmmxd);
+ if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXC) == 0)
+ __gnu_Unwind_Restore_WMMXC (&vrs->wmmxc);
}
/* A better way to do this would probably be to compare the absolute address
@@ -421,9 +446,80 @@ _Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context,
return _UVRSR_OK;
case _UVRSC_FPA:
+ return _UVRSR_NOT_IMPLEMENTED;
+
case _UVRSC_WMMXD:
+ {
+ _uw start = discriminator >> 16;
+ _uw count = discriminator & 0xffff;
+ struct wmmxd_regs tmp;
+ _uw *sp;
+ _uw *dest;
+
+ if ((representation != _UVRSD_UINT64) || start + count > 16)
+ return _UVRSR_FAILED;
+
+ if (vrs->demand_save_flags & DEMAND_SAVE_WMMXD)
+ {
+ /* Demand-save resisters for stage1. */
+ vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXD;
+ __gnu_Unwind_Save_WMMXD (&vrs->wmmxd);
+ }
+
+ /* Restore the registers from the stack. Do this by saving the
+ current WMMXD registers to a memory area, moving the in-memory
+ values into that area, and restoring from the whole area. */
+ __gnu_Unwind_Save_WMMXD (&tmp);
+
+ /* The stack address is only guaranteed to be word aligned, so
+ we can't use doubleword copies. */
+ sp = (_uw *) vrs->core.r[R_SP];
+ dest = (_uw *) &tmp.wd[start];
+ count *= 2;
+ while (count--)
+ *(dest++) = *(sp++);
+
+ /* Set the new stack pointer. */
+ vrs->core.r[R_SP] = (_uw) sp;
+
+ /* Reload the registers. */
+ __gnu_Unwind_Restore_WMMXD (&tmp);
+ }
+ return _UVRSR_OK;
+
case _UVRSC_WMMXC:
- return _UVRSR_NOT_IMPLEMENTED;
+ {
+ int i;
+ struct wmmxc_regs tmp;
+ _uw *sp;
+
+ if ((representation != _UVRSD_UINT32) || discriminator > 16)
+ return _UVRSR_FAILED;
+
+ if (vrs->demand_save_flags & DEMAND_SAVE_WMMXC)
+ {
+ /* Demand-save resisters for stage1. */
+ vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXC;
+ __gnu_Unwind_Save_WMMXC (&vrs->wmmxc);
+ }
+
+ /* Restore the registers from the stack. Do this by saving the
+ current WMMXC registers to a memory area, moving the in-memory
+ values into that area, and restoring from the whole area. */
+ __gnu_Unwind_Save_WMMXC (&tmp);
+
+ sp = (_uw *) vrs->core.r[R_SP];
+ for (i = 0; i < 4; i++)
+ if (discriminator & (1 << i))
+ tmp.wc[i] = *(sp++);
+
+ /* Set the new stack pointer. */
+ vrs->core.r[R_SP] = (_uw) sp;
+
+ /* Reload the registers. */
+ __gnu_Unwind_Restore_WMMXC (&tmp);
+ }
+ return _UVRSR_OK;
default:
return _UVRSR_FAILED;