This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: head: MIPS: A workaround for the R4000 divide/shift errata


On Mon, 23 Feb 2004, Maciej W. Rozycki wrote:

>  You are right here and this indeed convinces me.  I'll prepare an update 
> to this patch first.

 Here it is.

2004-02-24  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>

	* gcc/config/mips/mips.h (MASK_FIX_4000): New flag for workarounds 
	for R4000 errata.
	(TARGET_FIX_4000): New macro to control the workarounds.
	(TARGET_SWITCHES): Add "fix-4000" and "no-fix-4000" to control the 
	workarounds.
	gcc/config/mips/mips.c (mips_output_division): Add a workaround
	for the R4000 divide/shift errata.
	(mips_idiv_insns): New function.
	gcc/config/mips/mips.md (length): Use mips_idiv_insns() for 
	calculation for "idiv".
	doc/invoke.texi: Document the new switches.

 I've updated mips_output_division() to match reality -- if
TARGET_CHECK_ZERO_DIV and no TARGET_MIPS16 gas swaps the division and the
branch, so the target of the branch executes immediately after the
division.  So a "nop" is needed in this case as well.

 This leads to another conclusion -- the instruction count as calculated
by mips_idiv_insns() is too high by one in this case.  But so is the
current calculation, so we can discuss it separately.  As the swapping may 
be gas version-dependent, I suppose we might do that unconditionally in 
gcc.

  Maciej

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: macro@ds2.pg.gda.pl, PGP key available        +

gcc-3.4-20031107-mips-r4000-div.patch
diff -up --recursive --new-file gcc-3.4-20031107.macro/gcc/config/mips/mips.c gcc-3.4-20031107/gcc/config/mips/mips.c
--- gcc-3.4-20031107.macro/gcc/config/mips/mips.c	2003-11-07 08:14:32.000000000 +0000
+++ gcc-3.4-20031107/gcc/config/mips/mips.c	2004-02-24 06:20:26.000000000 +0000
@@ -1245,6 +1245,27 @@ mips_fetch_insns (rtx x)
 }
 
 
+/* Return the number of instructions needed for an integer division.  */
+
+int
+mips_idiv_insns (void)
+{
+  int count;
+
+  count = 1;
+  if (TARGET_CHECK_ZERO_DIV)
+    {
+      if (TARGET_MIPS16)
+	count += 2;
+      else
+	count += 3;
+    }
+  if (TARGET_FIX_4000)
+    count++;
+  return count;
+}
+
+
 /* Return truth value of whether OP can be used as an operands
    where a register or 16 bit unsigned integer is needed.  */
 
@@ -5000,6 +5021,12 @@ override_options (void)
       mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
       mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
     }
+
+  /* Default to working around R4000 errata only if the processor
+     was selected explicitly.  */
+  if ((target_flags_explicit & MASK_FIX_4000) == 0
+      && mips_matching_cpu_name_p (mips_arch_info->name, "r4000"))
+    target_flags |= MASK_FIX_4000;
 }
 
 /* Implement CONDITIONAL_REGISTER_USAGE.  */
@@ -9052,21 +9079,37 @@ mips_output_conditional_branch (rtx insn
 /* Used to output div or ddiv instruction DIVISION, which has the
    operands given by OPERANDS.  If we need a divide-by-zero check,
    output the instruction and return an asm string that traps if
-   operand 2 is zero.  Otherwise just return DIVISION itself.  */
+   operand 2 is zero.
+
+   The original R4000 has a cpu bug.  If a double-word or a variable
+   shift executes immediately after starting an integer division, the
+   shift may give an incorrect result.  Avoid this by adding a nop on
+   the R4000.  See quotations of errata #16 and #28 from "MIPS
+   R4000PC/SC Errata, Processor Revision 2.2 and 3.0" in mips.md for
+   details.
+
+   Otherwise just return DIVISION itself.  */
 
 const char *
 mips_output_division (const char *division, rtx *operands)
 {
+  const char *s = division;
+
   if (TARGET_CHECK_ZERO_DIV)
     {
-      output_asm_insn (division, operands);
+      output_asm_insn (s, operands);
 
       if (TARGET_MIPS16)
-	return "bnez\t%2,1f\n\tbreak\t7\n1:";
+	s = "bnez\t%2,1f\n\tbreak\t7\n1:";
       else
-	return "bne\t%2,%.,1f%#\n\tbreak\t7\n1:";
+	s = "bne\t%2,%.,1f%#\n\tbreak\t7\n1:";
+    }
+  if (TARGET_FIX_4000)
+    {
+      output_asm_insn (s, operands);
+      s = "nop";
     }
-  return division;
+  return s;
 }
 
 /* Return true if GIVEN is the same as CANONICAL, or if it is CANONICAL
diff -up --recursive --new-file gcc-3.4-20031107.macro/gcc/config/mips/mips.h gcc-3.4-20031107/gcc/config/mips/mips.h
--- gcc-3.4-20031107.macro/gcc/config/mips/mips.h	2003-11-04 22:13:30.000000000 +0000
+++ gcc-3.4-20031107/gcc/config/mips/mips.h	2004-02-23 21:33:02.000000000 +0000
@@ -170,6 +170,7 @@ extern const struct mips_cpu_info *mips_
 			   0x00800000	/* Store uninitialized
 					   consts in rodata */
 #define MASK_FIX_SB1       0x01000000   /* Work around SB-1 errata. */
+#define MASK_FIX_4000	   0x02000000	/* Work around R4000 errata.  */
 
 					/* Debug switches, not documented */
 #define MASK_DEBUG	0		/* unused */
@@ -258,6 +259,9 @@ extern const struct mips_cpu_info *mips_
 
 #define TARGET_FIX_SB1		(target_flags & MASK_FIX_SB1)
 
+					/* Work around R4000 errata.  */
+#define TARGET_FIX_4000		(target_flags & MASK_FIX_4000)
+
 /* True if we should use NewABI-style relocation operators for
    symbolic addresses.  This is never true for mips16 code,
    which has its own conventions.  */
@@ -591,6 +595,10 @@ extern const struct mips_cpu_info *mips_
      N_("Work around errata for early SB-1 revision 2 cores")},		\
   {"no-fix-sb1",         -MASK_FIX_SB1,					\
      N_("Don't work around errata for early SB-1 revision 2 cores")},	\
+  {"fix-4000",		  MASK_FIX_4000,				\
+     N_("Work around R4000 errata")},					\
+  {"no-fix-4000",	 -MASK_FIX_4000,				\
+     N_("Don't work around R4000 errata")},				\
   {"check-zero-division",-MASK_NO_CHECK_ZERO_DIV,			\
      N_("Trap on integer divide by zero")},				\
   {"no-check-zero-division", MASK_NO_CHECK_ZERO_DIV,			\
diff -up --recursive --new-file gcc-3.4-20031107.macro/gcc/config/mips/mips.md gcc-3.4-20031107/gcc/config/mips/mips.md
--- gcc-3.4-20031107.macro/gcc/config/mips/mips.md	2003-11-07 08:14:32.000000000 +0000
+++ gcc-3.4-20031107/gcc/config/mips/mips.md	2004-02-24 06:31:22.000000000 +0000
@@ -200,11 +200,8 @@
 	       (ne (symbol_ref "TARGET_MIPS16") (const_int 0)))
 	  (const_int 8)
 
-	  (and (eq_attr "type" "idiv")
-	       (ne (symbol_ref "TARGET_CHECK_ZERO_DIV") (const_int 0)))
-	  (cond [(ne (symbol_ref "TARGET_MIPS16") (const_int 0))
-		 (const_int 12)]
-		(const_int 16))
+	  (eq_attr "type" "idiv")
+	  (symbol_ref "mips_idiv_insns () * 4")
 	  ] (const_int 4)))
 
 ;; Attribute describing the processor.  This attribute must match exactly
diff -up --recursive --new-file gcc-3.4-20031107.macro/gcc/doc/invoke.texi gcc-3.4-20031107/gcc/doc/invoke.texi
--- gcc-3.4-20031107.macro/gcc/doc/invoke.texi	2003-11-03 21:44:14.000000000 +0000
+++ gcc-3.4-20031107/gcc/doc/invoke.texi	2004-02-23 21:31:42.000000000 +0000
@@ -490,7 +490,7 @@ in the following sections.
 -m4650  -msingle-float  -mmad @gol
 -EL  -EB  -G @var{num}  -nocpp @gol
 -mabi=32  -mabi=n32  -mabi=64  -mabi=eabi  -mabi-fake-default @gol
--mfix7000  -mfix-sb1  -mno-fix-sb1 @gol
+-mfix7000  -mfix-sb1  -mno-fix-sb1  -mfix-4000  -mno-fix-4000 @gol
 -mno-crt0 -mflush-func=@var{func} -mno-flush-func @gol
 -mbranch-likely -mno-branch-likely}
 
@@ -8447,6 +8447,17 @@ Work around certain SB-1 CPU core errata
 (This flag currently works around the SB-1 revision 2
 ``F1'' and ``F2'' floating point errata.)
 
+@item -mfix-4000
+@itemx -mno-fix-4000
+@opindex mfix-4000
+@opindex mno-fix-4000
+Work around certain R4000 CPU errata:
+@itemize @minus
+@item
+A double-word or a variable shift may give an incorrect result if executed
+immediately after starting an integer division.
+@end itemize
+
 @item -no-crt0
 @opindex no-crt0
 Do not include the default crt0.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]