[llvm] 3de3439 - [LoongArch] Add codegen support for ISD::FMA

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 12 19:05:54 PDT 2022


Author: gonglingqin
Date: 2022-09-13T10:04:41+08:00
New Revision: 3de3439bd7c04d6fcef9ec2f7c5e6cb727adc3a6

URL: https://github.com/llvm/llvm-project/commit/3de3439bd7c04d6fcef9ec2f7c5e6cb727adc3a6
DIFF: https://github.com/llvm/llvm-project/commit/3de3439bd7c04d6fcef9ec2f7c5e6cb727adc3a6.diff

LOG: [LoongArch] Add codegen support for ISD::FMA

Differential Revision: https://reviews.llvm.org/D133281

Added: 
    llvm/test/CodeGen/LoongArch/double-fma.ll
    llvm/test/CodeGen/LoongArch/float-fma.ll

Modified: 
    llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
    llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
    llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
    llvm/lib/Target/LoongArch/LoongArchISelLowering.h
    llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
index 0bd1a21667f45..1ef56d3100430 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
@@ -237,6 +237,25 @@ def : Pat<(loongarch_ftint FPR32:$src), (FTINTRZ_W_S FPR32:$src)>;
 
 // FP reciprocal operation
 def : Pat<(fdiv fpimm1, FPR32:$src), (FRECIP_S $src)>;
+
+// fmadd.s: fj * fk + fa
+def : Pat<(fma FPR32:$fj, FPR32:$fk, FPR32:$fa), (FMADD_S $fj, $fk, $fa)>;
+
+// fmsub.s: fj * fk - fa
+def : Pat<(fma FPR32:$fj, FPR32:$fk, (fneg FPR32:$fa)),
+          (FMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmadd.s: -(fj * fk + fa)
+def : Pat<(fneg (fma FPR32:$fj, FPR32:$fk, FPR32:$fa)),
+          (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmadd.s: -fj * fk - fa (the nsz flag on the FMA)
+def : Pat<(fma_nsz (fneg FPR32:$fj), FPR32:$fk, (fneg FPR32:$fa)),
+          (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmsub.s: -fj * fk + fa
+def : Pat<(fma (fneg FPR32:$fj), FPR32:$fk, FPR32:$fa),
+          (FNMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
 } // Predicates = [HasBasicF]
 
 let Predicates = [HasBasicF, IsLA64] in {

diff  --git a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
index d3ca5034f4e7a..9832c8877facf 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
@@ -236,6 +236,25 @@ def : Pat<(f64 (fpextend FPR32:$src)), (FCVT_D_S FPR32:$src)>;
 
 // FP reciprocal operation
 def : Pat<(fdiv fpimm1, FPR64:$src), (FRECIP_D $src)>;
+
+// fmadd.d: fj * fk + fa
+def : Pat<(fma FPR64:$fj, FPR64:$fk, FPR64:$fa), (FMADD_D $fj, $fk, $fa)>;
+
+// fmsub.d: fj * fk - fa
+def : Pat<(fma FPR64:$fj, FPR64:$fk, (fneg FPR64:$fa)),
+          (FMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmadd.d: -(fj * fk + fa)
+def : Pat<(fneg (fma FPR64:$fj, FPR64:$fk, FPR64:$fa)),
+          (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmadd.d: -fj * fk - fa (the nsz flag on the FMA)
+def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, (fneg FPR64:$fa)),
+          (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmsub.d: -(fj * fk - fa)
+def : Pat<(fma (fneg FPR64:$fj), FPR64:$fk, FPR64:$fa),
+          (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
 } // Predicates = [HasBasicD]
 
 /// Floating point constants

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index e0b0b419e5297..113f8b2f9b9aa 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -111,6 +111,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
     setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
     setOperationAction(ISD::BR_CC, MVT::f32, Expand);
+    setOperationAction(ISD::FMA, MVT::f32, Legal);
   }
   if (Subtarget.hasBasicD()) {
     setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
@@ -118,6 +119,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
     setOperationAction(ISD::BR_CC, MVT::f64, Expand);
     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
     setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
+    setOperationAction(ISD::FMA, MVT::f64, Legal);
   }
 
   // Effectively disable jump table generation.
@@ -1869,3 +1871,21 @@ Value *LoongArchTargetLowering::emitMaskedAtomicRMWIntrinsic(
     Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
   return Result;
 }
+
+bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
+    const MachineFunction &MF, EVT VT) const {
+  VT = VT.getScalarType();
+
+  if (!VT.isSimple())
+    return false;
+
+  switch (VT.getSimpleVT().SimpleTy) {
+  case MVT::f32:
+  case MVT::f64:
+    return true;
+  default:
+    break;
+  }
+
+  return false;
+}

diff  --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index c026b6bf2c81c..eb97622182e51 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -111,6 +111,9 @@ class LoongArchTargetLowering : public TargetLowering {
                           MachineFunction &MF,
                           unsigned Intrinsic) const override;
 
+  bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
+                                  EVT VT) const override;
+
 private:
   /// Target-specific function used to lower LoongArch calling conventions.
   typedef bool LoongArchCCAssignFn(const DataLayout &DL, LoongArchABI::ABI ABI,

diff  --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index 1e0cdd3a2fa44..d85427af2edab 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -249,6 +249,11 @@ def ImmSubFrom32 : SDNodeXForm<imm, [{
 
 def BaseAddr : ComplexPattern<iPTR, 1, "SelectBaseAddr">;
 
+def fma_nsz : PatFrag<(ops node:$fj, node:$fk, node:$fa),
+                      (fma node:$fj, node:$fk, node:$fa), [{
+  return N->getFlags().hasNoSignedZeros();
+}]>;
+
 //===----------------------------------------------------------------------===//
 // Instruction Formats
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/test/CodeGen/LoongArch/double-fma.ll b/llvm/test/CodeGen/LoongArch/double-fma.ll
new file mode 100644
index 0000000000000..6dd6284794337
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/double-fma.ll
@@ -0,0 +1,887 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 --mattr=+d --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch32 --mattr=+d --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32-CONTRACT-ON
+; RUN: llc --mtriple=loongarch32 --mattr=+d --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32-CONTRACT-OFF
+; RUN: llc --mtriple=loongarch64 --mattr=+d --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+d --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64-CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+d --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64-CONTRACT-OFF
+
+define double @fmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul double %a, %b
+  %add = fadd double %mul, %c
+  ret double %add
+}
+
+define double @fmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul double %a, %b
+  %sub = fsub double %mul, %c
+  ret double %sub
+}
+
+define double @fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul double %a, %b
+  %add = fadd double %mul, %c
+  %negadd = fneg double %add
+  ret double %negadd
+}
+
+define double @fnmadd_d_nsz(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg nsz double %a
+  %negc = fneg nsz double %c
+  %mul = fmul nsz double %nega, %b
+  %add = fadd nsz double %mul, %negc
+  ret double %add
+}
+
+;; Check that fnmadd.d is not emitted.
+define double @not_fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg double %a
+  %negc = fneg double %c
+  %mul = fmul double %nega, %b
+  %add = fadd double %mul, %negc
+  ret double %add
+}
+
+define double @fnmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg double %a
+  %mul = fmul double %nega, %b
+  %add = fadd double %mul, %c
+  ret double %add
+}
+
+define double @contract_fmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmadd_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmadd_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmadd_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmadd_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmadd_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmadd_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %add = fadd contract double %mul, %c
+  ret double %add
+}
+
+define double @contract_fmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmsub_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmsub_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmsub_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmsub_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmsub_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmsub_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %sub = fsub contract double %mul, %c
+  ret double %sub
+}
+
+define double @contract_fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %add = fadd contract double %mul, %c
+  %negadd = fneg contract double %add
+  ret double %negadd
+}
+
+define double @contract_fnmadd_d_nsz(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_d_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_d_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_d_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_d_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_d_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_d_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract nsz double %a
+  %negc = fneg contract nsz double %c
+  %mul = fmul contract nsz double %nega, %b
+  %add = fadd contract nsz double %mul, %negc
+  ret double %add
+}
+
+;; Check that fnmadd.d is not emitted.
+define double @not_contract_fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_contract_fnmadd_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_contract_fnmadd_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_contract_fnmadd_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_contract_fnmadd_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_contract_fnmadd_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_contract_fnmadd_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract double %a
+  %negc = fneg contract double %c
+  %mul = fmul contract double %nega, %b
+  %add = fadd contract double %mul, %negc
+  ret double %add
+}
+
+define double @contract_fnmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmsub_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmsub_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmsub_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmsub_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmsub_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract double %a
+  %mul = fmul contract double %nega, %b
+  %add = fadd contract double %mul, %c
+  ret double %add
+}
+
+declare double @llvm.fma.f64(double, double, double)
+
+define double @fmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_d_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_d_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_d_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_d_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_d_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_d_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %fma = call double @llvm.fma.f64(double %a, double %b, double %c)
+  ret double %fma
+}
+
+define double @fmsub_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_d_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_d_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_d_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_d_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_d_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_d_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg double %c
+  %fma = call double @llvm.fma.f64(double %a, double %b, double %negc)
+  ret double %fma
+}
+
+define double @fnmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %fma = call double @llvm.fma.f64(double %a, double %b, double %c)
+  %neg = fneg double %fma
+  ret double %neg
+}
+
+define double @fnmadd_d_nsz_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_nsz_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_nsz_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_nsz_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_nsz_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_nsz_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_nsz_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg double %a
+  %negc = fneg double %c
+  %fma = call nsz double @llvm.fma.f64(double %nega, double %b, double %negc)
+  ret double %fma
+}
+
+;; Check that fnmadd.d is not emitted.
+define double @not_fnmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_d_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_d_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_d_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_d_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_d_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_d_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg double %a
+  %negc = fneg double %c
+  %fma = call double @llvm.fma.f64(double %nega, double %b, double %negc)
+  ret double %fma
+}
+
+define double @fnmsub_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg double %a
+  %fma = call double @llvm.fma.f64(double %nega, double %b, double %c)
+  ret double %fma
+}
+
+define double @fnmsub_d_swap_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negb = fneg double %b
+  %fma = call double @llvm.fma.f64(double %a, double %negb, double %c)
+  ret double %fma
+}
+
+define double @fmadd_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_d_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_d_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_d_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_d_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_d_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_d_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %add = fadd contract double %mul, %c
+  ret double %add
+}
+
+define double @fmsub_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_d_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_d_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_d_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_d_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_d_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_d_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %sub = fsub contract double %mul, %c
+  ret double %sub
+}
+
+define double @fnmadd_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %add = fadd contract double %mul, %c
+  %negadd = fneg contract double %add
+  ret double %negadd
+}
+
+define double @fnmsub_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract double %a, %b
+  %sub = fsub contract double %c, %mul
+  ret double %sub
+}

diff  --git a/llvm/test/CodeGen/LoongArch/float-fma.ll b/llvm/test/CodeGen/LoongArch/float-fma.ll
new file mode 100644
index 0000000000000..54dc56784006f
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/float-fma.ll
@@ -0,0 +1,887 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32-CONTRACT-ON
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=LA32-CONTRACT-OFF
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64-CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=LA64-CONTRACT-OFF
+
+define float @fmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul float %a, %b
+  %add = fadd float %mul, %c
+  ret float %add
+}
+
+define float @fmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul float %a, %b
+  %sub = fsub float %mul, %c
+  ret float %sub
+}
+
+define float @fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul float %a, %b
+  %add = fadd float %mul, %c
+  %negadd = fneg float %add
+  ret float %negadd
+}
+
+define float @fnmadd_s_nsz(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg nsz float %a
+  %negc = fneg nsz float %c
+  %mul = fmul nsz float %nega, %b
+  %add = fadd nsz float %mul, %negc
+  ret float %add
+}
+
+;; Check that fnmadd.s is not emitted.
+define float @not_fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg float %a
+  %negc = fneg float %c
+  %mul = fmul float %nega, %b
+  %add = fadd float %mul, %negc
+  ret float %add
+}
+
+define float @fnmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg float %a
+  %mul = fmul float %nega, %b
+  %add = fadd float %mul, %c
+  ret float %add
+}
+
+define float @contract_fmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmadd_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmadd_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmadd_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmadd_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmadd_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmadd_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %add = fadd contract float %mul, %c
+  ret float %add
+}
+
+define float @contract_fmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmsub_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmsub_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmsub_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmsub_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmsub_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmsub_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %sub = fsub contract float %mul, %c
+  ret float %sub
+}
+
+define float @contract_fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %add = fadd contract float %mul, %c
+  %negadd = fneg contract float %add
+  ret float %negadd
+}
+
+define float @contract_fnmadd_s_nsz(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_s_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_s_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_s_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_s_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_s_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_s_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract nsz float %a
+  %negc = fneg contract nsz float %c
+  %mul = fmul contract nsz float %nega, %b
+  %add = fadd contract nsz float %mul, %negc
+  ret float %add
+}
+
+;; Check that fnmadd.s is not emitted.
+define float @not_contract_fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_contract_fnmadd_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_contract_fnmadd_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_contract_fnmadd_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_contract_fnmadd_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_contract_fnmadd_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_contract_fnmadd_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract float %a
+  %negc = fneg contract float %c
+  %mul = fmul contract float %nega, %b
+  %add = fadd contract float %mul, %negc
+  ret float %add
+}
+
+define float @contract_fnmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmsub_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmsub_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmsub_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmsub_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmsub_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract float %a
+  %mul = fmul contract float %nega, %b
+  %add = fadd contract float %mul, %c
+  ret float %add
+}
+
+declare float @llvm.fma.f64(float, float, float)
+
+define float @fmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_s_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_s_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_s_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_s_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_s_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_s_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %fma = call float @llvm.fma.f64(float %a, float %b, float %c)
+  ret float %fma
+}
+
+define float @fmsub_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_s_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_s_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_s_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_s_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_s_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_s_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg float %c
+  %fma = call float @llvm.fma.f64(float %a, float %b, float %negc)
+  ret float %fma
+}
+
+define float @fnmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %fma = call float @llvm.fma.f64(float %a, float %b, float %c)
+  %neg = fneg float %fma
+  ret float %neg
+}
+
+define float @fnmadd_s_nsz_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_nsz_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_nsz_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_nsz_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_nsz_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_nsz_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_nsz_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg float %a
+  %negc = fneg float %c
+  %fma = call nsz float @llvm.fma.f64(float %nega, float %b, float %negc)
+  ret float %fma
+}
+
+;; Check that fnmadd.s is not emitted.
+define float @not_fnmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_s_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_s_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_s_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_s_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_s_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_s_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg float %a
+  %negc = fneg float %c
+  %fma = call float @llvm.fma.f64(float %nega, float %b, float %negc)
+  ret float %fma
+}
+
+define float @fnmsub_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg float %a
+  %fma = call float @llvm.fma.f64(float %nega, float %b, float %c)
+  ret float %fma
+}
+
+define float @fnmsub_s_swap_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negb = fneg float %b
+  %fma = call float @llvm.fma.f64(float %a, float %negb, float %c)
+  ret float %fma
+}
+
+define float @fmadd_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_s_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_s_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_s_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_s_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_s_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_s_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %add = fadd contract float %mul, %c
+  ret float %add
+}
+
+define float @fmsub_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_s_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_s_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_s_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_s_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_s_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_s_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %sub = fsub contract float %mul, %c
+  ret float %sub
+}
+
+define float @fnmadd_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %add = fadd contract float %mul, %c
+  %negadd = fneg contract float %add
+  ret float %negadd
+}
+
+define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_contract:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_contract:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_contract:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_contract:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_contract:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_contract:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %mul = fmul contract float %a, %b
+  %sub = fsub contract float %c, %mul
+  ret float %sub
+}


        


More information about the llvm-commits mailing list