This patch updates MIPS to handle fused multiply and add instructions using the standard fp-contract infrastructure. Currently MIPS handles -mfused-madd as a target specific option and it is not affected by the -ffp-contract option.
This patch changes -mfused-madd to be an alias for -ffp-contract=fast by using the standard config/fused-madd.opt option file. It also adds fma, fms, fnma, and fnms instructions to be used with convert_mult_to_fma and updates the definitions of the non-fused multiply and add instructions that some MIPS architectures support. After this patch I found the following changes in behaviour: mips1, mips2, mips3, and mips32[r1] had no change because they have no fused (or unfused) madd instructions. loongson and r8000 have the most changes, they no longer generate msub instructions with -mfused-madd because that instruction does not generate the correct NAN in some cases (the sign may be wrong). If HONOR_NANS is not set then they will generate msub instructions. mips4 (other than r8000), mips32r2, mips64[r1], and mips64r2 will now generated [unfused] multiply and add instructions even if -mno-fused-madd (or -ffp-contract=on) are used because these instructions are not fused and will round in between the two operations. This means they give the same result as the individual instructions. mips32r6 and mips64r6 now obey -mno-fused-madd (or -ffp-contract=on) whereas before they were generating fused madds even when one of these options were used. One thing I did not put in this patch was to add code to use the mips32r6/mips64r6 msubf instruction. This instruction implements 'c - (a * b)', not '(a * b) - c' and since it not currently used by GCC I decided not to add it to this patch. I did run-time testing with mips32 and mips64, versions 1, 2, and 6. With other MIPS versions (mips[1234], r8000, loongson) I did compilations to assembly language and did a visual inspection of the code to compare the results before and after this patch was applied. OK to checkin? Steve Ellcey sell...@imgtec.com 2015-06-11 Steve Ellcey <sell...@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. diff --git a/gcc/config.gcc b/gcc/config.gcc index 13a567f..f8c6307 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 e81134e..3ed9804 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -4068,14 +4068,12 @@ 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_NANS (mode) - && !HONOR_SIGNED_ZEROS (mode)) + if (float_mode_p && ISA_HAS_UNFUSED_MADD4 + && !HONOR_NANS (mode) && !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_NANS and 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) @@ -4102,9 +4100,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; @@ -4136,14 +4132,11 @@ 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_NANS (mode) - && HONOR_SIGNED_ZEROS (mode)) + if (float_mode_p && ISA_HAS_UNFUSED_MADD4 && !HONOR_NANS (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> or + *nmsub4<mode> patterns. These patterns do not check + HONOR_NANS but not HONOR_SIGNED_ZEROS so we check the same. */ rtx op = XEXP (x, 0); if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS) && GET_CODE (XEXP (op, 0)) == MULT) @@ -4163,8 +4156,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 0a23fa2..4b2a6ed 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -2475,165 +2475,238 @@ ;; Floating point multiply accumulate instructions. -(define_insn "*madd4<mode>" +(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 "*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 cannot be used when HONOR_NANS +;; is true because they may return a +qNAN when a -qNAN is required by +;; IEEE 754-2008. + +(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) && !HONOR_NANS (<MODE>mode)") + +(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 && !HONOR_NANS (<MODE>mode)" + "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 && !HONOR_NANS (<MODE>mode)" "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_NANS (<MODE>mode) && !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_NANS (<MODE>mode) && !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) - && !HONOR_NANS (<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_NANS (<MODE>mode) && !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_NANS (<MODE>mode) && !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) - && !HONOR_NANS (<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_NANS (<MODE>mode) && !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) - && !HONOR_NANS (<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_NANS (<MODE>mode) && !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) - && !HONOR_NANS (<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) - && !HONOR_NANS (<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>" +;; We need to check for HONOR_NANS on nmadd4 and nmsub4 because the nmadd and +;; nmsub instructions will not negate qNaN the way IEEE 754-2008 expects. +;; i.e. (neg (qNAN)) would result in qNaN instead of -qNaN + +(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 && !HONOR_NANS (<MODE>mode)" + "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) - && !HONOR_NANS (<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 && !HONOR_NANS (<MODE>mode)" + "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 or NaNs. + +;; 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) && !HONOR_NANS (<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) && !HONOR_NANS (<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