[llvm] 9858b9b - [DAG] Fold pow2 masked bittest comparisons (#216302)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 19 06:17:15 PDT 2026
Author: Dhruva
Date: 2026-08-19T13:17:10Z
New Revision: 9858b9bee7f2173ff9d32face0d17a620d2eae90
URL: https://github.com/llvm/llvm-project/commit/9858b9bee7f2173ff9d32face0d17a620d2eae90
DIFF: https://github.com/llvm/llvm-project/commit/9858b9bee7f2173ff9d32face0d17a620d2eae90.diff
LOG: [DAG] Fold pow2 masked bittest comparisons (#216302)
Implements logic to merge bittest comparisons in `foldLogicOfSetCCs` .
Equivalent to the fold done in `foldLogOpOfMaskedICmps`.
Fold is valid when `LL1` and `RL1` are powers of 2.
```cpp
(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))
```
Fixes #214772 .
Added:
Modified:
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/test/CodeGen/X86/setcc-logic.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 053e993a49e66..8c3e487b44e9e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6814,6 +6814,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 (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);
+ }
+ }
+
// (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 c577849b45ee8..1390c666bb4ec 100644
--- a/llvm/test/CodeGen/X86/setcc-logic.ll
+++ b/llvm/test/CodeGen/X86/setcc-logic.ll
@@ -740,3 +740,136 @@ 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: notb %dil
+; CHECK-NEXT: testb $12, %dil
+; CHECK-NEXT: sete %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 @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:
+; 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
+ %c1 = icmp eq i32 %a1, 0
+ %c2 = icmp eq i32 %a2, 0
+ %res = or i1 %c1, %c2
+ 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:
+; 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
+}
More information about the llvm-commits
mailing list