[llvm] [DAG] SDPatternMatch - add m_Negative/m_StrictlyPositive/m_NonNegative/m_NonPositive/m_NonZero matchers (PR #175191)
Aryan Kadole via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 14 08:09:33 PST 2026
https://github.com/ak1932 updated https://github.com/llvm/llvm-project/pull/175191
>From fbd8f4bae0662c9d31d7cc31289416e7d33b8b94 Mon Sep 17 00:00:00 2001
From: ak1932 <aryankadole95 at gmail.com>
Date: Wed, 14 Jan 2026 02:00:06 +0530
Subject: [PATCH 1/2] [DAG] SDPatternMatch - add
m_Negative/m_StrictlyPositive/m_NonNegative/m_NonPositive/m_NonZero matchers
---
llvm/include/llvm/CodeGen/SDPatternMatch.h | 63 ++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/llvm/include/llvm/CodeGen/SDPatternMatch.h b/llvm/include/llvm/CodeGen/SDPatternMatch.h
index 5a7afcf7d54c1..11ab657d7efaf 100644
--- a/llvm/include/llvm/CodeGen/SDPatternMatch.h
+++ b/llvm/include/llvm/CodeGen/SDPatternMatch.h
@@ -20,6 +20,7 @@
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/Support/KnownBits.h"
namespace llvm {
namespace SDPatternMatch {
@@ -1182,6 +1183,46 @@ inline SpecificFP_match m_SpecificFP(double V) {
return SpecificFP_match(APFloat(V));
}
+struct Negative_match {
+ template <typename MatchContext>
+ bool match(const MatchContext &Ctx, SDValue N) {
+ const SelectionDAG *DAG = Ctx.getDAG();
+ return DAG && DAG->computeKnownBits(N).isNegative();
+ }
+};
+
+struct NonNegative_match {
+ template <typename MatchContext>
+ bool match(const MatchContext &Ctx, SDValue N) {
+ const SelectionDAG *DAG = Ctx.getDAG();
+ return DAG && DAG->computeKnownBits(N).isNonNegative();
+ }
+};
+
+struct StrictlyPositive_match {
+ template <typename MatchContext>
+ bool match(const MatchContext &Ctx, SDValue N) {
+ const SelectionDAG *DAG = Ctx.getDAG();
+ return DAG && DAG->computeKnownBits(N).isStrictlyPositive();
+ }
+};
+
+struct NonPositive_match {
+ template <typename MatchContext>
+ bool match(const MatchContext &Ctx, SDValue N) {
+ const SelectionDAG *DAG = Ctx.getDAG();
+ return DAG && DAG->computeKnownBits(N).isNonPositive();
+ }
+};
+
+struct NonZero_match {
+ template <typename MatchContext>
+ bool match(const MatchContext &Ctx, SDValue N) {
+ const SelectionDAG *DAG = Ctx.getDAG();
+ return DAG && DAG->computeKnownBits(N).isNonZero();
+ }
+};
+
struct Zero_match {
bool AllowUndefs;
@@ -1213,6 +1254,28 @@ struct AllOnes_match {
}
};
+inline Negative_match m_Negative() { return Negative_match(); }
+template <typename Pattern> inline auto m_Negative(const Pattern &P) {
+ return m_AllOf(m_Negative(), P);
+}
+inline NonNegative_match m_NonNegative() { return NonNegative_match(); }
+template <typename Pattern> inline auto m_NonNegative(const Pattern &P) {
+ return m_AllOf(m_NonNegative(), P);
+}
+inline StrictlyPositive_match m_StrictlyPositive() {
+ return StrictlyPositive_match();
+}
+template <typename Pattern> inline auto m_StrictlyPositive(const Pattern &P) {
+ return m_AllOf(m_StrictlyPositive(), P);
+}
+inline NonPositive_match m_NonPositive() { return NonPositive_match(); }
+template <typename Pattern> inline auto m_NonPositive(const Pattern &P) {
+ return m_AllOf(m_NonPositive(), P);
+}
+inline NonZero_match m_NonZero() { return NonZero_match(); }
+template <typename Pattern> inline auto m_NonZero(const Pattern &P) {
+ return m_AllOf(m_NonZero(), P);
+}
inline Ones_match m_One(bool AllowUndefs = false) {
return Ones_match(AllowUndefs);
}
>From 67903a88f16aba0cb0dd030d1816ad3a52353921 Mon Sep 17 00:00:00 2001
From: ak1932 <aryankadole95 at gmail.com>
Date: Thu, 8 Jan 2026 03:52:32 +0530
Subject: [PATCH 2/2] [DAG] Add Unit testing for
m_Negative/m_StrictlyPositive/m_NonNegative/m_NonPositive/m_NonZero matchers
---
.../CodeGen/SelectionDAGPatternMatchTest.cpp | 124 ++++++++++++++++++
llvm/unittests/CodeGen/SelectionDAGTestBase.h | 2 +-
2 files changed, 125 insertions(+), 1 deletion(-)
diff --git a/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp b/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp
index 8796c40254944..c8fd5baa397e1 100644
--- a/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp
+++ b/llvm/unittests/CodeGen/SelectionDAGPatternMatchTest.cpp
@@ -500,6 +500,23 @@ TEST_F(SelectionDAGPatternMatchTest, matchUnaryOp) {
SDValue Ctlz = DAG->getNode(ISD::CTLZ, DL, Int32VT, Op0);
SDValue Cttz = DAG->getNode(ISD::CTTZ, DL, Int32VT, Op0);
+ SDValue SignBit = DAG->getConstant(0x80000000u, DL, Int32VT);
+ SDValue LSB = DAG->getConstant(0x00000001u, DL, Int32VT);
+ // ~SignBit
+ SDValue NotSignBit = DAG->getNode(
+ ISD::XOR, DL, Int32VT, SignBit,
+ DAG->getConstant(APInt(Int32VT.getScalarSizeInBits(), -1, true), DL,
+ Int32VT));
+
+ // Clear sign bit of Op0
+ SDValue NonNegativeValue =
+ DAG->getNode(ISD::AND, DL, Int32VT, Op0, NotSignBit);
+ // Set sign bit to Op0
+ SDValue NegativeValue = DAG->getNode(ISD::OR, DL, Int32VT, Op0, SignBit);
+ // Set LSB of Op0
+ SDValue PositiveValue =
+ DAG->getNode(ISD::OR, DL, Int32VT, NonNegativeValue, LSB);
+
using namespace SDPatternMatch;
EXPECT_TRUE(sd_match(ZExt, m_UnaryOp(ISD::ZERO_EXTEND, m_Value())));
EXPECT_TRUE(sd_match(SExt, m_SExt(m_Value())));
@@ -525,6 +542,69 @@ TEST_F(SelectionDAGPatternMatchTest, matchUnaryOp) {
EXPECT_FALSE(sd_match(ZExt, m_Neg(m_Value())));
EXPECT_FALSE(sd_match(Sub, m_Neg(m_Value())));
EXPECT_FALSE(sd_match(Neg, m_Not(m_Value())));
+
+ SDValue BindVal;
+
+ EXPECT_FALSE(sd_match(Abs, DAG.get(), m_Negative()));
+
+ EXPECT_FALSE(
+ sd_match(NonNegativeValue, DAG.get(), m_Negative(m_Value(BindVal))));
+ EXPECT_NE(BindVal, NonNegativeValue);
+ EXPECT_FALSE(
+ sd_match(NonNegativeValue, DAG.get(), m_NonZero(m_Value(BindVal))));
+ EXPECT_NE(BindVal, NonNegativeValue);
+ EXPECT_FALSE(sd_match(NonNegativeValue, DAG.get(),
+ m_StrictlyPositive(m_Value(BindVal))));
+ EXPECT_NE(BindVal, NonNegativeValue);
+ EXPECT_FALSE(
+ sd_match(NonNegativeValue, DAG.get(), m_NonPositive(m_Value(BindVal))));
+ EXPECT_NE(BindVal, NonNegativeValue);
+
+ EXPECT_TRUE(
+ sd_match(NonNegativeValue, DAG.get(), m_NonNegative(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, NonNegativeValue);
+
+ EXPECT_FALSE(
+ sd_match(NegativeValue, DAG.get(), m_NonNegative(m_Value(BindVal))));
+ EXPECT_NE(BindVal, NegativeValue);
+ EXPECT_FALSE(
+ sd_match(NegativeValue, DAG.get(), m_StrictlyPositive(m_Value(BindVal))));
+ EXPECT_NE(BindVal, NegativeValue);
+
+ EXPECT_TRUE(sd_match(NegativeValue, DAG.get(), m_Negative(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, NegativeValue);
+ EXPECT_TRUE(sd_match(NegativeValue, DAG.get(), m_NonZero(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, NegativeValue);
+ EXPECT_TRUE(
+ sd_match(NegativeValue, DAG.get(), m_NonPositive(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, NegativeValue);
+
+ EXPECT_FALSE(
+ sd_match(PositiveValue, DAG.get(), m_Negative(m_Value(BindVal))));
+ EXPECT_NE(BindVal, PositiveValue);
+ EXPECT_FALSE(
+ sd_match(PositiveValue, DAG.get(), m_NonPositive(m_Value(BindVal))));
+ EXPECT_NE(BindVal, PositiveValue);
+
+ EXPECT_TRUE(sd_match(PositiveValue, DAG.get(), m_NonZero(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, PositiveValue);
+ EXPECT_TRUE(
+ sd_match(PositiveValue, DAG.get(), m_NonNegative(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, PositiveValue);
+ EXPECT_TRUE(
+ sd_match(PositiveValue, DAG.get(), m_StrictlyPositive(m_Value(BindVal))));
+ EXPECT_EQ(BindVal, PositiveValue);
+
+ // If DAG is not provided all matches fail regardless of the value
+ EXPECT_FALSE(sd_match(NegativeValue, m_Negative(m_Value(BindVal))));
+ EXPECT_FALSE(
+ sd_match(NonNegativeValue, m_NonNegative(m_Value(BindVal))));
+ EXPECT_FALSE(sd_match(NegativeValue, m_NonZero(m_Value(BindVal))));
+ EXPECT_FALSE(
+ sd_match(NegativeValue, m_NonPositive(m_Value(BindVal))));
+ EXPECT_FALSE(
+ sd_match(PositiveValue, m_StrictlyPositive(m_Value(BindVal))));
+
EXPECT_TRUE(sd_match(VScale, m_VScale(m_Value())));
EXPECT_TRUE(sd_match(FPToUI, m_FPToUI(m_Value())));
@@ -562,6 +642,8 @@ TEST_F(SelectionDAGPatternMatchTest, matchConstants) {
SDValue ConstSplat = DAG->getSplat(VInt32VT, DL, Const3);
SDValue Zero = DAG->getConstant(0, DL, Int32VT);
SDValue One = DAG->getConstant(1, DL, Int32VT);
+ SDValue MinusOne = DAG->getConstant(
+ APInt(Int32VT.getScalarSizeInBits(), -1, true), DL, Int32VT);
SDValue AllOnes = DAG->getConstant(APInt::getAllOnes(32), DL, Int32VT);
SDValue SetCC = DAG->getSetCC(DL, Int32VT, Arg0, Const3, ISD::SETULT);
@@ -581,6 +663,31 @@ TEST_F(SelectionDAGPatternMatchTest, matchConstants) {
EXPECT_TRUE(sd_match(One, DAG.get(), m_True()));
EXPECT_FALSE(sd_match(AllOnes, DAG.get(), m_True()));
+ EXPECT_TRUE(sd_match(MinusOne, DAG.get(), m_Negative()));
+ EXPECT_FALSE(sd_match(MinusOne, DAG.get(), m_NonNegative()));
+ EXPECT_TRUE(sd_match(MinusOne, DAG.get(), m_NonZero()));
+ EXPECT_TRUE(sd_match(MinusOne, DAG.get(), m_NonPositive()));
+ EXPECT_FALSE(sd_match(MinusOne, DAG.get(), m_StrictlyPositive()));
+
+ EXPECT_FALSE(sd_match(Zero, DAG.get(), m_Negative()));
+ EXPECT_TRUE(sd_match(Zero, DAG.get(), m_NonNegative()));
+ EXPECT_FALSE(sd_match(Zero, DAG.get(), m_NonZero()));
+ EXPECT_TRUE(sd_match(Zero, DAG.get(), m_NonPositive()));
+ EXPECT_FALSE(sd_match(Zero, DAG.get(), m_StrictlyPositive()));
+
+ EXPECT_FALSE(sd_match(One, DAG.get(), m_Negative()));
+ EXPECT_TRUE(sd_match(One, DAG.get(), m_NonNegative()));
+ EXPECT_TRUE(sd_match(One, DAG.get(), m_NonZero()));
+ EXPECT_FALSE(sd_match(One, DAG.get(), m_NonPositive()));
+ EXPECT_TRUE(sd_match(One, DAG.get(), m_StrictlyPositive()));
+
+ // If DAG is not provided all matches would fail
+ EXPECT_FALSE(sd_match(MinusOne, m_Negative()));
+ EXPECT_FALSE(sd_match(Zero, m_NonNegative()));
+ EXPECT_FALSE(sd_match(One, m_NonZero()));
+ EXPECT_FALSE(sd_match(Zero, m_NonPositive()));
+ EXPECT_FALSE(sd_match(One, m_StrictlyPositive()));
+
ISD::CondCode CC;
EXPECT_TRUE(sd_match(
SetCC, m_Node(ISD::SETCC, m_Value(), m_Value(), m_CondCode(CC))));
@@ -648,6 +755,8 @@ TEST_F(SelectionDAGPatternMatchTest, optionalResizing) {
EXPECT_TRUE(A == Op64);
EXPECT_TRUE(sd_match(Trunc, m_TruncOrSelf(m_Value(A))));
EXPECT_TRUE(A == Op64);
+
+ EXPECT_TRUE(sd_match(ZExt, DAG.get(), m_NonNegative(m_Value())));
}
TEST_F(SelectionDAGPatternMatchTest, matchNode) {
@@ -985,6 +1094,11 @@ TEST_F(SelectionDAGPatternMatchTest, MatchZeroOneAllOnes) {
SDValue VecSplat = DAG->getSplatBuildVector(VecVT, DL, SplatVal);
SDValue Bitcasted = DAG->getNode(ISD::BITCAST, DL, VecF32, VecSplat);
EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_Zero()));
+
+ EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_Negative()));
+ EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_NonZero()));
+ EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_StrictlyPositive()));
+ EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonPositive()));
}
// m_One: splat vector of 1 → bitcast
@@ -993,6 +1107,11 @@ TEST_F(SelectionDAGPatternMatchTest, MatchZeroOneAllOnes) {
SDValue VecSplat = DAG->getSplatBuildVector(VecVT, DL, SplatVal);
SDValue Bitcasted = DAG->getNode(ISD::BITCAST, DL, VecF32, VecSplat);
EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_One()));
+
+ EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_Negative()));
+ EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonZero()));
+ EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_NonPositive()));
+ EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_StrictlyPositive()));
}
// m_AllOnes: splat vector of -1 → bitcast
@@ -1001,6 +1120,11 @@ TEST_F(SelectionDAGPatternMatchTest, MatchZeroOneAllOnes) {
SDValue VecSplat = DAG->getSplatBuildVector(VecVT, DL, SplatVal);
SDValue Bitcasted = DAG->getNode(ISD::BITCAST, DL, VecF32, VecSplat);
EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_AllOnes()));
+
+ EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_Negative()));
+ EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonZero()));
+ EXPECT_TRUE(sd_match(Bitcasted, DAG.get(), m_NonPositive()));
+ EXPECT_FALSE(sd_match(Bitcasted, DAG.get(), m_StrictlyPositive()));
}
// splat vector with one undef → default should NOT match
diff --git a/llvm/unittests/CodeGen/SelectionDAGTestBase.h b/llvm/unittests/CodeGen/SelectionDAGTestBase.h
index 6b83c1e35c24c..bb9d672a2ff5b 100644
--- a/llvm/unittests/CodeGen/SelectionDAGTestBase.h
+++ b/llvm/unittests/CodeGen/SelectionDAGTestBase.h
@@ -34,7 +34,7 @@ class SelectionDAGTestBase : public testing::Test {
" ret i32 %1\n"
"}";
- Triple TargetTriple("aarch64--");
+ Triple TargetTriple("x86_64--");
std::string Error;
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
// FIXME: These tests do not depend on AArch64 specifically, but we have to
More information about the llvm-commits
mailing list