[llvm] [DAG] Fold pow2 masked bittest comparisons (PR #216302)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 18 10:58:00 PDT 2026
https://github.com/Xylecrack updated https://github.com/llvm/llvm-project/pull/216302
>From d77f4faef9aa9760444dcbb2659d6a68ebc6708b Mon Sep 17 00:00:00 2001
From: Dhruva Narayan K <dhruvakodiadka at gmail.com>
Date: Fri, 14 Aug 2026 15:14:40 +0500
Subject: [PATCH 1/3] Add tests
---
llvm/test/CodeGen/X86/setcc-logic.ll | 109 +++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/llvm/test/CodeGen/X86/setcc-logic.ll b/llvm/test/CodeGen/X86/setcc-logic.ll
index c577849b45ee8..c394f54b12d39 100644
--- a/llvm/test/CodeGen/X86/setcc-logic.ll
+++ b/llvm/test/CodeGen/X86/setcc-logic.ll
@@ -740,3 +740,112 @@ define <16 x i8> @or_cmp_ne_v4i32(<16 x i8> %x, <16 x i8> %y) {
%s = sext <16 x i1> %c to <16 x i8>
ret <16 x i8> %s
}
+
+;PR214772 - Merge bittest comparisions.
+
+define i1 @and_cmp_ne(i8 %x) {
+; CHECK-LABEL: and_cmp_ne:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: andb $8, %al
+; CHECK-NEXT: shrb $2, %dil
+; CHECK-NEXT: shrb $3, %al
+; CHECK-NEXT: andb %dil, %al
+; CHECK-NEXT: retq
+ %a1 = and i8 %x, 4
+ %a2 = and i8 %x, 8
+ %c1 = icmp ne i8 %a1, 0
+ %c2 = icmp ne i8 %a2, 0
+ %res = and i1 %c1, %c2
+ ret i1 %res
+}
+
+define i1 @or_cmp_eq(i32 %x) {
+; CHECK-LABEL: or_cmp_eq:
+; CHECK: # %bb.0:
+; CHECK-NEXT: testb $8, %dil
+; CHECK-NEXT: sete %cl
+; CHECK-NEXT: testb $32, %dil
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: orb %cl, %al
+; CHECK-NEXT: retq
+ %a1 = and i32 %x, 8
+ %a2 = and i32 %x, 32
+ %c1 = icmp eq i32 %a1, 0
+ %c2 = icmp eq i32 %a2, 0
+ %res = or i1 %c1, %c2
+ ret i1 %res
+}
+
+define i1 @not_pow2(i8 %x) {
+; CHECK-LABEL: not_pow2:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: andb $8, %al
+; CHECK-NEXT: testb $3, %dil
+; CHECK-NEXT: setne %cl
+; CHECK-NEXT: shrb $3, %al
+; CHECK-NEXT: andb %cl, %al
+; CHECK-NEXT: retq
+ %a1 = and i8 %x, 3
+ %a2 = and i8 %x, 8
+ %c1 = icmp ne i8 %a1, 0
+ %c2 = icmp ne i8 %a2, 0
+ %res = and i1 %c1, %c2
+ ret i1 %res
+}
+
+define i1 @diff_vars(i8 %x, i8 %y) {
+; CHECK-LABEL: diff_vars:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %eax
+; CHECK-NEXT: andb $8, %al
+; CHECK-NEXT: shrb $2, %dil
+; CHECK-NEXT: shrb $3, %al
+; CHECK-NEXT: andb %dil, %al
+; CHECK-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-NEXT: retq
+ %a1 = and i8 %x, 4
+ %a2 = and i8 %y, 8
+ %c1 = icmp ne i8 %a1, 0
+ %c2 = icmp ne i8 %a2, 0
+ %res = and i1 %c1, %c2
+ ret i1 %res
+}
+
+define i1 @nonzero_rhs(i8 %x) {
+; CHECK-LABEL: nonzero_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: andb $4, %al
+; CHECK-NEXT: andb $8, %dil
+; CHECK-NEXT: cmpb $1, %al
+; CHECK-NEXT: setne %al
+; CHECK-NEXT: shrb $3, %dil
+; CHECK-NEXT: andb %dil, %al
+; CHECK-NEXT: retq
+ %a1 = and i8 %x, 4
+ %a2 = and i8 %x, 8
+ %c1 = icmp ne i8 %a1, 1
+ %c2 = icmp ne i8 %a2, 0
+ %res = and i1 %c1, %c2
+ ret i1 %res
+}
+
+define i1 @mixed_cc(i8 %x) {
+; CHECK-LABEL: mixed_cc:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: andb $8, %al
+; CHECK-NEXT: testb $4, %dil
+; CHECK-NEXT: sete %cl
+; CHECK-NEXT: shrb $3, %al
+; CHECK-NEXT: andb %cl, %al
+; CHECK-NEXT: retq
+ %a1 = and i8 %x, 4
+ %a2 = and i8 %x, 8
+ %c1 = icmp eq i8 %a1, 0
+ %c2 = icmp ne i8 %a2, 0
+ %res = and i1 %c1, %c2
+ ret i1 %res
+}
>From 0e3672fa37afe1191cc57f3fc4b497adbef5e3cb Mon Sep 17 00:00:00 2001
From: Dhruva Narayan K <dhruvakodiadka at gmail.com>
Date: Fri, 14 Aug 2026 15:16:11 +0500
Subject: [PATCH 2/3] Add bittest fold and update test
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 20 +++++++++++++++++++
llvm/test/CodeGen/X86/setcc-logic.ll | 16 ++++++---------
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 595cc5d653de6..5beb4cd64c4ec 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6778,6 +6778,26 @@ SDValue DAGCombiner::foldLogicOfSetCCs(bool IsAnd, SDValue N0, SDValue N1,
}
}
+ // (and (setne (and X, LL1), 0), (setne (and X, RL1), 0))
+ // --> (seteq (and X, (LL1|RL1)), (LL1|RL1))
+ // (or (seteq (and X, LL1), 0), (seteq (and X, RL1), 0))
+ // --> (setne (and X, (LL1|RL1)), (LL1|RL1))
+ if (LL.getOpcode() == ISD::AND && RL.getOpcode() == ISD::AND &&
+ isNullConstant(LR) && isNullConstant(RR) && CC0 == CC1 &&
+ (CC0 == ISD::SETNE || CC0 == ISD::SETEQ)) {
+ SDValue LL0, LL1, RL0, RL1;
+ LL0 = LL.getOperand(0);
+ RL0 = RL.getOperand(0);
+ LL1 = LL.getOperand(1);
+ RL1 = RL.getOperand(1);
+ if (DAG.isKnownToBeAPowerOfTwo(LL1) && DAG.isKnownToBeAPowerOfTwo(RL1) &&
+ LL0 == RL0) {
+ SDValue Or = DAG.getNode(ISD::OR, SDLoc(N0), OpVT, LL1, RL1);
+ SDValue And = DAG.getNode(ISD::AND, SDLoc(N0), OpVT, LL0, Or);
+ return DAG.getSetCC(DL, VT, And, Or, IsAnd ? ISD::SETEQ : ISD::SETNE);
+ }
+ }
+
// (and (setne X, 0), (setne X, -1)) --> (setuge (add X, 1), 2)
// (or (seteq X, 0), (seteq X, -1)) --> (setult (add X, 1), 2)
if (LL == RL && CC0 == CC1 && OpVT.getScalarSizeInBits() > 1 && IsInteger &&
diff --git a/llvm/test/CodeGen/X86/setcc-logic.ll b/llvm/test/CodeGen/X86/setcc-logic.ll
index c394f54b12d39..e74347151984a 100644
--- a/llvm/test/CodeGen/X86/setcc-logic.ll
+++ b/llvm/test/CodeGen/X86/setcc-logic.ll
@@ -746,11 +746,9 @@ define <16 x i8> @or_cmp_ne_v4i32(<16 x i8> %x, <16 x i8> %y) {
define i1 @and_cmp_ne(i8 %x) {
; CHECK-LABEL: and_cmp_ne:
; CHECK: # %bb.0:
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: andb $8, %al
-; CHECK-NEXT: shrb $2, %dil
-; CHECK-NEXT: shrb $3, %al
-; CHECK-NEXT: andb %dil, %al
+; CHECK-NEXT: notb %dil
+; CHECK-NEXT: testb $12, %dil
+; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
%a1 = and i8 %x, 4
%a2 = and i8 %x, 8
@@ -763,11 +761,9 @@ define i1 @and_cmp_ne(i8 %x) {
define i1 @or_cmp_eq(i32 %x) {
; CHECK-LABEL: or_cmp_eq:
; CHECK: # %bb.0:
-; CHECK-NEXT: testb $8, %dil
-; CHECK-NEXT: sete %cl
-; CHECK-NEXT: testb $32, %dil
-; CHECK-NEXT: sete %al
-; CHECK-NEXT: orb %cl, %al
+; CHECK-NEXT: notl %edi
+; CHECK-NEXT: testb $40, %dil
+; CHECK-NEXT: setne %al
; CHECK-NEXT: retq
%a1 = and i32 %x, 8
%a2 = and i32 %x, 32
>From dfed9cf774bd5964db0125f0bd4de4ac9dcc2838 Mon Sep 17 00:00:00 2001
From: Dhruva Narayan K <dhruvakodiadka at gmail.com>
Date: Tue, 18 Aug 2026 22:56:54 +0500
Subject: [PATCH 3/3] Move LL0/RL0 check + add new tests
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 4 +--
llvm/test/CodeGen/X86/setcc-logic.ll | 28 +++++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 5beb4cd64c4ec..f2b92aac14c70 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6790,8 +6790,8 @@ SDValue DAGCombiner::foldLogicOfSetCCs(bool IsAnd, SDValue N0, SDValue N1,
RL0 = RL.getOperand(0);
LL1 = LL.getOperand(1);
RL1 = RL.getOperand(1);
- if (DAG.isKnownToBeAPowerOfTwo(LL1) && DAG.isKnownToBeAPowerOfTwo(RL1) &&
- LL0 == RL0) {
+ if (LL0 == RL0 && DAG.isKnownToBeAPowerOfTwo(LL1) &&
+ DAG.isKnownToBeAPowerOfTwo(RL1)) {
SDValue Or = DAG.getNode(ISD::OR, SDLoc(N0), OpVT, LL1, RL1);
SDValue And = DAG.getNode(ISD::AND, SDLoc(N0), OpVT, LL0, Or);
return DAG.getSetCC(DL, VT, And, Or, IsAnd ? ISD::SETEQ : ISD::SETNE);
diff --git a/llvm/test/CodeGen/X86/setcc-logic.ll b/llvm/test/CodeGen/X86/setcc-logic.ll
index e74347151984a..1390c666bb4ec 100644
--- a/llvm/test/CodeGen/X86/setcc-logic.ll
+++ b/llvm/test/CodeGen/X86/setcc-logic.ll
@@ -758,6 +758,20 @@ define i1 @and_cmp_ne(i8 %x) {
ret i1 %res
}
+define i1 @and_cmp_eq(i8 %x) {
+; CHECK-LABEL: and_cmp_eq:
+; CHECK: # %bb.0:
+; CHECK-NEXT: testb $12, %dil
+; CHECK-NEXT: sete %al
+; CHECK-NEXT: retq
+ %a1 = and i8 %x, 4
+ %a2 = and i8 %x, 8
+ %c1 = icmp eq i8 %a1, 0
+ %c2 = icmp eq i8 %a2, 0
+ %res = and i1 %c1, %c2
+ ret i1 %res
+}
+
define i1 @or_cmp_eq(i32 %x) {
; CHECK-LABEL: or_cmp_eq:
; CHECK: # %bb.0:
@@ -773,6 +787,20 @@ define i1 @or_cmp_eq(i32 %x) {
ret i1 %res
}
+define i1 @or_cmp_ne(i32 %x) {
+; CHECK-LABEL: or_cmp_ne:
+; CHECK: # %bb.0:
+; CHECK-NEXT: testb $40, %dil
+; CHECK-NEXT: setne %al
+; CHECK-NEXT: retq
+ %a1 = and i32 %x, 8
+ %a2 = and i32 %x, 32
+ %c1 = icmp ne i32 %a1, 0
+ %c2 = icmp ne i32 %a2, 0
+ %res = or i1 %c1, %c2
+ ret i1 %res
+}
+
define i1 @not_pow2(i8 %x) {
; CHECK-LABEL: not_pow2:
; CHECK: # %bb.0:
More information about the llvm-commits
mailing list