[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