[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