This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: head: MIPS: A workaround for the R4000 divide/shift errata
- From: "Maciej W. Rozycki" <macro at ds2 dot pg dot gda dot pl>
- To: Richard Sandiford <rsandifo at redhat dot com>
- Cc: Eric Christopher <echristo at redhat dot com>,binutils at sources dot redhat dot com
- Date: Tue, 24 Feb 2004 08:49:19 +0100 (CET)
- Subject: Re: head: MIPS: A workaround for the R4000 divide/shift errata
- Organization: Technical University of Gdansk
- References: <Pine.LNX.4.55.0402191819520.3794@jurand.ds.pg.gda.pl><87hdxmizre.fsf@redhat.com> <Pine.LNX.4.55.0402192203320.3794@jurand.ds.pg.gda.pl><87brnumzht.fsf@redhat.com> <mailpost.1077233012.25220@news-sj1-1><yov5d68aab2x.fsf@ldt-sj3-010.sj.broadcom.com> <yov58yiyaay8.fsf@ldt-sj3-010.sj.broadcom.com><1077234678.4140.19.camel@dzur.sfbay.redhat.com><Pine.LNX.4.55.0402201608080.29033@jurand.ds.pg.gda.pl> <87brnr8p8w.fsf@redhat.com><Pine.LNX.4.55.0402221641340.26503@jurand.ds.pg.gda.pl><yov51xomd26d.fsf@ldt-sj3-010.sj.broadcom.com> <1077507519.3636.39.camel@dzur.sfbay.redhat.com><87r7wmxl71.fsf@redhat.com> <Pine.LNX.4.55.0402231340020.1245@jurand.ds.pg.gda.pl>
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.