;; 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")])