diff options
author | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-03-07 13:04:15 +0000 |
---|---|---|
committer | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-03-07 13:04:15 +0000 |
commit | 89cd00700887cf6cc5d244d8175c6a4b82491aa2 (patch) | |
tree | 519234808030de5a62518b53c312f9e9c19e836a /gcc/config/arm | |
parent | 80fbffcbb859e9758c1d5b1b8d09311673b34e05 (diff) | |
download | gcc-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.S | 72 | ||||
-rw-r--r-- | gcc/config/arm/unwind-arm.c | 98 |
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; |