[llvm] InstCombine: Improve single use fabs SimplifyDemandedFPClass handling (PR #176359)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 16 07:36:40 PST 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/176359
>From 51bae73f4d6595196e51416b2a579abb8875a4c4 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 15 Jan 2026 14:06:24 +0100
Subject: [PATCH 1/2] InstCombine: Consider nsz when simplifying fabs/fneg uses
Later this trick should also be applied in the single use
case.
---
.../InstCombine/InstCombineSimplifyDemanded.cpp | 15 +++++++++++----
.../InstCombine/simplify-demanded-fpclass.ll | 6 +++---
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 2478ace4cc724..67123cbf13f7d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -3012,11 +3012,14 @@ Value *InstCombinerImpl::SimplifyMultipleUseDemandedFPClass(
KnownSrc.knownNot(fcInf);
// If the source value is known negative, we can directly fold to it.
-
- // TODO: If the only sign bit difference is for 0, ignore it for nsz.
if (KnownSrc.SignBit == true)
return Src;
+ // If the only sign bit difference is for 0, ignore it with nsz.
+ if ((FMF.noSignedZeros() || FabsFMF.noSignedZeros()) &&
+ KnownSrc.isKnownNever(KnownFPClass::OrderedGreaterThanZeroMask | fcNan))
+ return Src;
+
Known = KnownFPClass::fneg(KnownFPClass::fabs(KnownSrc));
break;
}
@@ -3034,11 +3037,15 @@ Value *InstCombinerImpl::SimplifyMultipleUseDemandedFPClass(
if ((DemandedMask & fcInf) == fcNone)
KnownSrc.knownNot(fcInf);
- // TODO: If the only sign bit difference is due to -0, look at source if
- // nsz.
if (KnownSrc.SignBit == false || ((DemandedMask & fcNan) == fcNone &&
KnownSrc.isKnownNever(fcNegative)))
return Src;
+
+ // If the only sign bit difference is due to -0, ignore it with nsz
+ if (FMF.noSignedZeros() &&
+ KnownSrc.isKnownNever(KnownFPClass::OrderedLessThanZeroMask | fcNan))
+ return Src;
+
Known = KnownFPClass::fabs(KnownSrc);
break;
}
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index c53cf037c8078..3425b20b16731 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -710,7 +710,7 @@ define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero_multipl
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[ALWAYS_POSITIVE_OR_NZERO]])
; CHECK-NEXT: store float [[FABS]], ptr [[PTR]], align 4
-; CHECK-NEXT: ret float [[FABS]]
+; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NZERO]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.positive.or.nzero)
store float %fabs, ptr %ptr
@@ -924,7 +924,7 @@ define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multip
; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
-; CHECK-NEXT: ret float [[FNEG_FABS]]
+; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_PZERO]]
;
%fabs = call nsz float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg float %fabs
@@ -938,7 +938,7 @@ define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multip
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[FABS]]
; CHECK-NEXT: store float [[FNEG_FABS]], ptr [[PTR]], align 4
-; CHECK-NEXT: ret float [[FNEG_FABS]]
+; CHECK-NEXT: ret float [[ALWAYS_NEGATIVE_OR_PZERO]]
;
%fabs = call float @llvm.fabs.f32(float %always.negative.or.pzero)
%fneg.fabs = fneg nsz float %fabs
>From bc8e314f053374177de56e4fd1430096fe4deec6 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 16 Jan 2026 12:29:12 +0100
Subject: [PATCH 2/2] InstCombine: Improve single use fabs
SimplifyDemandedFPClass handling
SimplifyDemandedFPClass's handling of fabs recently became smarter in
the multiple use case than single. Unify these so the single use case
is equally as smart. This includes propagating ninf / nnan context into
the instruction, and accounting for nsz if the only bit difference is
for zero.
---
.../InstCombineSimplifyDemanded.cpp | 59 +++++++++++--------
.../InstCombine/simplify-demanded-fpclass.ll | 33 +++++++++++
2 files changed, 69 insertions(+), 23 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 67123cbf13f7d..bf1bbfa158f97 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2033,6 +2033,30 @@ static Constant *getFPClassConstant(Type *Ty, FPClassTest Mask,
}
}
+/// Perform multiple-use aware simplfications for fabs(\p Src). Returns a
+/// replacement value if it's simplified, otherwise nullptr. Updates \p Known
+/// with the known fpclass if not simplified.
+static Value *simplifyDemandedFPClassFabs(KnownFPClass &Known, Value *Src,
+ FPClassTest DemandedMask,
+ KnownFPClass KnownSrc, bool NSZ) {
+ if ((DemandedMask & fcNan) == fcNone)
+ KnownSrc.knownNot(fcNan);
+ if ((DemandedMask & fcInf) == fcNone)
+ KnownSrc.knownNot(fcInf);
+
+ if (KnownSrc.SignBit == false ||
+ ((DemandedMask & fcNan) == fcNone && KnownSrc.isKnownNever(fcNegative)))
+ return Src;
+
+ // If the only sign bit difference is due to -0, ignore it with nsz
+ if (NSZ &&
+ KnownSrc.isKnownNever(KnownFPClass::OrderedLessThanZeroMask | fcNan))
+ return Src;
+
+ Known = KnownFPClass::fabs(KnownSrc);
+ return nullptr;
+}
+
static Value *
simplifyDemandedFPClassMinMax(KnownFPClass &Known, Intrinsic::ID IID,
const CallInst *CI, FPClassTest DemandedMask,
@@ -2469,17 +2493,18 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Instruction *I,
CallInst *CI = cast<CallInst>(I);
const Intrinsic::ID IID = CI->getIntrinsicID();
switch (IID) {
- case Intrinsic::fabs:
- if (SimplifyDemandedFPClass(I, 0, llvm::inverse_fabs(DemandedMask), Known,
- Depth + 1))
+ case Intrinsic::fabs: {
+ KnownFPClass KnownSrc;
+ if (SimplifyDemandedFPClass(I, 0, llvm::inverse_fabs(DemandedMask),
+ KnownSrc, Depth + 1))
return I;
- if (Known.SignBit == false ||
- ((DemandedMask & fcNan) == fcNone && Known.isKnownNever(fcNegative)))
- return CI->getArgOperand(0);
-
- Known.fabs();
+ if (Value *Simplified = simplifyDemandedFPClassFabs(
+ Known, CI->getArgOperand(0), DemandedMask, KnownSrc,
+ FMF.noSignedZeros()))
+ return Simplified;
break;
+ }
case Intrinsic::arithmetic_fence:
if (SimplifyDemandedFPClass(I, 0, DemandedMask, Known, Depth + 1))
return I;
@@ -3032,21 +3057,9 @@ Value *InstCombinerImpl::SimplifyMultipleUseDemandedFPClass(
KnownFPClass KnownSrc =
computeKnownFPClass(Src, fcAllFlags, CxtI, Depth + 1);
- if ((DemandedMask & fcNan) == fcNone)
- KnownSrc.knownNot(fcNan);
- if ((DemandedMask & fcInf) == fcNone)
- KnownSrc.knownNot(fcInf);
-
- if (KnownSrc.SignBit == false || ((DemandedMask & fcNan) == fcNone &&
- KnownSrc.isKnownNever(fcNegative)))
- return Src;
-
- // If the only sign bit difference is due to -0, ignore it with nsz
- if (FMF.noSignedZeros() &&
- KnownSrc.isKnownNever(KnownFPClass::OrderedLessThanZeroMask | fcNan))
- return Src;
-
- Known = KnownFPClass::fabs(KnownSrc);
+ if (Value *Simplified = simplifyDemandedFPClassFabs(
+ Known, Src, DemandedMask, KnownSrc, FMF.noSignedZeros()))
+ return Simplified;
break;
}
case Intrinsic::maximum:
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
index 3425b20b16731..f505fb5905a8e 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -705,6 +705,15 @@ define nofpclass(snan) float @fabs_src_known_positive_except_negzero_multiple_us
ret float %fabs
}
+define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero(float nofpclass(nan ninf nnorm nsub) %always.positive.or.nzero) {
+; CHECK-LABEL: define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]]) {
+; CHECK-NEXT: ret float [[ALWAYS_POSITIVE_OR_NZERO]]
+;
+ %fabs = call nsz float @llvm.fabs.f32(float %always.positive.or.nzero)
+ ret float %fabs
+}
+
define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero_multiple_uses(float nofpclass(nan ninf nnorm nsub) %always.positive.or.nzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fabs_nsz_src_known_positive_except_negzero_multiple_uses
; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ALWAYS_POSITIVE_OR_NZERO:%.*]], ptr [[PTR:%.*]]) {
@@ -918,6 +927,18 @@ define nofpclass(snan) float @fneg_fabs_src_known_negative_or_poszero_multiple_u
ret float %fneg.fabs
}
+define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero) {
+; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero
+; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]]) {
+; CHECK-NEXT: [[FABS:%.*]] = call nsz float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
+; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg float [[FABS]]
+; CHECK-NEXT: ret float [[FNEG_FABS]]
+;
+ %fabs = call nsz float @llvm.fabs.f32(float %always.negative.or.pzero)
+ %fneg.fabs = fneg float %fabs
+ ret float %fneg.fabs
+}
+
define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multiple_uses(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multiple_uses
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
@@ -932,6 +953,18 @@ define nofpclass(snan) float @fneg_fabs_nsz_src_known_negative_or_poszero_multip
ret float %fneg.fabs
}
+define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero) {
+; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero
+; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]]) {
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[ALWAYS_NEGATIVE_OR_PZERO]])
+; CHECK-NEXT: [[FNEG_FABS:%.*]] = fneg nsz float [[FABS]]
+; CHECK-NEXT: ret float [[FNEG_FABS]]
+;
+ %fabs = call float @llvm.fabs.f32(float %always.negative.or.pzero)
+ %fneg.fabs = fneg nsz float %fabs
+ ret float %fneg.fabs
+}
+
define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multiple_uses(float nofpclass(nan pinf pnorm psub) %always.negative.or.pzero, ptr %ptr) {
; CHECK-LABEL: define nofpclass(snan) float @fneg_nsz_fabs_src_known_negative_or_poszero_multiple_uses
; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ALWAYS_NEGATIVE_OR_PZERO:%.*]], ptr [[PTR:%.*]]) {
More information about the llvm-commits
mailing list