diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index d903e4a..f9e1eba 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -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")
