[llvm] 5e7e0d6 - [LoongArch] Fix pattern for FNMSUB_{S/D} instructions (#73742)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 28 23:21:25 PST 2023
Author: wanglei
Date: 2023-11-29T15:21:21+08:00
New Revision: 5e7e0d603204ede803323a825318e365a87f73e9
URL: https://github.com/llvm/llvm-project/commit/5e7e0d603204ede803323a825318e365a87f73e9
DIFF: https://github.com/llvm/llvm-project/commit/5e7e0d603204ede803323a825318e365a87f73e9.diff
LOG: [LoongArch] Fix pattern for FNMSUB_{S/D} instructions (#73742)
```
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.
Added:
Modified:
llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
llvm/lib/Target/LoongArch/LoongArchFloat64InstrInfo.td
llvm/test/CodeGen/LoongArch/double-fma.ll
llvm/test/CodeGen/LoongArch/float-fma.ll
Removed:
################################################################################
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: contract_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: contract_fnmsub_s_nsz:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmsub_s_nsz:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmsub_s_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: contract_fnmsub_s_nsz:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_s_nsz:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract nsz float %a
+ %mul = fmul contract nsz float %nega, %b
+ %add = fadd contract nsz float %mul, %c
+ ret float %add
+}
+
+;; Check that fnmsub.s is not emitted.
+define float @not_contract_fnmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_contract_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_contract_fnmsub_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_contract_fnmsub_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_contract_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_contract_fnmsub_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_contract_fnmsub_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
; LA64-CONTRACT-OFF-NEXT: ret
%nega = fneg contract float %a
%mul = fmul contract float %nega, %b
@@ -592,8 +760,8 @@ define float @fnmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
; LA64-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
; LA64-CONTRACT-OFF-NEXT: ret
%fma = call float @llvm.fma.f64(float %a, float %b, float %c)
- %neg = fneg float %fma
- ret float %neg
+ %negfma = fneg float %fma
+ ret float %negfma
}
define float @fnmadd_s_nsz_intrinsics(float %a, float %b, float %c) nounwind {
@@ -704,44 +872,87 @@ define float @fnmsub_s_intrinsics(float %a, float %b, float %c) nounwind {
; LA64-CONTRACT-OFF-LABEL: fnmsub_s_intrinsics:
; LA64-CONTRACT-OFF: # %bb.0:
; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %negc = fneg float %c
+ %fma = call float @llvm.fma.f64(float %a, float %b, float %negc)
+ %negfma = fneg float %fma
+ ret float %negfma
+}
+
+define float @fnmsub_s_nsz_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_nsz_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_nsz_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_nsz_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_nsz_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_nsz_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_nsz_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
; LA64-CONTRACT-OFF-NEXT: ret
%nega = fneg float %a
- %fma = call float @llvm.fma.f64(float %nega, float %b, float %c)
+ %fma = call nsz float @llvm.fma.f64(float %nega, float %b, float %c)
ret float %fma
}
-define float @fnmsub_s_swap_intrinsics(float %a, float %b, float %c) nounwind {
-; LA32-CONTRACT-FAST-LABEL: fnmsub_s_swap_intrinsics:
+;; Check that fnmsub.s is not emitted.
+define float @not_fnmsub_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmsub_s_intrinsics:
; LA32-CONTRACT-FAST: # %bb.0:
-; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; 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: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-ON-LABEL: not_fnmsub_s_intrinsics:
; LA32-CONTRACT-ON: # %bb.0:
-; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
; LA32-CONTRACT-ON-NEXT: ret
;
-; LA32-CONTRACT-OFF-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-OFF-LABEL: not_fnmsub_s_intrinsics:
; LA32-CONTRACT-OFF: # %bb.0:
-; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
; LA32-CONTRACT-OFF-NEXT: ret
;
-; LA64-CONTRACT-FAST-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-FAST-LABEL: not_fnmsub_s_intrinsics:
; LA64-CONTRACT-FAST: # %bb.0:
-; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; 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: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-ON-LABEL: not_fnmsub_s_intrinsics:
; LA64-CONTRACT-ON: # %bb.0:
-; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
; LA64-CONTRACT-ON-NEXT: ret
;
-; LA64-CONTRACT-OFF-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-OFF-LABEL: not_fnmsub_s_intrinsics:
; LA64-CONTRACT-OFF: # %bb.0:
-; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
; LA64-CONTRACT-OFF-NEXT: ret
- %negb = fneg float %b
- %fma = call float @llvm.fma.f64(float %a, float %negb, float %c)
+ %nega = fneg float %a
+ %fma = call float @llvm.fma.f64(float %nega, float %b, float %c)
ret float %fma
}
@@ -882,6 +1093,8 @@ define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind {
; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
; LA64-CONTRACT-OFF-NEXT: ret
%mul = fmul contract float %a, %b
- %sub = fsub contract float %c, %mul
- ret float %sub
+ %negc = fneg contract float %c
+ %add = fadd contract float %negc, %mul
+ %negadd = fneg contract float %add
+ ret float %negadd
}
More information about the llvm-commits
mailing list