[llvm] f4ecba3 - [KnownFPClass] Unify and refine interested classes for `KnownFPClass::log` (#219751)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 13 08:21:20 PDT 2026


Author: Eric Ross
Date: 2026-09-13T17:21:15+02:00
New Revision: f4ecba36726d6bede2ab58890dfcc861c2bb28a9

URL: https://github.com/llvm/llvm-project/commit/f4ecba36726d6bede2ab58890dfcc861c2bb28a9
DIFF: https://github.com/llvm/llvm-project/commit/f4ecba36726d6bede2ab58890dfcc861c2bb28a9.diff

LOG: [KnownFPClass] Unify and refine interested classes for `KnownFPClass::log` (#219751)

Previously, `ValueTracking` and `GISelValueTracking` only called
`KnownFPClass::log` when the requested classes included NaN or infinity.
As a result, narrowly interested queries could miss unconditional
deductions, for example, `log(x)` is never subnormal or negative zero
(With the exception of `PPCDoubleDouble`
https://github.com/llvm/llvm-project/issues/217658).

This change makes the interested-class handling consistent between
`ValueTracking` and `GISelValueTracking`. The source is queried only
when its classes are needed, but `KnownFPClass::log` is always called so
its unconditional deductions are preserved.

Future work:
- Fixing `KnownFPClass::log` for `PPCDoubleDouble`.

AI disclosure:
I used OpenAI Codex (sol 5.6) to help write the unit tests, which I
reviewed and ran locally.

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
    llvm/unittests/Analysis/ValueTrackingTest.cpp
    llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1580571a01451..0ba071eab51f8 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5627,29 +5627,38 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     case Intrinsic::experimental_constrained_log10:
     case Intrinsic::experimental_constrained_log2:
     case Intrinsic::amdgcn_log: {
-      Type *EltTy = II->getType()->getScalarType();
+      FPClassTest InterestedSrcs = fcNone;
 
-      // log(+inf) -> +inf
-      // log([+-]0.0) -> -inf
-      // log(-inf) -> nan
-      // log(-x) -> nan
-      if ((InterestedClasses & (fcNan | fcInf)) != fcNone) {
-        FPClassTest InterestedSrcs = InterestedClasses;
-        if ((InterestedClasses & fcNegInf) != fcNone)
-          InterestedSrcs |= fcZero | fcSubnormal;
-        if ((InterestedClasses & fcNan) != fcNone)
-          InterestedSrcs |= fcNan | fcNegative;
+      // log(negative) produces NaN.
+      if ((InterestedClasses & fcNan) != fcNone)
+        InterestedSrcs |= fcNan | fcNegative;
 
-        KnownFPClass KnownSrc;
-        computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
-                            KnownSrc, Q, Depth + 1);
+      // log(logical-zero) produces negative infinity.
+      if ((InterestedClasses & fcNegInf) != fcNone)
+        InterestedSrcs |= fcZero | fcSubnormal;
 
-        const Function *F = II->getFunction();
-        DenormalMode Mode = F ? F->getDenormalMode(EltTy->getFltSemantics())
-                              : DenormalMode::getDynamic();
-        Known = KnownFPClass::log(KnownSrc, Mode);
-      }
+      // log(x) < -0.0 if x < +1.0
+      if ((InterestedClasses & fcNegNormal) != fcNone)
+        InterestedSrcs |= fcPosSubnormal | fcPosNormal;
+
+      // log(x) >= +0.0 if x >= +1.0
+      if ((InterestedClasses & (fcPosZero | fcPosNormal)) != fcNone)
+        InterestedSrcs |= fcPosNormal;
+
+      // log(x) is positive infinity iff x is positive infinity.
+      if ((InterestedClasses & fcPosInf) != fcNone)
+        InterestedSrcs |= fcPosInf;
 
+      KnownFPClass KnownSrc;
+      if (InterestedSrcs != fcNone)
+        computeKnownFPClass(II->getArgOperand(0), DemandedElts, InterestedSrcs,
+                            KnownSrc, Q, Depth + 1);
+      const Function *F = II->getFunction();
+      DenormalMode Mode =
+          F ? F->getDenormalMode(
+                  II->getType()->getScalarType()->getFltSemantics())
+            : DenormalMode::getDynamic();
+      Known = KnownFPClass::log(KnownSrc, Mode);
       break;
     }
     case Intrinsic::pow: {

diff  --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 0bbafeb6dca41..4cdbeeebc39bb 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1612,22 +1612,33 @@ void GISelValueTracking::computeKnownFPClass(Register R,
   case TargetOpcode::G_FLOG:
   case TargetOpcode::G_FLOG2:
   case TargetOpcode::G_FLOG10: {
-    // log(+inf) -> +inf
-    // log([+-]0.0) -> -inf
-    // log(-inf) -> nan
-    // log(-x) -> nan
-    if ((InterestedClasses & (fcNan | fcInf)) == fcNone)
-      break;
+    FPClassTest InterestedSrcs = fcNone;
 
-    FPClassTest InterestedSrcs = InterestedClasses;
-    if ((InterestedClasses & fcNegInf) != fcNone)
-      InterestedSrcs |= fcZero | fcSubnormal;
+    // log(negative) produces NaN.
     if ((InterestedClasses & fcNan) != fcNone)
       InterestedSrcs |= fcNan | fcNegative;
 
+    // log(logical-zero) produces negative infinity.
+    if ((InterestedClasses & fcNegInf) != fcNone)
+      InterestedSrcs |= fcZero | fcSubnormal;
+
+    // log(x) < -0.0 if x < +1.0
+    if ((InterestedClasses & fcNegNormal) != fcNone)
+      InterestedSrcs |= fcPosSubnormal | fcPosNormal;
+
+    // log(x) >= +0.0 if x >= +1.0
+    if ((InterestedClasses & (fcPosZero | fcPosNormal)) != fcNone)
+      InterestedSrcs |= fcPosNormal;
+
+    // log(x) is positive infinity iff x is positive infinity.
+    if ((InterestedClasses & fcPosInf) != fcNone)
+      InterestedSrcs |= fcPosInf;
+
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
-    computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc, Depth + 1);
+    if (InterestedSrcs != fcNone)
+      computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc,
+                          Depth + 1);
 
     LLT Ty = MRI.getType(Val).getScalarType();
     const fltSemantics &FltSem = getFltSemanticForLLT(Ty);

diff  --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 0634f43f3e79c..9635c48525591 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1756,6 +1756,18 @@ TEST_F(ComputeKnownFPClassTest, CopySignNInfSrc0_PosSign) {
   expectKnownFPClass(fcPosZero | fcPosNormal | fcNan, false);
 }
 
+TEST_F(ComputeKnownFPClassTest, LogDeduceSubnormalOrNegativeZero) {
+  parseAssembly("declare float @llvm.log.f32(float)\n"
+                "define float @test(float %x) {\n"
+                "  %A = call float @llvm.log.f32(float %x)\n"
+                "  ret float %A\n"
+                "}\n");
+
+  KnownFPClass Known =
+      computeKnownFPClass(A, M->getDataLayout(), fcNegZero | fcSubnormal);
+  EXPECT_EQ(~(fcNegZero | fcSubnormal), Known.getKnownFPClasses());
+}
+
 TEST_F(ComputeKnownFPClassTest, UIToFP) {
   parseAssembly(
       "define float @test(i32 %arg0, i16 %arg1) {\n"

diff  --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index 8ff84820276d5..f5ac377f4f585 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -879,6 +879,30 @@ TEST_F(AArch64GISelMITest, TestFPClassFLogNeg) {
   EXPECT_EQ(std::nullopt, Known.getSignBit());
 }
 
+TEST_F(AArch64GISelMITest, TestFPClassFLogDeduceSubnormalOrNegativeZero) {
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %flog:_(s32) = G_FLOG %val
+    %copy_flog:_(s32) = COPY %flog
+)";
+
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known =
+      Info.computeKnownFPClass(SrcReg, fcNegZero | fcSubnormal);
+
+  EXPECT_EQ(~(fcNegZero | fcSubnormal), Known.getKnownFPClasses());
+  EXPECT_EQ(std::nullopt, Known.getSignBit());
+}
+
 TEST_F(AArch64GISelMITest, TestFPClassFLogPosZero) {
   StringRef MIRString = R"(
     %val:_(s32) = G_FCONSTANT float 0.0


        


More information about the llvm-commits mailing list