Generalize the code that handles (A&B)|(A&C) to work where B/C are not constants.
authorChris Lattner <sabre@nondot.org>
Sun, 8 Apr 2007 07:47:01 +0000 (07:47 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 8 Apr 2007 07:47:01 +0000 (07:47 +0000)
Add a new xform to simplify (A&B)|(~A&C).  THis implements InstCombine/or2.ll:test1

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35760 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp

index 2167144fc181fe64c6f47758e47162e0cca5f620..6cedee94b19a24b70f868d033bace7d2f87f51bb 100644 (file)
@@ -3709,36 +3709,89 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
     return BinaryOperator::createXor(NOr, C1);
   }
 
-  // (A & C1)|(B & C2)
-  if (match(Op0, m_And(m_Value(A), m_ConstantInt(C1))) &&
-      match(Op1, m_And(m_Value(B), m_ConstantInt(C2)))) {
-
-    if (A == B)  // (A & C1)|(A & C2) == A & (C1|C2)
-      return BinaryOperator::createAnd(A, 
-                 ConstantInt::get(C1->getValue() | C2->getValue()));
-
-
-    // If we have: ((V + N) & C1) | (V & C2)
-    // .. and C2 = ~C1 and C2 is 0+1+ and (N & C2) == 0
-    // replace with V+N.
-    if (C1->getValue() == ~C2->getValue()) {
-      Value *V1 = 0, *V2 = 0;
-      if ((C2->getValue() & (C2->getValue()+1)) == 0 && // C2 == 0+1+
-          match(A, m_Add(m_Value(V1), m_Value(V2)))) {
-        // Add commutes, try both ways.
-        if (V1 == B && MaskedValueIsZero(V2, C2->getValue()))
-          return ReplaceInstUsesWith(I, A);
-        if (V2 == B && MaskedValueIsZero(V1, C2->getValue()))
-          return ReplaceInstUsesWith(I, A);
-      }
-      // Or commutes, try both ways.
-      if ((C1->getValue() & (C1->getValue()+1)) == 0 &&
-          match(B, m_Add(m_Value(V1), m_Value(V2)))) {
-        // Add commutes, try both ways.
-        if (V1 == A && MaskedValueIsZero(V2, C1->getValue()))
-          return ReplaceInstUsesWith(I, B);
-        if (V2 == A && MaskedValueIsZero(V1, C1->getValue()))
-          return ReplaceInstUsesWith(I, B);
+  // (A & C)|(B & D)
+  Value *C, *D;
+  if (match(Op0, m_And(m_Value(A), m_Value(C))) &&
+      match(Op1, m_And(m_Value(B), m_Value(D)))) {
+
+    // Check to see if we have any common things being and'ed.  If so, find the
+    // terms for V1 & (V2|V3).
+    Value *V1 = 0, *V2 = 0, *V3 = 0;
+    if (isOnlyUse(Op0) || isOnlyUse(Op1)) {
+      if (A == B)      // (A & C)|(A & D) == A & (C|D)
+        V1 = A, V2 = C, V3 = D;
+      else if (A == D) // (A & C)|(B & A) == A & (B|C)
+        V1 = A, V2 = B, V3 = C;
+      else if (C == B) // (A & C)|(C & D) == C & (A|D)
+        V1 = C, V2 = A, V3 = D;
+      else if (C == D) // (A & C)|(B & C) == C & (A|B)
+        V1 = C, V2 = A, V3 = B;
+      
+      if (V1) {
+        Value *Or =
+          InsertNewInstBefore(BinaryOperator::createOr(V2, V3, "tmp"), I);
+        return BinaryOperator::createAnd(V1, Or);
+      }
+      
+      // (V1 & V3)|(V2 & ~V3) -> ((V1 ^ V2) & V3) ^ V2
+      if (isOnlyUse(Op0) && isOnlyUse(Op1)) {
+        // Try all combination of terms to find V3 and ~V3.
+        if (A->hasOneUse() && match(A, m_Not(m_Value(V3)))) {
+          if (V3 == B)
+            V1 = D, V2 = C;
+          else if (V3 == D)
+            V1 = B, V2 = C;
+        }
+        if (B->hasOneUse() && match(B, m_Not(m_Value(V3)))) {
+          if (V3 == A)
+            V1 = C, V2 = D;
+          else if (V3 == C)
+            V1 = A, V2 = D;
+        }
+        if (C->hasOneUse() && match(C, m_Not(m_Value(V3)))) {
+          if (V3 == B)
+            V1 = D, V2 = A;
+          else if (V3 == D)
+            V1 = B, V2 = A;
+        }
+        if (D->hasOneUse() && match(D, m_Not(m_Value(V3)))) {
+          if (V3 == A)
+            V1 = C, V2 = B;
+          else if (V3 == C)
+            V1 = A, V2 = B;
+        }
+        if (V1) {
+          A = InsertNewInstBefore(BinaryOperator::createXor(V1, V2, "tmp"), I);
+          A = InsertNewInstBefore(BinaryOperator::createAnd(A, V3, "tmp"), I);
+          return BinaryOperator::createXor(A, V2);
+        }
+      }
+    }
+    
+    C1 = dyn_cast<ConstantInt>(C);
+    C2 = dyn_cast<ConstantInt>(D);
+    if (C1 && C2) {  // (A & C1)|(B & C2)
+      // If we have: ((V + N) & C1) | (V & C2)
+      // .. and C2 = ~C1 and C2 is 0+1+ and (N & C2) == 0
+      // replace with V+N.
+      if (C1->getValue() == ~C2->getValue()) {
+        if ((C2->getValue() & (C2->getValue()+1)) == 0 && // C2 == 0+1+
+            match(A, m_Add(m_Value(V1), m_Value(V2)))) {
+          // Add commutes, try both ways.
+          if (V1 == B && MaskedValueIsZero(V2, C2->getValue()))
+            return ReplaceInstUsesWith(I, A);
+          if (V2 == B && MaskedValueIsZero(V1, C2->getValue()))
+            return ReplaceInstUsesWith(I, A);
+        }
+        // Or commutes, try both ways.
+        if ((C1->getValue() & (C1->getValue()+1)) == 0 &&
+            match(B, m_Add(m_Value(V1), m_Value(V2)))) {
+          // Add commutes, try both ways.
+          if (V1 == A && MaskedValueIsZero(V2, C1->getValue()))
+            return ReplaceInstUsesWith(I, B);
+          if (V2 == A && MaskedValueIsZero(V1, C1->getValue()))
+            return ReplaceInstUsesWith(I, B);
+        }
       }
     }
   }