[llvm] [LoongArch] Add codegen support for [X]VF{MSUB/NMADD/NMSUB}.{S/D} ins… (PR #74819)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 8 01:13:00 PST 2023


https://github.com/wangleiat created https://github.com/llvm/llvm-project/pull/74819

…tructions

This is similar to single and double-precision floating-point instructions.

>From f05fc3a67ef6e8cdc104e149ddf25110c8dc69c6 Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Fri, 8 Dec 2023 15:18:02 +0800
Subject: [PATCH] [LoongArch] Add codegen support for
 [X]VF{MSUB/NMADD/NMSUB}.{S/D} instructions

This is similar to single and double-precision floating-point
instructions.
---
 .../LoongArch/LoongArchLASXInstrInfo.td       |  26 +
 .../Target/LoongArch/LoongArchLSXInstrInfo.td |  26 +
 llvm/test/CodeGen/LoongArch/lasx/fma-v4f64.ll | 804 ++++++++++++++++++
 llvm/test/CodeGen/LoongArch/lasx/fma-v8f32.ll | 804 ++++++++++++++++++
 llvm/test/CodeGen/LoongArch/lsx/fma-v2f64.ll  | 804 ++++++++++++++++++
 llvm/test/CodeGen/LoongArch/lsx/fma-v4f32.ll  | 804 ++++++++++++++++++
 6 files changed, 3268 insertions(+)
 create mode 100644 llvm/test/CodeGen/LoongArch/lasx/fma-v4f64.ll
 create mode 100644 llvm/test/CodeGen/LoongArch/lasx/fma-v8f32.ll
 create mode 100644 llvm/test/CodeGen/LoongArch/lsx/fma-v2f64.ll
 create mode 100644 llvm/test/CodeGen/LoongArch/lsx/fma-v4f32.ll

diff --git a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
index 8559baa0e525f..ec6983d0f4871 100644
--- a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
@@ -1455,6 +1455,32 @@ def : Pat<(fma v8f32:$xj, v8f32:$xk, v8f32:$xa),
 def : Pat<(fma v4f64:$xj, v4f64:$xk, v4f64:$xa),
           (XVFMADD_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
 
+// XVFMSUB_{S/D}
+def : Pat<(fma v8f32:$xj, v8f32:$xk, (fneg v8f32:$xa)),
+          (XVFMSUB_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fma v4f64:$xj, v4f64:$xk, (fneg v4f64:$xa)),
+          (XVFMSUB_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+
+// XVFNMADD_{S/D}
+def : Pat<(fneg (fma v8f32:$xj, v8f32:$xk, v8f32:$xa)),
+          (XVFNMADD_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fneg (fma v4f64:$xj, v4f64:$xk, v4f64:$xa)),
+          (XVFNMADD_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+def : Pat<(fma_nsz (fneg v8f32:$xj), v8f32:$xk, (fneg v8f32:$xa)),
+          (XVFNMADD_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fma_nsz (fneg v4f64:$xj), v4f64:$xk, (fneg v4f64:$xa)),
+          (XVFNMADD_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+
+// XVFNMSUB_{S/D}
+def : Pat<(fneg (fma v8f32:$xj, v8f32:$xk, (fneg v8f32:$xa))),
+          (XVFNMSUB_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fneg (fma v4f64:$xj, v4f64:$xk, (fneg v4f64:$xa))),
+          (XVFNMSUB_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+def : Pat<(fma_nsz (fneg v8f32:$xj), v8f32:$xk, v8f32:$xa),
+          (XVFNMSUB_S v8f32:$xj, v8f32:$xk, v8f32:$xa)>;
+def : Pat<(fma_nsz (fneg v4f64:$xj), v4f64:$xk, v4f64:$xa),
+          (XVFNMSUB_D v4f64:$xj, v4f64:$xk, v4f64:$xa)>;
+
 // XVFSQRT_{S/D}
 defm : PatXrF<fsqrt, "XVFSQRT">;
 
diff --git a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
index 5947f241bb597..e468176885d75 100644
--- a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
@@ -1555,6 +1555,32 @@ def : Pat<(fma v4f32:$vj, v4f32:$vk, v4f32:$va),
 def : Pat<(fma v2f64:$vj, v2f64:$vk, v2f64:$va),
           (VFMADD_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
 
+// VFMSUB_{S/D}
+def : Pat<(fma v4f32:$vj, v4f32:$vk, (fneg v4f32:$va)),
+          (VFMSUB_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fma v2f64:$vj, v2f64:$vk, (fneg v2f64:$va)),
+          (VFMSUB_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+
+// VFNMADD_{S/D}
+def : Pat<(fneg (fma v4f32:$vj, v4f32:$vk, v4f32:$va)),
+          (VFNMADD_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fneg (fma v2f64:$vj, v2f64:$vk, v2f64:$va)),
+          (VFNMADD_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+def : Pat<(fma_nsz (fneg v4f32:$vj), v4f32:$vk, (fneg v4f32:$va)),
+          (VFNMADD_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fma_nsz (fneg v2f64:$vj), v2f64:$vk, (fneg v2f64:$va)),
+          (VFNMADD_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+
+// VFNMSUB_{S/D}
+def : Pat<(fneg (fma v4f32:$vj, v4f32:$vk, (fneg v4f32:$va))),
+          (VFNMSUB_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fneg (fma v2f64:$vj, v2f64:$vk, (fneg v2f64:$va))),
+          (VFNMSUB_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+def : Pat<(fma_nsz (fneg v4f32:$vj), v4f32:$vk, v4f32:$va),
+          (VFNMSUB_S v4f32:$vj, v4f32:$vk, v4f32:$va)>;
+def : Pat<(fma_nsz (fneg v2f64:$vj), v2f64:$vk, v2f64:$va),
+          (VFNMSUB_D v2f64:$vj, v2f64:$vk, v2f64:$va)>;
+
 // VFSQRT_{S/D}
 defm : PatVrF<fsqrt, "VFSQRT">;
 
diff --git a/llvm/test/CodeGen/LoongArch/lasx/fma-v4f64.ll b/llvm/test/CodeGen/LoongArch/lasx/fma-v4f64.ll
new file mode 100644
index 0000000000000..39dfee6bc2206
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lasx/fma-v4f64.ll
@@ -0,0 +1,804 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-OFF
+
+define void @fmadd_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfadd.d $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfadd.d $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul<4 x double> %v0, %v1
+  %add = fadd<4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul<4 x double> %v0, %v1
+  %sub = fsub<4 x double> %mul, %v2
+  store <4 x double> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfadd.d $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvbitrevi.d $xr0, $xr0, 63
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfadd.d $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvbitrevi.d $xr0, $xr0, 63
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul<4 x double> %v0, %v1
+  %add = fadd<4 x double> %mul, %v2
+  %negadd = fneg<4 x double> %add
+  store <4 x double> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmadd_v4f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v4f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v4f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.d $xr1, $xr1, 63
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v4f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.d $xr1, $xr1, 63
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg nsz<4 x double> %v0
+  %negv2 = fneg nsz<4 x double> %v2
+  %mul = fmul nsz<4 x double> %negv0, %v1
+  %add = fadd nsz<4 x double> %mul, %negv2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_fnmadd_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmadd_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-FAST-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmadd_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.d $xr1, $xr1, 63
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmadd_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.d $xr1, $xr1, 63
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg<4 x double> %v0
+  %negv2 = fneg<4 x double> %v2
+  %mul = fmul<4 x double> %negv0, %v1
+  %add = fadd<4 x double> %mul, %negv2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @fnmsub_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvbitrevi.d $xr0, $xr0, 63
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.d $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvbitrevi.d $xr0, $xr0, 63
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv2 = fneg<4 x double> %v2
+  %mul = fmul<4 x double> %v0, %v1
+  %add = fadd<4 x double> %mul, %negv2
+  %neg = fneg<4 x double> %add
+  store <4 x double> %neg, ptr %res
+  ret void
+}
+
+define void @fnmsub_v4f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v4f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v4f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v4f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg nsz<4 x double> %v0
+  %mul = fmul nsz<4 x double> %negv0, %v1
+  %add = fadd nsz<4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_fnmsub_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmsub_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-FAST-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmsub_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.d $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmsub_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.d $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg<4 x double> %v0
+  %mul = fmul<4 x double> %negv0, %v1
+  %add = fadd<4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmadd_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmadd_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmadd_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmadd_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %add = fadd contract <4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmsub_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmsub_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmsub_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmsub_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %sub = fsub contract <4 x double> %mul, %v2
+  store <4 x double> %sub, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %add = fadd contract <4 x double> %mul, %v2
+  %negadd = fneg contract <4 x double> %add
+  store <4 x double> %negadd, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v4f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v4f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v4f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v4f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg contract nsz<4 x double> %v0
+  %negv2 = fneg contract nsz<4 x double> %v2
+  %mul = fmul contract nsz<4 x double> %negv0, %v1
+  %add = fadd contract nsz<4 x double> %mul, %negv2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_contract_fnmadd_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmadd_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-FAST-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmadd_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-ON-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmadd_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-OFF-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg contract <4 x double> %v0
+  %negv2 = fneg contract <4 x double> %v2
+  %mul = fmul contract <4 x double> %negv0, %v1
+  %add = fadd contract <4 x double> %mul, %negv2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv2 = fneg contract <4 x double> %v2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %add = fadd contract <4 x double> %mul, %negv2
+  %neg = fneg contract <4 x double> %add
+  store <4 x double> %neg, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v4f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v4f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v4f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v4f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg contract nsz<4 x double> %v0
+  %mul = fmul contract nsz<4 x double> %negv0, %v1
+  %add = fadd contract nsz<4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_contract_fnmsub_v4f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmsub_v4f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-FAST-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmsub_v4f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-ON-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmsub_v4f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.d $xr2, $xr2, 63
+; CONTRACT-OFF-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %negv0 = fneg contract <4 x double> %v0
+  %mul = fmul contract <4 x double> %negv0, %v1
+  %add = fadd contract <4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @fmadd_v4f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v4f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v4f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v4f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %add = fadd contract <4 x double> %mul, %v2
+  store <4 x double> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v4f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v4f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v4f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v4f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %sub = fsub contract <4 x double> %mul, %v2
+  store <4 x double> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v4f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v4f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v4f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v4f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmadd.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %add = fadd contract <4 x double> %mul, %v2
+  %negadd = fneg contract <4 x double> %add
+  store <4 x double> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmsub_v4f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v4f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v4f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v4f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmsub.d $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x double>, ptr %a0
+  %v1 = load <4 x double>, ptr %a1
+  %v2 = load <4 x double>, ptr %a2
+  %mul = fmul contract <4 x double> %v0, %v1
+  %negv2 = fneg contract <4 x double> %v2
+  %add = fadd contract <4 x double> %negv2, %mul
+  %negadd = fneg contract <4 x double> %add
+  store <4 x double> %negadd, ptr %res
+  ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lasx/fma-v8f32.ll b/llvm/test/CodeGen/LoongArch/lasx/fma-v8f32.ll
new file mode 100644
index 0000000000000..33142864f233d
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lasx/fma-v8f32.ll
@@ -0,0 +1,804 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-OFF
+
+define void @fmadd_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfadd.s $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfadd.s $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul<8 x float> %v0, %v1
+  %add = fadd<8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul<8 x float> %v0, %v1
+  %sub = fsub<8 x float> %mul, %v2
+  store <8 x float> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfadd.s $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvbitrevi.w $xr0, $xr0, 31
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfadd.s $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvbitrevi.w $xr0, $xr0, 31
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul<8 x float> %v0, %v1
+  %add = fadd<8 x float> %mul, %v2
+  %negadd = fneg<8 x float> %add
+  store <8 x float> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmadd_v8f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v8f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v8f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.w $xr1, $xr1, 31
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v8f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.w $xr1, $xr1, 31
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg nsz<8 x float> %v0
+  %negv2 = fneg nsz<8 x float> %v2
+  %mul = fmul nsz<8 x float> %negv0, %v1
+  %add = fadd nsz<8 x float> %mul, %negv2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_fnmadd_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmadd_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-FAST-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmadd_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.w $xr1, $xr1, 31
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmadd_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.w $xr1, $xr1, 31
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg<8 x float> %v0
+  %negv2 = fneg<8 x float> %v2
+  %mul = fmul<8 x float> %negv0, %v1
+  %add = fadd<8 x float> %mul, %negv2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @fnmsub_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-ON-NEXT:    xvbitrevi.w $xr0, $xr0, 31
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.s $xr0, $xr0, $xr1
+; CONTRACT-OFF-NEXT:    xvbitrevi.w $xr0, $xr0, 31
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv2 = fneg<8 x float> %v2
+  %mul = fmul<8 x float> %v0, %v1
+  %add = fadd<8 x float> %mul, %negv2
+  %neg = fneg<8 x float> %add
+  store <8 x float> %neg, ptr %res
+  ret void
+}
+
+define void @fnmsub_v8f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v8f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v8f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v8f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg nsz<8 x float> %v0
+  %mul = fmul nsz<8 x float> %negv0, %v1
+  %add = fadd nsz<8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_fnmsub_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmsub_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-FAST-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmsub_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-ON-NEXT:    xvfsub.s $xr0, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmsub_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmul.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a3, 0
+; CONTRACT-OFF-NEXT:    xvfsub.s $xr0, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg<8 x float> %v0
+  %mul = fmul<8 x float> %negv0, %v1
+  %add = fadd<8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmadd_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmadd_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmadd_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmadd_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %add = fadd contract <8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmsub_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmsub_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmsub_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmsub_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %sub = fsub contract <8 x float> %mul, %v2
+  store <8 x float> %sub, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %add = fadd contract <8 x float> %mul, %v2
+  %negadd = fneg contract <8 x float> %add
+  store <8 x float> %negadd, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v8f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v8f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v8f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v8f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg contract nsz<8 x float> %v0
+  %negv2 = fneg contract nsz<8 x float> %v2
+  %mul = fmul contract nsz<8 x float> %negv0, %v1
+  %add = fadd contract nsz<8 x float> %mul, %negv2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_contract_fnmadd_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmadd_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-FAST-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmadd_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-ON-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmadd_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-OFF-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg contract <8 x float> %v0
+  %negv2 = fneg contract <8 x float> %v2
+  %mul = fmul contract <8 x float> %negv0, %v1
+  %add = fadd contract <8 x float> %mul, %negv2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv2 = fneg contract <8 x float> %v2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %add = fadd contract <8 x float> %mul, %negv2
+  %neg = fneg contract <8 x float> %add
+  store <8 x float> %neg, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v8f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v8f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v8f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v8f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg contract nsz<8 x float> %v0
+  %mul = fmul contract nsz<8 x float> %negv0, %v1
+  %add = fadd contract nsz<8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_contract_fnmsub_v8f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmsub_v8f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-FAST-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmsub_v8f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-ON-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmsub_v8f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvbitrevi.w $xr2, $xr2, 31
+; CONTRACT-OFF-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %negv0 = fneg contract <8 x float> %v0
+  %mul = fmul contract <8 x float> %negv0, %v1
+  %add = fadd contract <8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @fmadd_v8f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v8f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v8f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v8f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %add = fadd contract <8 x float> %mul, %v2
+  store <8 x float> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v8f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v8f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v8f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v8f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %sub = fsub contract <8 x float> %mul, %v2
+  store <8 x float> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v8f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v8f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v8f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v8f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmadd.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %add = fadd contract <8 x float> %mul, %v2
+  %negadd = fneg contract <8 x float> %add
+  store <8 x float> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmsub_v8f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v8f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-FAST-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-FAST-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-FAST-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-FAST-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v8f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-ON-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-ON-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-ON-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-ON-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v8f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    xvld $xr0, $a3, 0
+; CONTRACT-OFF-NEXT:    xvld $xr1, $a2, 0
+; CONTRACT-OFF-NEXT:    xvld $xr2, $a1, 0
+; CONTRACT-OFF-NEXT:    xvfnmsub.s $xr0, $xr2, $xr1, $xr0
+; CONTRACT-OFF-NEXT:    xvst $xr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <8 x float>, ptr %a0
+  %v1 = load <8 x float>, ptr %a1
+  %v2 = load <8 x float>, ptr %a2
+  %mul = fmul contract <8 x float> %v0, %v1
+  %negv2 = fneg contract <8 x float> %v2
+  %add = fadd contract <8 x float> %negv2, %mul
+  %negadd = fneg contract <8 x float> %add
+  store <8 x float> %negadd, ptr %res
+  ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/fma-v2f64.ll b/llvm/test/CodeGen/LoongArch/lsx/fma-v2f64.ll
new file mode 100644
index 0000000000000..3e06245e25b77
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lsx/fma-v2f64.ll
@@ -0,0 +1,804 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-OFF
+
+define void @fmadd_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfadd.d $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfadd.d $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul<2 x double> %v0, %v1
+  %add = fadd<2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul<2 x double> %v0, %v1
+  %sub = fsub<2 x double> %mul, %v2
+  store <2 x double> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfadd.d $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vbitrevi.d $vr0, $vr0, 63
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfadd.d $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vbitrevi.d $vr0, $vr0, 63
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul<2 x double> %v0, %v1
+  %add = fadd<2 x double> %mul, %v2
+  %negadd = fneg<2 x double> %add
+  store <2 x double> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmadd_v2f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v2f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v2f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.d $vr1, $vr1, 63
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v2f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.d $vr1, $vr1, 63
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg nsz<2 x double> %v0
+  %negv2 = fneg nsz<2 x double> %v2
+  %mul = fmul nsz<2 x double> %negv0, %v1
+  %add = fadd nsz<2 x double> %mul, %negv2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_fnmadd_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmadd_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-FAST-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmadd_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.d $vr1, $vr1, 63
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmadd_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.d $vr1, $vr1, 63
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg<2 x double> %v0
+  %negv2 = fneg<2 x double> %v2
+  %mul = fmul<2 x double> %negv0, %v1
+  %add = fadd<2 x double> %mul, %negv2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @fnmsub_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vbitrevi.d $vr0, $vr0, 63
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.d $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vbitrevi.d $vr0, $vr0, 63
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv2 = fneg<2 x double> %v2
+  %mul = fmul<2 x double> %v0, %v1
+  %add = fadd<2 x double> %mul, %negv2
+  %neg = fneg<2 x double> %add
+  store <2 x double> %neg, ptr %res
+  ret void
+}
+
+define void @fnmsub_v2f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v2f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v2f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v2f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg nsz<2 x double> %v0
+  %mul = fmul nsz<2 x double> %negv0, %v1
+  %add = fadd nsz<2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_fnmsub_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmsub_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-FAST-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmsub_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.d $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmsub_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.d $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg<2 x double> %v0
+  %mul = fmul<2 x double> %negv0, %v1
+  %add = fadd<2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmadd_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmadd_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmadd_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmadd_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %add = fadd contract <2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmsub_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmsub_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmsub_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmsub_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %sub = fsub contract <2 x double> %mul, %v2
+  store <2 x double> %sub, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %add = fadd contract <2 x double> %mul, %v2
+  %negadd = fneg contract <2 x double> %add
+  store <2 x double> %negadd, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v2f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v2f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v2f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v2f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg contract nsz<2 x double> %v0
+  %negv2 = fneg contract nsz<2 x double> %v2
+  %mul = fmul contract nsz<2 x double> %negv0, %v1
+  %add = fadd contract nsz<2 x double> %mul, %negv2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_contract_fnmadd_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmadd_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-FAST-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmadd_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-ON-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmadd_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-OFF-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg contract <2 x double> %v0
+  %negv2 = fneg contract <2 x double> %v2
+  %mul = fmul contract <2 x double> %negv0, %v1
+  %add = fadd contract <2 x double> %mul, %negv2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv2 = fneg contract <2 x double> %v2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %add = fadd contract <2 x double> %mul, %negv2
+  %neg = fneg contract <2 x double> %add
+  store <2 x double> %neg, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v2f64_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v2f64_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v2f64_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v2f64_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg contract nsz<2 x double> %v0
+  %mul = fmul contract nsz<2 x double> %negv0, %v1
+  %add = fadd contract nsz<2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_contract_fnmsub_v2f64(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmsub_v2f64:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-FAST-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmsub_v2f64:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-ON-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmsub_v2f64:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.d $vr2, $vr2, 63
+; CONTRACT-OFF-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %negv0 = fneg contract <2 x double> %v0
+  %mul = fmul contract <2 x double> %negv0, %v1
+  %add = fadd contract <2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @fmadd_v2f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v2f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v2f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v2f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %add = fadd contract <2 x double> %mul, %v2
+  store <2 x double> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v2f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v2f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v2f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v2f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %sub = fsub contract <2 x double> %mul, %v2
+  store <2 x double> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v2f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v2f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v2f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v2f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmadd.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %add = fadd contract <2 x double> %mul, %v2
+  %negadd = fneg contract <2 x double> %add
+  store <2 x double> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmsub_v2f64_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v2f64_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v2f64_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v2f64_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmsub.d $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <2 x double>, ptr %a0
+  %v1 = load <2 x double>, ptr %a1
+  %v2 = load <2 x double>, ptr %a2
+  %mul = fmul contract <2 x double> %v0, %v1
+  %negv2 = fneg contract <2 x double> %v2
+  %add = fadd contract <2 x double> %negv2, %mul
+  %negadd = fneg contract <2 x double> %add
+  store <2 x double> %negadd, ptr %res
+  ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/fma-v4f32.ll b/llvm/test/CodeGen/LoongArch/lsx/fma-v4f32.ll
new file mode 100644
index 0000000000000..b5e060c3ba7b9
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/lsx/fma-v4f32.ll
@@ -0,0 +1,804 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --fp-contract=fast < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --fp-contract=on < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx --fp-contract=off < %s \
+; RUN:   | FileCheck %s --check-prefix=CONTRACT-OFF
+
+define void @fmadd_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfadd.s $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfadd.s $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul<4 x float> %v0, %v1
+  %add = fadd<4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul<4 x float> %v0, %v1
+  %sub = fsub<4 x float> %mul, %v2
+  store <4 x float> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfadd.s $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vbitrevi.w $vr0, $vr0, 31
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfadd.s $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vbitrevi.w $vr0, $vr0, 31
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul<4 x float> %v0, %v1
+  %add = fadd<4 x float> %mul, %v2
+  %negadd = fneg<4 x float> %add
+  store <4 x float> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmadd_v4f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v4f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v4f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.w $vr1, $vr1, 31
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v4f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.w $vr1, $vr1, 31
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg nsz<4 x float> %v0
+  %negv2 = fneg nsz<4 x float> %v2
+  %mul = fmul nsz<4 x float> %negv0, %v1
+  %add = fadd nsz<4 x float> %mul, %negv2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_fnmadd_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmadd_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-FAST-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmadd_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.w $vr1, $vr1, 31
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmadd_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.w $vr1, $vr1, 31
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg<4 x float> %v0
+  %negv2 = fneg<4 x float> %v2
+  %mul = fmul<4 x float> %negv0, %v1
+  %add = fadd<4 x float> %mul, %negv2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @fnmsub_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-ON-NEXT:    vbitrevi.w $vr0, $vr0, 31
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.s $vr0, $vr0, $vr1
+; CONTRACT-OFF-NEXT:    vbitrevi.w $vr0, $vr0, 31
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv2 = fneg<4 x float> %v2
+  %mul = fmul<4 x float> %v0, %v1
+  %add = fadd<4 x float> %mul, %negv2
+  %neg = fneg<4 x float> %add
+  store <4 x float> %neg, ptr %res
+  ret void
+}
+
+define void @fnmsub_v4f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v4f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v4f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v4f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg nsz<4 x float> %v0
+  %mul = fmul nsz<4 x float> %negv0, %v1
+  %add = fadd nsz<4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_fnmsub_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_fnmsub_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-FAST-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_fnmsub_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-ON-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-ON-NEXT:    vfsub.s $vr0, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_fnmsub_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmul.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a3, 0
+; CONTRACT-OFF-NEXT:    vfsub.s $vr0, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg<4 x float> %v0
+  %mul = fmul<4 x float> %negv0, %v1
+  %add = fadd<4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmadd_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmadd_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmadd_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmadd_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %add = fadd contract <4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @contract_fmsub_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fmsub_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fmsub_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fmsub_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %sub = fsub contract <4 x float> %mul, %v2
+  store <4 x float> %sub, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %add = fadd contract <4 x float> %mul, %v2
+  %negadd = fneg contract <4 x float> %add
+  store <4 x float> %negadd, ptr %res
+  ret void
+}
+
+define void @contract_fnmadd_v4f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmadd_v4f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmadd_v4f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmadd_v4f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg contract nsz<4 x float> %v0
+  %negv2 = fneg contract nsz<4 x float> %v2
+  %mul = fmul contract nsz<4 x float> %negv0, %v1
+  %add = fadd contract nsz<4 x float> %mul, %negv2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmadd.s is not emitted.
+define void @not_contract_fnmadd_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmadd_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-FAST-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmadd_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-ON-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmadd_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-OFF-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg contract <4 x float> %v0
+  %negv2 = fneg contract <4 x float> %v2
+  %mul = fmul contract <4 x float> %negv0, %v1
+  %add = fadd contract <4 x float> %mul, %negv2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv2 = fneg contract <4 x float> %v2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %add = fadd contract <4 x float> %mul, %negv2
+  %neg = fneg contract <4 x float> %add
+  store <4 x float> %neg, ptr %res
+  ret void
+}
+
+define void @contract_fnmsub_v4f32_nsz(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: contract_fnmsub_v4f32_nsz:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: contract_fnmsub_v4f32_nsz:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: contract_fnmsub_v4f32_nsz:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg contract nsz<4 x float> %v0
+  %mul = fmul contract nsz<4 x float> %negv0, %v1
+  %add = fadd contract nsz<4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+;; Check that fnmsub.s is not emitted.
+define void @not_contract_fnmsub_v4f32(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: not_contract_fnmsub_v4f32:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-FAST-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: not_contract_fnmsub_v4f32:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-ON-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: not_contract_fnmsub_v4f32:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vbitrevi.w $vr2, $vr2, 31
+; CONTRACT-OFF-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %negv0 = fneg contract <4 x float> %v0
+  %mul = fmul contract <4 x float> %negv0, %v1
+  %add = fadd contract <4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @fmadd_v4f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmadd_v4f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmadd_v4f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmadd_v4f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %add = fadd contract <4 x float> %mul, %v2
+  store <4 x float> %add, ptr %res
+  ret void
+}
+
+define void @fmsub_v4f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fmsub_v4f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fmsub_v4f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fmsub_v4f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %sub = fsub contract <4 x float> %mul, %v2
+  store <4 x float> %sub, ptr %res
+  ret void
+}
+
+define void @fnmadd_v4f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmadd_v4f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmadd_v4f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmadd_v4f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmadd.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %add = fadd contract <4 x float> %mul, %v2
+  %negadd = fneg contract <4 x float> %add
+  store <4 x float> %negadd, ptr %res
+  ret void
+}
+
+define void @fnmsub_v4f32_contract(ptr %res, ptr %a0, ptr %a1, ptr %a2) nounwind {
+; CONTRACT-FAST-LABEL: fnmsub_v4f32_contract:
+; CONTRACT-FAST:       # %bb.0: # %entry
+; CONTRACT-FAST-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-FAST-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-FAST-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-FAST-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-FAST-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-FAST-NEXT:    ret
+;
+; CONTRACT-ON-LABEL: fnmsub_v4f32_contract:
+; CONTRACT-ON:       # %bb.0: # %entry
+; CONTRACT-ON-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-ON-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-ON-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-ON-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-ON-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-ON-NEXT:    ret
+;
+; CONTRACT-OFF-LABEL: fnmsub_v4f32_contract:
+; CONTRACT-OFF:       # %bb.0: # %entry
+; CONTRACT-OFF-NEXT:    vld $vr0, $a3, 0
+; CONTRACT-OFF-NEXT:    vld $vr1, $a2, 0
+; CONTRACT-OFF-NEXT:    vld $vr2, $a1, 0
+; CONTRACT-OFF-NEXT:    vfnmsub.s $vr0, $vr2, $vr1, $vr0
+; CONTRACT-OFF-NEXT:    vst $vr0, $a0, 0
+; CONTRACT-OFF-NEXT:    ret
+entry:
+  %v0 = load <4 x float>, ptr %a0
+  %v1 = load <4 x float>, ptr %a1
+  %v2 = load <4 x float>, ptr %a2
+  %mul = fmul contract <4 x float> %v0, %v1
+  %negv2 = fneg contract <4 x float> %v2
+  %add = fadd contract <4 x float> %negv2, %mul
+  %negadd = fneg contract <4 x float> %add
+  store <4 x float> %negadd, ptr %res
+  ret void
+}



More information about the llvm-commits mailing list