[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