mips.h (MASK_FIX_SB1): Bump.

* config/mips/mips.h (MASK_FIX_SB1): Bump.
	(MASK_FIX_R4400, TARGET_FIX_R4400): New macros.
	(TARGET_SWITCHES): Add -mfix-r4400 and -mno-fix-r4400.
	* config/mips/mips.c (mips_output_division): Fill the branch delay
	slot with a nop if TARGET_FIX_R4000.  Extend R4000 workarounds to
	TARGET_FIX_R4400.
	(mips_output_division): Adjust accordingly.
	(override_options): Make -march=r4400 imply -mfix-r4400 by default.
	* doc/invoke.texi: Document -mfix-r4400 and new errata workarounds.

Co-Authored-By: Richard Sandiford <rsandifo@redhat.com>

From-SVN: r78825
This commit is contained in:
Maciej W. Rozycki 2004-03-03 09:59:31 +01:00 committed by Richard Sandiford
parent ec8e098d3d
commit 6ba7b54780
4 changed files with 136 additions and 19 deletions

View File

@ -1,3 +1,16 @@
2004-03-03 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
Richard Sandiford <rsandifo@redhat.com>
* config/mips/mips.h (MASK_FIX_SB1): Bump.
(MASK_FIX_R4400, TARGET_FIX_R4400): New macros.
(TARGET_SWITCHES): Add -mfix-r4400 and -mno-fix-r4400.
* config/mips/mips.c (mips_output_division): Fill the branch delay
slot with a nop if TARGET_FIX_R4000. Extend R4000 workarounds to
TARGET_FIX_R4400.
(mips_output_division): Adjust accordingly.
(override_options): Make -march=r4400 imply -mfix-r4400 by default.
* doc/invoke.texi: Document -mfix-r4400 and new errata workarounds.
2004-03-03 Paolo Bonzini <bonzini@gnu.org>
* alias.c (rtx_equal_for_memref_p): Use predicates

View File

@ -1321,7 +1321,7 @@ mips_idiv_insns (void)
count = 1;
if (TARGET_CHECK_ZERO_DIV)
count += 2;
if (TARGET_FIX_R4000)
if (TARGET_FIX_R4000 || TARGET_FIX_R4400)
count++;
return count;
}
@ -5101,6 +5101,12 @@ override_options (void)
if ((target_flags_explicit & MASK_FIX_R4000) == 0
&& mips_matching_cpu_name_p (mips_arch_info->name, "r4000"))
target_flags |= MASK_FIX_R4000;
/* Default to working around R4400 errata only if the processor
was selected explicitly. */
if ((target_flags_explicit & MASK_FIX_R4400) == 0
&& mips_matching_cpu_name_p (mips_arch_info->name, "r4400"))
target_flags |= MASK_FIX_R4400;
}
/* Implement CONDITIONAL_REGISTER_USAGE. */
@ -9171,19 +9177,94 @@ mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p,
return 0;
}
/* 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.
/* Used to output div or ddiv instruction DIVISION, which has the operands
given by OPERANDS. Add in a divide-by-zero check if needed.
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.
When working around R4000 and R4400 errata, we need to make sure that
the division is not immediately followed by a shift[1][2]. We also
need to stop the division from being put into a branch delay slot[3].
The easiest way to avoid both problems is to add a nop after the
division. When a divide-by-zero check is neeeded, this nop can be
used to fill the branch delay slot.
Otherwise just return DIVISION itself. */
[1] If a double-word or a variable shift executes immediately
after starting an integer division, the shift may give an
incorrect result. See quotations of errata #16 and #28 from
"MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0"
in mips.md for details.
[2] A similar bug to [1] exists for all revisions of the
R4000 and the R4400 when run in an MC configuration.
From "MIPS R4000MC Errata, Processor Revision 2.2 and 3.0":
"19. In this following sequence:
ddiv (or ddivu or div or divu)
dsll32 (or dsrl32, dsra32)
if an MPT stall occurs, while the divide is slipping the cpu
pipeline, then the following double shift would end up with an
incorrect result.
Workaround: The compiler needs to avoid generating any
sequence with divide followed by extended double shift."
This erratum is also present in "MIPS R4400MC Errata, Processor
Revision 1.0" and "MIPS R4400MC Errata, Processor Revision 2.0
& 3.0" as errata #10 and #4, respectively.
[3] From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0"
(also valid for MIPS R4000MC processors):
"52. R4000SC: This bug does not apply for the R4000PC.
There are two flavors of this bug:
1) If the instruction just after divide takes an RF exception
(tlb-refill, tlb-invalid) and gets an instruction cache
miss (both primary and secondary) and the line which is
currently in secondary cache at this index had the first
data word, where the bits 5..2 are set, then R4000 would
get a wrong result for the div.
##1
nop
div r8, r9
------------------- # end-of page. -tlb-refill
nop
##2
nop
div r8, r9
------------------- # end-of page. -tlb-invalid
nop
2) If the divide is in the taken branch delay slot, where the
target takes RF exception and gets an I-cache miss for the
exception vector or where I-cache miss occurs for the
target address, under the above mentioned scenarios, the
div would get wrong results.
##1
j r2 # to next page mapped or unmapped
div r8,r9 # this bug would be there as long
# as there is an ICache miss and
nop # the "data pattern" is present
##2
beq r0, r0, NextPage # to Next page
div r8,r9
nop
This bug is present for div, divu, ddiv, and ddivu
instructions.
Workaround: For item 1), OS could make sure that the next page
after the divide instruction is also mapped. For item 2), the
compiler could make sure that the divide instruction is not in
the branch delay slot."
These processors have PRId values of 0x00004220 and 0x00004300 for
the R4000 and 0x00004400, 0x00004500 and 0x00004600 for the R4400. */
const char *
mips_output_division (const char *division, rtx *operands)
@ -9191,6 +9272,11 @@ mips_output_division (const char *division, rtx *operands)
const char *s;
s = division;
if (TARGET_FIX_R4000 || TARGET_FIX_R4400)
{
output_asm_insn (s, operands);
s = "nop";
}
if (TARGET_CHECK_ZERO_DIV)
{
if (TARGET_MIPS16)
@ -9205,11 +9291,6 @@ mips_output_division (const char *division, rtx *operands)
s = "break\t7%)\n1:";
}
}
if (TARGET_FIX_R4000)
{
output_asm_insn (s, operands);
s = "nop";
}
return s;
}

View File

@ -170,7 +170,8 @@ extern const struct mips_cpu_info *mips_tune_info;
0x00800000 /* Store uninitialized
consts in rodata */
#define MASK_FIX_R4000 0x01000000 /* Work around R4000 errata. */
#define MASK_FIX_SB1 0x02000000 /* Work around SB-1 errata. */
#define MASK_FIX_R4400 0x02000000 /* Work around R4400 errata. */
#define MASK_FIX_SB1 0x04000000 /* Work around SB-1 errata. */
/* Debug switches, not documented */
#define MASK_DEBUG 0 /* unused */
@ -252,6 +253,9 @@ extern const struct mips_cpu_info *mips_tune_info;
/* Work around R4000 errata. */
#define TARGET_FIX_R4000 (target_flags & MASK_FIX_R4000)
/* Work around R4400 errata. */
#define TARGET_FIX_R4400 (target_flags & MASK_FIX_R4400)
/* True if we should use NewABI-style relocation operators for
symbolic addresses. This is never true for mips16 code,
which has its own conventions. */
@ -596,6 +600,10 @@ extern const struct mips_cpu_info *mips_tune_info;
N_("Work around R4000 errata")}, \
{"no-fix-r4000", -MASK_FIX_R4000, \
N_("Don't work around R4000 errata")}, \
{"fix-r4400", MASK_FIX_R4400, \
N_("Work around R4400 errata")}, \
{"no-fix-r4400", -MASK_FIX_R4400, \
N_("Don't work around R4400 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, \

View File

@ -478,7 +478,8 @@ in the following sections.
-mcheck-zero-division -mno-check-zero-division @gol
-mmemcpy -mno-memcpy -mlong-calls -mno-long-calls @gol
-mmad -mno-mad -mfused-madd -mno-fused-madd -nocpp @gol
-mfix-r4000 -mno-fix-r4000 -mfix-sb1 -mno-fix-sb1 @gol
-mfix-r4000 -mno-fix-r4000 -mfix-r4400 -mno-fix-r4400 @gol
-mfix-sb1 -mno-fix-sb1 @gol
-mflush-func=@var{func} -mno-flush-func @gol
-mbranch-likely -mno-branch-likely}
@ -8048,6 +8049,20 @@ immediately after starting an integer division.
@item
A double-word or a variable shift may give an incorrect result if executed
while an integer multiplication is in progress.
@item
An integer division may give an incorrect result if started in a delay slot
of a taken branch or a jump.
@end itemize
@item -mfix-r4400
@itemx -mno-fix-r4400
@opindex mfix-r4400
@opindex mno-fix-r4400
Work around certain R4400 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 -mfix-sb1