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:
parent
ec8e098d3d
commit
6ba7b54780
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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, \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user