[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