* config/mips/mips.md: Complete the unfinished R4000
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Feb 2004 20:06:01 +0000 (20:06 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 28 Feb 2004 20:06:01 +0000 (20:06 +0000)
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
gcc/config/mips/mips.md
gcc/doc/invoke.texi

index 417c012..91fc115 100644 (file)
@@ -1,5 +1,28 @@
 2004-02-28  Maciej W. Rozycki  <macro@ds2.pg.gda.pl>
 
+       * 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  <macro@ds2.pg.gda.pl>
+
        * 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.
index 5b6af02..0858040 100644 (file)
 
         ;; 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")
    (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" "")
 {
   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]));
        (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")])
                 (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")
                 (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.
 
        (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"
    (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
              (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";
        (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")
          (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],
                   (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")
          (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],
                   (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")
           (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")])
           (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")])
index 3544332..c39eb46 100644 (file)
@@ -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