[llvm] [DAG] isKnownNeverZero - add DemandedElts argument (PR #182679)

Harrishan Raveendran via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 21 06:44:11 PST 2026


https://github.com/Harrish92 created https://github.com/llvm/llvm-project/pull/182679

Closes #181656 .

Following changes were made for isKnownNeverZero :
- Added BUILDVECTOR and SPLATVECTOR cases.
- Added support for DemandedElts arguments for SELECT/VSELECT cases.  
- Added tests for constants and SELECT/VSELECT.

>From f922803a7b9dabd4bc0a0fe3c45f5d6d59337f1a Mon Sep 17 00:00:00 2001
From: Harrish92 <harrishan.raveendran at epfl.ch>
Date: Sat, 21 Feb 2026 15:27:54 +0100
Subject: [PATCH 1/2] [DAG] isKnownNeverZero - add DemandedElts argument

---
 llvm/include/llvm/CodeGen/SelectionDAG.h      |  3 +
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 44 +++++++++-
 .../AArch64/AArch64SelectionDAGTest.cpp       | 82 +++++++++++++++++++
 3 files changed, 125 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index c45dec89b4b11..733df6ed880a1 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -2395,6 +2395,9 @@ class SelectionDAG {
   /// Test whether the given SDValue is known to contain non-zero value(s).
   LLVM_ABI bool isKnownNeverZero(SDValue Op, unsigned Depth = 0) const;
 
+  /// Test whether the given SDValue is known to contain non-zero value(s).
+  LLVM_ABI bool isKnownNeverZero(SDValue Op, const APInt &DemandedElts, unsigned Depth = 0) const; 
+
   /// Test whether the given float value is known to be positive. +0.0, +inf and
   /// +nan are considered positive, -0.0, -inf and -nan are not.
   LLVM_ABI bool cannotBeOrderedNegativeFP(SDValue Op) const;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 581553d41cb6d..d34f7ec657a06 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6147,15 +6147,35 @@ bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op) const {
 }
 
 bool SelectionDAG::isKnownNeverZero(SDValue Op, unsigned Depth) const {
+   EVT VT = Op.getValueType();
+
+  // Since the number of lanes in a scalable vector is unknown at compile time,
+  // we track one bit which is implicitly broadcast to all lanes.  This means
+  // that all lanes in a scalable vector are considered demanded.
+  APInt DemandedElts = VT.isFixedLengthVector()
+                           ? APInt::getAllOnes(VT.getVectorNumElements())
+                           : APInt(1, 1);
+
+  return isKnownNeverZero(Op, DemandedElts, Depth);
+}
+
+bool SelectionDAG::isKnownNeverZero(SDValue Op, const APInt &DemandedElts, unsigned Depth) const {
   if (Depth >= MaxRecursionDepth)
     return false; // Limit search depth.
+  
+  EVT OpVT = Op.getValueType();
+  unsigned BitWidth = OpVT.getScalarSizeInBits();
 
   assert(!Op.getValueType().isFloatingPoint() &&
          "Floating point types unsupported - use isKnownNeverZeroFloat");
 
   // If the value is a constant, we can obviously see if it is a zero or not.
-  if (ISD::matchUnaryPredicate(Op,
-                               [](ConstantSDNode *C) { return !C->isZero(); }))
+  auto IsNeverZero = [BitWidth](const ConstantSDNode *C) { 
+    APInt V = C->getAPIntValue().zextOrTrunc(BitWidth);
+    return !V.isZero(); 
+  };
+
+  if (ISD::matchUnaryPredicate(Op, IsNeverZero))
     return true;
 
   // TODO: Recognize more cases here. Most of the cases are also incomplete to
@@ -6164,14 +6184,30 @@ bool SelectionDAG::isKnownNeverZero(SDValue Op, unsigned Depth) const {
   default:
     break;
 
+  case ISD::BUILD_VECTOR:
+    // Are all operands of a build vector constant powers of two or zero?
+    if (all_of(enumerate(Op->ops()), [&](auto P) {
+          auto *C = dyn_cast<ConstantSDNode>(P.value());
+          return !DemandedElts[P.index()] || (C && IsNeverZero(C));
+        }))
+      return true;
+    break;
+
+  case ISD::SPLAT_VECTOR:
+    // Is the operand of a splat vector a constant power of two?
+    if (auto *C = dyn_cast<ConstantSDNode>(Op->getOperand(0)))
+      if (IsNeverZero(C))
+        return true;
+    break;
+
   case ISD::OR:
     return isKnownNeverZero(Op.getOperand(1), Depth + 1) ||
            isKnownNeverZero(Op.getOperand(0), Depth + 1);
 
   case ISD::VSELECT:
   case ISD::SELECT:
-    return isKnownNeverZero(Op.getOperand(1), Depth + 1) &&
-           isKnownNeverZero(Op.getOperand(2), Depth + 1);
+    return isKnownNeverZero(Op.getOperand(1), DemandedElts, Depth + 1) &&
+           isKnownNeverZero(Op.getOperand(2), DemandedElts, Depth + 1);
 
   case ISD::SHL: {
     if (Op->getFlags().hasNoSignedWrap() || Op->getFlags().hasNoUnsignedWrap())
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index b2b8dfb0c21fc..9273802fdf999 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1435,4 +1435,86 @@ TEST_F(AArch64SelectionDAGTest,
   EXPECT_EQ(KnownAVGCEILS.One, Ones);
 }
 
+// Piggy-backing on the AArch64 tests to verify
+// SelectionDAG::KnownNeverZero.
+TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Constants) {
+  SDLoc Loc;
+  auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
+  auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
+  auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
+  EXPECT_FALSE(DAG->isKnownNeverZero(Cst0));
+  EXPECT_TRUE(DAG->isKnownNeverZero(Cst4));
+  EXPECT_TRUE(DAG->isKnownNeverZero(CstBig));
+
+  auto VecVT = MVT::v2i16;
+  auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
+  auto Vec44 = DAG->getBuildVector(VecVT, Loc, {Cst4, Cst4});
+  auto Vec4Big = DAG->getBuildVector(VecVT, Loc, {Cst4, CstBig});
+  auto Vec0Big = DAG->getBuildVector(VecVT, Loc, {Cst0, CstBig});
+  EXPECT_FALSE(DAG->isKnownNeverZero(Vec04));
+  EXPECT_TRUE(DAG->isKnownNeverZero(Vec44));
+  EXPECT_FALSE(DAG->isKnownNeverZero(Vec4Big));
+  EXPECT_FALSE(DAG->isKnownNeverZero(Vec0Big));
+
+  APInt DemandLo(2, 1);
+  EXPECT_FALSE(DAG->isKnownNeverZero(Vec04, DemandLo));
+
+  APInt DemandHi(2, 2);
+  EXPECT_TRUE(DAG->isKnownNeverZero(Vec04, DemandHi));
+
+  auto SplatVT = MVT::nxv2i16;
+  auto Splat0 = DAG->getSplat(SplatVT, Loc, Cst0);
+  auto Splat4 = DAG->getSplat(SplatVT, Loc, Cst4);
+  auto SplatBig = DAG->getSplat(SplatVT, Loc, CstBig);
+  EXPECT_FALSE(DAG->isKnownNeverZero(Splat0));
+  EXPECT_TRUE(DAG->isKnownNeverZero(Splat4));
+  EXPECT_FALSE(DAG->isKnownNeverZero(SplatBig));
+}
+
+TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Select) {
+  SDLoc Loc; auto Cst0 = DAG->getConstant(0, Loc, MVT::i32); auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
+  auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
+  auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
+
+  auto Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 1, MVT::i1);
+  auto Select40 = DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, Cst0);
+  auto Select43 = DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, Cst3);
+  auto Select4Big =
+      DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, CstBig);
+
+  EXPECT_FALSE(DAG->isKnownNeverZero(Select40));
+  EXPECT_FALSE(DAG->isKnownNeverZero(Select40));
+  EXPECT_TRUE(DAG->isKnownNeverZero(Select43));
+  EXPECT_TRUE(DAG->isKnownNeverZero(Select4Big));
+
+  auto VecVT = MVT::v2i16;
+  auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
+  auto Vec44 = DAG->getBuildVector(VecVT, Loc, {Cst4, Cst4});
+  auto Vec4Big = DAG->getBuildVector(VecVT, Loc, {Cst4, CstBig});
+  auto Vec0Big = DAG->getBuildVector(VecVT, Loc, {Cst0, CstBig});
+
+  auto VecCond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc, 2, MVT::v2i1);
+  auto VSelect0444 =
+      DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec04, Vec44);
+  auto VSelect4444 =
+      DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec44, Vec44);
+  auto VSelect040Big =
+      DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec04, Vec0Big);
+  auto VSelect444Big =
+      DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec44, Vec4Big);
+
+  APInt DemandLo(2, 1);
+  EXPECT_FALSE(DAG->isKnownNeverZero(VSelect0444, DemandLo));
+  EXPECT_TRUE(DAG->isKnownNeverZero(VSelect444Big, DemandLo));
+
+  APInt DemandHi(2, 2);
+  EXPECT_FALSE(DAG->isKnownNeverZero(VSelect444Big, DemandHi));
+  EXPECT_TRUE(DAG->isKnownNeverZero(VSelect0444, DemandHi));
+
+  APInt DemandAll(2, 3);
+  EXPECT_FALSE(DAG->isKnownNeverZero(VSelect0444, DemandAll));
+  EXPECT_FALSE(DAG->isKnownNeverZero(VSelect040Big, DemandAll));
+  EXPECT_FALSE(DAG->isKnownNeverZero(VSelect444Big, DemandAll));
+  EXPECT_TRUE(DAG->isKnownNeverZero(VSelect4444, DemandAll));
+}
 } // end namespace llvm

>From 73cef1ec783ef23ce11c319c92330c51a2b482e5 Mon Sep 17 00:00:00 2001
From: Harrish92 <harrishan.raveendran at epfl.ch>
Date: Sat, 21 Feb 2026 15:29:00 +0100
Subject: [PATCH 2/2] style: format changes

---
 llvm/include/llvm/CodeGen/SelectionDAG.h              |  3 ++-
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp        | 11 ++++++-----
 .../Target/AArch64/AArch64SelectionDAGTest.cpp        |  4 +++-
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 733df6ed880a1..c9ca24a760e2c 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -2396,7 +2396,8 @@ class SelectionDAG {
   LLVM_ABI bool isKnownNeverZero(SDValue Op, unsigned Depth = 0) const;
 
   /// Test whether the given SDValue is known to contain non-zero value(s).
-  LLVM_ABI bool isKnownNeverZero(SDValue Op, const APInt &DemandedElts, unsigned Depth = 0) const; 
+  LLVM_ABI bool isKnownNeverZero(SDValue Op, const APInt &DemandedElts,
+                                 unsigned Depth = 0) const;
 
   /// Test whether the given float value is known to be positive. +0.0, +inf and
   /// +nan are considered positive, -0.0, -inf and -nan are not.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index d34f7ec657a06..61b3401109496 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6147,7 +6147,7 @@ bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op) const {
 }
 
 bool SelectionDAG::isKnownNeverZero(SDValue Op, unsigned Depth) const {
-   EVT VT = Op.getValueType();
+  EVT VT = Op.getValueType();
 
   // Since the number of lanes in a scalable vector is unknown at compile time,
   // we track one bit which is implicitly broadcast to all lanes.  This means
@@ -6159,10 +6159,11 @@ bool SelectionDAG::isKnownNeverZero(SDValue Op, unsigned Depth) const {
   return isKnownNeverZero(Op, DemandedElts, Depth);
 }
 
-bool SelectionDAG::isKnownNeverZero(SDValue Op, const APInt &DemandedElts, unsigned Depth) const {
+bool SelectionDAG::isKnownNeverZero(SDValue Op, const APInt &DemandedElts,
+                                    unsigned Depth) const {
   if (Depth >= MaxRecursionDepth)
     return false; // Limit search depth.
-  
+
   EVT OpVT = Op.getValueType();
   unsigned BitWidth = OpVT.getScalarSizeInBits();
 
@@ -6170,9 +6171,9 @@ bool SelectionDAG::isKnownNeverZero(SDValue Op, const APInt &DemandedElts, unsig
          "Floating point types unsupported - use isKnownNeverZeroFloat");
 
   // If the value is a constant, we can obviously see if it is a zero or not.
-  auto IsNeverZero = [BitWidth](const ConstantSDNode *C) { 
+  auto IsNeverZero = [BitWidth](const ConstantSDNode *C) {
     APInt V = C->getAPIntValue().zextOrTrunc(BitWidth);
-    return !V.isZero(); 
+    return !V.isZero();
   };
 
   if (ISD::matchUnaryPredicate(Op, IsNeverZero))
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 9273802fdf999..df69953f7454f 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1472,7 +1472,9 @@ TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Constants) {
 }
 
 TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Select) {
-  SDLoc Loc; auto Cst0 = DAG->getConstant(0, Loc, MVT::i32); auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
+  SDLoc Loc;
+  auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
+  auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
   auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
   auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
 



More information about the llvm-commits mailing list