https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/173881
>From bc98197502b1c444c12b96e7489c64f0baefe89f Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> 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 | 27 +++++--------- 6 files changed, 75 insertions(+), 33 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 2c6d11378e167..455d37019c965 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 @@ -99,8 +98,7 @@ define nofpclass(ninf) float @ret_nofpclass_ninf_log(i1 %cond, float %x, float n 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 @@ -112,8 +110,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 @@ -125,8 +122,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 @@ -138,8 +134,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 @@ -164,8 +159,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 @@ -203,8 +197,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 @@ -216,8 +209,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 @@ -242,8 +234,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 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
