[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