[llvm] aa22fca - [DAG] Add initial version of SelectionDAG::computeKnownFPClass (#188790)

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 30 07:08:57 PDT 2026


Author: Xinlong Chen
Date: 2026-03-30T14:08:44Z
New Revision: aa22fca59a4d541def13f18a496d4ca62f239adb

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

LOG: [DAG] Add initial version of SelectionDAG::computeKnownFPClass (#188790)

This patch adds an initial skeleton for `SelectionDAG::computeKnownFPClass`.

The initial version includes:
- DemandedElts wrapper and max depth early-out
- `ConstantFPSDNode` and `BUILD_VECTOR` handling
- `TargetLowering::computeKnownFPClassForTargetNode` virtual hook for backend extensions

Initial test coverage for constant scalars, BUILD_VECTOR, and max depth
early-out is added in `AArch64SelectionDAGTest.cpp`.

closes #175571

Added: 
    

Modified: 
    llvm/include/llvm/CodeGen/SelectionDAG.h
    llvm/include/llvm/CodeGen/TargetLowering.h
    llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
    llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
    llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 20846168e9a8e..c1012c940ed5b 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -40,6 +40,7 @@
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/KnownFPClass.h"
 #include "llvm/Support/RecyclingAllocator.h"
 #include <cassert>
 #include <cstdint>
@@ -2398,6 +2399,24 @@ class SelectionDAG {
   ///     X|Cst == X+Cst iff X&Cst = 0.
   LLVM_ABI bool isBaseWithConstantOffset(SDValue Op) const;
 
+  /// Determine floating-point class information about \p Op. For vectors, the
+  /// known FP classes are those shared by every demanded vector element.
+  /// \p InterestedClasses is a hint for which FP classes we care about;
+  /// the implementation may bail out early if it can determine that
+  /// none of the interested classes are possible.
+  LLVM_ABI KnownFPClass computeKnownFPClass(SDValue Op,
+                                            FPClassTest InterestedClasses,
+                                            unsigned Depth = 0) const;
+
+  /// Determine floating-point class information about \p Op. The
+  /// DemandedElts argument allows us to only collect the known FP classes
+  /// that are shared by the requested vector elements.
+  /// \p InterestedClasses is a hint for which FP classes we care about.
+  LLVM_ABI KnownFPClass computeKnownFPClass(SDValue Op,
+                                            const APInt &DemandedElts,
+                                            FPClassTest InterestedClasses,
+                                            unsigned Depth = 0) const;
+
   /// Test whether the given SDValue (or all elements of it, if it is a
   /// vector) is known to never be NaN in \p DemandedElts. If \p SNaN is true,
   /// returns if \p Op is known to never be a signaling NaN (it may still be a

diff  --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 2e66f574981ab..ec76318c4af5a 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -4448,6 +4448,15 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
   /// NOTE: You must check for implicit extensions of the constant by LD.
   virtual const Constant *getTargetConstantFromLoad(LoadSDNode *LD) const;
 
+  /// Determine floating-point class information for a target node. The
+  /// DemandedElts argument allows us to only collect the known FP classes
+  /// that are shared by the requested vector elements.
+  virtual void computeKnownFPClassForTargetNode(const SDValue Op,
+                                                KnownFPClass &Known,
+                                                const APInt &DemandedElts,
+                                                const SelectionDAG &DAG,
+                                                unsigned Depth = 0) const;
+
   /// If \p SNaN is false, \returns true if \p Op is known to never be any
   /// NaN. If \p sNaN is true, returns if \p Op is known to never be a signaling
   /// NaN.

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 58b9106c08e06..9094e8341627a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -64,6 +64,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/KnownBits.h"
+#include "llvm/Support/KnownFPClass.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachine.h"
@@ -6050,6 +6051,79 @@ bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const {
          (Op.isAnyAdd() || isADDLike(Op));
 }
 
+KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
+                                               FPClassTest InterestedClasses,
+                                               unsigned Depth) const {
+  EVT VT = Op.getValueType();
+  APInt DemandedElts = VT.isFixedLengthVector()
+                           ? APInt::getAllOnes(VT.getVectorNumElements())
+                           : APInt(1, 1);
+  return computeKnownFPClass(Op, DemandedElts, InterestedClasses, Depth);
+}
+
+KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
+                                               const APInt &DemandedElts,
+                                               FPClassTest InterestedClasses,
+                                               unsigned Depth) const {
+  KnownFPClass Known;
+
+  if (const auto *CFP = dyn_cast<ConstantFPSDNode>(Op))
+    return KnownFPClass(CFP->getValueAPF());
+
+  if (Depth >= MaxRecursionDepth)
+    return Known;
+
+  if (Op.getOpcode() == ISD::UNDEF)
+    return Known;
+
+  EVT VT = Op.getValueType();
+  assert((!VT.isFixedLengthVector() ||
+          DemandedElts.getBitWidth() == VT.getVectorNumElements()) &&
+         "Unexpected vector size");
+
+  if (!DemandedElts)
+    return Known;
+
+  unsigned Opcode = Op.getOpcode();
+  switch (Opcode) {
+  case ISD::POISON: {
+    Known.KnownFPClasses = fcNone;
+    Known.SignBit = false;
+    break;
+  }
+  case ISD::BUILD_VECTOR: {
+    assert(!VT.isScalableVector());
+    bool First = true;
+    for (unsigned I = 0, E = Op.getNumOperands(); I != E; ++I) {
+      if (!DemandedElts[I])
+        continue;
+
+      if (First) {
+        Known =
+            computeKnownFPClass(Op.getOperand(I), InterestedClasses, Depth + 1);
+        First = false;
+      } else {
+        Known |=
+            computeKnownFPClass(Op.getOperand(I), InterestedClasses, Depth + 1);
+      }
+
+      if (Known.isUnknown())
+        break;
+    }
+    break;
+  }
+  default:
+    if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
+        Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
+      TLI->computeKnownFPClassForTargetNode(Op, Known, DemandedElts, *this,
+                                            Depth);
+    }
+    break;
+  }
+
+  return Known;
+}
+
 bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN,
                                    unsigned Depth) const {
   EVT VT = Op.getValueType();

diff  --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 2c8926167b6da..30ad097f85596 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -4065,6 +4065,19 @@ bool TargetLowering::canCreateUndefOrPoisonForTargetNode(
   return true;
 }
 
+void TargetLowering::computeKnownFPClassForTargetNode(const SDValue Op,
+                                                      KnownFPClass &Known,
+                                                      const APInt &DemandedElts,
+                                                      const SelectionDAG &DAG,
+                                                      unsigned Depth) const {
+  assert((Op.getOpcode() >= ISD::BUILTIN_OP_END ||
+          Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN ||
+          Op.getOpcode() == ISD::INTRINSIC_W_CHAIN ||
+          Op.getOpcode() == ISD::INTRINSIC_VOID) &&
+         "Should use computeKnownFPClass if you don't know whether Op"
+         " is a target node!");
+}
+
 bool TargetLowering::isKnownNeverNaNForTargetNode(SDValue Op,
                                                   const APInt &DemandedElts,
                                                   const SelectionDAG &DAG,

diff  --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index b0c48e8c97995..12b7763274f6c 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -16,6 +16,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/KnownBits.h"
+#include "llvm/Support/KnownFPClass.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Target/TargetMachine.h"
@@ -1574,4 +1575,130 @@ TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Select) {
   EXPECT_FALSE(DAG->isKnownNeverZero(VSelect444Big, DemandAll));
   EXPECT_TRUE(DAG->isKnownNeverZero(VSelect4444, DemandAll));
 }
+
+// tests for SelectionDAG::computeKnownFPClass
+TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_ConstantScalar) {
+  SDLoc Loc;
+
+  SDValue PosZero = DAG->getConstantFP(APFloat::getZero(APFloat::IEEEsingle()),
+                                       Loc, MVT::f32);
+  KnownFPClass Known = DAG->computeKnownFPClass(PosZero, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosZero);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_FALSE(*Known.SignBit);
+
+  SDValue NegZero = DAG->getConstantFP(
+      APFloat::getZero(APFloat::IEEEsingle(), true), Loc, MVT::f32);
+  Known = DAG->computeKnownFPClass(NegZero, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcNegZero);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_TRUE(*Known.SignBit);
+
+  SDValue PosInf =
+      DAG->getConstantFP(APFloat::getInf(APFloat::IEEEsingle()), Loc, MVT::f32);
+  Known = DAG->computeKnownFPClass(PosInf, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosInf);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_FALSE(*Known.SignBit);
+
+  SDValue QNaN = DAG->getConstantFP(APFloat::getQNaN(APFloat::IEEEsingle()),
+                                    Loc, MVT::f32);
+  Known = DAG->computeKnownFPClass(QNaN, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcQNan);
+
+  SDValue One = DAG->getConstantFP(1.0, Loc, MVT::f32);
+  Known = DAG->computeKnownFPClass(One, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_FALSE(*Known.SignBit);
+}
+
+TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_BuildVector) {
+  SDLoc Loc;
+
+  SDValue PosOne = DAG->getConstantFP(1.0, Loc, MVT::f32);
+  SDValue PosTwo = DAG->getConstantFP(2.0, Loc, MVT::f32);
+  SDValue NegOne = DAG->getConstantFP(-1.0, Loc, MVT::f32);
+
+  EVT VecVT = MVT::v2f32;
+
+  SDValue VecPosPos = DAG->getBuildVector(VecVT, Loc, {PosOne, PosTwo});
+  KnownFPClass Known = DAG->computeKnownFPClass(VecPosPos, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_FALSE(*Known.SignBit);
+
+  SDValue VecPosNeg = DAG->getBuildVector(VecVT, Loc, {PosOne, NegOne});
+  Known = DAG->computeKnownFPClass(VecPosNeg, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosNormal | fcNegNormal);
+  EXPECT_FALSE(Known.SignBit.has_value());
+}
+
+TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_DemandedElts) {
+  SDLoc Loc;
+
+  SDValue PosOne = DAG->getConstantFP(1.0, Loc, MVT::f32);
+  SDValue NegOne = DAG->getConstantFP(-1.0, Loc, MVT::f32);
+  EVT VecVT = MVT::v2f32;
+  SDValue Vec = DAG->getBuildVector(VecVT, Loc, {PosOne, NegOne});
+
+  APInt DemandLo(2, 1);
+  KnownFPClass Known = DAG->computeKnownFPClass(Vec, DemandLo, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_FALSE(*Known.SignBit);
+
+  APInt DemandHi(2, 2);
+  Known = DAG->computeKnownFPClass(Vec, DemandHi, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcNegNormal);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_TRUE(*Known.SignBit);
+
+  APInt DemandAll(2, 3);
+  Known = DAG->computeKnownFPClass(Vec, DemandAll, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosNormal | fcNegNormal);
+  EXPECT_FALSE(Known.SignBit.has_value());
+
+  APInt DemandNone(2, 0);
+  Known = DAG->computeKnownFPClass(Vec, DemandNone, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcAllFlags);
+  EXPECT_FALSE(Known.SignBit.has_value());
+}
+
+TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_MaxDepth) {
+  SDLoc Loc;
+
+  SDValue PosOne = DAG->getConstantFP(1.0, Loc, MVT::f32);
+  SDValue PosTwo = DAG->getConstantFP(2.0, Loc, MVT::f32);
+  EVT VecVT = MVT::v2f32;
+  SDValue Vec = DAG->getBuildVector(VecVT, Loc, {PosOne, PosTwo});
+
+  // At depth 0, BUILD_VECTOR of constants is fully analyzed.
+  KnownFPClass Known = DAG->computeKnownFPClass(Vec, fcAllFlags, /*Depth=*/0);
+  EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
+
+  // At MaxRecursionDepth, the non-constant node bails out as unknown.
+  Known = DAG->computeKnownFPClass(Vec, fcAllFlags,
+                                   SelectionDAG::MaxRecursionDepth);
+  EXPECT_EQ(Known.KnownFPClasses, fcAllFlags);
+  EXPECT_FALSE(Known.SignBit.has_value());
+}
+
+TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_UndefAndPoison) {
+  SDLoc Loc;
+
+  // UNDEF is unknown — could be any FP class.
+  SDValue Undef = DAG->getUNDEF(MVT::f32);
+  KnownFPClass Known = DAG->computeKnownFPClass(Undef, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcAllFlags);
+  EXPECT_FALSE(Known.SignBit.has_value());
+
+  // POISON is fcNone — can be assumed to never be observed.
+  SDValue Poison = DAG->getPOISON(MVT::f32);
+  Known = DAG->computeKnownFPClass(Poison, fcAllFlags);
+  EXPECT_EQ(Known.KnownFPClasses, fcNone);
+  EXPECT_TRUE(Known.SignBit.has_value());
+  EXPECT_FALSE(*Known.SignBit);
+}
+
 } // end namespace llvm


        


More information about the llvm-commits mailing list