[llvm] [GlobalISel] Implement parity reasoning via G_CTPOP (PR #199078)

Tejas Gaikwad via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 21 01:13:43 PDT 2026


https://github.com/tejasgaikwad04 updated https://github.com/llvm/llvm-project/pull/199078

>From 26b593402d835b8640dc945d494e6bc12b5a12fc Mon Sep 17 00:00:00 2001
From: Tejas Gaikwad <tgaikwad966 at gmail.com>
Date: Thu, 21 May 2026 17:32:54 +0000
Subject: [PATCH 1/5] [GlobalISel][KnownBits] Use KnownBits::parity

---
 .../CodeGen/GlobalISel/GISelValueTracking.cpp | 42 ++++++++-
 .../GlobalISel/knownbits-ctpop-parity.mir     | 93 +++++++++++++++++++
 2 files changed, 134 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 5fcc84d0d76a1..b896678b5aedb 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -2150,18 +2150,58 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     const MachineMemOperand *MMO = *MI.memoperands_begin();
     return TyBits - MMO->getSizeInBits().getValue();
   }
-  case TargetOpcode::G_AND:
+  case TargetOpcode::G_AND: {
+    Register Op0 = MI.getOperand(1).getReg();
+    Register Op1 = MI.getOperand(2).getReg();
+
+    auto IsConstOne = [&](Register R) {
+      MachineInstr *Def = MRI.getVRegDef(R);
+      if (!Def || Def->getOpcode() != TargetOpcode::G_CONSTANT)
+        return false;
+
+      auto *C = Def->getOperand(1).getCImm();
+      return C && C->getValue().isOne();
+    };
+
+    auto IsCTPOP = [&](Register R) {
+      MachineInstr *Def = MRI.getVRegDef(R);
+      return Def && Def->getOpcode() == TargetOpcode::G_CTPOP;
+    };
+
+    if ((IsCTPOP(Op0) && IsConstOne(Op1)) ||
+        (IsCTPOP(Op1) && IsConstOne(Op0))) {
+      FirstAnswer = MRI.getType(R).getScalarSizeInBits();
+      break;
+    }
+
+    Register Src1 = MI.getOperand(1).getReg();
+    unsigned Src1NumSignBits =
+        computeNumSignBits(Src1, DemandedElts, Depth + 1);
+
+    if (Src1NumSignBits != 1) {
+      Register Src2 = MI.getOperand(2).getReg();
+      unsigned Src2NumSignBits =
+          computeNumSignBits(Src2, DemandedElts, Depth + 1);
+
+      FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits);
+    }
+
+    break;
+  }
   case TargetOpcode::G_OR:
   case TargetOpcode::G_XOR: {
     Register Src1 = MI.getOperand(1).getReg();
     unsigned Src1NumSignBits =
         computeNumSignBits(Src1, DemandedElts, Depth + 1);
+
     if (Src1NumSignBits != 1) {
       Register Src2 = MI.getOperand(2).getReg();
       unsigned Src2NumSignBits =
           computeNumSignBits(Src2, DemandedElts, Depth + 1);
+
       FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits);
     }
+
     break;
   }
   case TargetOpcode::G_ASHR: {
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
new file mode 100644
index 0000000000000..31ff3dcd2fa3d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
@@ -0,0 +1,93 @@
+# RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s
+
+--- |
+  declare i32 @llvm.ctpop.i32(i32)
+  declare i64 @llvm.ctpop.i64(i64)
+
+  define i32 @parity(i32 %x) {
+  entry:
+    %0 = call i32 @llvm.ctpop.i32(i32 %x)
+    %1 = and i32 %0, 1
+    ret i32 %1
+  }
+
+  define i1 @parity_bool(i32 %x) {
+  entry:
+    %0 = call i32 @llvm.ctpop.i32(i32 %x)
+    %1 = and i32 %0, 1
+    %2 = icmp ne i32 %1, 0
+    ret i1 %2
+  }
+
+  define i32 @parity_const() {
+  entry:
+    %0 = call i32 @llvm.ctpop.i32(i32 5)
+    %1 = and i32 %0, 1
+    ret i32 %1
+  }
+
+...
+
+# CHECK-LABEL: name: @parity
+# CHECK-NEXT: %0:_ KnownBits:???????????????????????????????? SignBits:1
+# CHECK-NEXT: %1:_ KnownBits:00000000000000000000000000?????? SignBits:26
+# CHECK-NEXT: %2:_ KnownBits:00000000000000000000000000000001 SignBits:31
+# CHECK-NEXT: %3:_ KnownBits:0000000000000000000000000000000? SignBits:32
+
+---
+name:            parity
+body:             |
+  bb.1.entry:
+    liveins: $w0
+
+    %0:_(i32) = COPY $w0
+    %1:_(i32) = G_CTPOP %0(i32)
+    %2:_(i32) = G_CONSTANT i32 1
+    %3:_(i32) = G_AND %1, %2
+
+    $w0 = COPY %3(i32)
+    RET_ReallyLR implicit $w0
+...
+
+# CHECK-LABEL: name: @parity_bool
+# CHECK-NEXT: %0:_ KnownBits:???????????????????????????????? SignBits:1
+# CHECK-NEXT: %1:_ KnownBits:00000000000000000000000000?????? SignBits:26
+# CHECK-NEXT: %2:_ KnownBits:00000000000000000000000000000001 SignBits:31
+# CHECK-NEXT: %3:_ KnownBits:0000000000000000000000000000000? SignBits:32
+# CHECK-NEXT: %4:_ KnownBits:00000000000000000000000000000000 SignBits:32
+# CHECK-NEXT: %5:_ KnownBits:? SignBits:1
+# CHECK-NEXT: %6:_ KnownBits:0000000? SignBits:7
+# CHECK-NEXT: %7:_ KnownBits:????????????????????????0000000? SignBits:1
+
+---
+name:            parity_bool
+body:             |
+  bb.1.entry:
+    liveins: $w0
+
+    %0:_(i32) = COPY $w0
+    %1:_(i32) = G_CTPOP %0(i32)
+    %2:_(i32) = G_CONSTANT i32 1
+    %3:_(i32) = G_AND %1, %2
+    %4:_(i32) = G_CONSTANT i32 0
+    %5:_(i1) = G_ICMP intpred(ne), %3(i32), %4
+    %6:_(i8) = G_ZEXT %5(i1)
+    %7:_(i32) = G_ANYEXT %6(i8)
+
+    $w0 = COPY %7(i32)
+    RET_ReallyLR implicit $w0
+...
+
+# CHECK-LABEL: name: @parity_const
+# CHECK-NEXT: %0:_ KnownBits:00000000000000000000000000000000 SignBits:32
+
+---
+name:            parity_const
+body:             |
+  bb.1.entry:
+
+    %0:_(i32) = G_CONSTANT i32 0
+
+    $w0 = COPY %0(i32)
+    RET_ReallyLR implicit $w0
+...
\ No newline at end of file

>From 0e219740a5bbf466b130c094401e00d9edb969a4 Mon Sep 17 00:00:00 2001
From: Tejas Gaikwad <tgaikwad966 at gmail.com>
Date: Fri, 29 May 2026 17:45:11 +0000
Subject: [PATCH 2/5] Addressing comments

---
 llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index b896678b5aedb..78af888067e89 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -2173,15 +2173,12 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
       FirstAnswer = MRI.getType(R).getScalarSizeInBits();
       break;
     }
-
-    Register Src1 = MI.getOperand(1).getReg();
     unsigned Src1NumSignBits =
-        computeNumSignBits(Src1, DemandedElts, Depth + 1);
+        computeNumSignBits(Op0, DemandedElts, Depth + 1);
 
     if (Src1NumSignBits != 1) {
-      Register Src2 = MI.getOperand(2).getReg();
       unsigned Src2NumSignBits =
-          computeNumSignBits(Src2, DemandedElts, Depth + 1);
+          computeNumSignBits(Op1, DemandedElts, Depth + 1);
 
       FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits);
     }

>From bea39ea179f6c611086e2585c600db3c8e70f53e Mon Sep 17 00:00:00 2001
From: Tejas Gaikwad <tgaikwad966 at gmail.com>
Date: Sun, 31 May 2026 10:27:15 +0000
Subject: [PATCH 3/5] addressing comments

---
 llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp             | 3 +--
 .../test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 78af888067e89..bc6f68118ba3a 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -2173,8 +2173,7 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
       FirstAnswer = MRI.getType(R).getScalarSizeInBits();
       break;
     }
-    unsigned Src1NumSignBits =
-        computeNumSignBits(Op0, DemandedElts, Depth + 1);
+    unsigned Src1NumSignBits = computeNumSignBits(Op0, DemandedElts, Depth + 1);
 
     if (Src1NumSignBits != 1) {
       unsigned Src2NumSignBits =
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
index 31ff3dcd2fa3d..1030b106a0b55 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
@@ -90,4 +90,4 @@ body:             |
 
     $w0 = COPY %0(i32)
     RET_ReallyLR implicit $w0
-...
\ No newline at end of file
+...

>From 8872abb1b46293bb57b4ab0a6af004b397136257 Mon Sep 17 00:00:00 2001
From: Tejas Gaikwad <tgaikwad966 at gmail.com>
Date: Thu, 4 Jun 2026 17:22:47 +0000
Subject: [PATCH 4/5] updating the code using mi_match

---
 llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index bc6f68118ba3a..11e7d36148ba3 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -2155,17 +2155,11 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     Register Op1 = MI.getOperand(2).getReg();
 
     auto IsConstOne = [&](Register R) {
-      MachineInstr *Def = MRI.getVRegDef(R);
-      if (!Def || Def->getOpcode() != TargetOpcode::G_CONSTANT)
-        return false;
-
-      auto *C = Def->getOperand(1).getCImm();
-      return C && C->getValue().isOne();
+      return mi_match(R, MRI, m_SpecificICst(1));
     };
 
     auto IsCTPOP = [&](Register R) {
-      MachineInstr *Def = MRI.getVRegDef(R);
-      return Def && Def->getOpcode() == TargetOpcode::G_CTPOP;
+      return MRI.getVRegDef(R)->getOpcode() == TargetOpcode::G_CTPOP;
     };
 
     if ((IsCTPOP(Op0) && IsConstOne(Op1)) ||

>From e680f17eca1f411edbca790e6a1566094c8693c1 Mon Sep 17 00:00:00 2001
From: Tejas Gaikwad <tgaikwad966 at gmail.com>
Date: Sun, 21 Jun 2026 08:13:24 +0000
Subject: [PATCH 5/5] Resolving suggestions

---
 .../CodeGen/GlobalISel/GISelValueTracking.cpp | 14 +++-------
 .../GlobalISel/knownbits-ctpop-parity.mir     | 28 -------------------
 2 files changed, 4 insertions(+), 38 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 11e7d36148ba3..e7db26b4bc4b4 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -2154,16 +2154,10 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
     Register Op0 = MI.getOperand(1).getReg();
     Register Op1 = MI.getOperand(2).getReg();
 
-    auto IsConstOne = [&](Register R) {
-      return mi_match(R, MRI, m_SpecificICst(1));
-    };
-
-    auto IsCTPOP = [&](Register R) {
-      return MRI.getVRegDef(R)->getOpcode() == TargetOpcode::G_CTPOP;
-    };
-
-    if ((IsCTPOP(Op0) && IsConstOne(Op1)) ||
-        (IsCTPOP(Op1) && IsConstOne(Op0))) {
+    if ((MRI.getVRegDef(Op0)->getOpcode() == TargetOpcode::G_CTPOP &&
+         mi_match(Op1, MRI, m_SpecificICst(1))) ||
+        (MRI.getVRegDef(Op1)->getOpcode() == TargetOpcode::G_CTPOP &&
+         mi_match(Op0, MRI, m_SpecificICst(1)))) {
       FirstAnswer = MRI.getType(R).getScalarSizeInBits();
       break;
     }
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
index 1030b106a0b55..6b5c4663275be 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/knownbits-ctpop-parity.mir
@@ -1,33 +1,5 @@
 # RUN: llc -mtriple=aarch64 -passes="print<gisel-value-tracking>" %s -filetype=null 2>&1 | FileCheck %s
 
---- |
-  declare i32 @llvm.ctpop.i32(i32)
-  declare i64 @llvm.ctpop.i64(i64)
-
-  define i32 @parity(i32 %x) {
-  entry:
-    %0 = call i32 @llvm.ctpop.i32(i32 %x)
-    %1 = and i32 %0, 1
-    ret i32 %1
-  }
-
-  define i1 @parity_bool(i32 %x) {
-  entry:
-    %0 = call i32 @llvm.ctpop.i32(i32 %x)
-    %1 = and i32 %0, 1
-    %2 = icmp ne i32 %1, 0
-    ret i1 %2
-  }
-
-  define i32 @parity_const() {
-  entry:
-    %0 = call i32 @llvm.ctpop.i32(i32 5)
-    %1 = and i32 %0, 1
-    ret i32 %1
-  }
-
-...
-
 # CHECK-LABEL: name: @parity
 # CHECK-NEXT: %0:_ KnownBits:???????????????????????????????? SignBits:1
 # CHECK-NEXT: %1:_ KnownBits:00000000000000000000000000?????? SignBits:26



More information about the llvm-commits mailing list