From 0eaca434ca26e585c3d61781f006859981850551 Mon Sep 17 00:00:00 2001 From: rsandifo Date: Wed, 3 Mar 2004 08:59:31 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@78825 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 13 ++++++ gcc/config/mips/mips.c | 119 +++++++++++++++++++++++++++++++++++++++++-------- gcc/config/mips/mips.h | 10 ++++- gcc/doc/invoke.texi | 17 ++++++- 4 files changed, 138 insertions(+), 21 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e5e5266..e812431 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-03-03 Maciej W. Rozycki + Richard Sandiford + + * 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 * alias.c (rtx_equal_for_memref_p): Use predicates diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index ee69fa3..bfd5970 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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. - - 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. */ +/* Used to output div or ddiv instruction DIVISION, which has the operands + given by OPERANDS. Add in a divide-by-zero check if needed. + + 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. + + [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; } diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 585b6f1..d2612c9 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -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, \ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a3e6232..4fb703c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 -- 2.7.4