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

login
register
mail settings
Submitter Fu, Chao-Ying
Date Nov. 2, 2010, 6:46 p.m.
Message ID <7C6479EB2BF52547AC332FD6034646DA301809A9@exchdb02.mips.com>
Download mbox | patch
Permalink /patch/69919/
State New
Headers show

Comments

Fu, Chao-Ying - Nov. 2, 2010, 6:46 p.m.
Richard Sandiford wrote:
> >   As you suggest, here is the revised patch.  These 6
> instructions are moved to DSPr1, so that
> > the corresponding builtin-funcitons can be called when
> "-mdsp" is used.
> > The destination register may be hilo or four DSP
> accumulators, depending on
> > the register constraint "ka" that depends on ISA_HAS_DSP_MULT.
> > And ISA_HAS_DSP_MULT is based on HAVE_AS_DSP_REV1_MULT from
> configuration-time.
> > I restore the test of dspr2-MULT.c and dspr2-MULTU.c to use
> -mdspr2, since -mdspr2 definitely
> > can trigger the usage of all four accumulators.
>
> The problem with this is that the condition on the expander:
>
> +(define_expand "mips_mult<u>"
> +  [(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"))))]
> +  "ISA_HAS_DSP && !TARGET_64BIT")
>
> doesn't match the condition on the associated insn:
>
>  (define_insn "<u>mulsidi3_32bit"
> -  [(set (match_operand:DI 0 "register_operand" "=x")
> +  [(set (match_operand:DI 0 "register_operand" "=ka")
>         (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"
> -  "mult<u>\t%1,%2"
> +  "!TARGET_64BIT && !TARGET_FIX_R4000"
> ...
>
> Note the !TARGET_FIX_R4000.  It might not make much sense, but there's
> nothing stopping someone from using -mdsp and -mfix-r4000 together.
> Although we _could_ either reject the combination or force
> MASK_FIX_R4000
> to false, that would set a bad precendent.  In general, -mfix-* flags
> should work "on top of" whatever ISA mode is selected.
>
> However, I like your idea of making the builtin functions
> available in rev1
> regardless of whether the assembler supports them, and
> falling back on the
> single accumulator if necessary.  It seems reasonable to use:
>
>   "!TARGET_64BIT && (!TARGET_FIX_R4000 || ISA_HAS_DSP)"

  Ok.  This predicate is better.

> here, with a comment:
>
> ;; As well as being named patterns, these instructions are used by the
> ;; __builtin_mips_mult<u>() functions.  We must always make
> those functions
> ;; available if !TARGET_64BIT && ISA_HAS_DSP.

  Ok.  Good comments.

>
> Also, now that you've merged the two mult define_insns (a good step,
> thanks), there's no need for the mips_mult<u> expander.  Just add:
>
> #define CODE_FOR_mips_mult CODE_FOR_mulsidi3_32bit
> #define CODE_FOR_mips_multu CODE_FOR_umulsidi3_32bit

  Ok.  Good to reduce code.

> to the builtins code in mips.c.  Similarly, <u>maddsidi4 and
> <u>msubsidi4 are now named patterns (which wasn't true when
> the DSP code was originally added), so we can do the same
> thing for mips_madd<u> and mips_msub<u>.

  Due to the order of input operands is different, I still need to keep mips_madd<u>
and mips_msub<u>.  Otherwise, the prototype of __builtin_mips_madd/maddu/msub/msubu
will not be matched.

> A similar problem (though not in this case a correctness problem)
> occurs with:
>
> -  "!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB ||
> ISA_HAS_DSPR2)"
> +  "!TARGET_64BIT && (ISA_HAS_MSAC || GENERATE_MADD_MSUB ||
> ISA_HAS_DSP)"
>
> GENERATE_MADD_MSUB is defined as:
>
> #define GENERATE_MADD_MSUB      (ISA_HAS_MADD_MSUB && !TUNE_74K)
>
> yet the 74k is a DSP target.  The old condition could be justified
> on the basis that, if you're tuning for the 74k but have all four
> accumulators available, it's better to use these instructions anyway.
> After the patch, we might use the instructions when tuning for the
> 74k and when only one accumulator is available, which is exactly
> the case that GENERATE_MADD_MSUB was trying to avoid.
>
> Still, I suppose -mtune=74k -mdsp, as opposed to -mtune=74k -mdspr2,
> is probably a niche combination, and I can't think of a good way out.
> I suppose we can just hope that anyone using that combination is
> prepared to upgrade their binutils or live the possible drop in
> performance.
>
> So, let's go with the MADD_MSUB conditions in your patch, but add:
>
> ;; As well as being named patterns, these instructions are used by the
> ;; __builtin_mips_madd<u>() functions.  We must always make
> those functions
> ;; available if !TARGET_64BIT && ISA_HAS_DSP.
> ;;
> ;; This leads to a slight inconsistency.  We honor any tuning
> overrides
> ;; in GENERATE_MADD_MSUB for -mno-dsp, but always ignore them
> for -mdsp,
> ;; even if !ISA_HAS_DSP_MULT.
>
> before <u>maddsidi4, and:
>
> ;; See the comment above <u>maddsidi4 for the relationship between
> ;; ISA_HAS_DSP and ISA_HAS_DSP_MULT.
>
> above <u>msubsidi4.

  Ok.  Good comments.

>
> Also, a minor nit, but let's call the macro HAVE_AS_DSPR1_MULT,
> for consistency with -mdspr2, ISA_HAS_DSPR2, etc.

  Ok.

  Here is the updated version.  I also updated mips_mulsidi3_gen_fun() in mips.c to have correct
returns.  Testing results are fine on mips-sde-elf (mips32r2).
No new failures.
Ex:
                === gcc Summary ===

# of expected passes            65004
# of unexpected failures        1864
# of expected failures          118
# of unresolved testcases       1523
# of unsupported tests          978
/home/fu/dev/gcc45/build/gcc/xgcc  version 4.6.0 20101027 (experimental) [trunk
revision 166016] (GCC)

  Ok to apply?  Thanks a lot!

Regards,
Chao-ying

gcc/ChangeLog
2010-11-02  Chao-ying Fu  <fu@mips.com>

        * configure.ac: Test assembler support for DSP Rev1 mult.
        * configure: Regenerate.
        * config.in: Regenerate.
        * config/mips/mips.h (ISA_HAS_DSP_MULT): New define.
        * config/mips/mips.c (CODE_FOR_mips_mult): New define.
        (CODE_FOR_mips_multu): New define.
        (mips_builtins): Move madd, maddu, msub, msubu,
        mult, multu from dspr2_32 to dsp_32.
        (mips_mulsidi3_gen_fn): Test (TARGET_FIX_R4000 && !ISA_HAS_DSP).
        Delete returns when ISA_HAS_DSPR2, because the old patterns are deleted.
        * config/mips/mips-dsp.md (mips_madd<u>, mips_msub<u>):
        New define_expand patterns.
        * config/mips/constraints.md (ka): Update the constraint to test
        ISA_HAS_DSP_MULT 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): Add comments.
        Change target constraint to "ka".
        Instead of !TARGET_FIX_R4000 && !ISA_HAS_DSPR2,
        use (!TARGET_FIX_R4000 || ISA_HAS_DSP).
        Emit the accumulator destination when ISA_HAS_DSP_MULT.
        (<u>msubsidi4): Add comments.
        Test ISA_HAS_DSP.
        Emit the accumulator destination when ISA_HAS_DSP_MULT.
        (<u>maddsidi4): Likewise.

        * 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-11-02  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.
Richard Sandiford - Nov. 3, 2010, 9:29 p.m.
"Fu, Chao-Ying" <fu@mips.com> writes:
>> to the builtins code in mips.c.  Similarly, <u>maddsidi4 and
>> <u>msubsidi4 are now named patterns (which wasn't true when
>> the DSP code was originally added), so we can do the same
>> thing for mips_madd<u> and mips_msub<u>.
>
>   Due to the order of input operands is different, I still need to keep mips_madd<u>
> and mips_msub<u>.  Otherwise, the prototype of __builtin_mips_madd/maddu/msub/msubu
> will not be matched.

Oh yeah, missed that.  I vaguely remember you might have had
to point this out to me before. :-/

The new patch is OK, thanks.  I see that the tests have things like:

> +/* { dg-final { scan-assembler "mult" } } */
> +/* { dg-final { scan-assembler "multu" } } */

which is weak: a multu will match both.  But that's a problem with
the existing tests too, and should be fixed separately.  It's better
to be consistent with the current code as far as this check-in is
concerned.

Richard

Patch

Index: gcc45/gcc/gcc/config/mips/mips.c
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips.c       2010-10-29 10:33:05.232481000 -0700
+++ gcc45/gcc/gcc/config/mips/mips.c    2010-11-01 11:49:56.786802000 -0700
@@ -12730,6 +12730,8 @@  AVAIL_NON_MIPS16 (cache, TARGET_CACHE_BU
 #define CODE_FOR_mips_subq_ph CODE_FOR_subv2hi3
 #define CODE_FOR_mips_subu_qb CODE_FOR_subv4qi3
 #define CODE_FOR_mips_mul_ph CODE_FOR_mulv2hi3
+#define CODE_FOR_mips_mult CODE_FOR_mulsidi3_32bit
+#define CODE_FOR_mips_multu CODE_FOR_umulsidi3_32bit

 #define CODE_FOR_loongson_packsswh CODE_FOR_vec_pack_ssat_v2si
 #define CODE_FOR_loongson_packsshb CODE_FOR_vec_pack_ssat_v4hi
@@ -12928,17 +12930,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),
@@ -16174,10 +16176,8 @@  mips_mulsidi3_gen_fn (enum rtx_code ext_
     }
   else
     {
-      if (TARGET_FIX_R4000)
+      if (TARGET_FIX_R4000 && !ISA_HAS_DSP)
        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;
     }
 }
Index: gcc45/gcc/gcc/config/mips/constraints.md
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/constraints.md       2010-10-29 10:33:05.431478000 -0700
+++ gcc45/gcc/gcc/config/mips/constraints.md    2010-11-01 10:51:34.202681000 -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_MULT ? 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-10-29 10:33:05.435477000 -0700
+++ gcc45/gcc/gcc/config/mips/mips-dspr2.md     2010-11-01 10:51:34.224676000 -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-10-29 10:33:05.535435000 -0700
+++ gcc45/gcc/gcc/config/mips/mips.md   2010-11-01 11:49:31.486075000 -0700
@@ -1731,12 +1731,20 @@ 
   DONE;
 })

+;; As well as being named patterns, these instructions are used by the
+;; __builtin_mips_mult<u>() functions.  We must always make those functions
+;; available if !TARGET_64BIT && ISA_HAS_DSP.
 (define_insn "<u>mulsidi3_32bit"
-  [(set (match_operand:DI 0 "register_operand" "=x")
+  [(set (match_operand:DI 0 "register_operand" "=ka")
        (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"
-  "mult<u>\t%1,%2"
+  "!TARGET_64BIT && (!TARGET_FIX_R4000 || ISA_HAS_DSP)"
+{
+  if (ISA_HAS_DSP_MULT)
+    return "mult<u>\t%q0,%1,%2";
+  else
+    return "mult<u>\t%1,%2";
+}
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")])

@@ -1856,6 +1864,13 @@ 
   [(set_attr "type" "imul")
    (set_attr "mode" "SI")])

+;; As well as being named patterns, these instructions are used by the
+;; __builtin_mips_msub<u>() functions.  We must always make those functions
+;; available if !TARGET_64BIT && ISA_HAS_DSP.
+;;
+;; This leads to a slight inconsistency.  We honor any tuning overrides
+;; in GENERATE_MADD_MSUB for -mno-dsp, but always ignore them for -mdsp,
+;; even if !ISA_HAS_DSP_MULT.
 (define_insn "<u>msubsidi4"
   [(set (match_operand:DI 0 "register_operand" "=ka")
         (minus:DI
@@ -1863,9 +1878,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_MULT)
     return "msub<u>\t%q0,%1,%2";
   else if (TARGET_MIPS5500 || GENERATE_MADD_MSUB)
     return "msub<u>\t%1,%2";
@@ -2036,18 +2051,20 @@ 
   [(set_attr "type"    "imadd")
    (set_attr "mode"    "SI")])

+;; See the comment above <u>msubsidi4 for the relationship between
+;; ISA_HAS_DSP and ISA_HAS_DSP_MULT.
 (define_insn "<u>maddsidi4"
   [(set (match_operand:DI 0 "register_operand" "=ka")
        (plus:DI
         (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_MULT)
     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   2010-10-29 10:33:05.692390000 -0700
+++ gcc45/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp.c        2010-11-01 10:51:34.410678000 -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/mips32-dsp-run.c
===================================================================
--- gcc45.orig/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp-run.c       2010-10-29 10:33:05.698387000 -0700
+++ gcc45/gcc/gcc/testsuite/gcc.target/mips/mips32-dsp-run.c    2010-11-01 10:51:34.432677000 -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-29 10:33:05.786385000 -0700
+++ gcc45/gcc/gcc/doc/extend.texi       2010-11-01 10:51:34.532675000 -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);
Index: gcc45/gcc/gcc/configure
===================================================================
--- gcc45.orig/gcc/gcc/configure        2010-10-29 10:33:05.915381000 -0700
+++ gcc45/gcc/gcc/configure     2010-11-01 11:06:59.404130000 -0700
@@ -24391,6 +24391,45 @@  $as_echo "#define HAVE_AS_DTPRELWORD 1"

 fi

+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for DSPR1 mult with four accumulators support" >&5
+$as_echo_n "checking assembler for DSPR1 mult with four accumulators support... " >&6; }
+if test "${gcc_cv_as_mips_dspr1_mult+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_mips_dspr1_mult=no
+  if test x$gcc_cv_as != x; then
+    echo '     .set    mips32r2
+       .set    nodspr2
+       .set    dsp
+       madd    $ac3,$4,$5
+       maddu   $ac3,$4,$5
+       msub    $ac3,$4,$5
+       msubu   $ac3,$4,$5
+       mult    $ac3,$4,$5
+       multu   $ac3,$4,$5' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+       gcc_cv_as_mips_dspr1_mult=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_mips_dspr1_mult" >&5
+$as_echo "$gcc_cv_as_mips_dspr1_mult" >&6; }
+if test $gcc_cv_as_mips_dspr1_mult = yes; then
+
+$as_echo "#define HAVE_AS_DSPR1_MULT 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler and linker for explicit JALR relocation" >&5
 $as_echo_n "checking assembler and linker for explicit JALR relocation... " >&6; }
     gcc_cv_as_ld_jalr_reloc=no
Index: gcc45/gcc/gcc/configure.ac
===================================================================
--- gcc45.orig/gcc/gcc/configure.ac     2010-10-29 10:33:05.919387000 -0700
+++ gcc45/gcc/gcc/configure.ac  2010-11-01 11:06:50.300948000 -0700
@@ -3658,6 +3658,20 @@  x:
       [AC_DEFINE(HAVE_AS_DTPRELWORD, 1,
          [Define if your assembler supports .dtprelword.])])

+    gcc_GAS_CHECK_FEATURE([DSPR1 mult with four accumulators support],
+      gcc_cv_as_mips_dspr1_mult,,,
+[      .set    mips32r2
+       .set    nodspr2
+       .set    dsp
+       madd    $ac3,$4,$5
+       maddu   $ac3,$4,$5
+       msub    $ac3,$4,$5
+       msubu   $ac3,$4,$5
+       mult    $ac3,$4,$5
+       multu   $ac3,$4,$5],,
+      [AC_DEFINE(HAVE_AS_DSPR1_MULT, 1,
+         [Define if your assembler supports DSPR1 mult.])])
+
     AC_MSG_CHECKING(assembler and linker for explicit JALR relocation)
     gcc_cv_as_ld_jalr_reloc=no
     if test $gcc_cv_as_mips_explicit_relocs = yes; then
Index: gcc45/gcc/gcc/config/mips/mips.h
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips.h       2010-10-29 10:33:05.620384000 -0700
+++ gcc45/gcc/gcc/config/mips/mips.h    2010-11-01 16:30:11.140899000 -0700
@@ -180,6 +180,13 @@  enum mips_code_readable_setting {
 #define TARGET_WRITABLE_EH_FRAME (flag_pic && TARGET_SHARED)
 #endif

+/* Test the assembler to set ISA_HAS_DSP_MULT to DSP Rev 1 or 2.  */
+#ifdef HAVE_AS_DSPR1_MULT
+#define ISA_HAS_DSP_MULT ISA_HAS_DSP
+#else
+#define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
+#endif
+
 /* Generate mips16 code */
 #define TARGET_MIPS16          ((target_flags & MASK_MIPS16) != 0)
 /* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
Index: gcc45/gcc/gcc/config.in
===================================================================
--- gcc45.orig/gcc/gcc/config.in        2010-10-29 10:33:05.962399000 -0700
+++ gcc45/gcc/gcc/config.in     2010-11-01 11:07:07.478399000 -0700
@@ -229,6 +229,12 @@ 
 #endif


+/* Define if your assembler supports DSPR1 mult. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_DSPR1_MULT
+#endif
+
+
 /* Define if your assembler supports .dtprelword. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_DTPRELWORD
Index: gcc45/gcc/gcc/config/mips/mips-dsp.md
===================================================================
--- gcc45.orig/gcc/gcc/config/mips/mips-dsp.md  2010-10-29 10:33:05.337472000 -0700
+++ gcc45/gcc/gcc/config/mips/mips-dsp.md       2010-11-01 11:48:27.517899000 -0700
@@ -1181,3 +1181,18 @@ 
   "%*bposge%1\t%0%/"
   [(set_attr "type"    "branch")])

+(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")