From 9728c9d15aceb958b36fef96e2f3b9e4d0d74dd7 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Thu, 25 Mar 2004 11:36:57 +0000 Subject: [PATCH] arm.c (vfp_print_multi): Remove. * config/arm/arm.c (vfp_print_multi): Remove. (arm_output_fldmx): New function. (vfp_emit_fstmx): Return block size, not insn. Add ARM10 VFPr1 bugfix. (arm_expand_prologue): Update to match. (arm_get_vfp_saved_size): New Function. (arm_get_frame_offsets): Use it. (arm_output_epilogue): Use new functions. From-SVN: r79950 --- gcc/ChangeLog | 10 +++ gcc/config/arm/arm.c | 195 ++++++++++++++++++++++--------------------- 2 files changed, 111 insertions(+), 94 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f82691862ee..505adaca56e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2004-03-25 Paul Brook + + * config/arm/arm.c (vfp_print_multi): Remove. + (arm_output_fldmx): New function. + (vfp_emit_fstmx): Return block size, not insn. Add ARM10 VFPr1 bugfix. + (arm_expand_prologue): Update to match. + (arm_get_vfp_saved_size): New Function. + (arm_get_frame_offsets): Use it. + (arm_output_epilogue): Use new functions. + 2004-03-24 Richard Henderson * alias.c (alias_invariant, alias_invariant_size): Mark GTY. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index a957a130f43..206647b1cb6 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -7809,29 +7809,35 @@ print_multi_reg (FILE *stream, const char *instr, int reg, int mask) } -/* Output the operands of a FLDM/FSTM instruction to STREAM. - REG is the base register, - INSTR is the possibly suffixed load or store instruction. - FMT specifies now to print the register name. - START and COUNT specify the register range. */ +/* Output a FLDMX 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. */ static void -vfp_print_multi (FILE *stream, const char *instr, int reg, - const char * fmt, int start, int count) +arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count) { int i; + /* Workaround ARM10 VFPr1 bug. */ + if (count == 2 && !arm_arch6) + { + if (reg == 15) + reg--; + count++; + } + fputc ('\t', stream); - asm_fprintf (stream, instr, reg); - fputs (", {", stream); + asm_fprintf (stream, "fldmfdx\t%r!, {", base); - for (i = start; i < start + count; i++) + for (i = reg; i < reg + count; i++) { - if (i > start) + if (i > reg) fputs (", ", stream); - asm_fprintf (stream, fmt, i); + asm_fprintf (stream, "d%d", i); } fputs ("}\n", stream); + } @@ -7863,9 +7869,10 @@ vfp_output_fstmx (rtx * operands) } -/* Emit RTL to save block of VFP register pairs to the stack. */ +/* Emit RTL to save block of VFP register pairs to the stack. Returns the + number of bytes pushed. */ -static rtx +static int vfp_emit_fstmx (int base_reg, int count) { rtx par; @@ -7873,6 +7880,16 @@ vfp_emit_fstmx (int base_reg, int count) rtx tmp, reg; int i; + /* Workaround ARM10 VFPr1 bug. Data corruption can occur when exactly two + register pairs are stored by a store multiple insn. We avoid this + by pushing an extra pair. */ + if (count == 2 && !arm_arch6) + { + if (base_reg == LAST_VFP_REGNUM - 3) + base_reg -= 2; + count++; + } + /* ??? The frame layout is implementation defined. We describe standard format 1 (equivalent to a FSTMD insn and unused pad word). We really need some way of representing the whole block so that the @@ -7922,7 +7939,9 @@ vfp_emit_fstmx (int base_reg, int count) par = emit_insn (par); REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, REG_NOTES (par)); - return par; + RTX_FRAME_RELATED_P (par) = 1; + + return count * 8 + 4; } @@ -8864,6 +8883,50 @@ arm_compute_save_reg_mask (void) return save_reg_mask; } + +/* Return the number of bytes required to save VFP registers. */ +static int +arm_get_vfp_saved_size (void) +{ + unsigned int regno; + int count; + int saved; + + saved = 0; + /* Space for saved VFP registers. */ + if (TARGET_HARD_FLOAT && TARGET_VFP) + { + count = 0; + for (regno = FIRST_VFP_REGNUM; + regno < LAST_VFP_REGNUM; + regno += 2) + { + if ((!regs_ever_live[regno] || call_used_regs[regno]) + && (!regs_ever_live[regno + 1] || call_used_regs[regno + 1])) + { + if (count > 0) + { + /* Workaround ARM10 VFPr1 bug. */ + if (count == 2 && !arm_arch6) + count++; + saved += count * 8 + 4; + } + count = 0; + } + else + count++; + } + if (count > 0) + { + if (count == 2 && !arm_arch6) + count++; + saved += count * 8 + 4; + } + } + return saved; +} + + /* Generate a function exit sequence. If REALLY_RETURN is false, then do everything bar the final return instruction. */ const char * @@ -9306,34 +9369,15 @@ arm_output_epilogue (rtx sibling) if (TARGET_HARD_FLOAT && TARGET_VFP) { - int nregs = 0; + int saved_size; - /* We save regs in pairs. */ - /* A special insn for saving/restoring VFP registers. This does - not have base+offset addressing modes, so we use IP to - hold the address. Each block requires nregs*2+1 words. */ - start_reg = FIRST_VFP_REGNUM; - /* Count how many blocks of registers need saving. */ - for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2) - { - if ((!regs_ever_live[reg] || call_used_regs[reg]) - && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) - { - if (start_reg != reg) - floats_offset += 4; - start_reg = reg + 2; - } - else - { - floats_offset += 8; - nregs++; - } - } - if (start_reg != reg) - floats_offset += 4; + /* The fldmx insn does not have base+offset addressing modes, + so we use IP to hold the address. */ + saved_size = arm_get_vfp_saved_size (); - if (nregs > 0) + if (saved_size > 0) { + floats_offset += saved_size; asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM, FP_REGNUM, floats_offset - vfp_offset); } @@ -9344,20 +9388,16 @@ arm_output_epilogue (rtx sibling) && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) { if (start_reg != reg) - { - vfp_print_multi (f, "fldmfdx\t%r!", IP_REGNUM, "d%d", - (start_reg - FIRST_VFP_REGNUM) / 2, - (reg - start_reg) / 2); - } + arm_output_fldmx (f, IP_REGNUM, + (start_reg - FIRST_VFP_REGNUM) / 2, + (reg - start_reg) / 2); start_reg = reg + 2; } } if (start_reg != reg) - { - vfp_print_multi (f, "fldmfdx\t%r!", IP_REGNUM, "d%d", - (start_reg - FIRST_VFP_REGNUM) / 2, - (reg - start_reg) / 2); - } + arm_output_fldmx (f, IP_REGNUM, + (start_reg - FIRST_VFP_REGNUM) / 2, + (reg - start_reg) / 2); } if (TARGET_IWMMXT) @@ -9478,20 +9518,16 @@ arm_output_epilogue (rtx sibling) && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) { if (start_reg != reg) - { - vfp_print_multi (f, "fldmfdx\t%r!", SP_REGNUM, "d%d", - (start_reg - FIRST_VFP_REGNUM) / 2, - (reg - start_reg) / 2); - } + arm_output_fldmx (f, SP_REGNUM, + (start_reg - FIRST_VFP_REGNUM) / 2, + (reg - start_reg) / 2); start_reg = reg + 2; } } if (start_reg != reg) - { - vfp_print_multi (f, "fldmfdx\t%r!", SP_REGNUM, "d%d", - (start_reg - FIRST_VFP_REGNUM) / 2, - (reg - start_reg) / 2); - } + arm_output_fldmx (f, SP_REGNUM, + (start_reg - FIRST_VFP_REGNUM) / 2, + (reg - start_reg) / 2); } if (TARGET_IWMMXT) for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++) @@ -9855,7 +9891,6 @@ arm_get_frame_offsets (void) struct arm_stack_offsets *offsets; unsigned long func_type; int leaf; - bool new_block; int saved; HOST_WIDE_INT frame_size; @@ -9915,27 +9950,7 @@ arm_get_frame_offsets (void) /* Space for saved VFP registers. */ if (TARGET_HARD_FLOAT && TARGET_VFP) - { - new_block = TRUE; - for (regno = FIRST_VFP_REGNUM; - regno < LAST_VFP_REGNUM; - regno += 2) - { - if ((regs_ever_live[regno] && !call_used_regs[regno]) - || (regs_ever_live[regno + 1] - && !call_used_regs[regno + 1])) - { - if (new_block) - { - saved += 4; - new_block = FALSE; - } - saved += 8; - } - else - new_block = TRUE; - } - } + saved += arm_get_vfp_saved_size (); } } else /* TARGET_THUMB */ @@ -10317,22 +10332,14 @@ arm_expand_prologue (void) && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) { if (start_reg != reg) - { - insn = vfp_emit_fstmx (start_reg, - (reg - start_reg) / 2); - RTX_FRAME_RELATED_P (insn) = 1; - saved_regs += (start_reg - reg) * 4 + 4; - } + saved_regs += vfp_emit_fstmx (start_reg, + (reg - start_reg) / 2); start_reg = reg + 2; } } if (start_reg != reg) - { - insn = vfp_emit_fstmx (start_reg, - (reg - start_reg) / 2); - RTX_FRAME_RELATED_P (insn) = 1; - saved_regs += (start_reg - reg) * 4 + 4; - } + saved_regs += vfp_emit_fstmx (start_reg, + (reg - start_reg) / 2); } } -- 2.30.2