[llvm] r341426 - [InstCombine] fix xor-or-xor fold to check uses and handle commutes

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 4 16:22:13 PDT 2018


Author: spatel
Date: Tue Sep  4 16:22:13 2018
New Revision: 341426

URL: http://llvm.org/viewvc/llvm-project?rev=341426&view=rev
Log:
[InstCombine] fix xor-or-xor fold to check uses and handle commutes

I'm probably missing some way to use m_Deferred to remove the code
duplication, but that can be a follow-up.

The improvement in demand_shrink_nsw.ll is an example of missing
the fold because the pattern matching was deficient. I didn't try
to follow the bits in that test, but Alive says it's correct:
https://rise4fun.com/Alive/ugc

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll
    llvm/trunk/test/Transforms/InstCombine/xor2.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp?rev=341426&r1=341425&r2=341426&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Tue Sep  4 16:22:13 2018
@@ -2791,41 +2791,30 @@ Instruction *InstCombiner::visitXor(Bina
       match(Op0, m_OneUse(m_c_And(m_Value(X), m_Specific(Op1)))))
     return BinaryOperator::CreateAnd(Op1, Builder.CreateNot(X));
 
-  {
-    Value *A, *B, *C, *D;
-    // (A ^ C)^(A | B) -> ((~A) & B) ^ C
-    if (match(Op0, m_Xor(m_Value(D), m_Value(C))) &&
-        match(Op1, m_Or(m_Value(A), m_Value(B)))) {
-      if (D == A)
-        return BinaryOperator::CreateXor(
-            Builder.CreateAnd(Builder.CreateNot(A), B), C);
-      if (D == B)
-        return BinaryOperator::CreateXor(
-            Builder.CreateAnd(Builder.CreateNot(B), A), C);
-    }
-    // (A | B)^(A ^ C) -> ((~A) & B) ^ C
-    if (match(Op0, m_Or(m_Value(A), m_Value(B))) &&
-        match(Op1, m_Xor(m_Value(D), m_Value(C)))) {
-      if (D == A)
-        return BinaryOperator::CreateXor(
-            Builder.CreateAnd(Builder.CreateNot(A), B), C);
-      if (D == B)
-        return BinaryOperator::CreateXor(
-            Builder.CreateAnd(Builder.CreateNot(B), A), C);
-    }
-    // (A & B) ^ (A ^ B) -> (A | B)
-    if (match(Op0, m_And(m_Value(A), m_Value(B))) &&
-        match(Op1, m_c_Xor(m_Specific(A), m_Specific(B))))
-      return BinaryOperator::CreateOr(A, B);
-    // (A ^ B) ^ (A & B) -> (A | B)
-    if (match(Op0, m_Xor(m_Value(A), m_Value(B))) &&
-        match(Op1, m_c_And(m_Specific(A), m_Specific(B))))
-      return BinaryOperator::CreateOr(A, B);
-  }
+  Value *A, *B, *C;
+  // (A ^ B) ^ (A | C) --> (~A & C) ^ B -- There are 4 commuted variants.
+  if (match(&I, m_c_Xor(m_OneUse(m_Xor(m_Value(A), m_Value(B))),
+                        m_OneUse(m_c_Or(m_Deferred(A), m_Value(C))))))
+      return BinaryOperator::CreateXor(
+          Builder.CreateAnd(Builder.CreateNot(A), C), B);
+
+  // (A ^ B) ^ (B | C) --> (~B & C) ^ A -- There are 4 commuted variants.
+  if (match(&I, m_c_Xor(m_OneUse(m_Xor(m_Value(A), m_Value(B))),
+                        m_OneUse(m_c_Or(m_Deferred(B), m_Value(C))))))
+      return BinaryOperator::CreateXor(
+          Builder.CreateAnd(Builder.CreateNot(B), C), A);
+
+  // (A & B) ^ (A ^ B) -> (A | B)
+  if (match(Op0, m_And(m_Value(A), m_Value(B))) &&
+      match(Op1, m_c_Xor(m_Specific(A), m_Specific(B))))
+    return BinaryOperator::CreateOr(A, B);
+  // (A ^ B) ^ (A & B) -> (A | B)
+  if (match(Op0, m_Xor(m_Value(A), m_Value(B))) &&
+      match(Op1, m_c_And(m_Specific(A), m_Specific(B))))
+    return BinaryOperator::CreateOr(A, B);
 
   // (A & ~B) ^ ~A -> ~(A & B)
   // (~B & A) ^ ~A -> ~(A & B)
-  Value *A, *B;
   if (match(Op0, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
       match(Op1, m_Not(m_Specific(A))))
     return BinaryOperator::CreateNot(Builder.CreateAnd(A, B));

Modified: llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll?rev=341426&r1=341425&r2=341426&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/demand_shrink_nsw.ll Tue Sep  4 16:22:13 2018
@@ -2,22 +2,18 @@
 ; RUN: opt -instcombine -o - -S %s | FileCheck %s
 
 ; The constant at %v35 should be shrunk, but this must lead to the nsw flag of
-; %v43 getting removed so that %v44 is not illegally optimized away.
+; %v43 getting removed.
 
 define i32 @foo(i32 %arg) {
 ; CHECK-LABEL: @foo(
 ; CHECK-NEXT:    [[V33:%.*]] = and i32 [[ARG:%.*]], 223
 ; CHECK-NEXT:    [[V34:%.*]] = xor i32 [[V33]], 29
 ; CHECK-NEXT:    [[V35:%.*]] = add nuw nsw i32 [[V34]], 1362915575
-; CHECK-NEXT:    [[V37:%.*]] = or i32 [[V34]], 1874836915
-; CHECK-NEXT:    [[V38:%.*]] = and i32 [[V34]], 221
-; CHECK-NEXT:    [[V39:%.*]] = xor i32 [[V38]], 1874836915
-; CHECK-NEXT:    [[V40:%.*]] = xor i32 [[V37]], [[V39]]
-; CHECK-NEXT:    [[V41:%.*]] = shl nuw nsw i32 [[V40]], 1
+; CHECK-NEXT:    [[V40:%.*]] = shl nuw nsw i32 [[V34]], 1
+; CHECK-NEXT:    [[V41:%.*]] = and i32 [[V40]], 290
 ; CHECK-NEXT:    [[V42:%.*]] = sub nsw i32 [[V35]], [[V41]]
 ; CHECK-NEXT:    [[V43:%.*]] = add nuw i32 [[V42]], 1533579450
-; CHECK-NEXT:    [[V44:%.*]] = or i32 [[V43]], -2147483648
-; CHECK-NEXT:    [[V45:%.*]] = xor i32 [[V44]], 749011377
+; CHECK-NEXT:    [[V45:%.*]] = xor i32 [[V43]], 749011377
 ; CHECK-NEXT:    ret i32 [[V45]]
 ;
   %v33 = and i32 %arg, 223

Modified: llvm/trunk/test/Transforms/InstCombine/xor2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/xor2.ll?rev=341426&r1=341425&r2=341426&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/xor2.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/xor2.ll Tue Sep  4 16:22:13 2018
@@ -330,9 +330,9 @@ define i32 @xor_or_xor_common_op_commute
 
 define i32 @xor_or_xor_common_op_commute2(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @xor_or_xor_common_op_commute2(
-; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[C:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %c, %a
@@ -360,9 +360,9 @@ define i32 @xor_or_xor_common_op_commute
 
 define i32 @xor_or_xor_common_op_commute4(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @xor_or_xor_common_op_commute4(
-; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[C:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AB:%.*]] = or i32 [[B:%.*]], [[A]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %c, %a
@@ -390,9 +390,9 @@ define i32 @xor_or_xor_common_op_commute
 
 define i32 @xor_or_xor_common_op_commute6(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @xor_or_xor_common_op_commute6(
-; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[C:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AB]], [[AC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %c, %a
@@ -420,9 +420,9 @@ define i32 @xor_or_xor_common_op_commute
 
 define i32 @xor_or_xor_common_op_commute8(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @xor_or_xor_common_op_commute8(
-; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[C:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AB:%.*]] = or i32 [[B:%.*]], [[A]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AB]], [[AC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %c, %a
@@ -435,9 +435,8 @@ define i32 @xor_or_xor_common_op_extra_u
 ; CHECK-LABEL: @xor_or_xor_common_op_extra_use1(
 ; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
 ; CHECK-NEXT:    store i32 [[AC]], i32* [[P:%.*]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C]]
+; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %a, %c
@@ -449,11 +448,10 @@ define i32 @xor_or_xor_common_op_extra_u
 
 define i32 @xor_or_xor_common_op_extra_use2(i32 %a, i32 %b, i32 %c, i32* %p) {
 ; CHECK-LABEL: @xor_or_xor_common_op_extra_use2(
-; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AC:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
 ; CHECK-NEXT:    store i32 [[AB]], i32* [[P:%.*]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %a, %c
@@ -469,9 +467,7 @@ define i32 @xor_or_xor_common_op_extra_u
 ; CHECK-NEXT:    store i32 [[AC]], i32* [[P1:%.*]], align 4
 ; CHECK-NEXT:    [[AB:%.*]] = or i32 [[A]], [[B:%.*]]
 ; CHECK-NEXT:    store i32 [[AB]], i32* [[P2:%.*]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A]], -1
-; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[B]]
-; CHECK-NEXT:    [[R:%.*]] = xor i32 [[TMP2]], [[C]]
+; CHECK-NEXT:    [[R:%.*]] = xor i32 [[AC]], [[AB]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %ac = xor i32 %a, %c




More information about the llvm-commits mailing list