Commit 9728c9d1 by Paul Brook Committed by Paul Brook

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
parent 32f4b1ed
2004-03-25 Paul Brook <paul@codesourcery.com>
* 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 <rth@redhat.com> 2004-03-24 Richard Henderson <rth@redhat.com>
* alias.c (alias_invariant, alias_invariant_size): Mark GTY. * alias.c (alias_invariant, alias_invariant_size): Mark GTY.
......
...@@ -7809,29 +7809,35 @@ print_multi_reg (FILE *stream, const char *instr, int reg, int mask) ...@@ -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. /* Output a FLDMX instruction to STREAM.
REG is the base register, BASE if the register containing the address.
INSTR is the possibly suffixed load or store instruction. REG and COUNT specify the register range.
FMT specifies now to print the register name. Extra registers may be added to avoid hardware bugs. */
START and COUNT specify the register range. */
static void static void
vfp_print_multi (FILE *stream, const char *instr, int reg, arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
const char * fmt, int start, int count)
{ {
int i; int i;
/* Workaround ARM10 VFPr1 bug. */
if (count == 2 && !arm_arch6)
{
if (reg == 15)
reg--;
count++;
}
fputc ('\t', stream); fputc ('\t', stream);
asm_fprintf (stream, instr, reg); asm_fprintf (stream, "fldmfdx\t%r!, {", base);
fputs (", {", stream);
for (i = start; i < start + count; i++) for (i = reg; i < reg + count; i++)
{ {
if (i > start) if (i > reg)
fputs (", ", stream); fputs (", ", stream);
asm_fprintf (stream, fmt, i); asm_fprintf (stream, "d%d", i);
} }
fputs ("}\n", stream); fputs ("}\n", stream);
} }
...@@ -7863,9 +7869,10 @@ vfp_output_fstmx (rtx * operands) ...@@ -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) vfp_emit_fstmx (int base_reg, int count)
{ {
rtx par; rtx par;
...@@ -7873,6 +7880,16 @@ vfp_emit_fstmx (int base_reg, int count) ...@@ -7873,6 +7880,16 @@ vfp_emit_fstmx (int base_reg, int count)
rtx tmp, reg; rtx tmp, reg;
int i; 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 /* ??? 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).
We really need some way of representing the whole block so that the 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) ...@@ -7922,7 +7939,9 @@ vfp_emit_fstmx (int base_reg, int count)
par = emit_insn (par); par = emit_insn (par);
REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
REG_NOTES (par)); 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) ...@@ -8864,6 +8883,50 @@ arm_compute_save_reg_mask (void)
return save_reg_mask; 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 /* Generate a function exit sequence. If REALLY_RETURN is false, then do
everything bar the final return instruction. */ everything bar the final return instruction. */
const char * const char *
...@@ -9306,34 +9369,15 @@ arm_output_epilogue (rtx sibling) ...@@ -9306,34 +9369,15 @@ arm_output_epilogue (rtx sibling)
if (TARGET_HARD_FLOAT && TARGET_VFP) if (TARGET_HARD_FLOAT && TARGET_VFP)
{ {
int nregs = 0; int saved_size;
/* We save regs in pairs. */ /* The fldmx insn does not have base+offset addressing modes,
/* A special insn for saving/restoring VFP registers. This does so we use IP to hold the address. */
not have base+offset addressing modes, so we use IP to saved_size = arm_get_vfp_saved_size ();
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;
if (nregs > 0) if (saved_size > 0)
{ {
floats_offset += saved_size;
asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM, asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
FP_REGNUM, floats_offset - vfp_offset); FP_REGNUM, floats_offset - vfp_offset);
} }
...@@ -9344,20 +9388,16 @@ arm_output_epilogue (rtx sibling) ...@@ -9344,20 +9388,16 @@ arm_output_epilogue (rtx sibling)
&& (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
{ {
if (start_reg != reg) if (start_reg != reg)
{ arm_output_fldmx (f, IP_REGNUM,
vfp_print_multi (f, "fldmfdx\t%r!", IP_REGNUM, "d%d", (start_reg - FIRST_VFP_REGNUM) / 2,
(start_reg - FIRST_VFP_REGNUM) / 2, (reg - start_reg) / 2);
(reg - start_reg) / 2);
}
start_reg = reg + 2; start_reg = reg + 2;
} }
} }
if (start_reg != reg) if (start_reg != reg)
{ arm_output_fldmx (f, IP_REGNUM,
vfp_print_multi (f, "fldmfdx\t%r!", IP_REGNUM, "d%d", (start_reg - FIRST_VFP_REGNUM) / 2,
(start_reg - FIRST_VFP_REGNUM) / 2, (reg - start_reg) / 2);
(reg - start_reg) / 2);
}
} }
if (TARGET_IWMMXT) if (TARGET_IWMMXT)
...@@ -9478,20 +9518,16 @@ arm_output_epilogue (rtx sibling) ...@@ -9478,20 +9518,16 @@ arm_output_epilogue (rtx sibling)
&& (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
{ {
if (start_reg != reg) if (start_reg != reg)
{ arm_output_fldmx (f, SP_REGNUM,
vfp_print_multi (f, "fldmfdx\t%r!", SP_REGNUM, "d%d", (start_reg - FIRST_VFP_REGNUM) / 2,
(start_reg - FIRST_VFP_REGNUM) / 2, (reg - start_reg) / 2);
(reg - start_reg) / 2);
}
start_reg = reg + 2; start_reg = reg + 2;
} }
} }
if (start_reg != reg) if (start_reg != reg)
{ arm_output_fldmx (f, SP_REGNUM,
vfp_print_multi (f, "fldmfdx\t%r!", SP_REGNUM, "d%d", (start_reg - FIRST_VFP_REGNUM) / 2,
(start_reg - FIRST_VFP_REGNUM) / 2, (reg - start_reg) / 2);
(reg - start_reg) / 2);
}
} }
if (TARGET_IWMMXT) if (TARGET_IWMMXT)
for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++) for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
...@@ -9855,7 +9891,6 @@ arm_get_frame_offsets (void) ...@@ -9855,7 +9891,6 @@ arm_get_frame_offsets (void)
struct arm_stack_offsets *offsets; struct arm_stack_offsets *offsets;
unsigned long func_type; unsigned long func_type;
int leaf; int leaf;
bool new_block;
int saved; int saved;
HOST_WIDE_INT frame_size; HOST_WIDE_INT frame_size;
...@@ -9915,27 +9950,7 @@ arm_get_frame_offsets (void) ...@@ -9915,27 +9950,7 @@ arm_get_frame_offsets (void)
/* Space for saved VFP registers. */ /* Space for saved VFP registers. */
if (TARGET_HARD_FLOAT && TARGET_VFP) if (TARGET_HARD_FLOAT && TARGET_VFP)
{ saved += arm_get_vfp_saved_size ();
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;
}
}
} }
} }
else /* TARGET_THUMB */ else /* TARGET_THUMB */
...@@ -10317,22 +10332,14 @@ arm_expand_prologue (void) ...@@ -10317,22 +10332,14 @@ arm_expand_prologue (void)
&& (!regs_ever_live[reg + 1] || call_used_regs[reg + 1])) && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
{ {
if (start_reg != reg) if (start_reg != reg)
{ saved_regs += vfp_emit_fstmx (start_reg,
insn = vfp_emit_fstmx (start_reg, (reg - start_reg) / 2);
(reg - start_reg) / 2);
RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += (start_reg - reg) * 4 + 4;
}
start_reg = reg + 2; start_reg = reg + 2;
} }
} }
if (start_reg != reg) if (start_reg != reg)
{ saved_regs += vfp_emit_fstmx (start_reg,
insn = vfp_emit_fstmx (start_reg, (reg - start_reg) / 2);
(reg - start_reg) / 2);
RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += (start_reg - reg) * 4 + 4;
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment