[llvm] 1cb7416 - [DAG] combineShiftAnd1ToBitTest - match "and (srl (not X), C)), 1 --> (and X, 1<<C) == 0" patterns
Simon Pilgrim via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 16 03:13:45 PDT 2022
Author: Simon Pilgrim
Date: 2022-07-16T11:00:07+01:00
New Revision: 1cb7416ee3763db5731492fd91013fde331d243e
URL: https://github.com/llvm/llvm-project/commit/1cb7416ee3763db5731492fd91013fde331d243e
DIFF: https://github.com/llvm/llvm-project/commit/1cb7416ee3763db5731492fd91013fde331d243e.diff
LOG: [DAG] combineShiftAnd1ToBitTest - match "and (srl (not X), C)), 1 --> (and X, 1<<C) == 0" patterns
combineShiftAnd1ToBitTest already matches "and (not (srl X, C)), 1 --> (and X, 1<<C) == 0" patterns, but we can end up with situations where the not is before the shift.
Part of some yak shaving for D127115 to generalise the "xor (X >> ShiftC), XorC --> (not X) >> ShiftC" fold.
Added:
Modified:
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/test/CodeGen/X86/test-vs-bittest.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index cbabdc99cf0a..73d0f91fba84 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -5978,44 +5978,64 @@ static SDValue combineShiftAnd1ToBitTest(SDNode *And, SelectionDAG &DAG) {
if (!TLI.isTypeLegal(VT))
return SDValue();
- // Look through an optional extension and find a 'not'.
- // TODO: Should we favor test+set even without the 'not' op?
- SDValue Not = And->getOperand(0), And1 = And->getOperand(1);
- if (Not.getOpcode() == ISD::ANY_EXTEND)
- Not = Not.getOperand(0);
- if (!isBitwiseNot(Not) || !Not.hasOneUse() || !isOneConstant(And1))
+ // Look through an optional extension.
+ SDValue And0 = And->getOperand(0), And1 = And->getOperand(1);
+ if (And0.getOpcode() == ISD::ANY_EXTEND && And0.hasOneUse())
+ And0 = And0.getOperand(0);
+ if (!isOneConstant(And1) || !And0.hasOneUse())
return SDValue();
- // Look though an optional truncation. The source operand may not be the same
- // type as the original 'and', but that is ok because we are masking off
- // everything but the low bit.
- SDValue Srl = Not.getOperand(0);
- if (Srl.getOpcode() == ISD::TRUNCATE)
- Srl = Srl.getOperand(0);
+ SDValue Src = And0;
+
+ // Attempt to find a 'not' op.
+ // TODO: Should we favor test+set even without the 'not' op?
+ bool FoundNot = false;
+ if (isBitwiseNot(Src)) {
+ FoundNot = true;
+ Src = Src.getOperand(0);
+
+ // Look though an optional truncation. The source operand may not be the
+ // same type as the original 'and', but that is ok because we are masking
+ // off everything but the low bit.
+ if (Src.getOpcode() == ISD::TRUNCATE && Src.hasOneUse())
+ Src = Src.getOperand(0);
+ }
// Match a shift-right by constant.
- if (Srl.getOpcode() != ISD::SRL || !Srl.hasOneUse() ||
- !isa<ConstantSDNode>(Srl.getOperand(1)))
+ if (Src.getOpcode() != ISD::SRL || !Src.hasOneUse())
return SDValue();
// We might have looked through casts that make this transform invalid.
// TODO: If the source type is wider than the result type, do the mask and
// compare in the source type.
- const APInt &ShiftAmt = Srl.getConstantOperandAPInt(1);
- unsigned VTBitWidth = VT.getSizeInBits();
- if (ShiftAmt.uge(VTBitWidth))
+ unsigned VTBitWidth = VT.getScalarSizeInBits();
+ SDValue ShiftAmt = Src.getOperand(1);
+ auto *ShiftAmtC = dyn_cast<ConstantSDNode>(ShiftAmt);
+ if (!ShiftAmtC || !ShiftAmtC->getAPIntValue().ult(VTBitWidth))
return SDValue();
- if (!TLI.hasBitTest(Srl.getOperand(0), Srl.getOperand(1)))
+ // Set source to shift source.
+ Src = Src.getOperand(0);
+
+ // Try again to find a 'not' op.
+ // TODO: Should we favor test+set even with two 'not' ops?
+ if (!FoundNot) {
+ if (!isBitwiseNot(Src))
+ return SDValue();
+ Src = Src.getOperand(0);
+ }
+
+ if (!TLI.hasBitTest(Src, ShiftAmt))
return SDValue();
// Turn this into a bit-test pattern using mask op + setcc:
// and (not (srl X, C)), 1 --> (and X, 1<<C) == 0
+ // and (srl (not X), C)), 1 --> (and X, 1<<C) == 0
SDLoc DL(And);
- SDValue X = DAG.getZExtOrTrunc(Srl.getOperand(0), DL, VT);
+ SDValue X = DAG.getZExtOrTrunc(Src, DL, VT);
EVT CCVT = TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
SDValue Mask = DAG.getConstant(
- APInt::getOneBitSet(VTBitWidth, ShiftAmt.getZExtValue()), DL, VT);
+ APInt::getOneBitSet(VTBitWidth, ShiftAmtC->getZExtValue()), DL, VT);
SDValue NewAnd = DAG.getNode(ISD::AND, DL, VT, X, Mask);
SDValue Zero = DAG.getConstant(0, DL, VT);
SDValue Setcc = DAG.getSetCC(DL, CCVT, NewAnd, Zero, ISD::SETEQ);
diff --git a/llvm/test/CodeGen/X86/test-vs-bittest.ll b/llvm/test/CodeGen/X86/test-vs-bittest.ll
index 76cf265db8f1..77ec67ea1b9a 100644
--- a/llvm/test/CodeGen/X86/test-vs-bittest.ll
+++ b/llvm/test/CodeGen/X86/test-vs-bittest.ll
@@ -574,10 +574,9 @@ define i64 @is_upper_bit_clear_i64(i64 %x) {
define i64 @is_upper_bit_clear_i64_not(i64 %x) {
; CHECK-LABEL: is_upper_bit_clear_i64_not:
; CHECK: # %bb.0:
-; CHECK-NEXT: movq %rdi, %rax
-; CHECK-NEXT: notq %rax
-; CHECK-NEXT: shrq $39, %rax
-; CHECK-NEXT: andl $1, %eax
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: btq $39, %rdi
+; CHECK-NEXT: setae %al
; CHECK-NEXT: retq
%n = xor i64 %x, -1
%sh = lshr i64 %n, 39
@@ -601,10 +600,9 @@ define i64 @is_lower_bit_clear_i64(i64 %x) {
define i64 @is_lower_bit_clear_i64_not(i64 %x) {
; CHECK-LABEL: is_lower_bit_clear_i64_not:
; CHECK: # %bb.0:
-; CHECK-NEXT: movq %rdi, %rax
-; CHECK-NEXT: notl %eax
-; CHECK-NEXT: shrl $16, %eax
-; CHECK-NEXT: andl $1, %eax
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: testl $65536, %edi # imm = 0x10000
+; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
%n = xor i64 %x, -1
%sh = lshr i64 %n, 16
@@ -628,10 +626,9 @@ define i32 @is_bit_clear_i32(i32 %x) {
define i32 @is_bit_clear_i32_not(i32 %x) {
; CHECK-LABEL: is_bit_clear_i32_not:
; CHECK: # %bb.0:
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: notl %eax
-; CHECK-NEXT: shrl $27, %eax
-; CHECK-NEXT: andl $1, %eax
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: testl $134217728, %edi # imm = 0x8000000
+; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
%n = xor i32 %x, -1
%sh = lshr i32 %n, 27
@@ -656,10 +653,9 @@ define i16 @is_bit_clear_i16(i16 %x) {
define i16 @is_bit_clear_i16_not(i16 %x) {
; CHECK-LABEL: is_bit_clear_i16_not:
; CHECK: # %bb.0:
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: notl %eax
-; CHECK-NEXT: shrl $2, %eax
-; CHECK-NEXT: andl $1, %eax
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: testb $4, %dil
+; CHECK-NEXT: sete %al
; CHECK-NEXT: # kill: def $ax killed $ax killed $eax
; CHECK-NEXT: retq
%n = xor i16 %x, -1
@@ -683,11 +679,8 @@ define i8 @is_bit_clear_i8(i8 %x) {
define i8 @is_bit_clear_i8_not(i8 %x) {
; CHECK-LABEL: is_bit_clear_i8_not:
; CHECK: # %bb.0:
-; CHECK-NEXT: movl %edi, %eax
-; CHECK-NEXT: notb %al
-; CHECK-NEXT: shrb $2, %al
-; CHECK-NEXT: andb $1, %al
-; CHECK-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-NEXT: testb $4, %dil
+; CHECK-NEXT: sete %al
; CHECK-NEXT: retq
%n = xor i8 %x, -1
%sh = lshr i8 %n, 2
More information about the llvm-commits
mailing list