]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
arm.c (vfp_print_multi): Remove.
authorPaul Brook <paul@codesourcery.com>
Thu, 25 Mar 2004 11:36:57 +0000 (11:36 +0000)
committerPaul Brook <pbrook@gcc.gnu.org>
Thu, 25 Mar 2004 11:36:57 +0000 (11:36 +0000)
* 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
gcc/config/arm/arm.c

index f82691862eeeeacab77f7bc9a5afe9b78e238914..505adaca56e93d818972bd9ee3b34bbd39fc2a61 100644 (file)
@@ -1,3 +1,13 @@
+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>
 
        * alias.c (alias_invariant, alias_invariant_size): Mark GTY.
index a957a130f43f9f83e993158dfeb6ff165323d741..206647b1cb6411a12f1d8b3a30f9fbd86de22dea 100644 (file)
@@ -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);
        }
     }