[DAGCombiner] Add fold for `~x & x` -> `0`
authorNoah Goldstein <goldstein.w.n@gmail.com>
Thu, 2 Mar 2023 17:40:00 +0000 (11:40 -0600)
committerNoah Goldstein <goldstein.w.n@gmail.com>
Tue, 7 Mar 2023 02:30:20 +0000 (20:30 -0600)
This is generally done by the InstCombine, but can be emitted as an
intermediate step and is cheap to handle.

Differential Revision: https://reviews.llvm.org/D145143

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/test/CodeGen/X86/combine-and.ll
llvm/test/CodeGen/X86/fold-masked-merge.ll
llvm/test/CodeGen/X86/setcc-combine.ll

index 54c088b..bbec05c 100644 (file)
@@ -2582,6 +2582,12 @@ static bool isADDLike(SDValue V, const SelectionDAG &DAG) {
   return false;
 }
 
+static bool
+areBitwiseNotOfEachother(SDValue Op0, SDValue Op1) {
+  return (isBitwiseNot(Op0) && Op0.getOperand(0) == Op1) ||
+         (isBitwiseNot(Op1) && Op1.getOperand(0) == Op0);
+}
+
 /// Try to fold a node that behaves like an ADD (note that N isn't necessarily
 /// an ISD::ADD here, it could for example be an ISD::OR if we know that there
 /// are no common bits set in the operands).
@@ -6625,6 +6631,10 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
       !DAG.isConstantIntBuildVectorOrConstantInt(N1))
     return DAG.getNode(ISD::AND, SDLoc(N), VT, N1, N0);
 
+  if (areBitwiseNotOfEachother(N0, N1))
+    return DAG.getConstant(APInt::getZero(VT.getScalarSizeInBits()), SDLoc(N),
+                           VT);
+
   // fold vector ops
   if (VT.isVector()) {
     if (SDValue FoldedVOp = SimplifyVBinOp(N, SDLoc(N)))
index 6a7dd07..da52c62 100644 (file)
@@ -1180,12 +1180,12 @@ define <4 x i32> @neg_scalar_broadcast_two_uses(i32 %a0, <4 x i32> %a1, ptr %a2)
 define <2 x i64> @andnp_xx(<2 x i64> %v0) nounwind {
 ; SSE-LABEL: andnp_xx:
 ; SSE:       # %bb.0:
-; SSE-NEXT:    andnps %xmm0, %xmm0
+; SSE-NEXT:    xorps %xmm0, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX-LABEL: andnp_xx:
 ; AVX:       # %bb.0:
-; AVX-NEXT:    vandnps %xmm0, %xmm0, %xmm0
+; AVX-NEXT:    vxorps %xmm0, %xmm0, %xmm0
 ; AVX-NEXT:    retq
   %x = xor <2 x i64> %v0, <i64 -1, i64 -1>
   %y = and <2 x i64> %v0, %x
@@ -1195,12 +1195,12 @@ define <2 x i64> @andnp_xx(<2 x i64> %v0) nounwind {
 define <2 x i64> @andnp_xx_2(<2 x i64> %v0) nounwind {
 ; SSE-LABEL: andnp_xx_2:
 ; SSE:       # %bb.0:
-; SSE-NEXT:    andnps %xmm0, %xmm0
+; SSE-NEXT:    xorps %xmm0, %xmm0
 ; SSE-NEXT:    retq
 ;
 ; AVX-LABEL: andnp_xx_2:
 ; AVX:       # %bb.0:
-; AVX-NEXT:    vandnps %xmm0, %xmm0, %xmm0
+; AVX-NEXT:    vxorps %xmm0, %xmm0, %xmm0
 ; AVX-NEXT:    retq
   %x = xor <2 x i64> %v0, <i64 -1, i64 -1>
   %y = and <2 x i64> %x, %v0
@@ -1210,9 +1210,7 @@ define <2 x i64> @andnp_xx_2(<2 x i64> %v0) nounwind {
 define i64 @andn_xx(i64 %v0) nounwind {
 ; CHECK-LABEL: andn_xx:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq %rdi, %rax
-; CHECK-NEXT:    notq %rax
-; CHECK-NEXT:    andq %rdi, %rax
+; CHECK-NEXT:    xorl %eax, %eax
 ; CHECK-NEXT:    retq
   %x = xor i64 %v0, -1
   %y = and i64 %v0, %x
@@ -1222,9 +1220,7 @@ define i64 @andn_xx(i64 %v0) nounwind {
 define i64 @andn_xx_2(i64 %v0) nounwind {
 ; CHECK-LABEL: andn_xx_2:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq %rdi, %rax
-; CHECK-NEXT:    notq %rax
-; CHECK-NEXT:    andq %rdi, %rax
+; CHECK-NEXT:    xorl %eax, %eax
 ; CHECK-NEXT:    retq
   %x = xor i64 %v0, -1
   %y = and i64 %x, %v0
index d2c00df..135494a 100644 (file)
@@ -187,21 +187,11 @@ define i32 @not_a_masked_merge3(i32 %a0, i32 %a1, i32 %a2) {
 
 ; not a masked merge: `not` operand must not be on same `and`.
 define i32 @not_a_masked_merge4(i32 %a0, i32 %a1, i32 %a2) {
-; NOBMI-LABEL: not_a_masked_merge4:
-; NOBMI:       # %bb.0:
-; NOBMI-NEXT:    andl %esi, %edi
-; NOBMI-NEXT:    movl %edx, %eax
-; NOBMI-NEXT:    notl %eax
-; NOBMI-NEXT:    andl %edx, %eax
-; NOBMI-NEXT:    orl %edi, %eax
-; NOBMI-NEXT:    retq
-;
-; BMI-LABEL: not_a_masked_merge4:
-; BMI:       # %bb.0:
-; BMI-NEXT:    andl %esi, %edi
-; BMI-NEXT:    andnl %edx, %edx, %eax
-; BMI-NEXT:    orl %edi, %eax
-; BMI-NEXT:    retq
+; CHECK-LABEL: not_a_masked_merge4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    andl %esi, %eax
+; CHECK-NEXT:    retq
   %and0 = and i32 %a0, %a1
   %not = xor i32 %a2, -1
   %and1 = and i32 %not, %a2
index d225d42..c2ee789 100644 (file)
@@ -244,14 +244,9 @@ define void @test_i1_uge(ptr%A2) {
 ; CHECK-LABEL: test_i1_uge:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    movzbl (%rdi), %eax
-; CHECK-NEXT:    movl %eax, %ecx
-; CHECK-NEXT:    xorb $1, %cl
-; CHECK-NEXT:    andb %cl, %al
-; CHECK-NEXT:    movzbl %al, %eax
-; CHECK-NEXT:    andl $1, %eax
-; CHECK-NEXT:    negq %rax
-; CHECK-NEXT:    andb $1, %cl
-; CHECK-NEXT:    movb %cl, (%rdi,%rax)
+; CHECK-NEXT:    notb %al
+; CHECK-NEXT:    andb $1, %al
+; CHECK-NEXT:    movb %al, (%rdi)
 ; CHECK-NEXT:    retq
   %L5 = load i1, ptr %A2
   %C3 = icmp ne i1 %L5, true