Patchwork Update MIPS DSP madd, maddu, msub, msubu, mult, multu

login
register
mail settings
Submitter Fu, Chao-Ying
Date Oct. 26, 2010, 1:16 a.m.
Message ID <7C6479EB2BF52547AC332FD6034646DA3017EC1B@exchdb02.mips.com>
Download mbox | patch
Permalink /patch/69153/
State New
Headers show

Comments

Fu, Chao-Ying - Oct. 26, 2010, 1:16 a.m.
Hi All,

  Here is the GCC patch to move madd/maddu/msubu/msub/mult/multu from MIPS DSP r2 to DSP r1.
Note that the Binutils patch has been committed to FSF binutils mainline.
http://sourceware.org/ml/binutils/2010-10/msg00331.html
http://sourceware.org/ml/binutils/2010-10/msg00424.html

  I lightly tested the GCC patch by running mips.exp on a cross-build of mips-sde-elf (mips32r2).
There are no new failures.

Ex:
# make check-gcc//mips-sim-sde32 RUNTESTFLAGS="mips.exp"

                === gcc Summary ===

# of expected passes            951
# of unexpected failures        7
# of unsupported tests          2
/home/fu/dev/gcc45/build/gcc/xgcc  version 4.6.0 20101025 (experimental) [trunk
revision 165927] (GCC)

FAIL: gcc.target/mips/dspr2-MULT.c scan-assembler ac2
FAIL: gcc.target/mips/dspr2-MULTU.c scan-assembler ac2
FAIL: gcc.target/mips/extend-1.c scan-assembler-times \tdsll\t 5
FAIL: gcc.target/mips/extend-1.c scan-assembler-times \tdsra\t 5
FAIL: gcc.target/mips/loongson-shift-count-truncated-1.c (test for excess errors)
FAIL: gcc.target/mips/octeon-exts-6.c scan-assembler-times \texts\t 5
FAIL: gcc.target/mips/pr37362.c (test for excess errors)

  dspr2-MULT.c and dspr2-MULTU.c fail before and after the patch.  Need to debug
why $ac2 is not used by the register allocator.

  Any feedback?
  Thanks!

Regards,
Chao-ying

gcc/ChangeLog
2010-10-25  Chao-ying Fu  <fu@mips.com>

        * config/mips/mips.c (mips_builtins): Move madd, maddu, msub, msubu,
        mult, multu from dspr2_32 to dsp_32.

        * config/mips/mips-dsp.md (mips_mult<u>, mips_madd<u>, mips_msub<u>):
        New patterns.

        * config/mips/constraints.md (ka): Update the constraint to test
        ISA_HAS_DSP instead of ISA_HAS_DSPR2.

        * config/mips/mips-dspr2.md (mips_madd<u>, mips_msub<u>, mips_mult,
        mips_multu): Delete.

        * config/mips/mips.md (<u>mulsidi3_32bit): Test !ISA_HAS_DSP.
        (<u>msubsidi4): Test ISA_HAS_DSP.
        (<u>maddsidi4): Test ISA_HAS_DSP.

        * doc/extend.texi (MIPS DSP Built-in Functions): Move madd, maddu,
        msub, msubu, mult, multu built-in functions from DSP r2 to DSP r1.

gcc/testsuite/ChangeLog
2010-10-25  Chao-ying Fu  <fu@mips.com>

        * gcc.target/mips/mips32-dsp.c: Add tests for madd, maddu, msub,
        msubu, mult, multu.
        * gcc.target/mips/mips32-dsp-run.c: Likewise.
        * gcc.target/mips/dspr2-MULT.c: Pass -mdsp, instead of -mdspr2.
        * gcc.target/mips/dspr2-MULTU.c: Likewise.
Richard Sandiford - Oct. 27, 2010, 6:05 p.m.
"Fu, Chao-Ying" <fu@mips.com> writes:
>   Here is the GCC patch to move madd/maddu/msubu/msub/mult/multu from MIPS DSP r2 to DSP r1.
> Note that the Binutils patch has been committed to FSF binutils mainline.
> http://sourceware.org/ml/binutils/2010-10/msg00331.html
> http://sourceware.org/ml/binutils/2010-10/msg00424.html
>[...]
>   Any feedback?

Looks good.  My main concern is that the patch as-is introduces
a dependency on bleeding-edge binutils.  That's not such a problem
for cases where the user has explicitly called a __builtin_*() function
in rev1 code, because that simply didn't work before.  But it is a problem
for cases where the compiler is automatically using these instructions.
You'll get assembler errors when compiling ordinary C code, which never
looks good.

I think we need to add a configure-time check to see whether the
assembler has your patch.  There are quite a few existing examples
of this.  Then we should introduce a new macro such as:

    ISA_HAS_DSP_MULT

This macro can be defined to ISA_HAS_DSP if the assembler has your fix
and ISA_HAS_DSPR2 otherwise.

Richard
Fu, Chao-Ying - Oct. 27, 2010, 9:26 p.m.
Richard Sandiford wrote:
> "Fu, Chao-Ying" <fu@mips.com> writes:
> >   Here is the GCC patch to move 
> madd/maddu/msubu/msub/mult/multu from MIPS DSP r2 to DSP r1.
> > Note that the Binutils patch has been committed to FSF 
> binutils mainline.
> > http://sourceware.org/ml/binutils/2010-10/msg00331.html
> > http://sourceware.org/ml/binutils/2010-10/msg00424.html
> >[...]
> >   Any feedback?
> 
> Looks good.  My main concern is that the patch as-is introduces
> a dependency on bleeding-edge binutils.  That's not such a problem
> for cases where the user has explicitly called a 
> __builtin_*() function
> in rev1 code, because that simply didn't work before.  But it 
> is a problem
> for cases where the compiler is automatically using these 
> instructions.
> You'll get assembler errors when compiling ordinary C code, 
> which never
> looks good.
> 
> I think we need to add a configure-time check to see whether the
> assembler has your patch.  There are quite a few existing examples
> of this.  Then we should introduce a new macro such as:
> 
>     ISA_HAS_DSP_MULT
> 
> This macro can be defined to ISA_HAS_DSP if the assembler has your fix
> and ISA_HAS_DSPR2 otherwise.
> 

  I will update my patch to have a configure-time check and ues ISA_HAS_DSP_MULT.
Thanks a lot!

Regards,
Chao-ying

Patch

Index: gcc45/gcc/gcc/config/mips/mips.c
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips.c       2010-10-25 15:14:09.000000000 -0700
+++ gcc45/gcc/gcc/config/mips/mips.c    2010-10-25 15:22:53.234256000 -0700
@@ -12928,17 +12928,17 @@  static const struct mips_builtin_descrip
   DIRECT_BUILTIN (extpdp, MIPS_SI_FTYPE_DI_SI, dsp_32),
   DIRECT_BUILTIN (shilo, MIPS_DI_FTYPE_DI_SI, dsp_32),
   DIRECT_BUILTIN (mthlip, MIPS_DI_FTYPE_DI_SI, dsp_32),
+  DIRECT_BUILTIN (madd, MIPS_DI_FTYPE_DI_SI_SI, dsp_32),
+  DIRECT_BUILTIN (maddu, MIPS_DI_FTYPE_DI_USI_USI, dsp_32),
+  DIRECT_BUILTIN (msub, MIPS_DI_FTYPE_DI_SI_SI, dsp_32),
+  DIRECT_BUILTIN (msubu, MIPS_DI_FTYPE_DI_USI_USI, dsp_32),
+  DIRECT_BUILTIN (mult, MIPS_DI_FTYPE_SI_SI, dsp_32),
+  DIRECT_BUILTIN (multu, MIPS_DI_FTYPE_USI_USI, dsp_32),

   /* The following are for the MIPS DSP ASE REV 2 (32-bit only).  */
   DIRECT_BUILTIN (dpa_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, dspr2_32),
   DIRECT_BUILTIN (dps_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, dspr2_32),
-  DIRECT_BUILTIN (madd, MIPS_DI_FTYPE_DI_SI_SI, dspr2_32),
-  DIRECT_BUILTIN (maddu, MIPS_DI_FTYPE_DI_USI_USI, dspr2_32),
-  DIRECT_BUILTIN (msub, MIPS_DI_FTYPE_DI_SI_SI, dspr2_32),
-  DIRECT_BUILTIN (msubu, MIPS_DI_FTYPE_DI_USI_USI, dspr2_32),
   DIRECT_BUILTIN (mulsa_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, dspr2_32),
-  DIRECT_BUILTIN (mult, MIPS_DI_FTYPE_SI_SI, dspr2_32),
-  DIRECT_BUILTIN (multu, MIPS_DI_FTYPE_USI_USI, dspr2_32),
   DIRECT_BUILTIN (dpax_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, dspr2_32),
   DIRECT_BUILTIN (dpsx_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, dspr2_32),
   DIRECT_BUILTIN (dpaqx_s_w_ph, MIPS_DI_FTYPE_DI_V2HI_V2HI, dspr2_32),
Index: gcc45/gcc/gcc/config/mips/mips-dsp.md
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips-dsp.md  2010-06-11 10:42:46.000000000 -0700
+++ gcc45/gcc/gcc/config/mips/mips-dsp.md       2010-10-25 15:24:03.652673000 -0700
@@ -1181,3 +1181,28 @@ 
   "%*bposge%1\t%0%/"
   [(set_attr "type"    "branch")])

+(define_insn "mips_mult<u>"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (mult:DI
+        (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
+        (any_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
+  "ISA_HAS_DSP && !TARGET_64BIT"
+  "mult<u>\t%q0,%1,%2"
+  [(set_attr "type"     "imul")
+   (set_attr "mode"     "SI")])
+
+(define_expand "mips_madd<u>"
+  [(set (match_operand:DI 0 "register_operand")
+       (plus:DI
+        (mult:DI (any_extend:DI (match_operand:SI 2 "register_operand"))
+                 (any_extend:DI (match_operand:SI 3 "register_operand")))
+        (match_operand:DI 1 "register_operand")))]
+  "ISA_HAS_DSP && !TARGET_64BIT")
+
+(define_expand "mips_msub<u>"
+  [(set (match_operand:DI 0 "register_operand")
+       (minus:DI
+        (match_operand:DI 1 "register_operand")
+        (mult:DI (any_extend:DI (match_operand:SI 2 "register_operand"))
+                 (any_extend:DI (match_operand:SI 3 "register_operand")))))]
+  "ISA_HAS_DSP && !TARGET_64BIT")
Index: gcc45/gcc/gcc/config/mips/constraints.md
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/constraints.md       2009-08-11 10:53:56.000000000 -0700
+++ gcc45/gcc/gcc/config/mips/constraints.md    2010-10-25 15:25:36.799926000 -0700
@@ -86,8 +86,8 @@ 

 ;; Registers that can be used as the target of multiply-accumulate
 ;; instructions.  The core MIPS32 ISA provides a hi/lo madd,
-;; but the DSPr2 version allows any accumulator target.
-(define_register_constraint "ka" "ISA_HAS_DSPR2 ? ACC_REGS : MD_REGS")
+;; but the DSP version allows any accumulator target.
+(define_register_constraint "ka" "ISA_HAS_DSP ? ACC_REGS : MD_REGS")

 (define_constraint "kf"
   "@internal"
Index: gcc45/gcc/gcc/config/mips/mips-dspr2.md
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips-dspr2.md        2010-06-11 10:42:46.000000000 -0700
+++ gcc45/gcc/gcc/config/mips/mips-dspr2.md     2010-10-25 15:25:21.081340000 -0700
@@ -224,22 +224,6 @@ 
   [(set_attr "type"    "imadd")
    (set_attr "mode"    "SI")])

-(define_expand "mips_madd<u>"
-  [(set (match_operand:DI 0 "register_operand")
-       (plus:DI
-        (mult:DI (any_extend:DI (match_operand:SI 2 "register_operand"))
-                 (any_extend:DI (match_operand:SI 3 "register_operand")))
-        (match_operand:DI 1 "register_operand")))]
-  "ISA_HAS_DSPR2 && !TARGET_64BIT")
-
-(define_expand "mips_msub<u>"
-  [(set (match_operand:DI 0 "register_operand")
-       (minus:DI
-        (match_operand:DI 1 "register_operand")
-        (mult:DI (any_extend:DI (match_operand:SI 2 "register_operand"))
-                 (any_extend:DI (match_operand:SI 3 "register_operand")))))]
-  "ISA_HAS_DSPR2 && !TARGET_64BIT")
-
 (define_insn "mulv2hi3"
   [(parallel
     [(set (match_operand:V2HI 0 "register_operand" "=d")
@@ -320,26 +304,6 @@ 
   [(set_attr "type"    "imadd")
    (set_attr "mode"    "SI")])

-(define_insn "mips_mult"
-  [(set (match_operand:DI 0 "register_operand" "=a")
-       (mult:DI
-        (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
-        (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
-  "ISA_HAS_DSPR2 && !TARGET_64BIT"
-  "mult\t%q0,%1,%2"
-  [(set_attr "type"    "imul")
-   (set_attr "mode"    "SI")])
-
-(define_insn "mips_multu"
-  [(set (match_operand:DI 0 "register_operand" "=a")
-       (mult:DI
-        (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
-        (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
-  "ISA_HAS_DSPR2 && !TARGET_64BIT"
-  "multu\t%q0,%1,%2"
-  [(set_attr "type"    "imul")
-   (set_attr "mode"    "SI")])
-
 (define_insn "mips_precr_qb_ph"
   [(set (match_operand:V4QI 0 "register_operand" "=d")
        (unspec:V4QI [(match_operand:V2HI 1 "reg_or_0_operand" "dYG")
Index: gcc45/gcc/gcc/config/mips/mips.md
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips.md      2010-06-28 15:53:36.000000000 -0700
+++ gcc45/gcc/gcc/config/mips/mips.md   2010-10-25 15:26:10.937728000 -0700
@@ -1735,7 +1735,7 @@ 
   [(set (match_operand:DI 0 "register_operand" "=x")
        (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
                 (any_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
-  "!TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DSPR2"
+  "!TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_DSP"
   "mult<u>\t%1,%2"
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")])
@@ -1863,9 +1863,9 @@ 
           (mult:DI
              (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
              (any_extend:DI (match_operand:SI 2 "register_operand" "d")))))]
-  "!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB || ISA_HAS_DSPR2)"
+  "!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB || ISA_HAS_DSP)"
 {
-  if (ISA_HAS_DSPR2)
+  if (ISA_HAS_DSP)
     return "msub<u>\t%q0,%1,%2";
   else if (TARGET_MIPS5500 || GENERATE_MADD_MSUB)
     return "msub<u>\t%1,%2";
@@ -2042,12 +2042,12 @@ 
         (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d"))
                  (any_extend:DI (match_operand:SI 2 "register_operand" "d")))
         (match_operand:DI 3 "register_operand" "0")))]
-  "(TARGET_MAD || ISA_HAS_MACC || GENERATE_MADD_MSUB || ISA_HAS_DSPR2)
+  "(TARGET_MAD || ISA_HAS_MACC || GENERATE_MADD_MSUB || ISA_HAS_DSP)
    && !TARGET_64BIT"
 {
   if (TARGET_MAD)
     return "mad<u>\t%1,%2";
-  else if (ISA_HAS_DSPR2)
+  else if (ISA_HAS_DSP)
     return "madd<u>\t%q0,%1,%2";
   else if (GENERATE_MADD_MSUB || TARGET_MIPS5500)
     return "madd<u>\t%1,%2";
Index: gcc45/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp.c
===================================================================
--- gcc45.orig/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp.c   2009-03-31 17:42:43.000000000 -0700
+++ gcc45/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp.c        2010-10-25 15:57:24.541763000 -0700
@@ -92,6 +92,12 @@ 
 /* { dg-final { scan-assembler "lhx?" } } */
 /* { dg-final { scan-assembler "lwx?" } } */
 /* { dg-final { scan-assembler "bposge32" } } */
+/* { dg-final { scan-assembler "madd" } } */
+/* { dg-final { scan-assembler "maddu" } } */
+/* { dg-final { scan-assembler "msub" } } */
+/* { dg-final { scan-assembler "msubu" } } */
+/* { dg-final { scan-assembler "mult" } } */
+/* { dg-final { scan-assembler "multu" } } */

 #include <stdlib.h>
 #include <stdio.h>
@@ -101,6 +107,7 @@  typedef short v2q15 __attribute__ ((vect

 typedef int q31;
 typedef int i32;
+typedef unsigned int ui32;
 typedef long long a64;

 NOMIPS16 void test_MIPS_DSP (void);
@@ -150,6 +157,7 @@  NOMIPS16 void test_MIPS_DSP ()
   v2q15 v2q15_a,v2q15_b,v2q15_c,v2q15_r,v2q15_s;
   q31 q31_a,q31_b,q31_c,q31_r,q31_s;
   i32 i32_a,i32_b,i32_c,i32_r,i32_s;
+  ui32 ui32_a,ui32_b,ui32_c;
   a64 a64_a,a64_b,a64_c,a64_r,a64_s;

   void *ptr_a;
@@ -1088,5 +1096,63 @@  NOMIPS16 void test_MIPS_DSP ()
   i32_r = __builtin_mips_bposge32 ();
   if (i32_r != i32_s)
     abort ();
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  i32_b = 0x80000000;
+  i32_c = 0x11112222;
+  a64_s = 0xF7776EEF12345678LL;
+  a64_r = __builtin_mips_madd (a64_a, i32_b, i32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  ui32_b = 0x80000000;
+  ui32_c = 0x11112222;
+  a64_s = 0x0888911112345678LL;
+  a64_r = __builtin_mips_maddu (a64_a, ui32_b, ui32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  i32_b = 0x80000000;
+  i32_c = 0x11112222;
+  a64_s = 0x0888911112345678LL;
+  a64_r = __builtin_mips_msub (a64_a, i32_b, i32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  ui32_b = 0x80000000;
+  ui32_c = 0x11112222;
+  a64_s = 0xF7776EEF12345678LL;
+  a64_r = __builtin_mips_msubu (a64_a, ui32_b, ui32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  i32_a = 0x80000000;
+  i32_b = 0x11112222;
+  a64_s = 0xF7776EEF00000000LL;
+  a64_r = __builtin_mips_mult (i32_a, i32_b);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  ui32_a = 0x80000000;
+  ui32_b = 0x11112222;
+  a64_s = 0x888911100000000LL;
+  a64_r = __builtin_mips_multu (ui32_a, ui32_b);
+  if (a64_r != a64_s)
+    abort ();
+#endif
 }

Index: gcc45/gcc/gcc/testsuite/gcc.target/mips/dspr2-MULT.c
===================================================================
--- gcc45.orig/gcc/gcc/testsuite/gcc.target/mips/dspr2-MULT.c   2009-05-06 12:32:39.000000000 -0700
+++ gcc45/gcc/gcc/testsuite/gcc.target/mips/dspr2-MULT.c        2010-10-25 16:00:39.094539000 -0700
@@ -1,7 +1,7 @@ 
-/* Test MIPS32 DSP REV 2 MULT instruction.  Tune for a CPU that has
+/* Test MIPS32 DSP MULT instruction.  Tune for a CPU that has
    pipelined mult.  */
 /* { dg-do compile } */
-/* { dg-options "-mgp32 -mdspr2 -O2 -ffixed-hi -ffixed-lo -mtune=74kc" } */
+/* { dg-options "-mgp32 -mdsp -O2 -ffixed-hi -ffixed-lo -mtune=74kc" } */

 /* { dg-final { scan-assembler "\tmult\t" } } */
 /* { dg-final { scan-assembler "ac1" } } */
Index: gcc45/gcc/gcc/testsuite/gcc.target/mips/dspr2-MULTU.c
===================================================================
--- gcc45.orig/gcc/gcc/testsuite/gcc.target/mips/dspr2-MULTU.c  2009-05-06 12:32:39.000000000 -0700
+++ gcc45/gcc/gcc/testsuite/gcc.target/mips/dspr2-MULTU.c       2010-10-25 16:00:54.934054000 -0700
@@ -1,7 +1,7 @@ 
-/* Test MIPS32 DSP REV 2 MULTU instruction.  Tune for a CPU that has
+/* Test MIPS32 DSP MULTU instruction.  Tune for a CPU that has
    pipelined multu.  */
 /* { dg-do compile } */
-/* { dg-options "-mgp32 -mdspr2 -O2 -ffixed-hi -ffixed-lo -mtune=74kc" } */
+/* { dg-options "-mgp32 -mdsp -O2 -ffixed-hi -ffixed-lo -mtune=74kc" } */

 /* { dg-final { scan-assembler "\tmultu\t" } } */
 /* { dg-final { scan-assembler "ac1" } } */
Index: gcc45/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp-run.c
===================================================================
--- gcc45.orig/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp-run.c       2009-03-31 17:42:43.000000000 -0700
+++ gcc45/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp-run.c    2010-10-25 16:03:14.039008000 -0700
@@ -10,6 +10,7 @@  typedef short v2q15 __attribute__ ((vect

 typedef int q31;
 typedef int i32;
+typedef unsigned int ui32;
 typedef long long a64;

 NOMIPS16 void test_MIPS_DSP (void);
@@ -59,6 +60,7 @@  NOMIPS16 void test_MIPS_DSP ()
   v2q15 v2q15_a,v2q15_b,v2q15_c,v2q15_r,v2q15_s;
   q31 q31_a,q31_b,q31_c,q31_r,q31_s;
   i32 i32_a,i32_b,i32_c,i32_r,i32_s;
+  ui32 ui32_a,ui32_b,ui32_c;
   a64 a64_a,a64_b,a64_c,a64_r,a64_s;

   void *ptr_a;
@@ -997,5 +999,63 @@  NOMIPS16 void test_MIPS_DSP ()
   i32_r = __builtin_mips_bposge32 ();
   if (i32_r != i32_s)
     abort ();
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  i32_b = 0x80000000;
+  i32_c = 0x11112222;
+  a64_s = 0xF7776EEF12345678LL;
+  a64_r = __builtin_mips_madd (a64_a, i32_b, i32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  ui32_b = 0x80000000;
+  ui32_c = 0x11112222;
+  a64_s = 0x0888911112345678LL;
+  a64_r = __builtin_mips_maddu (a64_a, ui32_b, ui32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  i32_b = 0x80000000;
+  i32_c = 0x11112222;
+  a64_s = 0x0888911112345678LL;
+  a64_r = __builtin_mips_msub (a64_a, i32_b, i32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  a64_a = 0x12345678;
+  ui32_b = 0x80000000;
+  ui32_c = 0x11112222;
+  a64_s = 0xF7776EEF12345678LL;
+  a64_r = __builtin_mips_msubu (a64_a, ui32_b, ui32_c);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  i32_a = 0x80000000;
+  i32_b = 0x11112222;
+  a64_s = 0xF7776EEF00000000LL;
+  a64_r = __builtin_mips_mult (i32_a, i32_b);
+  if (a64_r != a64_s)
+    abort ();
+#endif
+
+#ifndef __mips64
+  ui32_a = 0x80000000;
+  ui32_b = 0x11112222;
+  a64_s = 0x888911100000000LL;
+  a64_r = __builtin_mips_multu (ui32_a, ui32_b);
+  if (a64_r != a64_s)
+    abort ();
+#endif
 }

Index: gcc45/gcc/gcc/doc/extend.texi
===================================================================
--- gcc45.orig/gcc/gcc/doc/extend.texi  2010-10-22 16:27:36.000000000 -0700
+++ gcc45/gcc/gcc/doc/extend.texi       2010-10-25 16:15:41.201844000 -0700
@@ -9628,6 +9628,12 @@  i32 __builtin_mips_lbux (void *, i32)
 i32 __builtin_mips_lhx (void *, i32)
 i32 __builtin_mips_lwx (void *, i32)
 i32 __builtin_mips_bposge32 (void)
+a64 __builtin_mips_madd (a64, i32, i32);
+a64 __builtin_mips_maddu (a64, ui32, ui32);
+a64 __builtin_mips_msub (a64, i32, i32);
+a64 __builtin_mips_msubu (a64, ui32, ui32);
+a64 __builtin_mips_mult (i32, i32);
+a64 __builtin_mips_multu (ui32, ui32);
 @end smallexample

 The following built-in functions map directly to a particular MIPS DSP REV 2
@@ -9647,18 +9653,12 @@  i32 __builtin_mips_cmpgdu_lt_qb (v4i8, v
 i32 __builtin_mips_cmpgdu_le_qb (v4i8, v4i8);
 a64 __builtin_mips_dpa_w_ph (a64, v2i16, v2i16);
 a64 __builtin_mips_dps_w_ph (a64, v2i16, v2i16);
-a64 __builtin_mips_madd (a64, i32, i32);
-a64 __builtin_mips_maddu (a64, ui32, ui32);
-a64 __builtin_mips_msub (a64, i32, i32);
-a64 __builtin_mips_msubu (a64, ui32, ui32);
 v2i16 __builtin_mips_mul_ph (v2i16, v2i16);
 v2i16 __builtin_mips_mul_s_ph (v2i16, v2i16);
 q31 __builtin_mips_mulq_rs_w (q31, q31);
 v2q15 __builtin_mips_mulq_s_ph (v2q15, v2q15);
 q31 __builtin_mips_mulq_s_w (q31, q31);
 a64 __builtin_mips_mulsa_w_ph (a64, v2i16, v2i16);
-a64 __builtin_mips_mult (i32, i32);
-a64 __builtin_mips_multu (ui32, ui32);
 v4i8 __builtin_mips_precr_qb_ph (v2i16, v2i16);
 v2i16 __builtin_mips_precr_sra_ph_w (i32, i32, imm0_31);
 v2i16 __builtin_mips_precr_sra_r_ph_w (i32, i32, imm0_31);