diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fee14941bc88123fce744df546f2f6bde875c671..20a2d09c31aa9cd504fbf47aafd386c8000c87b0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2009-11-21  Adam Nemet  <adambnemet@gmail.com>
+
+	* config/mips/mips-protos.h (mulsidi3_gen_fn): New typedef.
+	(mips_mulsidi3_gen_fn): Declare new function.
+	* config/mips/mips.c (mips_mulsidi3_gen_fn): New function.
+	* config/mips/mips.md (<u>mulsidi3): Change condition to use
+	mips_mulsidi3_gen_fn.  Use mips_mulsidi3_gen_fn to generate the
+	insn.
+	(<u>mulsidi3_64bit): Don't match for ISA_HAS_DMUL3.
+	(mulsidi3_64bit_dmul): New define_insn.
+
 2009-11-21  Ben Elliston  <bje@au.ibm.com>
 
 	* gengtype-lex.l: Enable noinput flex option.
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 716b7acad82cfed956108cfbb5917bc65fe711a8..e4fbb32b9591223e8979e123e5195601f3484900 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -346,4 +346,9 @@ extern void mips_final_prescan_insn (rtx, rtx *, int);
 extern int mips_trampoline_code_size (void);
 extern void mips_function_profiler (FILE *);
 
+typedef rtx (*mulsidi3_gen_fn) (rtx, rtx, rtx);
+#ifdef RTX_CODE
+extern mulsidi3_gen_fn mips_mulsidi3_gen_fn (enum rtx_code);
+#endif
+
 #endif /* ! GCC_MIPS_PROTOS_H */
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index c8c1dca25ce37a26cde44951b738db583513eaef..eeff72d4b3378c4b055c551cb09a0d65f927c2f0 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -15982,6 +15982,39 @@ mips_final_postscan_insn (FILE *file ATTRIBUTE_UNUSED, rtx insn,
   if (mips_need_noat_wrapper_p (insn, opvec, noperands))
     mips_pop_asm_switch (&mips_noat);
 }
+
+/* Return the function that is used to expand the <u>mulsidi3 pattern.
+   EXT_CODE is the code of the extension used.  Return NULL if widening
+   multiplication shouldn't be used.  */
+
+mulsidi3_gen_fn
+mips_mulsidi3_gen_fn (enum rtx_code ext_code)
+{
+  bool signed_p;
+
+  signed_p = ext_code == SIGN_EXTEND;
+  if (TARGET_64BIT)
+    {
+      /* Don't use widening multiplication with MULT when we have DMUL.  Even
+	 with the extension of its input operands DMUL is faster.  Note that
+	 the extension is not needed for signed multiplication.  In order to
+	 ensure that we always remove the redundant sign-extension in this
+	 case we still expand mulsidi3 for DMUL.  */
+      if (ISA_HAS_DMUL3)
+	return signed_p ? gen_mulsidi3_64bit_dmul : NULL;
+      if (TARGET_FIX_R4000)
+	return NULL;
+      return signed_p ? gen_mulsidi3_64bit : gen_umulsidi3_64bit;
+    }
+  else
+    {
+      if (TARGET_FIX_R4000)
+	return signed_p ? gen_mulsidi3_32bit_r4000 : gen_umulsidi3_32bit_r4000;
+      if (ISA_HAS_DSPR2)
+	return signed_p ? gen_mips_mult : gen_mips_multu;
+      return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
+    }
+}
 
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 76fc37bd479a74e7b949839897a5b54f7863efe2..2179b8a46c68469445fb7da395660fe2397d8d4c 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -1847,15 +1847,10 @@
   [(set (match_operand:DI 0 "register_operand")
 	(mult:DI (any_extend:DI (match_operand:SI 1 "register_operand"))
 		 (any_extend:DI (match_operand:SI 2 "register_operand"))))]
-  "!TARGET_64BIT || !TARGET_FIX_R4000"
+  "mips_mulsidi3_gen_fn (<CODE>) != NULL"
 {
-  if (TARGET_64BIT)
-    emit_insn (gen_<u>mulsidi3_64bit (operands[0], operands[1], operands[2]));
-  else if (TARGET_FIX_R4000)
-    emit_insn (gen_<u>mulsidi3_32bit_r4000 (operands[0], operands[1],
-					    operands[2]));
-  else
-    emit_insn (gen_<u>mulsidi3_32bit (operands[0], operands[1], operands[2]));
+  mulsidi3_gen_fn fn = mips_mulsidi3_gen_fn (<CODE>);
+  emit_insn (fn (operands[0], operands[1], operands[2]));
   DONE;
 })
 
@@ -1885,7 +1880,7 @@
 		 (any_extend:DI (match_operand:SI 2 "register_operand" "d"))))
    (clobber (match_scratch:TI 3 "=x"))
    (clobber (match_scratch:DI 4 "=d"))]
-  "TARGET_64BIT && !TARGET_FIX_R4000"
+  "TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DMUL3"
   "#"
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")
@@ -1961,6 +1956,17 @@
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")])
 
+;; See comment before the ISA_HAS_DMUL3 case in mips_mulsidi3_gen_fn.
+(define_insn "mulsidi3_64bit_dmul"
+  [(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"))]
+  "TARGET_64BIT && ISA_HAS_DMUL3"
+  "dmul\t%0,%1,%2"
+  [(set_attr "type" "imul3")
+   (set_attr "mode" "DI")])
+
 ;; Widening multiply with negation.
 (define_insn "*muls<u>_di"
   [(set (match_operand:DI 0 "register_operand" "=x")
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 009b3335d285f24b689494068ccd380748c2a6c2..445691ab939ae036c77987f02ade7b7c717c1380 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2009-11-21  Adam Nemet  <adambnemet@gmail.com>
+
+	* gcc.target/mips/mult-1.c: Forbid octeon.
+	* gcc.target/mips/octeon-dmul-3.c: New test.
+
 2009-11-21  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
 
 	* gcc.dg/tree-ssa/vrp47.c: Fix target check.
diff --git a/gcc/testsuite/gcc.target/mips/mult-1.c b/gcc/testsuite/gcc.target/mips/mult-1.c
index d82a47782636bd6d4719e5175492f51d8ec5dcb7..43dd08c0b52177f024d5a856a13bb901fe0174a3 100644
--- a/gcc/testsuite/gcc.target/mips/mult-1.c
+++ b/gcc/testsuite/gcc.target/mips/mult-1.c
@@ -1,6 +1,6 @@
 /* For SI->DI widening multiplication we should use DINS to combine the two
-   halves.  */
-/* { dg-options "-O -mgp64 isa_rev>=2" } */
+   halves.  For Octeon use DMUL with explicit widening.  */
+/* { dg-options "-O -mgp64 isa_rev>=2 forbid_cpu=octeon" } */
 /* { dg-final { scan-assembler "\tdins\t" } } */
 /* { dg-final { scan-assembler-not "\tdsll\t" } } */
 /* { dg-final { scan-assembler-not "\tdsrl\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/octeon-dmul-3.c b/gcc/testsuite/gcc.target/mips/octeon-dmul-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..01f0eefca8001260ac577b7ef051cdc119a40d1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/octeon-dmul-3.c
@@ -0,0 +1,19 @@
+/* Use DMUL for widening multiplication too.  */
+/* { dg-options "-O -march=octeon -mgp64" } */
+/* { dg-final { scan-assembler-times "\tdmul\t" 2 } } */
+/* { dg-final { scan-assembler-not "\td?mult\t" } } */
+/* { dg-final { scan-assembler-times "\tdext\t" 2 } } */
+
+NOMIPS16 long long
+f (int i, int j)
+{
+  i++;
+  return (long long) i * j;
+}
+
+NOMIPS16 unsigned long long
+g (unsigned int i, unsigned int j)
+{
+  i++;
+  return (unsigned long long) i * j;
+}