From 99460684dc53681e5ed6bc116c9fdb436df1ae7c Mon Sep 17 00:00:00 2001 From: rsandifo Date: Sat, 28 Feb 2004 20:06:01 +0000 Subject: [PATCH] * config/mips/mips.md: Complete the unfinished R4000 multiply/shift errata workaround. Improve documentation. (hazard): Use TARGET_FIX_R4000 to decide whether an "imul" instruction has a hilo hazard. (mulsi3, mulsi3_internal, mulsi3_r4000): Use TARGET_FIX_R4000. (muldi3, muldi3_internal): Likewise. (muldi3_internal2): Remove, replacing with... (muldi3_mult3, muldi3_r4000): ...these new patterns. (mulsidi3): Take the errata into account. (mulsidi3_32bit): Remove, replacing with... (mulsidi3_32bit_internal, mulsidi3_32bit_r4000): ...these new patterns. (mulsidi3_64bit, mulsidi3_64bit_parts): Disable if TARGET_FIX_R4000. (umulsidi3): Take the errata into account. (umulsidi3_32bit): Remove, replacing with.. (umulsidi3_32bit_internal, umulsidi3_32bit_r4000): ...these patterns. (umulsi3_highpart, umulsi3_highpart_internal): Disable if TARGET_FIX_R4000. (smulsi3_highpart, smulsi3_highpart_internal): Likewise. (smuldi3_highpart, umuldi3_highpart): Likewise. * doc/invoke.texi: Document the errata workaround. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@78622 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 23 +++++++ gcc/config/mips/mips.md | 164 ++++++++++++++++++++++++++++++++++++------------ gcc/doc/invoke.texi | 3 + 3 files changed, 150 insertions(+), 40 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 417c012..91fc115 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,28 @@ 2004-02-28 Maciej W. Rozycki + * config/mips/mips.md: Complete the unfinished R4000 + multiply/shift errata workaround. Improve documentation. + (hazard): Use TARGET_FIX_R4000 to decide whether an "imul" instruction + has a hilo hazard. + (mulsi3, mulsi3_internal, mulsi3_r4000): Use TARGET_FIX_R4000. + (muldi3, muldi3_internal): Likewise. + (muldi3_internal2): Remove, replacing with... + (muldi3_mult3, muldi3_r4000): ...these new patterns. + (mulsidi3): Take the errata into account. + (mulsidi3_32bit): Remove, replacing with... + (mulsidi3_32bit_internal, mulsidi3_32bit_r4000): ...these new patterns. + (mulsidi3_64bit, mulsidi3_64bit_parts): Disable if TARGET_FIX_R4000. + (umulsidi3): Take the errata into account. + (umulsidi3_32bit): Remove, replacing with.. + (umulsidi3_32bit_internal, umulsidi3_32bit_r4000): ...these patterns. + (umulsi3_highpart, umulsi3_highpart_internal): Disable if + TARGET_FIX_R4000. + (smulsi3_highpart, smulsi3_highpart_internal): Likewise. + (smuldi3_highpart, umuldi3_highpart): Likewise. + * doc/invoke.texi: Document the errata workaround. + +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. diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 5b6af02..0858040 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -233,7 +233,7 @@ ;; The r4000 multiplication patterns include an mflo instruction. (and (eq_attr "type" "imul") - (ne (symbol_ref "TARGET_MIPS4000") (const_int 0))) + (ne (symbol_ref "TARGET_FIX_R4000") (const_int 0))) (const_string "hilo") (and (eq_attr "type" "hilo") @@ -1420,9 +1420,51 @@ (set_attr "length" "8")]) -;; ??? The R4000 (only) has a cpu bug. If a double-word shift executes while -;; a multiply is in progress, it may give an incorrect result. Avoid -;; this by keeping the mflo with the mult on the R4000. +;; The original R4000 has a cpu bug. If a double-word or a variable +;; shift executes while an integer multiplication is in progress, the +;; shift may give an incorrect result. Avoid this by keeping the mflo +;; with the mult on the R4000. +;; +;; From "MIPS R4000PC/SC Errata, Processor Revision 2.2 and 3.0" +;; (also valid for MIPS R4000MC processors): +;; +;; "16. R4000PC, R4000SC: Please refer to errata 28 for an update to +;; this errata description. +;; The following code sequence causes the R4000 to incorrectly +;; execute the Double Shift Right Arithmetic 32 (dsra32) +;; instruction. If the dsra32 instruction is executed during an +;; integer multiply, the dsra32 will only shift by the amount in +;; specified in the instruction rather than the amount plus 32 +;; bits. +;; instruction 1: mult rs,rt integer multiply +;; instruction 2-12: dsra32 rd,rt,rs doubleword shift +;; right arithmetic + 32 +;; Workaround: A dsra32 instruction placed after an integer +;; multiply should not be one of the 11 instructions after the +;; multiply instruction." +;; +;; and: +;; +;; "28. R4000PC, R4000SC: The text from errata 16 should be replaced by +;; the following description. +;; All extended shifts (shift by n+32) and variable shifts (32 and +;; 64-bit versions) may produce incorrect results under the +;; following conditions: +;; 1) An integer multiply is currently executing +;; 2) These types of shift instructions are executed immediately +;; following an integer divide instruction. +;; Workaround: +;; 1) Make sure no integer multiply is running wihen these +;; instruction are executed. If this cannot be predicted at +;; compile time, then insert a "mfhi" to R0 instruction +;; immediately after the integer multiply instruction. This +;; will cause the integer multiply to complete before the shift +;; is executed. +;; 2) Separate integer divide and these two classes of shift +;; instructions by another instruction or a noop." +;; +;; These processors have PRId values of 0x00004220 and 0x00004300, +;; respectively. (define_expand "mulsi3" [(set (match_operand:SI 0 "register_operand" "") @@ -1432,7 +1474,7 @@ { if (GENERATE_MULT3_SI || TARGET_MAD) emit_insn (gen_mulsi3_mult3 (operands[0], operands[1], operands[2])); - else if (!TARGET_MIPS4000 || TARGET_MIPS16) + else if (!TARGET_FIX_R4000) emit_insn (gen_mulsi3_internal (operands[0], operands[1], operands[2])); else emit_insn (gen_mulsi3_r4000 (operands[0], operands[1], operands[2])); @@ -1498,7 +1540,7 @@ (mult:SI (match_operand:SI 1 "register_operand" "d") (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SI 3 "=h"))] - "!TARGET_MIPS4000 || TARGET_MIPS16" + "!TARGET_FIX_R4000" "mult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI")]) @@ -1509,7 +1551,7 @@ (match_operand:SI 2 "register_operand" "d"))) (clobber (match_scratch:SI 3 "=h")) (clobber (match_scratch:SI 4 "=l"))] - "TARGET_MIPS4000 && !TARGET_MIPS16" + "TARGET_FIX_R4000" "mult\t%1,%2\;mflo\t%0" [(set_attr "type" "imul") (set_attr "mode" "SI") @@ -1829,42 +1871,47 @@ (match_operand:DI 2 "register_operand" "")))] "TARGET_64BIT" { - if (GENERATE_MULT3_DI || TARGET_MIPS4000) - emit_insn (gen_muldi3_internal2 (operands[0], operands[1], operands[2])); - else + if (GENERATE_MULT3_DI) + emit_insn (gen_muldi3_mult3 (operands[0], operands[1], operands[2])); + else if (!TARGET_FIX_R4000) emit_insn (gen_muldi3_internal (operands[0], operands[1], operands[2])); + else + emit_insn (gen_muldi3_r4000 (operands[0], operands[1], operands[2])); DONE; }) +(define_insn "muldi3_mult3" + [(set (match_operand:DI 0 "register_operand" "=d") + (mult:DI (match_operand:DI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "d"))) + (clobber (match_scratch:DI 3 "=h")) + (clobber (match_scratch:DI 4 "=l"))] + "TARGET_64BIT && GENERATE_MULT3_DI" + "dmult\t%0,%1,%2" + [(set_attr "type" "imul") + (set_attr "mode" "DI")]) + (define_insn "muldi3_internal" [(set (match_operand:DI 0 "register_operand" "=l") (mult:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d"))) (clobber (match_scratch:DI 3 "=h"))] - "TARGET_64BIT && !TARGET_MIPS4000" + "TARGET_64BIT && !TARGET_FIX_R4000" "dmult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "DI")]) -(define_insn "muldi3_internal2" +(define_insn "muldi3_r4000" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (match_operand:DI 1 "register_operand" "d") (match_operand:DI 2 "register_operand" "d"))) (clobber (match_scratch:DI 3 "=h")) (clobber (match_scratch:DI 4 "=l"))] - "TARGET_64BIT && (GENERATE_MULT3_DI || TARGET_MIPS4000)" -{ - if (GENERATE_MULT3_DI) - return "dmult\t%0,%1,%2"; - else - return "dmult\t%1,%2\;mflo\t%0"; -} + "TARGET_64BIT && TARGET_FIX_R4000" + "dmult\t%1,%2\;mflo\t%0" [(set_attr "type" "imul") (set_attr "mode" "DI") - (set (attr "length") - (if_then_else (ne (symbol_ref "GENERATE_MULT3_DI") (const_int 0)) - (const_int 4) - (const_int 8)))]) + (set_attr "length" "8")]) ;; ??? We could define a mulditi3 pattern when TARGET_64BIT. @@ -1877,25 +1924,43 @@ (clobber (scratch:DI)) (clobber (scratch:DI)) (clobber (scratch:DI))])] - "" + "!TARGET_64BIT || !TARGET_FIX_R4000" { if (!TARGET_64BIT) { - emit_insn (gen_mulsidi3_32bit (operands[0], operands[1], operands[2])); + if (!TARGET_FIX_R4000) + emit_insn (gen_mulsidi3_32bit_internal (operands[0], operands[1], + operands[2])); + else + emit_insn (gen_mulsidi3_32bit_r4000 (operands[0], operands[1], + operands[2])); DONE; } }) -(define_insn "mulsidi3_32bit" +(define_insn "mulsidi3_32bit_internal" [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))] - "!TARGET_64BIT" + "!TARGET_64BIT && !TARGET_FIX_R4000" "mult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI")]) +(define_insn "mulsidi3_32bit_r4000" + [(set (match_operand:DI 0 "register_operand" "=d") + (mult:DI + (sign_extend:DI (match_operand:SI 1 "register_operand" "d")) + (sign_extend:DI (match_operand:SI 2 "register_operand" "d")))) + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h"))] + "!TARGET_64BIT && TARGET_FIX_R4000" + "mult\t%1,%2\;mflo\t%L0;mfhi\t%M0" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "12")]) + (define_insn_and_split "*mulsidi3_64bit" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (match_operator:DI 1 "extend_operator" @@ -1905,7 +1970,8 @@ (clobber (match_scratch:DI 5 "=l")) (clobber (match_scratch:DI 6 "=h")) (clobber (match_scratch:DI 7 "=d"))] - "TARGET_64BIT && GET_CODE (operands[1]) == GET_CODE (operands[2])" + "TARGET_64BIT && !TARGET_FIX_R4000 + && GET_CODE (operands[1]) == GET_CODE (operands[2])" "#" "&& reload_completed" [(parallel @@ -1956,7 +2022,8 @@ (match_operator:DI 4 "extend_operator" [(match_dup 2)]) (match_operator:DI 5 "extend_operator" [(match_dup 3)])) (const_int 32)))] - "TARGET_64BIT && GET_CODE (operands[4]) == GET_CODE (operands[5])" + "TARGET_64BIT && !TARGET_FIX_R4000 + && GET_CODE (operands[4]) == GET_CODE (operands[5])" { if (GET_CODE (operands[4]) == SIGN_EXTEND) return "mult\t%2,%3"; @@ -1975,26 +2042,43 @@ (clobber (scratch:DI)) (clobber (scratch:DI)) (clobber (scratch:DI))])] - "" + "!TARGET_64BIT || !TARGET_FIX_R4000" { if (!TARGET_64BIT) { - emit_insn (gen_umulsidi3_32bit (operands[0], operands[1], - operands[2])); + if (!TARGET_FIX_R4000) + emit_insn (gen_umulsidi3_32bit_internal (operands[0], operands[1], + operands[2])); + else + emit_insn (gen_umulsidi3_32bit_r4000 (operands[0], operands[1], + operands[2])); DONE; } }) -(define_insn "umulsidi3_32bit" +(define_insn "umulsidi3_32bit_internal" [(set (match_operand:DI 0 "register_operand" "=x") (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))] - "!TARGET_64BIT" + "!TARGET_64BIT && !TARGET_FIX_R4000" "multu\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI")]) +(define_insn "umulsidi3_32bit_r4000" + [(set (match_operand:DI 0 "register_operand" "=d") + (mult:DI + (zero_extend:DI (match_operand:SI 1 "register_operand" "d")) + (zero_extend:DI (match_operand:SI 2 "register_operand" "d")))) + (clobber (match_scratch:DI 3 "=l")) + (clobber (match_scratch:DI 4 "=h"))] + "!TARGET_64BIT && TARGET_FIX_R4000" + "multu\t%1,%2\;mflo\t%L0;mfhi\t%M0" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set_attr "length" "12")]) + ;; Widening multiply with negation. (define_insn "*muls_di" [(set (match_operand:DI 0 "register_operand" "=x") @@ -2064,7 +2148,7 @@ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "")) (zero_extend:DI (match_operand:SI 2 "register_operand" ""))) (const_int 32))))] - "" + "ISA_HAS_MULHI || !TARGET_FIX_R4000" { if (ISA_HAS_MULHI) emit_insn (gen_umulsi3_highpart_mulhi_internal (operands[0], operands[1], @@ -2083,7 +2167,7 @@ (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=l"))] - "!ISA_HAS_MULHI" + "!ISA_HAS_MULHI && !TARGET_FIX_R4000" "multu\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") @@ -2131,7 +2215,7 @@ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "")) (sign_extend:DI (match_operand:SI 2 "register_operand" ""))) (const_int 32))))] - "" + "ISA_HAS_MULHI || !TARGET_FIX_R4000" { if (ISA_HAS_MULHI) emit_insn (gen_smulsi3_highpart_mulhi_internal (operands[0], operands[1], @@ -2150,7 +2234,7 @@ (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=l"))] - "!ISA_HAS_MULHI" + "!ISA_HAS_MULHI && !TARGET_FIX_R4000" "mult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "SI") @@ -2199,7 +2283,7 @@ (sign_extend:TI (match_operand:DI 2 "register_operand" "d"))) (const_int 64)))) (clobber (match_scratch:DI 3 "=l"))] - "TARGET_64BIT" + "TARGET_64BIT && !TARGET_FIX_R4000" "dmult\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "DI")]) @@ -2213,7 +2297,7 @@ (zero_extend:TI (match_operand:DI 2 "register_operand" "d"))) (const_int 64)))) (clobber (match_scratch:DI 3 "=l"))] - "TARGET_64BIT" + "TARGET_64BIT && !TARGET_FIX_R4000" "dmultu\t%1,%2" [(set_attr "type" "imul") (set_attr "mode" "DI")]) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 3544332..c39eb46 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -8055,6 +8055,9 @@ Work around certain R4000 CPU errata: @item A double-word or a variable shift may give an incorrect result if executed 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. @end itemize @item -mfix-sb1 -- 2.7.4