From 4649040309b011c972e0ffbd0e1c336cb490eed3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sat, 28 Feb 2004 20:59:24 +0100 Subject: [PATCH] mips-protos.h (mips_idiv_insns): Declare. * config/mips/mips-protos.h (mips_idiv_insns): Declare. * config/mips/mips.h (MASK_FIX_SB1): Bump. (MASK_FIX_R4000, TARGET_FIX_R4000): New macros. (TARGET_SWITCHES): Add -mfix-r4000 and -mno-fix-r4000. * config/mips/mips.c (mips_idiv_insns): New function. (override_options): Make -march=r4000 imply -mfix-r4000 by default. (mips_output_division): Add a workaround for the R4000 divide/shift errata. * config/mips/mips.md (length): Use mips_idiv_insns() to calculate the length of an "idiv" instruction. * doc/invoke.texi: Document the new switches. From-SVN: r78621 --- gcc/ChangeLog | 14 +++++++++ gcc/config/mips/mips-protos.h | 1 + gcc/config/mips/mips.c | 53 +++++++++++++++++++++++++++++++---- gcc/config/mips/mips.h | 10 ++++++- gcc/config/mips/mips.md | 7 ++--- gcc/doc/invoke.texi | 16 +++++++++-- 6 files changed, 88 insertions(+), 13 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 21e6db059dc..417c0127010 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2004-02-28 Maciej W. Rozycki + + * config/mips/mips-protos.h (mips_idiv_insns): Declare. + * config/mips/mips.h (MASK_FIX_SB1): Bump. + (MASK_FIX_R4000, TARGET_FIX_R4000): New macros. + (TARGET_SWITCHES): Add -mfix-r4000 and -mno-fix-r4000. + * config/mips/mips.c (mips_idiv_insns): New function. + (override_options): Make -march=r4000 imply -mfix-r4000 by default. + (mips_output_division): Add a workaround for the R4000 divide/shift + errata. + * config/mips/mips.md (length): Use mips_idiv_insns() to calculate + the length of an "idiv" instruction. + * doc/invoke.texi: Document the new switches. + 2004-02-28 Kazu Hirata * doc/tm.texi (IS_COSTLY_DEPENDENCE): Change to diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 222c93d3b3f..b5128ba5830 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -30,6 +30,7 @@ extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, int); extern int mips_address_insns (rtx, enum machine_mode); extern int mips_const_insns (rtx); extern int mips_fetch_insns (rtx); +extern int mips_idiv_insns (void); extern bool mips_legitimate_address_p (enum machine_mode, rtx, int); extern bool mips_legitimize_address (rtx *, enum machine_mode); extern rtx mips_gotoff_page (rtx); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 852a8c8ba39..84494c2eb55 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -1350,6 +1350,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_R4000) + 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. */ @@ -5111,6 +5132,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_R4000) == 0 + && mips_matching_cpu_name_p (mips_arch_info->name, "r4000")) + target_flags |= MASK_FIX_R4000; } /* Implement CONDITIONAL_REGISTER_USAGE. */ @@ -9185,21 +9212,37 @@ mips_output_conditional_branch (rtx insn, rtx *operands, int two_operands_p, /* 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_R4000) + { + 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 --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index e404d3dc1a3..9c9ab0e8a1b 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -169,7 +169,8 @@ extern const struct mips_cpu_info *mips_tune_info; #define MASK_UNINIT_CONST_IN_RODATA \ 0x00800000 /* Store uninitialized consts in rodata */ -#define MASK_FIX_SB1 0x01000000 /* Work around SB-1 errata. */ +#define MASK_FIX_R4000 0x01000000 /* Work around R4000 errata. */ +#define MASK_FIX_SB1 0x02000000 /* Work around SB-1 errata. */ /* Debug switches, not documented */ #define MASK_DEBUG 0 /* unused */ @@ -248,6 +249,9 @@ extern const struct mips_cpu_info *mips_tune_info; #define TARGET_FIX_SB1 (target_flags & MASK_FIX_SB1) + /* Work around R4000 errata. */ +#define TARGET_FIX_R4000 (target_flags & MASK_FIX_R4000) + /* True if we should use NewABI-style relocation operators for symbolic addresses. This is never true for mips16 code, which has its own conventions. */ @@ -588,6 +592,10 @@ extern const struct mips_cpu_info *mips_tune_info; 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-r4000", MASK_FIX_R4000, \ + N_("Work around R4000 errata")}, \ + {"no-fix-r4000", -MASK_FIX_R4000, \ + 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 --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index ae6b8985391..5b6af02c2de 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -204,11 +204,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 --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index dcf11d70723..35443329758 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -478,8 +478,9 @@ 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-sb1 -mno-fix-sb1 -mflush-func=@var{func} @gol --mno-flush-func -mbranch-likely -mno-branch-likely} +-mfix-r4000 -mno-fix-r4000 -mfix-sb1 -mno-fix-sb1 @gol +-mflush-func=@var{func} -mno-flush-func @gol +-mbranch-likely -mno-branch-likely} @emph{i386 and x86-64 Options} @gccoptlist{-mtune=@var{cpu-type} -march=@var{cpu-type} @gol @@ -8045,6 +8046,17 @@ circumstances. Tell the MIPS assembler to not run its preprocessor over user assembler files (with a @samp{.s} suffix) when assembling them. +@item -mfix-r4000 +@itemx -mno-fix-r4000 +@opindex mfix-r4000 +@opindex mno-fix-r4000 +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 -mfix-sb1 @itemx -mno-fix-sb1 @opindex mfix-sb1 -- 2.30.2