diff mbox

[MIPS] Enable fp-contract on MIPS and update -mfused-madd

Message ID 1434642321.18552.20.camel@ubuntu-sellcey
State New
Headers show

Commit Message

Steve Ellcey June 18, 2015, 3:45 p.m. UTC
On Thu, 2015-06-18 at 13:04 +0100, Maciej W. Rozycki wrote:

> 
>  This change looks good to me, I have no objections.  Thanks.
> 
>   Maciej

OK, I checked in the prequel patch and here is a new copy of the
original patch based off of that (and with no HONOR_NAN checks in the
fma/madd instructions).

OK for checkin?

Steve Ellcey
sellcey@imgtec.com


2015-06-18  Steve Ellcey  <sellcey@imgtec.com>

	* config.gcc (mips*-*-*): Add fused-madd.opt.
	* config/mips/mips.opt (mfused-madd): Remove.
	* config/mips/mips.c (mips_rtx_costs): Update cost calculations.
	* config/mips/mips.h (TARGET_MIPS8000): New.
	(ISA_HAS_FP_MADD4_MSUB4): Remove.
	(ISA_HAS_FP_MADDF_MSUBF): Remove.
	(ISA_HAS_FP_MADD3_MSUB3): Remove.
	(ISA_HAS_NMADD4_NMSUB4): Remove.
	(ISA_HAS_NMADD3_NMSUB3): Remove.
	(ISA_HAS_FUSED_MADD4): New.
	(ISA_HAS_UNFUSED_MADD4): New.
	(ISA_HAS_FUSED_MADDF): New.
	(ISA_HAS_FUSED_MADD3): New.
	* config/mips/mips.md: (fma<mode>4) Change from insn to expand.
	(*fma<mode>4_madd3) New.
	(*fma<mode>4_madd4) New.
	(*fma<mode>4_maddf) New.
	(fms<mode>4) New.
	(*fms<mode>4_msub3) New.
	(*fms<mode>4_msub4) New.
	(fnma<mode>4) New.
	(*fnma<mode>4_nmadd3) New.
	(*fnma<mode>4_nmadd4) New.
	(fnms<mode>4) New.
	(*fnms<mode>4_nmsub3) New.
	(*fnms<mode>4_nmsub4) New.
	(*madd4<mode>) Modify to be unfused only.
	(*msub4<mode>) Modify to be unfused only.
	(*nmadd4<mode>) Modify to be unfused only.
	(*nmsub4<mode>) Modify to be unfused only.
	(*madd3<mode>) Remove.
	(*msub3<mode>) Remove.
	(*nmadd3<mode>) Remove.
	(*nmsub3<mode>) Remove.
	(*nmadd3<mode>_fastmath) Remove.
	(*nmsub3<mode>_fastmath) Remove.
	(*nmadd4<mode>_fastmath) Update condition.
	(*nmsub4<mode>_fastmath)  Update condition.

Comments

Maciej W. Rozycki June 29, 2015, 4:08 p.m. UTC | #1
Richard, please have a look at my question below in a reference to your 
previous statement.

On Thu, 18 Jun 2015, Steve Ellcey wrote:

> OK, I checked in the prequel patch and here is a new copy of the
> original patch based off of that (and with no HONOR_NAN checks in the
> fma/madd instructions).
> 
> OK for checkin?

 Please see below for my notes.

> 2015-06-18  Steve Ellcey  <sellcey@imgtec.com>
> 
> 	* config.gcc (mips*-*-*): Add fused-madd.opt.

 Please use angle brackets as per 
<https://www.gnu.org/prep/standards/html_node/Indicating-the-Part-Changed.html>, 
i.e.:

	* config.gcc <mips*-*-*>: Add fused-madd.opt.

There's no function or similar entity involved here and `mips*-*-*' is a 
case value like with the C language's `switch' statement where you'd use 
angle brackets too to refer to individual cases.

> 	(*nmsub4<mode>_fastmath)  Update condition.

 Extraneous space here.

> diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
> index f6912e1..4f5692c 100644
> --- a/gcc/config/mips/mips.md
> +++ b/gcc/config/mips/mips.md
[...]
> +;; fnma is defined in GCC as (fma (neg op1) op2 op3)
> +;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
> +;; The mips nmsub instructions implement -((op1 * op2) - op3)
> +;; This transformation means we may return the wrong signed zero
> +;; so we check HONOR_SIGNED_ZEROS.
> +
> +(define_expand "fnma<mode>4"
> +  [(set (match_operand:ANYF 0 "register_operand")
> +	(fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand"))
> +		  (match_operand:ANYF 2 "register_operand")
> +		  (match_operand:ANYF 3 "register_operand")))]
> +  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)
> +   && !HONOR_SIGNED_ZEROS (<MODE>mode)")

 Have you considered the alternative/complementary approach proposed by 
Richard here: <http://gcc.gnu.org/ml/gcc-patches/2010-11/msg00680.html>, 
i.e. to introduce further expanders, e.g.:

fmanM4: (neg:M (fma:M OP1 OP2 OP3))		(multiply-add, negated)

fmsnM4: (neg:M (fma:M OP1 OP2 (neg:M OP3)))	(multiply-subtract, negated)

?

 These patterns wouldn't need a check for !HONOR_SIGNED_ZEROS as they 
match the respective hardware instructions in an exact manner.  Therefore 
I think they would be more useful as they would also suit software that 
claims/requires full IEEE Std 754 compliance.

 Richard, do you maintain the introduction of these additional operations
would be a good idea and one you're willing to support for the purpose of 
patch acceptance/approval if implemented?

> +;; fnms is defined as: (fma (neg op1) op2 (neg op3))
> +;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
> +;; The mips nmadd instructions implement -((op1 * op2) + op3)
> +;; This transformation means we may return the wrong signed zero
> +;; so we check HONOR_SIGNED_ZEROS.
> +
> +(define_expand "fnms<mode>4"
> +  [(set (match_operand:ANYF 0 "register_operand")
> +	(fma:ANYF
> +	  (neg:ANYF (match_operand:ANYF 1 "register_operand"))
> +	  (match_operand:ANYF 2 "register_operand")
> +	  (neg:ANYF (match_operand:ANYF 3 "register_operand"))))]
> +  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)
> +   && !HONOR_SIGNED_ZEROS (<MODE>mode)")

 Same observation here.

 The change looks good to me otherwise.

  Maciej
Matthew Fortune June 29, 2015, 7:07 p.m. UTC | #2
Maciej W. Rozycki <macro@linux-mips.org> writes:
> Richard, please have a look at my question below in a reference to your
> previous statement.
> 
> On Thu, 18 Jun 2015, Steve Ellcey wrote:
> 
> > OK, I checked in the prequel patch and here is a new copy of the
> > original patch based off of that (and with no HONOR_NAN checks in the
> > fma/madd instructions).
> >
> > OK for checkin?
> 
>  Please see below for my notes.
> 
> > 2015-06-18  Steve Ellcey  <sellcey@imgtec.com>
> >
> > 	* config.gcc (mips*-*-*): Add fused-madd.opt.
> 
>  Please use angle brackets as per
> <https://www.gnu.org/prep/standards/html_node/Indicating-the-Part-Changed.html>,
> i.e.:
> 
> 	* config.gcc <mips*-*-*>: Add fused-madd.opt.
> 
> There's no function or similar entity involved here and `mips*-*-*' is a
> case value like with the C language's `switch' statement where you'd use
> angle brackets too to refer to individual cases.
> 
> > 	(*nmsub4<mode>_fastmath)  Update condition.
> 
>  Extraneous space here.
> 
>  The change looks good to me otherwise.
> 
>   Maciej

If nobody can identify any further functional issues with this patch then
I'd like to get this committed and pursue enhancements as a second round.
Catherine, would you be happy for this to be committed on that basis?

Thanks,
Matthew
Moore, Catherine June 29, 2015, 7:12 p.m. UTC | #3
> -----Original Message-----
> From: Matthew Fortune [mailto:Matthew.Fortune@imgtec.com]
> Sent: Monday, June 29, 2015 3:07 PM
> To: Maciej W. Rozycki; Steve Ellcey; Moore, Catherine; Richard Biener
> Cc: Richard Sandiford; Richard Sandiford; Myers, Joseph; gcc-
> patches@gcc.gnu.org
> Subject: RE: [Patch, MIPS] Enable fp-contract on MIPS and update -mfused-
> madd
> 
> Maciej W. Rozycki <macro@linux-mips.org> writes:
> > Richard, please have a look at my question below in a reference to
> > your previous statement.
> >
> > On Thu, 18 Jun 2015, Steve Ellcey wrote:
> >
> > > OK, I checked in the prequel patch and here is a new copy of the
> > > original patch based off of that (and with no HONOR_NAN checks in
> > > the fma/madd instructions).
> > >
> > > OK for checkin?
> >
> >  Please see below for my notes.
> >
> > > 2015-06-18  Steve Ellcey  <sellcey@imgtec.com>
> > >
> > > 	* config.gcc (mips*-*-*): Add fused-madd.opt.
> >
> >  Please use angle brackets as per
> > <https://www.gnu.org/prep/standards/html_node/Indicating-the-Part-
> Chan
> > ged.html>,
> > i.e.:
> >
> > 	* config.gcc <mips*-*-*>: Add fused-madd.opt.
> >
> > There's no function or similar entity involved here and `mips*-*-*' is
> > a case value like with the C language's `switch' statement where you'd
> > use angle brackets too to refer to individual cases.
> >
> > > 	(*nmsub4<mode>_fastmath)  Update condition.
> >
> >  Extraneous space here.
> >
> >  The change looks good to me otherwise.
> >
> >   Maciej
> 
> If nobody can identify any further functional issues with this patch then I'd
> like to get this committed and pursue enhancements as a second round.
> Catherine, would you be happy for this to be committed on that basis?
> 
Yes, this is fine with me.
Richard Biener June 30, 2015, 7:32 a.m. UTC | #4
On Mon, Jun 29, 2015 at 6:08 PM, Maciej W. Rozycki <macro@linux-mips.org> wrote:
> Richard, please have a look at my question below in a reference to your
> previous statement.
>
> On Thu, 18 Jun 2015, Steve Ellcey wrote:
>
>> OK, I checked in the prequel patch and here is a new copy of the
>> original patch based off of that (and with no HONOR_NAN checks in the
>> fma/madd instructions).
>>
>> OK for checkin?
>
>  Please see below for my notes.
>
>> 2015-06-18  Steve Ellcey  <sellcey@imgtec.com>
>>
>>       * config.gcc (mips*-*-*): Add fused-madd.opt.
>
>  Please use angle brackets as per
> <https://www.gnu.org/prep/standards/html_node/Indicating-the-Part-Changed.html>,
> i.e.:
>
>         * config.gcc <mips*-*-*>: Add fused-madd.opt.
>
> There's no function or similar entity involved here and `mips*-*-*' is a
> case value like with the C language's `switch' statement where you'd use
> angle brackets too to refer to individual cases.
>
>>       (*nmsub4<mode>_fastmath)  Update condition.
>
>  Extraneous space here.
>
>> diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
>> index f6912e1..4f5692c 100644
>> --- a/gcc/config/mips/mips.md
>> +++ b/gcc/config/mips/mips.md
> [...]
>> +;; fnma is defined in GCC as (fma (neg op1) op2 op3)
>> +;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
>> +;; The mips nmsub instructions implement -((op1 * op2) - op3)
>> +;; This transformation means we may return the wrong signed zero
>> +;; so we check HONOR_SIGNED_ZEROS.
>> +
>> +(define_expand "fnma<mode>4"
>> +  [(set (match_operand:ANYF 0 "register_operand")
>> +     (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand"))
>> +               (match_operand:ANYF 2 "register_operand")
>> +               (match_operand:ANYF 3 "register_operand")))]
>> +  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)
>> +   && !HONOR_SIGNED_ZEROS (<MODE>mode)")
>
>  Have you considered the alternative/complementary approach proposed by
> Richard here: <http://gcc.gnu.org/ml/gcc-patches/2010-11/msg00680.html>,
> i.e. to introduce further expanders, e.g.:
>
> fmanM4: (neg:M (fma:M OP1 OP2 OP3))             (multiply-add, negated)
>
> fmsnM4: (neg:M (fma:M OP1 OP2 (neg:M OP3)))     (multiply-subtract, negated)
>
> ?
>
>  These patterns wouldn't need a check for !HONOR_SIGNED_ZEROS as they
> match the respective hardware instructions in an exact manner.  Therefore
> I think they would be more useful as they would also suit software that
> claims/requires full IEEE Std 754 compliance.
>
>  Richard, do you maintain the introduction of these additional operations
> would be a good idea and one you're willing to support for the purpose of
> patch acceptance/approval if implemented?

Yes, esp. if there is now a second architecture that has such instructions.

Thanks,
Richard.

>> +;; fnms is defined as: (fma (neg op1) op2 (neg op3))
>> +;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
>> +;; The mips nmadd instructions implement -((op1 * op2) + op3)
>> +;; This transformation means we may return the wrong signed zero
>> +;; so we check HONOR_SIGNED_ZEROS.
>> +
>> +(define_expand "fnms<mode>4"
>> +  [(set (match_operand:ANYF 0 "register_operand")
>> +     (fma:ANYF
>> +       (neg:ANYF (match_operand:ANYF 1 "register_operand"))
>> +       (match_operand:ANYF 2 "register_operand")
>> +       (neg:ANYF (match_operand:ANYF 3 "register_operand"))))]
>> +  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)
>> +   && !HONOR_SIGNED_ZEROS (<MODE>mode)")
>
>  Same observation here.
>
>  The change looks good to me otherwise.
>
>   Maciej
Steve Ellcey July 6, 2015, 5:35 p.m. UTC | #5
On Mon, 2015-06-29 at 12:07 -0700, Matthew Fortune wrote:

> If nobody can identify any further functional issues with this patch then
> I'd like to get this committed and pursue enhancements as a second round.
> Catherine, would you be happy for this to be committed on that basis?
> 
> Thanks,
> Matthew

Sorry for the delay (I was on vacation), I fixed up the ChangeLog issues
Maciej pointed out and checked this patch in.

Steve Ellcey
sellcey@imgtec.com
diff mbox

Patch

diff --git a/gcc/config.gcc b/gcc/config.gcc
index 805638d..fa1dd40 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -418,7 +418,7 @@  microblaze*-*-*)
 mips*-*-*)
 	cpu_type=mips
 	extra_headers="loongson.h"
-	extra_options="${extra_options} g.opt mips/mips-tables.opt"
+	extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt"
 	;;
 nds32*)
 	cpu_type=nds32
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 1c837cf..df5ab22 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -4066,13 +4066,11 @@  mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
       return true;
 
     case MINUS:
-      if (float_mode_p
-	  && (ISA_HAS_NMADD4_NMSUB4 || ISA_HAS_NMADD3_NMSUB3)
-	  && TARGET_FUSED_MADD
-	  && !HONOR_SIGNED_ZEROS (mode))
+      if (float_mode_p && ISA_HAS_UNFUSED_MADD4 && !HONOR_SIGNED_ZEROS (mode))
 	{
-	  /* See if we can use NMADD or NMSUB.  See mips.md for the
-	     associated patterns.  */
+	  /* See if we can use NMADD or NMSUB via the *nmadd4<mode>_fastmath
+	     or *nmsub4<mode>_fastmath patterns.  These patterns check for
+	     HONOR_SIGNED_ZEROS so we check here too.  */
 	  rtx op0 = XEXP (x, 0);
 	  rtx op1 = XEXP (x, 1);
 	  if (GET_CODE (op0) == MULT && GET_CODE (XEXP (op0, 0)) == NEG)
@@ -4099,9 +4097,7 @@  mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
 	{
 	  /* If this is part of a MADD or MSUB, treat the PLUS as
 	     being free.  */
-	  if ((ISA_HAS_FP_MADD4_MSUB4 || ISA_HAS_FP_MADD3_MSUB3)
-	      && TARGET_FUSED_MADD
-	      && GET_CODE (XEXP (x, 0)) == MULT)
+	  if (ISA_HAS_UNFUSED_MADD4 && GET_CODE (XEXP (x, 0)) == MULT)
 	    *total = 0;
 	  else
 	    *total = mips_cost->fp_add;
@@ -4133,13 +4129,10 @@  mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
       return true;
 
     case NEG:
-      if (float_mode_p
-	  && (ISA_HAS_NMADD4_NMSUB4 || ISA_HAS_NMADD3_NMSUB3)
-	  && TARGET_FUSED_MADD
-	  && HONOR_SIGNED_ZEROS (mode))
+      if (float_mode_p && ISA_HAS_UNFUSED_MADD4)
 	{
-	  /* See if we can use NMADD or NMSUB.  See mips.md for the
-	     associated patterns.  */
+	  /* See if we can use NMADD or NMSUB via the *nmadd4<mode> or
+	     *nmsub4<mode> patterns.  */
 	  rtx op = XEXP (x, 0);
 	  if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
 	      && GET_CODE (XEXP (op, 0)) == MULT)
@@ -4159,8 +4152,7 @@  mips_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
       return false;
 
     case FMA:
-      if (ISA_HAS_FP_MADDF_MSUBF)
-	*total = mips_fp_mult_cost (mode);
+      *total = mips_fp_mult_cost (mode);
       return false;
 
     case MULT:
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index bceef31..7a6f917 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -236,6 +236,7 @@  struct mips_cpu_info {
 #define TARGET_MIPS5500             (mips_arch == PROCESSOR_R5500)
 #define TARGET_MIPS5900             (mips_arch == PROCESSOR_R5900)
 #define TARGET_MIPS7000             (mips_arch == PROCESSOR_R7000)
+#define TARGET_MIPS8000             (mips_arch == PROCESSOR_R8000)
 #define TARGET_MIPS9000             (mips_arch == PROCESSOR_R9000)
 #define TARGET_OCTEON		    (mips_arch == PROCESSOR_OCTEON	\
 				     || mips_arch == PROCESSOR_OCTEON2	\
@@ -998,22 +999,21 @@  struct mips_cpu_info {
 /* Integer multiply-accumulate instructions should be generated.  */
 #define GENERATE_MADD_MSUB	(TARGET_IMADD && !TARGET_MIPS16)
 
-/* ISA has floating-point madd and msub instructions 'd = a * b [+-] c'.  */
-#define ISA_HAS_FP_MADD4_MSUB4  ISA_HAS_FP4
+/* ISA has 4 operand fused madd instructions of the form
+   'd = [+-] (a * b [+-] c)'.  */
+#define ISA_HAS_FUSED_MADD4	TARGET_MIPS8000
 
-/* ISA has floating-point MADDF and MSUBF instructions 'd = d [+-] a * b'.  */
-#define ISA_HAS_FP_MADDF_MSUBF  (mips_isa_rev >= 6)
+/* ISA has 4 operand unfused madd instructions of the form
+   'd = [+-] (a * b [+-] c)'.  */
+#define ISA_HAS_UNFUSED_MADD4	(ISA_HAS_FP4 && !TARGET_MIPS8000)
 
-/* ISA has floating-point madd and msub instructions 'c = a * b [+-] c'.  */
-#define ISA_HAS_FP_MADD3_MSUB3  TARGET_LOONGSON_2EF
+/* ISA has 3 operand r6 fused madd instructions of the form
+   'c = c [+-] (a * b)'.  */
+#define ISA_HAS_FUSED_MADDF	(mips_isa_rev >= 6)
 
-/* ISA has floating-point nmadd and nmsub instructions
-   'd = -((a * b) [+-] c)'.  */
-#define ISA_HAS_NMADD4_NMSUB4	ISA_HAS_FP4
-
-/* ISA has floating-point nmadd and nmsub instructions
-   'c = -((a * b) [+-] c)'.  */
-#define ISA_HAS_NMADD3_NMSUB3	TARGET_LOONGSON_2EF
+/* ISA has 3 operand loongson fused madd instructions of the form
+   'c = [+-] (a * b [+-] c)'.  */
+#define ISA_HAS_FUSED_MADD3	TARGET_LOONGSON_2EF
 
 /* ISA has floating-point RECIP.fmt and RSQRT.fmt instructions.  The
    MIPS64 rev. 1 ISA says that RECIP.D and RSQRT.D are unpredictable when
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index f6912e1..4f5692c 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -2475,164 +2475,239 @@ 
 
 ;; Floating point multiply accumulate instructions.
 
-;; The various multiply accumulate instructions can be used even when
-;; HONOR_NANS is true because while IEEE 754-2008 requires the negate
-;; operation to negate the sign of a NAN and the MIPS neg instruction does
-;; not do this, the multiply and add (or minus) parts of these instructions
-;; have no requirement on how the sign of a NAN is handled and so the final
-;; sign bit of the entire operation is undefined.
+(define_expand "fma<mode>4"
+  [(set (match_operand:ANYF 0 "register_operand")
+	(fma:ANYF (match_operand:ANYF 1 "register_operand")
+		  (match_operand:ANYF 2 "register_operand")
+		  (match_operand:ANYF 3 "register_operand")))]
+  "ISA_HAS_FUSED_MADDF || ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4")
 
-(define_insn "*madd4<mode>"
+(define_insn "*fma<mode>4_madd3"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
-			      (match_operand:ANYF 2 "register_operand" "f"))
-		   (match_operand:ANYF 3 "register_operand" "f")))]
-  "ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD"
+	(fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
+		  (match_operand:ANYF 2 "register_operand" "f")
+		  (match_operand:ANYF 3 "register_operand" "0")))]
+  "ISA_HAS_FUSED_MADD3"
+  "madd.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmadd")
+   (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "*fma<mode>4_madd4"
+  [(set (match_operand:ANYF 0 "register_operand" "=f")
+	(fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
+		  (match_operand:ANYF 2 "register_operand" "f")
+		  (match_operand:ANYF 3 "register_operand" "f")))]
+  "ISA_HAS_FUSED_MADD4"
   "madd.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "fma<mode>4"
+(define_insn "*fma<mode>4_maddf"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
 	(fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
 		  (match_operand:ANYF 2 "register_operand" "f")
 		  (match_operand:ANYF 3 "register_operand" "0")))]
-  "ISA_HAS_FP_MADDF_MSUBF"
+  "ISA_HAS_FUSED_MADDF"
   "maddf.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*madd3<mode>"
+;; The fms, fnma, and fnms instructions can be used even when HONOR_NANS
+;; is true because while IEEE 754-2008 requires the negate operation to
+;; negate the sign of a NAN and the MIPS neg instruction does not do this,
+;; the fma part of the instruction has no requirement on how the sign of
+;; a NAN is handled and so the final sign bit of the entire operation is
+;; undefined.
+
+(define_expand "fms<mode>4"
+  [(set (match_operand:ANYF 0 "register_operand")
+	(fma:ANYF (match_operand:ANYF 1 "register_operand")
+		  (match_operand:ANYF 2 "register_operand")
+		  (neg:ANYF (match_operand:ANYF 3 "register_operand"))))]
+  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)")
+
+(define_insn "*fms<mode>4_msub3"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
-			      (match_operand:ANYF 2 "register_operand" "f"))
-		   (match_operand:ANYF 3 "register_operand" "0")))]
-  "ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD"
-  "madd.<fmt>\t%0,%1,%2"
+	(fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
+		  (match_operand:ANYF 2 "register_operand" "f")
+		  (neg:ANYF (match_operand:ANYF 3 "register_operand" "0"))))]
+  "ISA_HAS_FUSED_MADD3"
+  "msub.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*msub4<mode>"
+(define_insn "*fms<mode>4_msub4"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
-			       (match_operand:ANYF 2 "register_operand" "f"))
-		    (match_operand:ANYF 3 "register_operand" "f")))]
-  "ISA_HAS_FP_MADD4_MSUB4 && TARGET_FUSED_MADD"
+	(fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
+		  (match_operand:ANYF 2 "register_operand" "f")
+		  (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
+  "ISA_HAS_FUSED_MADD4"
   "msub.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*msub3<mode>"
+;; fnma is defined in GCC as (fma (neg op1) op2 op3)
+;; (-op1 * op2) + op3 ==> -(op1 * op2) + op3 ==> -((op1 * op2) - op3)
+;; The mips nmsub instructions implement -((op1 * op2) - op3)
+;; This transformation means we may return the wrong signed zero
+;; so we check HONOR_SIGNED_ZEROS.
+
+(define_expand "fnma<mode>4"
+  [(set (match_operand:ANYF 0 "register_operand")
+	(fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand"))
+		  (match_operand:ANYF 2 "register_operand")
+		  (match_operand:ANYF 3 "register_operand")))]
+  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)
+   && !HONOR_SIGNED_ZEROS (<MODE>mode)")
+
+(define_insn "*fnma<mode>4_nmsub3"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
-			       (match_operand:ANYF 2 "register_operand" "f"))
-		    (match_operand:ANYF 3 "register_operand" "0")))]
-  "ISA_HAS_FP_MADD3_MSUB3 && TARGET_FUSED_MADD"
-  "msub.<fmt>\t%0,%1,%2"
+	(fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
+		  (match_operand:ANYF 2 "register_operand" "f")
+		  (match_operand:ANYF 3 "register_operand" "0")))]
+  "ISA_HAS_FUSED_MADD3 && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "nmsub.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmadd4<mode>"
+(define_insn "*fnma<mode>4_nmsub4"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(neg:ANYF (plus:ANYF
-		   (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
-			      (match_operand:ANYF 2 "register_operand" "f"))
-		   (match_operand:ANYF 3 "register_operand" "f"))))]
-  "ISA_HAS_NMADD4_NMSUB4
-   && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (<MODE>mode)"
-  "nmadd.<fmt>\t%0,%3,%1,%2"
+	(fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
+		  (match_operand:ANYF 2 "register_operand" "f")
+		  (match_operand:ANYF 3 "register_operand" "f")))]
+  "ISA_HAS_FUSED_MADD4 && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "nmsub.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmadd3<mode>"
+;; fnms is defined as: (fma (neg op1) op2 (neg op3))
+;; ((-op1) * op2) - op3 ==> -(op1 * op2) - op3 ==> -((op1 * op2) + op3)
+;; The mips nmadd instructions implement -((op1 * op2) + op3)
+;; This transformation means we may return the wrong signed zero
+;; so we check HONOR_SIGNED_ZEROS.
+
+(define_expand "fnms<mode>4"
+  [(set (match_operand:ANYF 0 "register_operand")
+	(fma:ANYF
+	  (neg:ANYF (match_operand:ANYF 1 "register_operand"))
+	  (match_operand:ANYF 2 "register_operand")
+	  (neg:ANYF (match_operand:ANYF 3 "register_operand"))))]
+  "(ISA_HAS_FUSED_MADD3 || ISA_HAS_FUSED_MADD4)
+   && !HONOR_SIGNED_ZEROS (<MODE>mode)")
+
+(define_insn "*fnms<mode>4_nmadd3"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(neg:ANYF (plus:ANYF
-		   (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
-			      (match_operand:ANYF 2 "register_operand" "f"))
-		   (match_operand:ANYF 3 "register_operand" "0"))))]
-  "ISA_HAS_NMADD3_NMSUB3
-   && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (<MODE>mode)"
+	(fma:ANYF
+	  (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
+	  (match_operand:ANYF 2 "register_operand" "f")
+	  (neg:ANYF (match_operand:ANYF 3 "register_operand" "0"))))]
+  "ISA_HAS_FUSED_MADD3 && !HONOR_SIGNED_ZEROS (<MODE>mode)"
   "nmadd.<fmt>\t%0,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmadd4<mode>_fastmath"
+(define_insn "*fnms<mode>4_nmadd4"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(minus:ANYF
-	 (mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
-		    (match_operand:ANYF 2 "register_operand" "f"))
-	 (match_operand:ANYF 3 "register_operand" "f")))]
-  "ISA_HAS_NMADD4_NMSUB4
-   && TARGET_FUSED_MADD
-   && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+	(fma:ANYF
+	  (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
+	  (match_operand:ANYF 2 "register_operand" "f")
+	  (neg:ANYF (match_operand:ANYF 3 "register_operand" "f"))))]
+  "ISA_HAS_FUSED_MADD4 && !HONOR_SIGNED_ZEROS (<MODE>mode)"
   "nmadd.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmadd3<mode>_fastmath"
+;; Non-fused Floating point multiply accumulate instructions.
+
+;; These instructions are not fused and round in between the multiply
+;; and the add (or subtract) so they are equivalent to the separate
+;; multiply and add/sub instructions.
+
+(define_insn "*madd4<mode>"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(minus:ANYF
-	 (mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
-		    (match_operand:ANYF 2 "register_operand" "f"))
-	 (match_operand:ANYF 3 "register_operand" "0")))]
-  "ISA_HAS_NMADD3_NMSUB3
-   && TARGET_FUSED_MADD
-   && !HONOR_SIGNED_ZEROS (<MODE>mode)"
-  "nmadd.<fmt>\t%0,%1,%2"
+	(plus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
+			      (match_operand:ANYF 2 "register_operand" "f"))
+		   (match_operand:ANYF 3 "register_operand" "f")))]
+  "ISA_HAS_UNFUSED_MADD4"
+  "madd.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmsub4<mode>"
+(define_insn "*msub4<mode>"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
-	(neg:ANYF (minus:ANYF
-		   (mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
-			      (match_operand:ANYF 3 "register_operand" "f"))
-		   (match_operand:ANYF 1 "register_operand" "f"))))]
-  "ISA_HAS_NMADD4_NMSUB4
-   && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (<MODE>mode)"
-  "nmsub.<fmt>\t%0,%1,%2,%3"
+	(minus:ANYF (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
+			       (match_operand:ANYF 2 "register_operand" "f"))
+		    (match_operand:ANYF 3 "register_operand" "f")))]
+  "ISA_HAS_UNFUSED_MADD4"
+  "msub.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmsub3<mode>"
+;; Like with the fused fms, fnma, and fnms instructions, these unfused
+;; instructions can be used even if HONOR_NANS is set because while
+;; IEEE 754-2008 requires the negate operation to negate the sign of a
+;; NAN and the MIPS neg instruction does not do this, the multiply and
+;; add (or subtract) part of the instruction has no requirement on how
+;; the sign of a NAN is handled and so the final sign bit of the entire
+;; operation is undefined.
+
+(define_insn "*nmadd4<mode>"
+  [(set (match_operand:ANYF 0 "register_operand" "=f")
+	(neg:ANYF (plus:ANYF
+		   (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
+			      (match_operand:ANYF 2 "register_operand" "f"))
+		   (match_operand:ANYF 3 "register_operand" "f"))))]
+  "ISA_HAS_UNFUSED_MADD4"
+  "nmadd.<fmt>\t%0,%3,%1,%2"
+  [(set_attr "type" "fmadd")
+   (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "*nmsub4<mode>"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
 	(neg:ANYF (minus:ANYF
-		   (mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
-			      (match_operand:ANYF 3 "register_operand" "f"))
-		   (match_operand:ANYF 1 "register_operand" "0"))))]
-  "ISA_HAS_NMADD3_NMSUB3
-   && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (<MODE>mode)"
-  "nmsub.<fmt>\t%0,%1,%2"
+		   (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
+			      (match_operand:ANYF 2 "register_operand" "f"))
+		   (match_operand:ANYF 3 "register_operand" "f"))))]
+  "ISA_HAS_UNFUSED_MADD4"
+  "nmsub.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmsub4<mode>_fastmath"
+;; Fast-math Non-fused Floating point multiply accumulate instructions.
+
+;; These instructions are not fused but the expressions they match are
+;; not exactly what the instruction implements in the sense that they
+;; may not generate the properly signed zeros.
+
+;; This instruction recognizes  ((-op1) * op2) - op3 and generates an
+;; nmadd which is really -((op1 * op2) + op3).  They are equivalent
+;; except for the sign bit when the result is zero or NaN.
+
+(define_insn "*nmadd4<mode>_fastmath"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
 	(minus:ANYF
-	 (match_operand:ANYF 1 "register_operand" "f")
-	 (mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
-		    (match_operand:ANYF 3 "register_operand" "f"))))]
-  "ISA_HAS_NMADD4_NMSUB4
-   && TARGET_FUSED_MADD
+	  (mult:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
+		     (match_operand:ANYF 2 "register_operand" "f"))
+	  (match_operand:ANYF 3 "register_operand" "f")))]
+  "ISA_HAS_UNFUSED_MADD4
    && !HONOR_SIGNED_ZEROS (<MODE>mode)"
-  "nmsub.<fmt>\t%0,%1,%2,%3"
+  "nmadd.<fmt>\t%0,%3,%1,%2"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
-(define_insn "*nmsub3<mode>_fastmath"
+;; This instruction recognizes (op1 - (op2 * op3) and generates an
+;; nmsub which is really -((op2 * op3) - op1).  They are equivalent
+;; except for the sign bit when the result is zero or NaN.
+
+(define_insn "*nmsub4<mode>_fastmath"
   [(set (match_operand:ANYF 0 "register_operand" "=f")
 	(minus:ANYF
-	 (match_operand:ANYF 1 "register_operand" "f")
-	 (mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
-		    (match_operand:ANYF 3 "register_operand" "0"))))]
-  "ISA_HAS_NMADD3_NMSUB3
-   && TARGET_FUSED_MADD
+	  (match_operand:ANYF 1 "register_operand" "f")
+	  (mult:ANYF (match_operand:ANYF 2 "register_operand" "f")
+		     (match_operand:ANYF 3 "register_operand" "f"))))]
+  "ISA_HAS_UNFUSED_MADD4
    && !HONOR_SIGNED_ZEROS (<MODE>mode)"
-  "nmsub.<fmt>\t%0,%1,%2"
+  "nmsub.<fmt>\t%0,%1,%2,%3"
   [(set_attr "type" "fmadd")
    (set_attr "mode" "<UNITMODE>")])
 
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index a9baebe..348c6e0 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -209,10 +209,6 @@  mflush-func=
 Target RejectNegative Joined Var(mips_cache_flush_func) Init(CACHE_FLUSH_FUNC)
 -mflush-func=FUNC	Use FUNC to flush the cache before calling stack trampolines
 
-mfused-madd
-Target Report Var(TARGET_FUSED_MADD) Init(1)
-Generate floating-point multiply-add instructions
-
 mabs=
 Target RejectNegative Joined Enum(mips_ieee_754_value) Var(mips_abs) Init(MIPS_IEEE_754_DEFAULT)
 -mabs=MODE	Select the IEEE 754 ABS/NEG instruction execution mode