https://github.com/arsenm updated 
https://github.com/llvm/llvm-project/pull/173881

>From b7cff00f49dbc0d18153bbcadfb4dc419409d933 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           | 46 +++++++------------
 llvm/lib/Support/KnownFPClass.cpp             | 17 +++++++
 .../InstCombineSimplifyDemanded.cpp           | 37 +++++++++++++++
 .../simplify-demanded-fpclass-log.ll          | 27 ++++-------
 6 files changed, 88 insertions(+), 48 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..4fbbfd1a0cf12 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5369,44 +5369,30 @@ void computeKnownFPClass(const Value *V, const APInt 
&DemandedElts,
     case Intrinsic::experimental_constrained_log2:
     case Intrinsic::amdgcn_log: {
       Type *EltTy = II->getType()->getScalarType();
-      if (IID == Intrinsic::amdgcn_log && EltTy->isFloatTy())
-        Known.knownNot(fcSubnormal);
-
-      Known.knownNot(fcNegZero);
 
       // log(+inf) -> +inf
       // log([+-]0.0) -> -inf
       // log(-inf) -> nan
       // log(-x) -> nan
-      if ((InterestedClasses & (fcNan | fcInf)) == fcNone)
-        break;
-
-      FPClassTest InterestedSrcs = InterestedClasses;
-      if ((InterestedClasses & fcNegInf) != fcNone)
-        InterestedSrcs |= fcZero | fcSubnormal;
-      if ((InterestedClasses & fcNan) != fcNone)
-        InterestedSrcs |= fcNan | (fcNegative & ~fcNan);
-
-      KnownFPClass KnownSrc;
-      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;
+      if ((InterestedClasses & (fcNan | fcInf)) != fcNone) {
+        FPClassTest InterestedSrcs = InterestedClasses;
+        if ((InterestedClasses & fcNegInf) != fcNone)
+          InterestedSrcs |= fcZero | fcSubnormal;
+        if ((InterestedClasses & fcNan) != fcNone)
+          InterestedSrcs |= fcNan | (fcNegative & ~fcNan);
 
-      const fltSemantics &FltSem = EltTy->getFltSemantics();
-      DenormalMode Mode = F->getDenormalMode(FltSem);
+        KnownFPClass KnownSrc;
+        computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
+                            KnownSrc, Q, Depth + 1);
 
-      if (KnownSrc.isKnownNeverLogicalZero(Mode))
-        Known.knownNot(fcNegInf);
+        const Function *F = II->getFunction();
+        DenormalMode Mode = F ? F->getDenormalMode(EltTy->getFltSemantics())
+                              : DenormalMode::getDynamic();
+        Known = KnownFPClass::log(KnownSrc, Mode);
+      }
 
+      if (IID == Intrinsic::amdgcn_log && EltTy->isFloatTy())
+        Known.knownNot(fcSubnormal);
       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 6de3ad70d4ad7..0ae828711ce7e 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

Reply via email to