@@ -431,6 +431,11 @@ (define_code_attr return_pred [(return "direct_return ()")
(simple_return "1")])
(define_code_attr return_str [(return "") (simple_return "simple_")])
+; Signed/unsigned variants of ops.
+(define_code_iterator any_extend [sign_extend zero_extend])
+(define_code_attr u [(sign_extend "") (zero_extend "u")])
+(define_code_attr su [(sign_extend "s") (zero_extend "u")])
+
; Various instructions that come in SI and DI forms.
; A generic w/d attribute, for things like cmpw/cmpd.
(define_mode_attr wd [(QI "b")
@@ -454,6 +459,10 @@ (define_mode_attr sel [(SI "") (DI "64")])
;; Bitmask for shift instructions
(define_mode_attr hH [(SI "h") (DI "H")])
+;; A mode twice the size of the given mode
+(define_mode_attr dmode [(SI "di") (DI "ti")])
+(define_mode_attr DMODE [(SI "DI") (DI "TI")])
+
;; Suffix for reload patterns
(define_mode_attr ptrsize [(SI "32bit")
(DI "64bit")])
@@ -2767,6 +2776,100 @@ (define_insn_and_split "*mul<mode>3_dot2"
(set_attr "length" "4,8")])
+(define_expand "<su>mul<mode>3_highpart"
+ [(set (match_operand:GPR 0 "gpc_reg_operand")
+ (subreg:GPR
+ (mult:<DMODE> (any_extend:<DMODE>
+ (match_operand:GPR 1 "gpc_reg_operand"))
+ (any_extend:<DMODE>
+ (match_operand:GPR 2 "gpc_reg_operand")))
+ 0))]
+ ""
+{
+ if (<MODE>mode == SImode && TARGET_POWERPC64)
+ {
+ emit_insn (gen_<su>mulsi3_highpart_64 (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+
+ if (!WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_<su>mul<mode>3_highpart_le (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+})
+
+(define_insn "*<su>mul<mode>3_highpart"
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+ (subreg:GPR
+ (mult:<DMODE> (any_extend:<DMODE>
+ (match_operand:GPR 1 "gpc_reg_operand" "r"))
+ (any_extend:<DMODE>
+ (match_operand:GPR 2 "gpc_reg_operand" "r")))
+ 0))]
+ "WORDS_BIG_ENDIAN && !(<MODE>mode == SImode && TARGET_POWERPC64)"
+ "mulh<wd><u> %0,%1,%2"
+ [(set_attr "type" "mul")
+ (set_attr "size" "<bits>")])
+
+(define_insn "<su>mulsi3_highpart_le"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (subreg:SI
+ (mult:DI (any_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (any_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ 4))]
+ "!WORDS_BIG_ENDIAN && !TARGET_POWERPC64"
+ "mulhw<u> %0,%1,%2"
+ [(set_attr "type" "mul")])
+
+(define_insn "<su>muldi3_highpart_le"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (subreg:DI
+ (mult:TI (any_extend:TI
+ (match_operand:DI 1 "gpc_reg_operand" "r"))
+ (any_extend:TI
+ (match_operand:DI 2 "gpc_reg_operand" "r")))
+ 8))]
+ "!WORDS_BIG_ENDIAN && TARGET_POWERPC64"
+ "mulhd<u> %0,%1,%2"
+ [(set_attr "type" "mul")
+ (set_attr "size" "64")])
+
+(define_insn "<su>mulsi3_highpart_64"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (any_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (any_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ "TARGET_POWERPC64"
+ "mulhw<u> %0,%1,%2"
+ [(set_attr "type" "mul")])
+
+(define_expand "<u>mul<mode><dmode>3"
+ [(set (match_operand:<DMODE> 0 "gpc_reg_operand")
+ (mult:<DMODE> (any_extend:<DMODE>
+ (match_operand:GPR 1 "gpc_reg_operand"))
+ (any_extend:<DMODE>
+ (match_operand:GPR 2 "gpc_reg_operand"))))]
+ "!(<MODE>mode == SImode && TARGET_POWERPC64)"
+{
+ rtx l = gen_reg_rtx (<MODE>mode);
+ rtx h = gen_reg_rtx (<MODE>mode);
+ emit_insn (gen_mul<mode>3 (l, operands[1], operands[2]));
+ emit_insn (gen_<su>mul<mode>3_highpart (h, operands[1], operands[2]));
+ emit_move_insn (gen_lowpart (<MODE>mode, operands[0]), l);
+ emit_move_insn (gen_highpart (<MODE>mode, operands[0]), h);
+ DONE;
+})
+
+
(define_insn "udiv<mode>3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
@@ -6622,96 +6725,6 @@ (define_insn "*negdi2_noppc64"
[(set_attr "type" "two")
(set_attr "length" "8")])
-(define_insn "mulsidi3"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
- (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
- (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
- "! TARGET_POWERPC64"
-{
- return (WORDS_BIG_ENDIAN)
- ? \"mulhw %0,%1,%2\;mullw %L0,%1,%2\"
- : \"mulhw %L0,%1,%2\;mullw %0,%1,%2\";
-}
- [(set_attr "type" "mul")
- (set_attr "length" "8")])
-
-(define_split
- [(set (match_operand:DI 0 "gpc_reg_operand" "")
- (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
- (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
- "! TARGET_POWERPC64 && reload_completed"
- [(set (match_dup 3)
- (truncate:SI
- (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
- (sign_extend:DI (match_dup 2)))
- (const_int 32))))
- (set (match_dup 4)
- (mult:SI (match_dup 1)
- (match_dup 2)))]
- "
-{
- int endian = (WORDS_BIG_ENDIAN == 0);
- operands[3] = operand_subword (operands[0], endian, 0, DImode);
- operands[4] = operand_subword (operands[0], 1 - endian, 0, DImode);
-}")
-
-(define_insn "umulsidi3"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
- (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
- (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
- "! TARGET_POWERPC64"
- "*
-{
- return (WORDS_BIG_ENDIAN)
- ? \"mulhwu %0,%1,%2\;mullw %L0,%1,%2\"
- : \"mulhwu %L0,%1,%2\;mullw %0,%1,%2\";
-}"
- [(set_attr "type" "mul")
- (set_attr "length" "8")])
-
-(define_split
- [(set (match_operand:DI 0 "gpc_reg_operand" "")
- (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
- (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
- "! TARGET_POWERPC64 && reload_completed"
- [(set (match_dup 3)
- (truncate:SI
- (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
- (zero_extend:DI (match_dup 2)))
- (const_int 32))))
- (set (match_dup 4)
- (mult:SI (match_dup 1)
- (match_dup 2)))]
- "
-{
- int endian = (WORDS_BIG_ENDIAN == 0);
- operands[3] = operand_subword (operands[0], endian, 0, DImode);
- operands[4] = operand_subword (operands[0], 1 - endian, 0, DImode);
-}")
-
-(define_insn "smulsi3_highpart"
- [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
- (truncate:SI
- (lshiftrt:DI (mult:DI (sign_extend:DI
- (match_operand:SI 1 "gpc_reg_operand" "%r"))
- (sign_extend:DI
- (match_operand:SI 2 "gpc_reg_operand" "r")))
- (const_int 32))))]
- ""
- "mulhw %0,%1,%2"
- [(set_attr "type" "mul")])
-
-(define_insn "umulsi3_highpart"
- [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
- (truncate:SI
- (lshiftrt:DI (mult:DI (zero_extend:DI
- (match_operand:SI 1 "gpc_reg_operand" "%r"))
- (zero_extend:DI
- (match_operand:SI 2 "gpc_reg_operand" "r")))
- (const_int 32))))]
- ""
- "mulhwu %0,%1,%2"
- [(set_attr "type" "mul")])
;; Shift by a variable amount is too complex to be worth open-coding. We
;; just handle shifts by constants.
@@ -6758,60 +6771,6 @@ (define_insn "*ashrdisi3_noppc64be"
;; PowerPC64 DImode operations.
-(define_insn "smuldi3_highpart"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
- (truncate:DI
- (lshiftrt:TI (mult:TI (sign_extend:TI
- (match_operand:DI 1 "gpc_reg_operand" "%r"))
- (sign_extend:TI
- (match_operand:DI 2 "gpc_reg_operand" "r")))
- (const_int 64))))]
- "TARGET_POWERPC64"
- "mulhd %0,%1,%2"
- [(set_attr "type" "mul")
- (set_attr "size" "64")])
-
-(define_insn "umuldi3_highpart"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
- (truncate:DI
- (lshiftrt:TI (mult:TI (zero_extend:TI
- (match_operand:DI 1 "gpc_reg_operand" "%r"))
- (zero_extend:TI
- (match_operand:DI 2 "gpc_reg_operand" "r")))
- (const_int 64))))]
- "TARGET_POWERPC64"
- "mulhdu %0,%1,%2"
- [(set_attr "type" "mul")
- (set_attr "size" "64")])
-
-(define_expand "mulditi3"
- [(set (match_operand:TI 0 "gpc_reg_operand")
- (mult:TI (sign_extend:TI (match_operand:DI 1 "gpc_reg_operand"))
- (sign_extend:TI (match_operand:DI 2 "gpc_reg_operand"))))]
- "TARGET_POWERPC64"
-{
- rtx l = gen_reg_rtx (DImode), h = gen_reg_rtx (DImode);
- emit_insn (gen_muldi3 (l, operands[1], operands[2]));
- emit_insn (gen_smuldi3_highpart (h, operands[1], operands[2]));
- emit_move_insn (gen_lowpart (DImode, operands[0]), l);
- emit_move_insn (gen_highpart (DImode, operands[0]), h);
- DONE;
-})
-
-(define_expand "umulditi3"
- [(set (match_operand:TI 0 "gpc_reg_operand")
- (mult:TI (zero_extend:TI (match_operand:DI 1 "gpc_reg_operand"))
- (zero_extend:TI (match_operand:DI 2 "gpc_reg_operand"))))]
- "TARGET_POWERPC64"
-{
- rtx l = gen_reg_rtx (DImode), h = gen_reg_rtx (DImode);
- emit_insn (gen_muldi3 (l, operands[1], operands[2]));
- emit_insn (gen_umuldi3_highpart (h, operands[1], operands[2]));
- emit_move_insn (gen_lowpart (DImode, operands[0]), l);
- emit_move_insn (gen_highpart (DImode, operands[0]), h);
- DONE;
-})
-
(define_insn "*rotldi3_internal4"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(and:DI (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r")