===================================================================
@@ -3827,6 +3827,10 @@ mips_rtx_costs (rtx x, int code, int out
*total = mips_cost->int_mult_si;
return false;
+ case FMA:
+ *total = mips_fp_mult_cost (mode);
+ return false;
+
case DIV:
/* Check for a reciprocal. */
if (float_mode_p
===================================================================
@@ -2077,158 +2077,176 @@ (define_insn "<u>maddsidi4"
;; Floating point multiply accumulate instructions.
-(define_insn "*madd4<mode>"
- [(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"
- "madd.<fmt>\t%0,%3,%1,%2"
- [(set_attr "type" "fmadd")
- (set_attr "mode" "<UNITMODE>")])
-
-(define_insn "*madd3<mode>"
- [(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"
+(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_FP_MADD3_MSUB3 || ISA_HAS_FP_MADD4_MSUB4")
+
+(define_insn "*fma<mode>4_madd3"
+ [(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_MADD3_MSUB3"
"madd.<fmt>\t%0,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*msub4<mode>"
+(define_insn "*fma<mode>4_madd4"
[(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"
- "msub.<fmt>\t%0,%3,%1,%2"
+ (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_FP_MADD4_MSUB4"
+ "madd.<fmt>\t%0,%3,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*msub3<mode>"
- [(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"
+(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_FP_MADD3_MSUB3 || ISA_HAS_FP_MADD4_MSUB4")
+
+(define_insn "*fms<mode>4_msub3"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (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_FP_MADD3_MSUB3"
"msub.<fmt>\t%0,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmadd4<mode>"
+(define_insn "*fms<mode>4_msub4"
[(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 (<MODE>mode)
- && TARGET_FUSED_MADD
- && HONOR_SIGNED_ZEROS (<MODE>mode)
- && !HONOR_NANS (<MODE>mode)"
- "nmadd.<fmt>\t%0,%3,%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" "f"))))]
+ "ISA_HAS_FP_MADD4_MSUB4"
+ "msub.<fmt>\t%0,%3,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmadd3<mode>"
+;; If we're ignoring signed zeros, we can use NMADD (-(a * b + c)) to
+;; implement fnms (-a * b - c, which is unconditionally equivalent to
+;; -(a * b) - c).
+(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_NMADD3_NMSUB3 (<MODE>mode) || ISA_HAS_NMADD4_NMSUB4 (<MODE>mode))
+ && !HONOR_SIGNED_ZEROS (<MODE>mode)
+ && !HONOR_NANS (<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"))))]
+ (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_NMADD3_NMSUB3 (<MODE>mode)
- && TARGET_FUSED_MADD
- && HONOR_SIGNED_ZEROS (<MODE>mode)
+ && !HONOR_SIGNED_ZEROS (<MODE>mode)
&& !HONOR_NANS (<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")))]
+ (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_NMADD4_NMSUB4 (<MODE>mode)
- && TARGET_FUSED_MADD
&& !HONOR_SIGNED_ZEROS (<MODE>mode)
&& !HONOR_NANS (<MODE>mode)"
"nmadd.<fmt>\t%0,%3,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmadd3<mode>_fastmath"
+(define_insn "*nmadd3"
[(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 (<MODE>mode)
- && TARGET_FUSED_MADD
- && !HONOR_SIGNED_ZEROS (<MODE>mode)
- && !HONOR_NANS (<MODE>mode)"
+ (neg:ANYF
+ (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_NMADD3_NMSUB3 (<MODE>mode) && !HONOR_NANS (<MODE>mode)"
"nmadd.<fmt>\t%0,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmsub4<mode>"
+(define_insn "*nmadd4"
[(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 (<MODE>mode)
- && TARGET_FUSED_MADD
- && HONOR_SIGNED_ZEROS (<MODE>mode)
- && !HONOR_NANS (<MODE>mode)"
- "nmsub.<fmt>\t%0,%1,%2,%3"
+ (neg:ANYF
+ (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_NMADD4_NMSUB4 (<MODE>mode) && !HONOR_NANS (<MODE>mode)"
+ "nmadd.<fmt>\t%0,%3,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmsub3<mode>"
+;; If we're ignoring signed zeros, we can use NMSUB (-(a * b - c)) to
+;; implement fnma (-a * b + c, which is unconditionally equivalent to
+;; -(a * b) + c).
+(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_NMADD3_NMSUB3 (<MODE>mode) || ISA_HAS_NMADD4_NMSUB4 (<MODE>mode))
+ && !HONOR_SIGNED_ZEROS (<MODE>mode)
+ && !HONOR_NANS (<MODE>mode)")
+
+(define_insn "*fnma<mode>4_nmsub3"
[(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"))))]
+ (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_NMADD3_NMSUB3 (<MODE>mode)
- && TARGET_FUSED_MADD
- && HONOR_SIGNED_ZEROS (<MODE>mode)
+ && !HONOR_SIGNED_ZEROS (<MODE>mode)
&& !HONOR_NANS (<MODE>mode)"
"nmsub.<fmt>\t%0,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmsub4<mode>_fastmath"
+(define_insn "*fnma<mode>4_nmsub4"
[(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"))))]
+ (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_NMADD4_NMSUB4 (<MODE>mode)
- && TARGET_FUSED_MADD
&& !HONOR_SIGNED_ZEROS (<MODE>mode)
&& !HONOR_NANS (<MODE>mode)"
- "nmsub.<fmt>\t%0,%1,%2,%3"
+ "nmsub.<fmt>\t%0,%3,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
-(define_insn "*nmsub3<mode>_fastmath"
+(define_insn "*nmsub3"
[(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 (<MODE>mode)
- && TARGET_FUSED_MADD
- && !HONOR_SIGNED_ZEROS (<MODE>mode)
- && !HONOR_NANS (<MODE>mode)"
+ (neg:ANYF
+ (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_NMADD3_NMSUB3 (<MODE>mode) && !HONOR_NANS (<MODE>mode)"
"nmsub.<fmt>\t%0,%1,%2"
[(set_attr "type" "fmadd")
(set_attr "mode" "<UNITMODE>")])
+(define_insn "*nmsub4"
+ [(set (match_operand:ANYF 0 "register_operand" "=f")
+ (neg:ANYF
+ (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_NMADD4_NMSUB4 (<MODE>mode) && !HONOR_NANS (<MODE>mode)"
+ "nmsub.<fmt>\t%0,%3,%1,%2"
+ [(set_attr "type" "fmadd")
+ (set_attr "mode" "<UNITMODE>")])
+
;;
;; ....................
;;
===================================================================
@@ -292,6 +292,13 @@ foreach option {
lappend mips_option_groups $option "-f(no-|)$option"
}
+# Add -ffoo= options to mips_option_groups.
+foreach option {
+ fp-contract
+} {
+ lappend mips_option_groups $option "-f$option=.*"
+}
+
# A list of option groups that have an impact on the ABI.
set mips_abi_groups {
abi
===================================================================
@@ -0,0 +1,82 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -fno-fast-math -ffp-contract=off" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 3 } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* We should not use NMADD or NMSUB without -ffinite-math-only because
+ those instructions may perform arithmetic negation. */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+not_nmadd_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+not_nmsub_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+not_nmadd_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, -d);
+}
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, d);
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+not_nmadd_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+not_nmsub_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+not_nmadd_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, -d);
+}
+
+NOMIPS16 double
+not_nmsub_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, d);
+}
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -fno-fast-math -ffp-contract=off -ffinite-math-only" } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+NOMIPS16 float
+nmadd_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 double
+nmadd_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, d);
+}
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -fno-fast-math -ffp-contract=off -ffinite-math-only" } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+
+NOMIPS16 float
+nmsub_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 double
+nmsub_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, -d);
+}
===================================================================
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -fno-fast-math -ffp-contract=off -ffinite-math-only" } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* These patterns can only use NMADD if -fno-signed-zeros is in effect. */
+
+NOMIPS16 float
+not_nmadd_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, -d);
+}
+
+NOMIPS16 double
+not_nmadd_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, -d);
+}
===================================================================
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -fno-fast-math -ffp-contract=off -ffinite-math-only" } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* These patterns can only use NMSUB if -fno-signed-zeros is in effect. */
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, d);
+}
+
+NOMIPS16 double
+not_nmsub_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, d);
+}
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -ffast-math" } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+NOMIPS16 float
+nmadd_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, -d);
+}
+
+NOMIPS16 double
+nmadd_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, -d);
+}
===================================================================
@@ -0,0 +1,16 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -ffast-math" } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+
+NOMIPS16 float
+nmsub_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, d);
+}
+
+NOMIPS16 double
+nmsub_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, d);
+}
===================================================================
@@ -0,0 +1,81 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O -ffast-math" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.d\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.d\t" 2 } } */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+nmadd_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+nmsub_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+nmadd_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, -d);
+}
+
+NOMIPS16 float
+nmsub_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, d);
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+nmadd_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+nmsub_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+nmadd_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, -d);
+}
+
+NOMIPS16 double
+nmsub_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, d);
+}
===================================================================
@@ -0,0 +1,70 @@
+/* { dg-options "-mpaired-single -O3 -fno-fast-math -ftree-vectorize -ffp-contract=off" } */
+/* { dg-final { scan-assembler "\tmadd\\.ps\t" } } */
+/* { dg-final { scan-assembler "\tmsub\\.s\t" } } */
+/* { dg-final { scan-assembler-not "\tmsub\\.ps\t" } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* We should not use NMADD or NMSUB without -ffinite-math-only because
+ those instructions may perform arithmetic negation. We don't really
+ expect the nmadd_ps and nmsub_ps functions to use MADD.PS and MSUB.PS,
+ but there's no reason in principle why they shouldn't.
+
+ ??? At the moment, we don't vectorize msub_ps, but we probably should. */
+
+#define N 512
+float a[N], b[N], c[N], d[N];
+
+NOMIPS16 void
+madd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (b[i], c[i], d[i]);
+}
+
+NOMIPS16 float
+msub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (b[i], c[i], -d[i]);
+}
+
+NOMIPS16 float
+not_nmadd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -__builtin_fmaf (b[i], c[i], d[i]);
+}
+
+NOMIPS16 float
+not_nmsub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -__builtin_fmaf (b[i], c[i], -d[i]);
+}
+
+NOMIPS16 float
+not_nmadd_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (-b[i], c[i], -d[i]);
+}
+
+NOMIPS16 float
+not_nmsub_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (-b[i], c[i], d[i]);
+}
===================================================================
@@ -0,0 +1,62 @@
+/* { dg-options "-mpaired-single -O -ffast-math -ftree-vectorize" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.ps\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.ps\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.ps\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.ps\t" 2 } } */
+
+#define N 512
+float a[N], b[N], c[N], d[N];
+
+NOMIPS16 void
+madd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (b[i], c[i], d[i]);
+}
+
+NOMIPS16 float
+msub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (b[i], c[i], -d[i]);
+}
+
+NOMIPS16 float
+nmadd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -__builtin_fmaf (b[i], c[i], d[i]);
+}
+
+NOMIPS16 float
+nmsub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -__builtin_fmaf (b[i], c[i], -d[i]);
+}
+
+NOMIPS16 float
+nmadd_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (-b[i], c[i], -d[i]);
+}
+
+NOMIPS16 float
+nmsub_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = __builtin_fmaf (-b[i], c[i], d[i]);
+}
===================================================================
@@ -0,0 +1,79 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O3 -fno-fast-math -ffp-contract=off" } */
+/* { dg-final { scan-assembler-not "\tmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tmsub\\." } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* No function should use fused operations, however high the -O level. */
+
+NOMIPS16 float
+not_madd_s (float b, float c, float d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 float
+not_msub_s (float b, float c, float d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 float
+not_nmadd_s (float b, float c, float d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 float
+not_nmsub_s (float b, float c, float d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 float
+not_nmadd_s_2 (float b, float c, float d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return -b * c + d;
+}
+
+NOMIPS16 double
+not_madd_d (double b, double c, double d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 double
+not_msub_d (double b, double c, double d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 double
+not_nmadd_d (double b, double c, double d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 double
+not_nmsub_d (double b, double c, double d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 double
+not_nmadd_d_2 (double b, double c, double d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 double
+not_nmsub_d_2 (double b, double c, double d)
+{
+ return -b * c + d;
+}
===================================================================
@@ -0,0 +1,82 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O2 -fno-fast-math -ffp-contract=fast" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 3 } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* We should not use NMADD or NMSUB without -ffinite-math-only because
+ those instructions may perform arithmetic negation. */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 float
+not_nmadd_s (float b, float c, float d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 float
+not_nmsub_s (float b, float c, float d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 float
+not_nmadd_s_2 (float b, float c, float d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return -b * c + d;
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 double
+not_nmadd_d (double b, double c, double d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 double
+not_nmsub_d (double b, double c, double d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 double
+not_nmadd_d_2 (double b, double c, double d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 double
+not_nmsub_d_2 (double b, double c, double d)
+{
+ return -b * c + d;
+}
===================================================================
@@ -0,0 +1,81 @@
+/* { dg-options "-mgp64 -mhard-float isa>=4 -O2 -ffast-math" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.d\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.d\t" 2 } } */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 float
+nmadd_s (float b, float c, float d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 float
+nmsub_s (float b, float c, float d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 float
+nmadd_s_2 (float b, float c, float d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 float
+nmsub_s_2 (float b, float c, float d)
+{
+ return -b * c + d;
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 double
+nmadd_d (double b, double c, double d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 double
+nmsub_d (double b, double c, double d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 double
+nmadd_d_2 (double b, double c, double d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 double
+nmsub_d_2 (double b, double c, double d)
+{
+ return -b * c + d;
+}
===================================================================
@@ -0,0 +1,64 @@
+/* { dg-options "-mpaired-single -O3 -fno-fast-math -ftree-vectorize -ffp-contract=off" } */
+/* { dg-final { scan-assembler-not "\tmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tmsub\\." } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* No function should use fused operations, however high the -O level. */
+
+#define N 512
+float a[N], b[N], c[N], d[N];
+
+NOMIPS16 void
+not_madd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = b[i] * c[i] + d[i];
+}
+
+NOMIPS16 float
+not_msub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = b[i] * c[i] - d[i];
+}
+
+NOMIPS16 float
+not_nmadd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -(b[i] * c[i] + d[i]);
+}
+
+NOMIPS16 float
+not_nmsub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -(b[i] * c[i] - d[i]);
+}
+
+NOMIPS16 float
+not_nmadd_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -b[i] * c[i] - d[i];
+}
+
+NOMIPS16 float
+not_nmsub_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -b[i] * c[i] + d[i];
+}
===================================================================
@@ -0,0 +1,65 @@
+/* { dg-options "-mpaired-single -O2 -fno-fast-math -ftree-vectorize -ffp-contract=fast" } */
+/* { dg-final { scan-assembler "\tmadd\\.ps" } } */
+/* { dg-final { scan-assembler "\tmsub\\.ps" } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* We should not use NMADD or NMSUB without -ffinite-math-only because
+ those instructions may perform arithmetic negation. */
+
+#define N 512
+float a[N], b[N], c[N], d[N];
+
+NOMIPS16 void
+madd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = b[i] * c[i] + d[i];
+}
+
+NOMIPS16 float
+msub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = b[i] * c[i] - d[i];
+}
+
+NOMIPS16 float
+not_nmadd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -(b[i] * c[i] + d[i]);
+}
+
+NOMIPS16 float
+not_nmsub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -(b[i] * c[i] - d[i]);
+}
+
+NOMIPS16 float
+not_nmadd_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -b[i] * c[i] - d[i];
+}
+
+NOMIPS16 float
+not_nmsub_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -b[i] * c[i] + d[i];
+}
===================================================================
@@ -0,0 +1,62 @@
+/* { dg-options "-mpaired-single -O2 -ffast-math -ftree-vectorize" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.ps" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.ps" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.ps" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.ps" 2 } } */
+
+#define N 512
+float a[N], b[N], c[N], d[N];
+
+NOMIPS16 void
+madd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = b[i] * c[i] + d[i];
+}
+
+NOMIPS16 float
+msub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = b[i] * c[i] - d[i];
+}
+
+NOMIPS16 float
+nmadd_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -(b[i] * c[i] + d[i]);
+}
+
+NOMIPS16 float
+nmsub_ps (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -(b[i] * c[i] - d[i]);
+}
+
+NOMIPS16 float
+nmadd_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -b[i] * c[i] - d[i];
+}
+
+NOMIPS16 float
+nmsub_ps_2 (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ a[i] = -b[i] * c[i] + d[i];
+}
===================================================================
@@ -0,0 +1,82 @@
+/* { dg-options "-mgp64 -mhard-float isa=loongson -O3 -fno-fast-math -ffp-contract=off" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 3 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 3 } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* We should not use NMADD or NMSUB without -ffinite-math-only because
+ those instructions may perform arithmetic negation. */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+not_nmadd_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+not_nmsub_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+not_nmadd_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, -d);
+}
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, d);
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+not_nmadd_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+not_nmsub_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+not_nmadd_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, -d);
+}
+
+NOMIPS16 double
+not_nmsub_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, d);
+}
===================================================================
@@ -0,0 +1,81 @@
+/* { dg-options "-mgp64 -mhard-float isa=loongson -O -ffast-math" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.d\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.d\t" 2 } } */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return __builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+nmadd_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, d);
+}
+
+NOMIPS16 float
+nmsub_s (float b, float c, float d)
+{
+ return -__builtin_fmaf (b, c, -d);
+}
+
+NOMIPS16 float
+nmadd_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, -d);
+}
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return __builtin_fmaf (-b, c, d);
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return __builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+nmadd_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, d);
+}
+
+NOMIPS16 double
+nmsub_d (double b, double c, double d)
+{
+ return -__builtin_fma (b, c, -d);
+}
+
+NOMIPS16 double
+nmadd_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, -d);
+}
+
+NOMIPS16 double
+nmsub_d_2 (double b, double c, double d)
+{
+ return __builtin_fma (-b, c, d);
+}
===================================================================
@@ -0,0 +1,79 @@
+/* { dg-options "-mgp64 -mhard-float isa=loongson -O3 -fno-fast-math -ffp-contract=off" } */
+/* { dg-final { scan-assembler-not "\tmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tmsub\\." } } */
+/* { dg-final { scan-assembler-not "\tnmadd\\." } } */
+/* { dg-final { scan-assembler-not "\tnmsub\\." } } */
+
+/* No function should use fused operations, however high the -O level. */
+
+NOMIPS16 float
+not_madd_s (float b, float c, float d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 float
+not_msub_s (float b, float c, float d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 float
+not_nmadd_s (float b, float c, float d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 float
+not_nmsub_s (float b, float c, float d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 float
+not_nmadd_s_2 (float b, float c, float d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 float
+not_nmsub_s_2 (float b, float c, float d)
+{
+ return -b * c + d;
+}
+
+NOMIPS16 double
+not_madd_d (double b, double c, double d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 double
+not_msub_d (double b, double c, double d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 double
+not_nmadd_d (double b, double c, double d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 double
+not_nmsub_d (double b, double c, double d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 double
+not_nmadd_d_2 (double b, double c, double d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 double
+not_nmsub_d_2 (double b, double c, double d)
+{
+ return -b * c + d;
+}
===================================================================
@@ -0,0 +1,81 @@
+/* { dg-options "-mgp64 -mhard-float isa=loongson -O2 -ffast-math" } */
+/* { dg-final { scan-assembler-times "\tmadd\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.s\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tmadd\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tmsub\\.d\t" 1 } } */
+/* { dg-final { scan-assembler-times "\tnmadd\\.d\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tnmsub\\.d\t" 2 } } */
+
+NOMIPS16 float
+madd_s (float b, float c, float d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 float
+msub_s (float b, float c, float d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 float
+nmadd_s (float b, float c, float d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 float
+nmsub_s (float b, float c, float d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 float
+nmadd_s_2 (float b, float c, float d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 float
+nmsub_s_2 (float b, float c, float d)
+{
+ return -b * c + d;
+}
+
+NOMIPS16 double
+madd_d (double b, double c, double d)
+{
+ return b * c + d;
+}
+
+NOMIPS16 double
+msub_d (double b, double c, double d)
+{
+ return b * c + -d;
+}
+
+NOMIPS16 double
+nmadd_d (double b, double c, double d)
+{
+ return -(b * c + d);
+}
+
+NOMIPS16 double
+nmsub_d (double b, double c, double d)
+{
+ return -(b * c + -d);
+}
+
+NOMIPS16 double
+nmadd_d_2 (double b, double c, double d)
+{
+ return -b * c - d;
+}
+
+NOMIPS16 double
+nmsub_d_2 (double b, double c, double d)
+{
+ return -b * c + d;
+}