[llvm-branch-commits] [llvm] InstCombine: Handle log/log2/log10 in SimplifyDemandedFPClass (PR #173881)
Matt Arsenault via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Dec 29 09:00:16 PST 2025
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/173881
None
>From 51c1ea4c559d98cf6ed9b1876b4b56ea1b328133 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 22 Dec 2025 23:06:20 +0100
Subject: [PATCH] InstCombine: Handle log/log2/log10 in SimplifyDemandedFPClass
---
llvm/include/llvm/ADT/FloatingPointMode.h | 5 +++
llvm/include/llvm/Support/KnownFPClass.h | 4 ++
llvm/lib/Analysis/ValueTracking.cpp | 18 ++-------
llvm/lib/Support/KnownFPClass.cpp | 17 +++++++++
.../InstCombineSimplifyDemanded.cpp | 37 +++++++++++++++++++
.../simplify-demanded-fpclass-log.ll | 35 ++++++------------
6 files changed, 78 insertions(+), 38 deletions(-)
diff --git a/llvm/include/llvm/ADT/FloatingPointMode.h b/llvm/include/llvm/ADT/FloatingPointMode.h
index a9702c65e631f..0605e0b4f4cf9 100644
--- a/llvm/include/llvm/ADT/FloatingPointMode.h
+++ b/llvm/include/llvm/ADT/FloatingPointMode.h
@@ -153,6 +153,11 @@ struct DenormalMode {
Input == DenormalModeKind::PositiveZero;
}
+ /// Return true if input denormals may be implicitly treated as 0.
+ constexpr bool inputsMayBeZero() const {
+ return inputsAreZero() || Input == DenormalMode::Dynamic;
+ }
+
/// Return true if output denormals should be flushed to 0.
constexpr bool outputsAreZero() const {
return Output == DenormalModeKind::PreserveSign ||
diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 62df87ad8a67e..07d74f2867089 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -263,6 +263,10 @@ struct KnownFPClass {
LLVM_ABI void propagateCanonicalizingSrc(const KnownFPClass &Src,
DenormalMode Mode);
+ /// Propagate known class for log/log2/log10
+ static LLVM_ABI KnownFPClass
+ log(const KnownFPClass &Src, DenormalMode Mode = DenormalMode::getDynamic());
+
void resetAll() { *this = KnownFPClass(); }
};
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index cddd6f9c25074..bac863cb3c67c 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5391,22 +5391,10 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
KnownSrc, Q, Depth + 1);
- if (KnownSrc.isKnownNeverPosInfinity())
- Known.knownNot(fcPosInf);
-
- if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
- Known.knownNot(fcNan);
-
const Function *F = II->getFunction();
- if (!F)
- break;
-
- const fltSemantics &FltSem = EltTy->getFltSemantics();
- DenormalMode Mode = F->getDenormalMode(FltSem);
-
- if (KnownSrc.isKnownNeverLogicalZero(Mode))
- Known.knownNot(fcNegInf);
-
+ DenormalMode Mode = F ? F->getDenormalMode(EltTy->getFltSemantics())
+ : DenormalMode::getDynamic();
+ Known = KnownFPClass::log(KnownSrc, Mode);
break;
}
case Intrinsic::powi: {
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 125bee00c38ff..ff98908fdb2c4 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -226,3 +226,20 @@ void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
propagateDenormal(Src, Mode);
propagateNaN(Src, /*PreserveSign=*/true);
}
+
+KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc,
+ DenormalMode Mode) {
+ KnownFPClass Known;
+ Known.knownNot(fcNegZero);
+
+ if (KnownSrc.isKnownNeverPosInfinity())
+ Known.knownNot(fcPosInf);
+
+ if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
+ Known.knownNot(fcNan);
+
+ if (KnownSrc.isKnownNeverLogicalZero(Mode))
+ Known.knownNot(fcNegInf);
+
+ return Known;
+}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 33ece6c2b69d8..3cb4c629b9108 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -2202,6 +2202,43 @@ Value *InstCombinerImpl::SimplifyDemandedUseFPClass(Value *V,
Known = KnownFPClass::exp(KnownSrc);
break;
}
+ case Intrinsic::log:
+ case Intrinsic::log2:
+ case Intrinsic::log10: {
+ FPClassTest DemandedSrcMask = DemandedMask & (fcNan | fcPosInf);
+
+ Type *EltTy = VTy->getScalarType();
+ DenormalMode Mode = F.getDenormalMode(EltTy->getFltSemantics());
+
+ // log(x < 0) = nan
+ if (DemandedMask & fcNan)
+ DemandedSrcMask |= (fcNegative & ~fcNegZero);
+
+ // log(0) = -inf
+ if (DemandedMask & fcNegInf) {
+ DemandedSrcMask |= fcZero;
+
+ // No value produces subnormal result.
+ if (Mode.inputsMayBeZero())
+ DemandedSrcMask |= fcSubnormal;
+ }
+
+ if (DemandedMask & fcNormal)
+ DemandedSrcMask |= fcNormal | fcSubnormal;
+
+ // log(1) = 0
+ if (DemandedMask & fcZero)
+ DemandedSrcMask |= fcPosNormal;
+
+ KnownFPClass KnownSrc;
+ if (SimplifyDemandedFPClass(I, 0, DemandedSrcMask, KnownSrc, Depth + 1))
+ return I;
+
+ Known = KnownFPClass::log(KnownSrc, Mode);
+
+ FPClassTest ValidResults = DemandedMask & Known.KnownFPClasses;
+ return getFPClassConstant(VTy, ValidResults, /*IsCanonicalizing=*/true);
+ }
case Intrinsic::canonicalize: {
Type *EltTy = VTy->getScalarType();
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll
index d6f2cab6687ab..87973fa36b478 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-log.ll
@@ -5,8 +5,7 @@
define nofpclass(inf norm sub zero) float @ret_nofpclass_only_nan__log(float %unknown) {
; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_nofpclass_only_nan__log(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
-; CHECK-NEXT: ret float [[RESULT]]
+; CHECK-NEXT: ret float 0x7FF8000000000000
;
%result = call float @llvm.log.f32(float %unknown)
ret float %result
@@ -16,8 +15,7 @@ define nofpclass(inf norm sub zero) float @ret_nofpclass_only_nan__log(float %un
define nofpclass(nan inf norm sub) float @ret_nofpclass_only_zero__log(float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @ret_nofpclass_only_zero__log(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
-; CHECK-NEXT: ret float [[RESULT]]
+; CHECK-NEXT: ret float 0.000000e+00
;
%result = call float @llvm.log.f32(float %unknown)
ret float %result
@@ -57,7 +55,7 @@ define nofpclass(nan pinf norm sub zero) float @ret_nofpclass_only_ninf__log(flo
define nofpclass(nan inf norm sub pzero) float @ret_nofpclass_only_nzero__log(float %unknown) {
; CHECK-LABEL: define nofpclass(nan inf pzero sub norm) float @ret_nofpclass_only_nzero__log(
; CHECK-SAME: float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: ret float -0.000000e+00
+; CHECK-NEXT: ret float poison
;
%result = call float @llvm.log.f32(float %unknown)
ret float %result
@@ -87,8 +85,7 @@ define nofpclass(norm sub zero) float @ret_nofpclass_only_inf_nan__log(float %un
define nofpclass(ninf) float @ret_nofpclass_ninf_log(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf_log(
; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0.000000e+00, float [[X]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[X]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float 0.0, float %x
@@ -100,8 +97,7 @@ define nofpclass(ninf) float @ret_nofpclass_ninf_log(i1 %cond, float %x) {
define nofpclass(pinf) float @ret_nofpclass_pinf_log_select_inf_or_unknown(i1 %cond, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf_log_select_inf_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float 0x7ff0000000000000, float %unknown
@@ -113,8 +109,7 @@ define nofpclass(pinf) float @ret_nofpclass_pinf_log_select_inf_or_unknown(i1 %c
define nofpclass(pinf) float @ret_nofpclass_pinf_log2_select_inf_or_unknown(i1 %cond, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf_log2_select_inf_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log2.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log2.f32(float [[UNKNOWN]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float 0x7ff0000000000000, float %unknown
@@ -126,8 +121,7 @@ define nofpclass(pinf) float @ret_nofpclass_pinf_log2_select_inf_or_unknown(i1 %
define nofpclass(pinf) float @ret_nofpclass_pinf_log10_select_inf_or_unknown(i1 %cond, float %unknown) {
; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf_log10_select_inf_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log10.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log10.f32(float [[UNKNOWN]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float 0x7ff0000000000000, float %unknown
@@ -139,8 +133,7 @@ define nofpclass(pinf) float @ret_nofpclass_pinf_log10_select_inf_or_unknown(i1
define nofpclass(ninf norm zero) float @ret_nofpclass_nan_or_sub__log_select__finite_positive__unknown(i1 %cond, float nofpclass(inf nnorm nsub nan) %must.be.finite.positive, float %unknown) {
; CHECK-LABEL: define nofpclass(ninf zero norm) float @ret_nofpclass_nan_or_sub__log_select__finite_positive__unknown(
; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan inf nsub nnorm) [[MUST_BE_FINITE_POSITIVE:%.*]], float [[UNKNOWN:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_FINITE_POSITIVE]], float [[UNKNOWN]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float %must.be.finite.positive, float %unknown
@@ -165,8 +158,7 @@ define nofpclass(ninf norm zero) float @ret_nofpclass_nan_or_sub__log_select__fi
define nofpclass(pinf nan norm zero) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__ieee(i1 %cond, float nofpclass(ninf norm nan) %must.be.pinf.or.sub.or.zero, float nofpclass(zero) %not.zero) {
; CHECK-LABEL: define nofpclass(nan pinf zero norm) float @ret_ninf_or_sub__log_select__pinf_or_sub_orzero__else_not0__ieee(
; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(nan ninf norm) [[MUST_BE_PINF_OR_SUB_OR_ZERO:%.*]], float nofpclass(zero) [[NOT_ZERO:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_PINF_OR_SUB_OR_ZERO]], float [[NOT_ZERO]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[MUST_BE_PINF_OR_SUB_OR_ZERO]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float %must.be.pinf.or.sub.or.zero, float %not.zero
@@ -204,8 +196,7 @@ define nofpclass(pinf nan norm zero) float @ret_ninf_or_sub__log_select__pinf_or
define nofpclass(inf nan pnorm sub zero) float @ret_only_nnorm__log__select_unknown_or_infnan(i1 %cond, float %unknown, float nofpclass(norm sub zero) %b) {
; CHECK-LABEL: define nofpclass(nan inf zero sub pnorm) float @ret_only_nnorm__log__select_unknown_or_infnan(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(zero sub norm) [[B:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[UNKNOWN]], float [[B]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float %unknown, float %b
@@ -217,8 +208,7 @@ define nofpclass(inf nan pnorm sub zero) float @ret_only_nnorm__log__select_unkn
define nofpclass(inf nan nnorm sub zero) float @ret_only_pnorm__log__select_unknown_or_infnan(i1 %cond, float %unknown, float nofpclass(norm sub zero) %b) {
; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @ret_only_pnorm__log__select_unknown_or_infnan(
; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]], float nofpclass(zero sub norm) [[B:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[UNKNOWN]], float [[B]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[UNKNOWN]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float %unknown, float %b
@@ -243,8 +233,7 @@ define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_pnormnan_or
define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_nnormnan_or_unknown(i1 %cond, float nofpclass(inf sub zero pnorm) %nnorm.or.nan, float %b) {
; CHECK-LABEL: define nofpclass(nan inf norm) float @ret_only_zero_sub__log__select_nnormnan_or_unknown(
; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero sub pnorm) [[NNORM_OR_NAN:%.*]], float [[B:%.*]]) {
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[NNORM_OR_NAN]], float [[B]]
-; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[SELECT]])
+; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.log.f32(float [[B]])
; CHECK-NEXT: ret float [[RESULT]]
;
%select = select i1 %cond, float %nnorm.or.nan, float %b
More information about the llvm-branch-commits
mailing list