[llvm] [LoongArch] Fix pattern for FNMSUB_{S/D} instructions (PR #73742)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 28 20:01:11 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-loongarch

Author: wanglei (wangleiat)

<details>
<summary>Changes</summary>

```
when a=c=-0.0, b=0.0:
-(a * b + (-c)) = -0.0
-a * b + c = 0.0
(fneg (fma a, b (-c))) != (fma (fneg a), b ,c)
```

See https://reviews.llvm.org/D90901 for a similar discussion on X86.

---

Patch is 27.84 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/73742.diff


4 Files Affected:

- (modified) llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td (+6-2) 
- (modified) llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td (+5-1) 
- (modified) llvm/test/CodeGen/LoongArch/double-fma.ll (+236-23) 
- (modified) llvm/test/CodeGen/LoongArch/float-fma.ll (+236-23) 


``````````diff
diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
index 6f35609df705f66..808d73958ff9896 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
@@ -295,8 +295,12 @@ def : Pat<(fneg (fma FPR32:$fj, FPR32:$fk, FPR32:$fa)),
 def : Pat<(fma_nsz (fneg FPR32:$fj), FPR32:$fk, (fneg FPR32:$fa)),
           (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
 
-// fnmsub.s: -fj * fk + fa
-def : Pat<(fma (fneg FPR32:$fj), FPR32:$fk, FPR32:$fa),
+// fnmsub.s: -(fj * fk - fa)
+def : Pat<(fneg (fma FPR32:$fj, FPR32:$fk, (fneg FPR32:$fa))),
+          (FNMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmsub.s: -fj * fk + fa (the nsz flag on the FMA)
+def : Pat<(fma_nsz (fneg FPR32:$fj), FPR32:$fk, FPR32:$fa),
           (FNMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
 } // Predicates = [HasBasicF]
 
diff --git a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
index c2103b02b448a42..6e0ac286e8f4d76 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
@@ -263,7 +263,11 @@ def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, (fneg FPR64:$fa)),
           (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
 
 // fnmsub.d: -(fj * fk - fa)
-def : Pat<(fma (fneg FPR64:$fj), FPR64:$fk, FPR64:$fa),
+def : Pat<(fneg (fma FPR64:$fj, FPR64:$fk, (fneg FPR64:$fa))),
+          (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmsub.d: -fj * fk + fa (the nsz flag on the FMA)
+def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, FPR64:$fa),
           (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
 } // Predicates = [HasBasicD]
 
diff --git a/llvm/test/CodeGen/LoongArch/double-fma.ll b/llvm/test/CodeGen/LoongArch/double-fma.ll
index 6dd628479433753..58d20c62a668aec 100644
--- a/llvm/test/CodeGen/LoongArch/double-fma.ll
+++ b/llvm/test/CodeGen/LoongArch/double-fma.ll
@@ -236,13 +236,15 @@ define double @fnmsub_d(double %a, double %b, double %c) nounwind {
 ; LA32-CONTRACT-ON-LABEL: fnmsub_d:
 ; LA32-CONTRACT-ON:       # %bb.0:
 ; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
-; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
 ; LA32-CONTRACT-ON-NEXT:    ret
 ;
 ; LA32-CONTRACT-OFF-LABEL: fnmsub_d:
 ; LA32-CONTRACT-OFF:       # %bb.0:
 ; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
-; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
 ; LA32-CONTRACT-OFF-NEXT:    ret
 ;
 ; LA64-CONTRACT-FAST-LABEL: fnmsub_d:
@@ -253,12 +255,98 @@ define double @fnmsub_d(double %a, double %b, double %c) nounwind {
 ; LA64-CONTRACT-ON-LABEL: fnmsub_d:
 ; LA64-CONTRACT-ON:       # %bb.0:
 ; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
-; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
 ; LA64-CONTRACT-ON-NEXT:    ret
 ;
 ; LA64-CONTRACT-OFF-LABEL: fnmsub_d:
 ; LA64-CONTRACT-OFF:       # %bb.0:
 ; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg double %c
+  %mul = fmul double %a, %b
+  %add = fadd double %mul, %negc
+  %neg = fneg double %add
+  ret double %neg
+}
+
+define double @fnmsub_d_nsz(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg nsz double %a
+  %mul = fmul nsz double %nega, %b
+  %add = fadd nsz double %mul, %c
+  ret double %add
+}
+
+;; Check that fnmsub.d is not emitted.
+define double @not_fnmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmsub_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmsub_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmsub_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmsub_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmsub_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmsub_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.d $fa0, $fa0, $fa1
 ; LA64-CONTRACT-OFF-NEXT:    fsub.d $fa0, $fa2, $fa0
 ; LA64-CONTRACT-OFF-NEXT:    ret
   %nega = fneg double %a
@@ -483,6 +571,86 @@ define double @contract_fnmsub_d(double %a, double %b, double %c) nounwind {
 ; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_d:
 ; LA64-CONTRACT-OFF:       # %bb.0:
 ; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg contract double %c
+  %mul = fmul contract double %a, %b
+  %add = fadd contract double %mul, %negc
+  %neg = fneg contract double %add
+  ret double %neg
+}
+
+define double @contract_fnmsub_d_nsz(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmsub_d_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmsub_d_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmsub_d_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmsub_d_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmsub_d_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_d_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg contract nsz double %a
+  %mul = fmul contract nsz double %nega, %b
+  %add = fadd contract nsz double %mul, %c
+  ret double %add
+}
+
+;; Check that fnmsub.d is not emitted.
+define double @not_contract_fnmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_contract_fnmsub_d:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_contract_fnmsub_d:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_contract_fnmsub_d:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_contract_fnmsub_d:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_contract_fnmsub_d:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_contract_fnmsub_d:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-OFF-NEXT:    ret
   %nega = fneg contract double %a
   %mul = fmul contract double %nega, %b
@@ -592,8 +760,8 @@ define double @fnmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
 ; LA64-CONTRACT-OFF-NEXT:    fnmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-OFF-NEXT:    ret
   %fma = call double @llvm.fma.f64(double %a, double %b, double %c)
-  %neg = fneg double %fma
-  ret double %neg
+  %negfma = fneg double %fma
+  ret double %negfma
 }
 
 define double @fnmadd_d_nsz_intrinsics(double %a, double %b, double %c) nounwind {
@@ -704,44 +872,87 @@ define double @fnmsub_d_intrinsics(double %a, double %b, double %c) nounwind {
 ; LA64-CONTRACT-OFF-LABEL: fnmsub_d_intrinsics:
 ; LA64-CONTRACT-OFF:       # %bb.0:
 ; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg double %c
+  %fma = call double @llvm.fma.f64(double %a, double %b, double %negc)
+  %negfma = fneg double %fma
+  ret double %negfma
+}
+
+define double @fnmsub_d_nsz_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_nsz_intrinsics:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_nsz_intrinsics:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_nsz_intrinsics:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_nsz_intrinsics:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_nsz_intrinsics:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_nsz_intrinsics:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-OFF-NEXT:    ret
   %nega = fneg double %a
-  %fma = call double @llvm.fma.f64(double %nega, double %b, double %c)
+  %fma = call nsz double @llvm.fma.f64(double %nega, double %b, double %c)
   ret double %fma
 }
 
-define double @fnmsub_d_swap_intrinsics(double %a, double %b, double %c) nounwind {
-; LA32-CONTRACT-FAST-LABEL: fnmsub_d_swap_intrinsics:
+;; Check that fnmsub.d is not emitted.
+define double @not_fnmsub_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmsub_d_intrinsics:
 ; LA32-CONTRACT-FAST:       # %bb.0:
-; LA32-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA32-CONTRACT-FAST-NEXT:    ret
 ;
-; LA32-CONTRACT-ON-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-ON-LABEL: not_fnmsub_d_intrinsics:
 ; LA32-CONTRACT-ON:       # %bb.0:
-; LA32-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA32-CONTRACT-ON-NEXT:    ret
 ;
-; LA32-CONTRACT-OFF-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-OFF-LABEL: not_fnmsub_d_intrinsics:
 ; LA32-CONTRACT-OFF:       # %bb.0:
-; LA32-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA32-CONTRACT-OFF-NEXT:    ret
 ;
-; LA64-CONTRACT-FAST-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-FAST-LABEL: not_fnmsub_d_intrinsics:
 ; LA64-CONTRACT-FAST:       # %bb.0:
-; LA64-CONTRACT-FAST-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-FAST-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-FAST-NEXT:    ret
 ;
-; LA64-CONTRACT-ON-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-ON-LABEL: not_fnmsub_d_intrinsics:
 ; LA64-CONTRACT-ON:       # %bb.0:
-; LA64-CONTRACT-ON-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-ON-NEXT:    ret
 ;
-; LA64-CONTRACT-OFF-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-OFF-LABEL: not_fnmsub_d_intrinsics:
 ; LA64-CONTRACT-OFF:       # %bb.0:
-; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    fmadd.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-OFF-NEXT:    ret
-  %negb = fneg double %b
-  %fma = call double @llvm.fma.f64(double %a, double %negb, double %c)
+  %nega = fneg double %a
+  %fma = call double @llvm.fma.f64(double %nega, double %b, double %c)
   ret double %fma
 }
 
@@ -882,6 +1093,8 @@ define double @fnmsub_d_contract(double %a, double %b, double %c) nounwind {
 ; LA64-CONTRACT-OFF-NEXT:    fnmsub.d $fa0, $fa0, $fa1, $fa2
 ; LA64-CONTRACT-OFF-NEXT:    ret
   %mul = fmul contract double %a, %b
-  %sub = fsub contract double %c, %mul
-  ret double %sub
+  %negc = fneg contract double %c
+  %add = fadd contract double %negc, %mul
+  %negadd = fneg contract double %add
+  ret double %negadd
 }
diff --git a/llvm/test/CodeGen/LoongArch/float-fma.ll b/llvm/test/CodeGen/LoongArch/float-fma.ll
index 54dc56784006f12..c236255d971a208 100644
--- a/llvm/test/CodeGen/LoongArch/float-fma.ll
+++ b/llvm/test/CodeGen/LoongArch/float-fma.ll
@@ -236,13 +236,15 @@ define float @fnmsub_s(float %a, float %b, float %c) nounwind {
 ; LA32-CONTRACT-ON-LABEL: fnmsub_s:
 ; LA32-CONTRACT-ON:       # %bb.0:
 ; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
-; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
 ; LA32-CONTRACT-ON-NEXT:    ret
 ;
 ; LA32-CONTRACT-OFF-LABEL: fnmsub_s:
 ; LA32-CONTRACT-OFF:       # %bb.0:
 ; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
-; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
 ; LA32-CONTRACT-OFF-NEXT:    ret
 ;
 ; LA64-CONTRACT-FAST-LABEL: fnmsub_s:
@@ -253,12 +255,98 @@ define float @fnmsub_s(float %a, float %b, float %c) nounwind {
 ; LA64-CONTRACT-ON-LABEL: fnmsub_s:
 ; LA64-CONTRACT-ON:       # %bb.0:
 ; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
-; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT:    fneg.s $fa0, $fa0
 ; LA64-CONTRACT-ON-NEXT:    ret
 ;
 ; LA64-CONTRACT-OFF-LABEL: fnmsub_s:
 ; LA64-CONTRACT-OFF:       # %bb.0:
 ; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg float %c
+  %mul = fmul float %a, %b
+  %add = fadd float %mul, %negc
+  %neg = fneg float %add
+  ret float %neg
+}
+
+define float @fnmsub_s_nsz(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_nsz:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_nsz:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_nsz:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_nsz:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_nsz:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_nsz:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %nega = fneg nsz float %a
+  %mul = fmul nsz float %nega, %b
+  %add = fadd nsz float %mul, %c
+  ret float %add
+}
+
+;; Check that fnmsub.s is not emitted.
+define float @not_fnmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmsub_s:
+; LA32-CONTRACT-FAST:       # %bb.0:
+; LA32-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT:    ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmsub_s:
+; LA32-CONTRACT-ON:       # %bb.0:
+; LA32-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT:    ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmsub_s:
+; LA32-CONTRACT-OFF:       # %bb.0:
+; LA32-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT:    ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmsub_s:
+; LA64-CONTRACT-FAST:       # %bb.0:
+; LA64-CONTRACT-FAST-NEXT:    fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT:    fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT:    ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmsub_s:
+; LA64-CONTRACT-ON:       # %bb.0:
+; LA64-CONTRACT-ON-NEXT:    fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT:    fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT:    ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmsub_s:
+; LA64-CONTRACT-OFF:       # %bb.0:
+; LA64-CONTRACT-OFF-NEXT:    fmul.s $fa0, $fa0, $fa1
 ; LA64-CONTRACT-OFF-NEXT:    fsub.s $fa0, $fa2, $fa0
 ; LA64-CONTRACT-OFF-NEXT:    ret
   %nega = fneg float %a
@@ -483,6 +571,86 @@ define float @contract_fnmsub_s(float %a, float %b, float %c) nounwind {
 ; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_s:
 ; LA64-CONTRACT-OFF:       # %bb.0:
 ; LA64-CONTRACT-OFF-NEXT:    fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT:    ret
+  %negc = fneg contract float %c
+  %mul = fmul contract float %a, %b
+  %add = fadd contract float %mul, %negc
+  %neg = fneg contract float %add
+  ret float %neg
+}
+
+define float @contract_fnmsub_s_nsz(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: co...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/73742


More information about the llvm-commits mailing list