aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Shinwell <shinwell@codesourcery.com>2006-08-18 14:10:05 +0000
committerMark Shinwell <shinwell@codesourcery.com>2006-08-18 14:10:05 +0000
commitffbcce998159d130afe1755896f50dabf2bc616c (patch)
treee77e6a2f408b5fcea47c03556a191a45a7118e8c
parentfe987a1fbb72f2fd298d6625e63520f2ef14fd93 (diff)
* config/arm/arm.c (arm_output_fldmx): Output FLDMD instead ofcsl/renesas/4.1-8
FLDMX if target supports FLDMD. (vfp_output_fstmx): Output FSTMD instead of FSTMX if target supports FLDMD. (vfp_emit_fstmx): Don't leave space in the frame layout for the FSTMX format word if using FSTMD. (arm_get_vfp_saved_size): Don't add in space for the FSTMX format word if using FSTMD/FLDMD instead of FSTMX/FLDMX. (arm_output_epilogue): Adjust comment to reflect use of FSTMD. (arm_unwind_emit_sequence): Don't compensate for the FSTMX format word if emitting FSTMD. Also emit "vsave" assembler directives in such cases rather than "save". * config/arm/libunwind.S (gnu_Unwind_Restore_VFP, gnu_Unwind_Save_VFP): Adjust comments. (gnu_Unwind_Restore_VFP_D, gnu_Unwind_Save_VFP_D): New functions for saving and restoring using FSTMD and FLDMD, rather than FSTMX and FLDMX. (gnu_Unwind_Restore_VFP_D_16_to_31, gnu_Unwind_Restore_VFP_D_16_to_31): New functions for saving and restoring the VFPv3 registers 16 .. 31. * config/arm/pr-support.c (gnu_unwind_execute): Add conditional compilation case to correctly handle unwind opcode 0xc8 when using VFP. * config/arm/unwind-arm.c (struct vfpv3_regs): New. (DEMAND_SAVE_VFP_D, DEMAND_SAVE_VFP_V3): New flags. (__gnu_Unwind_Save_VFP_D, __gnu_Unwind_Restore_VFP_D, __gnu_Unwind_Save_VFP_D_16_to_31, __gnu_Unwind_Restore_VFP_D_16_to_31): Declare. (restore_non_core_regs): Restore registers using FLDMD rather than FLDMX if required. Also handle restoration of VFPv3 registers. (_Unwind_VRS_Pop): Handle saving and restoring of registers using FSTMD and FLDMD if required; also handle VFPv3 registers 16 .. 31, including cases where the caller specifies a range of registers that overlaps the d15/d16 boundary. * config/arm/arm.h (TARGET_FLDMX): New. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/csl/sourcerygxx-4_1@116239 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--ChangeLog.csl37
-rw-r--r--gcc/config/arm/arm.c36
-rw-r--r--gcc/config/arm/arm.h4
-rw-r--r--gcc/config/arm/libunwind.S30
-rw-r--r--gcc/config/arm/pr-support.c22
-rw-r--r--gcc/config/arm/unwind-arm.c138
6 files changed, 229 insertions, 38 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index 37212b34154..2fe05e054b8 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,40 @@
+2006-08-18 Mark Shinwell <shinwell@codesourcery.com>
+
+ * config/arm/arm.c (arm_output_fldmx): Output FLDMD instead of
+ FLDMX if target supports FLDMD.
+ (vfp_output_fstmx): Output FSTMD instead of FSTMX if target supports
+ FLDMD.
+ (vfp_emit_fstmx): Don't leave space in the frame layout for the
+ FSTMX format word if using FSTMD.
+ (arm_get_vfp_saved_size): Don't add in space for the FSTMX format word
+ if using FSTMD/FLDMD instead of FSTMX/FLDMX.
+ (arm_output_epilogue): Adjust comment to reflect use of FSTMD.
+ (arm_unwind_emit_sequence): Don't compensate for the FSTMX format
+ word if emitting FSTMD. Also emit "vsave" assembler directives in
+ such cases rather than "save".
+ * config/arm/libunwind.S (gnu_Unwind_Restore_VFP,
+ gnu_Unwind_Save_VFP): Adjust comments.
+ (gnu_Unwind_Restore_VFP_D, gnu_Unwind_Save_VFP_D): New functions
+ for saving and restoring using FSTMD and FLDMD, rather than
+ FSTMX and FLDMX.
+ (gnu_Unwind_Restore_VFP_D_16_to_31, gnu_Unwind_Restore_VFP_D_16_to_31):
+ New functions for saving and restoring the VFPv3 registers 16 .. 31.
+ * config/arm/pr-support.c (gnu_unwind_execute): Add conditional
+ compilation case to correctly handle unwind opcode 0xc8 when using
+ VFP.
+ * config/arm/unwind-arm.c (struct vfpv3_regs): New.
+ (DEMAND_SAVE_VFP_D, DEMAND_SAVE_VFP_V3): New flags.
+ (__gnu_Unwind_Save_VFP_D, __gnu_Unwind_Restore_VFP_D,
+ __gnu_Unwind_Save_VFP_D_16_to_31, __gnu_Unwind_Restore_VFP_D_16_to_31):
+ Declare.
+ (restore_non_core_regs): Restore registers using FLDMD rather than
+ FLDMX if required. Also handle restoration of VFPv3 registers.
+ (_Unwind_VRS_Pop): Handle saving and restoring of registers using
+ FSTMD and FLDMD if required; also handle VFPv3 registers 16 .. 31,
+ including cases where the caller specifies a range of registers
+ that overlaps the d15/d16 boundary.
+ * config/arm/arm.h (TARGET_FLDMX): New.
+
2006-08-16 Mark Shinwell <shinwell@codesourcery.com>
gcc/
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 8713bb39f92..488991ebefa 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -8712,7 +8712,7 @@ print_multi_reg (FILE *stream, const char *instr, unsigned reg,
}
-/* Output a FLDMX instruction to STREAM.
+/* Output a FLDMX or FLDMD instruction to STREAM.
BASE if the register containing the address.
REG and COUNT specify the register range.
Extra registers may be added to avoid hardware bugs. */
@@ -8731,7 +8731,7 @@ arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
}
fputc ('\t', stream);
- asm_fprintf (stream, "fldmfdx\t%r!, {", base);
+ asm_fprintf (stream, "fldmfd%c\t%r!, {", TARGET_FLDMX ? 'x' : 'd', base);
for (i = reg; i < reg + count; i++)
{
@@ -8754,7 +8754,7 @@ vfp_output_fstmx (rtx * operands)
int base;
int i;
- strcpy (pattern, "fstmfdx\t%m0!, {%P1");
+ sprintf (pattern, "fstmfd%c\t%%m0!, {%%P1", TARGET_FLDMX ? 'x' : 'd');
p = strlen (pattern);
gcc_assert (GET_CODE (operands[1]) == REG);
@@ -8781,6 +8781,7 @@ vfp_emit_fstmx (int base_reg, int count)
rtx dwarf;
rtx tmp, reg;
int i;
+ int pad = TARGET_FLDMX ? 4 : 0;
/* Workaround ARM10 VFPr1 bug. Data corruption can occur when exactly two
register pairs are stored by a store multiple insn. We avoid this
@@ -8793,7 +8794,9 @@ vfp_emit_fstmx (int base_reg, int count)
}
/* ??? The frame layout is implementation defined. We describe
- standard format 1 (equivalent to a FSTMD insn and unused pad word).
+ standard format 1 (equivalent to a FSTMD insn and unused pad word)
+ for architectures pre-v6, and FSTMD insn format without the pad
+ word for v6+.
We really need some way of representing the whole block so that the
unwinder can figure it out at runtime. */
par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
@@ -8813,7 +8816,7 @@ vfp_emit_fstmx (int base_reg, int count)
tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
gen_rtx_PLUS (SImode, stack_pointer_rtx,
- GEN_INT (-(count * 8 + 4))));
+ GEN_INT (-(count * 8 + pad))));
RTX_FRAME_RELATED_P (tmp) = 1;
XVECEXP (dwarf, 0, 0) = tmp;
@@ -8844,7 +8847,7 @@ vfp_emit_fstmx (int base_reg, int count)
REG_NOTES (par));
RTX_FRAME_RELATED_P (par) = 1;
- return count * 8 + 4;
+ return count * 8 + pad;
}
@@ -9830,6 +9833,10 @@ arm_get_vfp_saved_size (void)
unsigned int regno;
int count;
int saved;
+ /* Check if we need to allow for the format word that
+ is used by the FLDMX and FSTMX instructions. (If we are using
+ FLDMD and FSTMD then no such space is required.) */
+ int space_for_format_word = TARGET_FLDMX ? 4 : 0;
saved = 0;
/* Space for saved VFP registers. */
@@ -9848,7 +9855,7 @@ arm_get_vfp_saved_size (void)
/* Workaround ARM10 VFPr1 bug. */
if (count == 2 && !arm_arch6)
count++;
- saved += count * 8 + 4;
+ saved += count * 8 + space_for_format_word;
}
count = 0;
}
@@ -9859,7 +9866,7 @@ arm_get_vfp_saved_size (void)
{
if (count == 2 && !arm_arch6)
count++;
- saved += count * 8 + 4;
+ saved += count * 8 + space_for_format_word;
}
}
return saved;
@@ -10289,8 +10296,8 @@ arm_output_epilogue (rtx sibling)
{
int saved_size;
- /* The fldmx insn does not have base+offset addressing modes,
- so we use IP to hold the address. */
+ /* The fldmx and fldmd insns do not have base+offset addressing
+ modes, so we use IP to hold the address. */
saved_size = arm_get_vfp_saved_size ();
if (saved_size > 0)
@@ -16085,12 +16092,15 @@ arm_unwind_emit_sequence (FILE * asm_out_file, rtx p)
offset -= 4;
}
reg_size = 4;
+ fprintf (asm_out_file, "\t.save {");
}
else if (IS_VFP_REGNUM (reg))
{
- /* FPA register saves use an additional word. */
- offset -= 4;
+ /* VFP register saves using FSTMX require an extra word. */
+ if (TARGET_FLDMX)
+ offset -= 4;
reg_size = 8;
+ fprintf (asm_out_file, TARGET_FLDMX ? "\t.save {" : "\t.vsave {");
}
else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
{
@@ -16107,8 +16117,6 @@ arm_unwind_emit_sequence (FILE * asm_out_file, rtx p)
if (offset != nregs * reg_size)
abort ();
- fprintf (asm_out_file, "\t.save {");
-
offset = 0;
lastreg = 0;
/* The remaining insns will describe the stores. */
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 88eff57e1ab..1f962da9650 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -215,6 +215,10 @@ extern GTY(()) rtx aof_pic_label;
for Thumb-2. */
#define TARGET_UNIFIED_ASM TARGET_THUMB2
+/* True if FLDMX and FSTMX instructions must be used in function prologues
+ and epilogues rather than FLDMD and FSTMD instructions.
+ (This does not affect use of FLDMD and FSTMD anywhere else.) */
+#define TARGET_FLDMX !arm_arch6
/* True iff the full BPABI is being used. If TARGET_BPABI is true,
then TARGET_AAPCS_BASED must be true -- but the converse does not
diff --git a/gcc/config/arm/libunwind.S b/gcc/config/arm/libunwind.S
index 1585eb206ba..b541005da35 100644
--- a/gcc/config/arm/libunwind.S
+++ b/gcc/config/arm/libunwind.S
@@ -79,20 +79,46 @@ ARM_FUNC_START restore_core_regs
FUNC_END restore_core_regs
UNPREFIX restore_core_regs
-/* Load VFP registers d0-d15 from the address in r0. */
+/* Load VFP registers d0-d15 from the address in r0.
+ Use this to load from FSTMX format. */
ARM_FUNC_START gnu_Unwind_Restore_VFP
/* Use the generic coprocessor form so that gas doesn't complain
on soft-float targets. */
ldc p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */
RET
-/* Store VFR regsters d0-d15 to the address in r0. */
+/* Store VFP registers d0-d15 to the address in r0.
+ Use this to store in FSTMX format. */
ARM_FUNC_START gnu_Unwind_Save_VFP
/* Use the generic coprocessor form so that gas doesn't complain
on soft-float targets. */
stc p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */
RET
+/* Load VFP registers d0-d15 from the address in r0.
+ Use this to load from FSTMD format. */
+ARM_FUNC_START gnu_Unwind_Restore_VFP_D
+ ldc p11,cr0,[r0],{0x20} /* fldmiad r0, {d0-d15} */
+ RET
+
+/* Store VFP registers d0-d15 to the address in r0.
+ Use this to store in FLDMD format. */
+ARM_FUNC_START gnu_Unwind_Save_VFP_D
+ stc p11,cr0,[r0],{0x20} /* fstmiad r0, {d0-d15} */
+ RET
+
+/* Load VFP registers d16-d31 from the address in r0.
+ Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */
+ARM_FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31
+ ldcl p11,cr0,[r0],{0x20} /* vldm r0, {d16-d31} */
+ RET
+
+/* Store VFP registers d16-d31 to the address in r0.
+ Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */
+ARM_FUNC_START gnu_Unwind_Save_VFP_D_16_to_31
+ stcl p11,cr0,[r0],{0x20} /* vstm r0, {d16-d31} */
+ RET
+
/* Wrappers to save core registers, then call the real routine. */
.macro UNWIND_WRAPPER name nargs
diff --git a/gcc/config/arm/pr-support.c b/gcc/config/arm/pr-support.c
index 0e750bf3e09..b7d22458536 100644
--- a/gcc/config/arm/pr-support.c
+++ b/gcc/config/arm/pr-support.c
@@ -282,13 +282,23 @@ __gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws)
}
if (op == 0xc8)
{
- /* Pop FPA registers. */
- op = next_unwind_byte (uws);
+#ifndef __VFP_FP__
+ /* Pop FPA registers. */
+ op = next_unwind_byte (uws);
op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
- if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
- != _UVRSR_OK)
- return _URC_FAILURE;
- continue;
+ if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+#else
+ /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */
+ op = next_unwind_byte (uws);
+ op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
+ if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE)
+ != _UVRSR_OK)
+ return _URC_FAILURE;
+ continue;
+#endif
}
if (op == 0xc9)
{
diff --git a/gcc/config/arm/unwind-arm.c b/gcc/config/arm/unwind-arm.c
index b3f8a00dcb5..ce4579e23f2 100644
--- a/gcc/config/arm/unwind-arm.c
+++ b/gcc/config/arm/unwind-arm.c
@@ -73,6 +73,13 @@ struct vfp_regs
_uw pad;
};
+struct vfpv3_regs
+{
+ /* Always populated via VSTM, so no need for the "pad" field from
+ vfp_regs (which is used to store the format word for FSTMX). */
+ _uw64 d[16];
+};
+
struct fpa_reg
{
_uw w[3];
@@ -113,10 +120,14 @@ typedef struct
struct core_regs core;
_uw prev_sp; /* Only valid during forced unwinding. */
struct vfp_regs vfp;
+ struct vfpv3_regs vfp_regs_16_to_31;
struct fpa_regs fpa;
} phase1_vrs;
-#define DEMAND_SAVE_VFP 1
+#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 */
/* This must match the structure created by the assembly wrappers. */
typedef struct
@@ -142,15 +153,33 @@ void __attribute__((noreturn)) restore_core_regs (struct core_regs *);
/* Coprocessor register state manipulation functions. */
+/* Routines for FLDMX/FSTMX format... */
void __gnu_Unwind_Save_VFP (struct vfp_regs * p);
void __gnu_Unwind_Restore_VFP (struct vfp_regs * p);
+/* ...and those for FLDMD/FSTMD format... */
+void __gnu_Unwind_Save_VFP_D (struct vfp_regs * p);
+void __gnu_Unwind_Restore_VFP_D (struct vfp_regs * p);
+
+/* ...and those for VLDM/VSTM format, saving/restoring only registers
+ 16 through 31. */
+void __gnu_Unwind_Save_VFP_D_16_to_31 (struct vfpv3_regs * p);
+void __gnu_Unwind_Restore_VFP_D_16_to_31 (struct vfpv3_regs * p);
+
/* Restore coprocessor state after phase1 unwinding. */
static void
restore_non_core_regs (phase1_vrs * vrs)
{
if ((vrs->demand_save_flags & DEMAND_SAVE_VFP) == 0)
- __gnu_Unwind_Restore_VFP (&vrs->vfp);
+ {
+ if (vrs->demand_save_flags & DEMAND_SAVE_VFP_D)
+ __gnu_Unwind_Restore_VFP_D (&vrs->vfp);
+ else
+ __gnu_Unwind_Restore_VFP (&vrs->vfp);
+ }
+
+ if ((vrs->demand_save_flags & DEMAND_SAVE_VFP_V3) == 0)
+ __gnu_Unwind_Restore_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31);
}
/* A better way to do this would probably be to compare the absolute address
@@ -273,35 +302,101 @@ _Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context,
_uw start = discriminator >> 16;
_uw count = discriminator & 0xffff;
struct vfp_regs tmp;
+ struct vfpv3_regs tmp_16_to_31;
+ int tmp_count;
_uw *sp;
_uw *dest;
+ int num_vfpv3_regs = 0;
+ /* We use an approximation here by bounding _UVRSD_DOUBLE
+ register numbers at 32 always, since we can't detect if
+ VFPv3 isn't present (in such a case the upper limit is 16). */
if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
- || start + count > 16)
+ || start + count > (representation == _UVRSD_VFPX ? 16 : 32)
+ || (representation == _UVRSD_VFPX && start >= 16))
return _UVRSR_FAILED;
- if (vrs->demand_save_flags & DEMAND_SAVE_VFP)
+ /* Check if we're being asked to pop VFPv3-only registers
+ (numbers 16 through 31). */
+ if (start >= 16)
+ num_vfpv3_regs = count;
+ else if (start + count > 16)
+ num_vfpv3_regs = start + count - 16;
+
+ if (num_vfpv3_regs && representation != _UVRSD_DOUBLE)
+ return _UVRSR_FAILED;
+
+ /* Demand-save coprocessor registers for stage1. */
+ if (start < 16 && (vrs->demand_save_flags & DEMAND_SAVE_VFP))
{
- /* Demand-save resisters for stage1. */
vrs->demand_save_flags &= ~DEMAND_SAVE_VFP;
- __gnu_Unwind_Save_VFP (&vrs->vfp);
+
+ if (representation == _UVRSD_DOUBLE)
+ {
+ /* Save in FLDMD/FSTMD format. */
+ vrs->demand_save_flags |= DEMAND_SAVE_VFP_D;
+ __gnu_Unwind_Save_VFP_D (&vrs->vfp);
+ }
+ else
+ {
+ /* Save in FLDMX/FSTMX format. */
+ vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_D;
+ __gnu_Unwind_Save_VFP (&vrs->vfp);
+ }
+ }
+
+ if (num_vfpv3_regs > 0
+ && (vrs->demand_save_flags & DEMAND_SAVE_VFP_V3))
+ {
+ vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_V3;
+ __gnu_Unwind_Save_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31);
}
/* Restore the registers from the stack. Do this by saving the
current VFP registers to a memory area, moving the in-memory
values into that area, and restoring from the whole area.
For _UVRSD_VFPX we assume FSTMX standard format 1. */
- __gnu_Unwind_Save_VFP (&tmp);
-
- /* The stack address is only guaranteed to be word aligned, so
+ if (representation == _UVRSD_VFPX)
+ __gnu_Unwind_Save_VFP (&tmp);
+ else
+ {
+ /* Save registers 0 .. 15 if required. */
+ if (start < 16)
+ __gnu_Unwind_Save_VFP_D (&tmp);
+
+ /* Save VFPv3 registers 16 .. 31 if required. */
+ if (num_vfpv3_regs)
+ __gnu_Unwind_Save_VFP_D_16_to_31 (&tmp_16_to_31);
+ }
+
+ /* Work out how many registers below register 16 need popping. */
+ tmp_count = num_vfpv3_regs > 0 ? 16 - start : count;
+
+ /* Copy registers below 16, if needed.
+ 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.d[start];
- count *= 2;
- while (count--)
- *(dest++) = *(sp++);
-
- /* Skip the pad word */
+ if (tmp_count > 0)
+ {
+ tmp_count *= 2;
+ dest = (_uw *) &tmp.d[start];
+ while (tmp_count--)
+ *(dest++) = *(sp++);
+ }
+
+ /* Copy VFPv3 registers numbered >= 16, if needed. */
+ if (num_vfpv3_regs > 0)
+ {
+ /* num_vfpv3_regs is needed below, so copy it. */
+ int tmp_count_2 = num_vfpv3_regs * 2;
+ int vfpv3_start = start < 16 ? 16 : start;
+
+ dest = (_uw *) &tmp_16_to_31.d[vfpv3_start - 16];
+ while (tmp_count_2--)
+ *(dest++) = *(sp++);
+ }
+
+ /* Skip the format word space if using FLDMX/FSTMX format. */
if (representation == _UVRSD_VFPX)
sp++;
@@ -309,7 +404,18 @@ _Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context,
vrs->core.r[R_SP] = (_uw) sp;
/* Reload the registers. */
- __gnu_Unwind_Restore_VFP (&tmp);
+ if (representation == _UVRSD_VFPX)
+ __gnu_Unwind_Restore_VFP (&tmp);
+ else
+ {
+ /* Restore registers 0 .. 15 if required. */
+ if (start < 16)
+ __gnu_Unwind_Restore_VFP_D (&tmp);
+
+ /* Restore VFPv3 registers 16 .. 31 if required. */
+ if (num_vfpv3_regs > 0)
+ __gnu_Unwind_Restore_VFP_D_16_to_31 (&tmp_16_to_31);
+ }
}
return _UVRSR_OK;