[llvm] 6d3db28 - [InstCombine] Generalize complex OR patterns to AND

Stanislav Mekhanoshin via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 17 10:47:45 PST 2021


Author: Stanislav Mekhanoshin
Date: 2021-11-17T10:47:36-08:00
New Revision: 6d3db28088267203ab4a42c5da0d53c0a259f316

URL: https://github.com/llvm/llvm-project/commit/6d3db28088267203ab4a42c5da0d53c0a259f316
DIFF: https://github.com/llvm/llvm-project/commit/6d3db28088267203ab4a42c5da0d53c0a259f316.diff

LOG: [InstCombine] Generalize complex OR patterns to AND

For every pattern with only NOT, OR, and AND operations there is
always a symmetrical attern with AND and OR swapped.

This adds 2 transformations: https://reviews.llvm.org/D113526

```
(~(a & b) | c) & (~(a & c) | b) --> ~((b ^ c) & a)
(~(a & b) | c) & ~(a & c) --> ~((b | c) & a)
```

```
----------------------------------------
define i4 @src(i4 %a, i4 %b, i4 %c) {
%0:
  %and1 = and i4 %b, %a
  %not1 = xor i4 %and1, 15
  %and2 = and i4 %a, %c
  %not2 = xor i4 %and2, 15
  %or = or i4 %not2, %b
  %r = and i4 %or, %not1
  ret i4 %r
}
=>
define i4 @tgt(i4 %a, i4 %b, i4 %c) {
%0:
  %or = or i4 %b, %c
  %and = and i4 %or, %a
  %r = xor i4 %and, 15
  ret i4 %r
}
Transformation seems to be correct!

----------------------------------------
define i4 @src(i4 %a, i4 %b, i4 %c) {
%0:
  %and1 = and i4 %a, %b
  %not1 = xor i4 %and1, 15
  %or1 = or i4 %not1, %c
  %and2 = and i4 %a, %c
  %not2 = xor i4 %and2, 15
  %or2 = or i4 %not2, %b
  %and3 = and i4 %or1, %or2
  ret i4 %and3
}
=>
define i4 @tgt(i4 %a, i4 %b, i4 %c) {
%0:
  %xor = xor i4 %b, %c
  %and = and i4 %xor, %a
  %not = xor i4 %and, 15
  ret i4 %not
}
Transformation seems to be correct!
```

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/and-xor-or.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index a392597e2de8e..06c9bf650f37f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1715,6 +1715,72 @@ Instruction *InstCombinerImpl::narrowMaskedBinOp(BinaryOperator &And) {
   return new ZExtInst(Builder.CreateAnd(NewBO, X), Ty);
 }
 
+/// Try folding relatively complex patterns for both And and Or operations
+/// with all And and Or swapped.
+static Instruction *foldComplexAndOrPatterns(BinaryOperator &I,
+                                             InstCombiner::BuilderTy &Builder) {
+  const Instruction::BinaryOps Opcode = I.getOpcode();
+  assert(Opcode == Instruction::And || Opcode == Instruction::Or);
+
+  // Flip the logic operation.
+  const Instruction::BinaryOps FlippedOpcode =
+      (Opcode == Instruction::And) ? Instruction::Or : Instruction::And;
+
+  Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
+  Value *A, *B, *C;
+
+  // (~(A | B) & C) | ... --> ...
+  // (~(A & B) | C) & ... --> ...
+  // TODO: One use checks are conservative. We just need to check that a total
+  //       number of multiple used values does not exceed reduction
+  //       in operations.
+  if (match(Op0, m_c_BinOp(FlippedOpcode,
+                           m_Not(m_BinOp(Opcode, m_Value(A), m_Value(B))),
+                           m_Value(C)))) {
+    // (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
+    // (~(A & B) | C) & (~(A & C) | B) --> ~((B ^ C) & A)
+    if (match(Op1,
+              m_OneUse(m_c_BinOp(FlippedOpcode,
+                                 m_OneUse(m_Not(m_c_BinOp(Opcode, m_Specific(A),
+                                                          m_Specific(C)))),
+                                 m_Specific(B))))) {
+      Value *Xor = Builder.CreateXor(B, C);
+      return (Opcode == Instruction::Or)
+                 ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A))
+                 : BinaryOperator::CreateNot(Builder.CreateAnd(Xor, A));
+    }
+
+    // (~(A | B) & C) | (~(B | C) & A) --> (A ^ C) & ~B
+    // (~(A & B) | C) & (~(B & C) | A) --> ~((A ^ C) & B)
+    if (match(Op1,
+              m_OneUse(m_c_BinOp(FlippedOpcode,
+                                 m_OneUse(m_Not(m_c_BinOp(Opcode, m_Specific(B),
+                                                          m_Specific(C)))),
+                                 m_Specific(A))))) {
+      Value *Xor = Builder.CreateXor(A, C);
+      return (Opcode == Instruction::Or)
+                 ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B))
+                 : BinaryOperator::CreateNot(Builder.CreateAnd(Xor, B));
+    }
+
+    // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
+    // (~(A & B) | C) & ~(A & C) --> ~((B | C) & A)
+    if (match(Op1, m_OneUse(m_Not(m_OneUse(
+                       m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)))))))
+      return BinaryOperator::CreateNot(Builder.CreateBinOp(
+          Opcode, Builder.CreateBinOp(FlippedOpcode, B, C), A));
+
+    // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
+    // (~(A & B) | C) & ~(B & C) --> ~((A | C) & B)
+    if (match(Op1, m_OneUse(m_Not(m_OneUse(
+                       m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)))))))
+      return BinaryOperator::CreateNot(Builder.CreateBinOp(
+          Opcode, Builder.CreateBinOp(FlippedOpcode, A, C), B));
+  }
+
+  return nullptr;
+}
+
 // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
 // here. We should standardize that construct where it is needed or choose some
 // other way to ensure that commutated variants of patterns are not missed.
@@ -1740,6 +1806,9 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
   if (Instruction *Xor = foldAndToXor(I, Builder))
     return Xor;
 
+  if (Instruction *X = foldComplexAndOrPatterns(I, Builder))
+    return X;
+
   // (A|B)&(A|C) -> A|(B&C) etc
   if (Value *V = SimplifyUsingDistributiveLaws(I))
     return replaceInstUsesWith(I, V);
@@ -2489,6 +2558,9 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
   if (Instruction *Xor = foldOrToXor(I, Builder))
     return Xor;
 
+  if (Instruction *X = foldComplexAndOrPatterns(I, Builder))
+    return X;
+
   // (A&B)|(A&C) -> A&(B|C) etc
   if (Value *V = SimplifyUsingDistributiveLaws(I))
     return replaceInstUsesWith(I, V);
@@ -2624,40 +2696,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
   if (match(Op0, m_And(m_Or(m_Specific(Op1), m_Value(C)), m_Value(A))))
     return BinaryOperator::CreateOr(Op1, Builder.CreateAnd(A, C));
 
-  // (~(A | B) & C) | ... --> ...
-  // TODO: One use checks are conservative. We just need to check that a total
-  //       number of multiple used values does not exceed reduction
-  //       in operations.
-  if (match(Op0, m_c_And(m_Not(m_Or(m_Value(A), m_Value(B))), m_Value(C)))) {
-    // (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
-    if (match(Op1, m_OneUse(m_c_And(
-                       m_OneUse(m_Not(m_c_Or(m_Specific(A), m_Specific(C)))),
-                       m_Specific(B))))) {
-      Value *Xor = Builder.CreateXor(B, C);
-      return BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A));
-    }
-
-    // (~(A | B) & C) | (~(B | C) & A) --> (A ^ C) & ~B
-    if (match(Op1, m_OneUse(m_c_And(
-                       m_OneUse(m_Not(m_c_Or(m_Specific(B), m_Specific(C)))),
-                       m_Specific(A))))) {
-      Value *Xor = Builder.CreateXor(A, C);
-      return BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B));
-    }
-
-    // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
-    if (match(Op1,
-              m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(C)))))))
-      return BinaryOperator::CreateNot(
-          Builder.CreateOr(Builder.CreateAnd(B, C), A));
-
-    // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
-    if (match(Op1,
-              m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(B), m_Specific(C)))))))
-      return BinaryOperator::CreateNot(
-          Builder.CreateOr(Builder.CreateAnd(A, C), B));
-  }
-
   if (Instruction *DeMorgan = matchDeMorgansLaws(I, Builder))
     return DeMorgan;
 

diff  --git a/llvm/test/Transforms/InstCombine/and-xor-or.ll b/llvm/test/Transforms/InstCombine/and-xor-or.ll
index 5b5517c4acf4c..adeb333b88c9e 100644
--- a/llvm/test/Transforms/InstCombine/and-xor-or.ll
+++ b/llvm/test/Transforms/InstCombine/and-xor-or.ll
@@ -1066,13 +1066,9 @@ define i32 @or_not_and_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
 
 define i32 @and_not_or(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %a, %b
@@ -1088,13 +1084,9 @@ define i32 @and_not_or(i32 %a, i32 %b, i32 %c) {
 define i32 @and_not_or_commute1(i32 %a, i32 %b0, i32 %c) {
 ; CHECK-LABEL: @and_not_or_commute1(
 ; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
@@ -1111,13 +1103,9 @@ define i32 @and_not_or_commute1(i32 %a, i32 %b0, i32 %c) {
 define i32 @and_not_or_commute2(i32 %a, i32 %b0, i32 %c) {
 ; CHECK-LABEL: @and_not_or_commute2(
 ; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR2]], [[OR1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
@@ -1133,13 +1121,9 @@ define i32 @and_not_or_commute2(i32 %a, i32 %b0, i32 %c) {
 
 define i32 @and_not_or_commute3(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or_commute3(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[C]], [[A]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %b, %a
@@ -1155,13 +1139,9 @@ define i32 @and_not_or_commute3(i32 %a, i32 %b, i32 %c) {
 define i32 @and_not_or_commute4(i32 %a, i32 %b, i32 %c0) {
 ; CHECK-LABEL: @and_not_or_commute4(
 ; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[C]], [[NOT1]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[C]], [[A]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization
@@ -1179,13 +1159,9 @@ define i32 @and_not_or_commute5(i32 %a0, i32 %b, i32 %c0) {
 ; CHECK-LABEL: @and_not_or_commute5(
 ; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
 ; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[C]], [[NOT1]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
@@ -1202,13 +1178,9 @@ define i32 @and_not_or_commute5(i32 %a0, i32 %b, i32 %c0) {
 
 define i32 @and_not_or_commute6(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or_commute6(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[C]], [[A]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %a, %b
@@ -1223,13 +1195,9 @@ define i32 @and_not_or_commute6(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_not_or_commute7(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or_commute7(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %b, %a
@@ -1246,13 +1214,9 @@ define i32 @and_not_or_commute8(i32 %a0, i32 %b0, i32 %c) {
 ; CHECK-LABEL: @and_not_or_commute8(
 ; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
 ; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[B]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
@@ -1272,13 +1236,9 @@ define i32 @and_not_or_commute9(i32 %a0, i32 %b0, i32 %c0) {
 ; CHECK-NEXT:    [[A:%.*]] = sdiv i32 42, [[A0:%.*]]
 ; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
 ; CHECK-NEXT:    [[C:%.*]] = sdiv i32 42, [[C0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A]], [[B]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[C]], [[NOT1]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization
@@ -1298,11 +1258,9 @@ define i32 @and_not_or_extra_not_use1(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or_extra_not_use1(
 ; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[NOT1]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
@@ -1345,10 +1303,9 @@ define i32 @and_not_or_extra_and_use1(i32 %a, i32 %b, i32 %c) {
 ; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
 ; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[OR1]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
@@ -1389,12 +1346,9 @@ define i32 @and_not_or_extra_and_use2(i32 %a, i32 %b, i32 %c) {
 define i32 @and_not_or_extra_or_use1(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or_extra_or_use1(
 ; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[AND1]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
@@ -1411,13 +1365,10 @@ define i32 @and_not_or_extra_or_use1(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_not_or_extra_or_use2(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_not_or_extra_or_use2(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[NOT1:%.*]] = xor i32 [[AND1]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR2:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = and i32 [[OR1]], [[OR2]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[AND2]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
@@ -1777,11 +1728,9 @@ define i32 @or_and_not_not_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
 
 define i32 @and_or_not_not(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %b, %a
@@ -1796,11 +1745,9 @@ define i32 @and_or_not_not(i32 %a, i32 %b, i32 %c) {
 define i32 @and_or_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute1(
 ; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
@@ -1815,11 +1762,9 @@ define i32 @and_or_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
 
 define i32 @and_or_not_not_commute2(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute2(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %b, %a
@@ -1833,11 +1778,9 @@ define i32 @and_or_not_not_commute2(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_or_not_not_commute3(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute3(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[C:%.*]], [[A]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %b, %a
@@ -1851,11 +1794,9 @@ define i32 @and_or_not_not_commute3(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_or_not_not_commute4(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute4(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %a, %b
@@ -1869,11 +1810,9 @@ define i32 @and_or_not_not_commute4(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_or_not_not_commute5(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute5(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %b, %a
@@ -1888,11 +1827,9 @@ define i32 @and_or_not_not_commute5(i32 %a, i32 %b, i32 %c) {
 define i32 @and_or_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute6(
 ; CHECK-NEXT:    [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[C:%.*]], [[A]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[B]], [[NOT2]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
@@ -1907,11 +1844,9 @@ define i32 @and_or_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
 
 define i32 @and_or_not_not_commute7(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_commute7(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[C:%.*]], [[A]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
   %and1 = and i32 %a, %b
@@ -1946,11 +1881,11 @@ define i32 @and_or_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_or_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_extra_not_use2(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
 ; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[NOT2]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
@@ -1966,11 +1901,12 @@ define i32 @and_or_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_or_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_extra_and_use(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
 ; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C]], [[B]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[OR]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;
@@ -2006,11 +1942,10 @@ define i32 @and_or_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
 
 define i32 @and_or_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @and_or_not_not_extra_or_use2(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A]], [[C:%.*]]
-; CHECK-NEXT:    [[NOT2:%.*]] = xor i32 [[AND2]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[NOT2]], [[B]]
-; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[AND1]], [[OR]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[A]]
+; CHECK-NEXT:    [[AND3:%.*]] = xor i32 [[TMP2]], -1
 ; CHECK-NEXT:    call void @use(i32 [[AND2]])
 ; CHECK-NEXT:    ret i32 [[AND3]]
 ;


        


More information about the llvm-commits mailing list