[PATCH] Instcombine (A|B) ^(A^B) to A&B

David Majnemer david.majnemer at gmail.com
Tue Aug 12 09:10:45 PDT 2014


I believe the following is a simpler, but equivalent, wording of this transform.

```
--- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2508,6 +2508,18 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
       if ((A == C && B == D) || (A == D && B == C))
         return BinaryOperator::CreateXor(A, B);
     }
+    // (A ^ B)^(A | B) -> A & B
+    if (match(Op0I, m_Xor(m_Value(A), m_Value(B))) &&
+        match(Op1I, m_Or(m_Value(C), m_Value(D)))) {
+      if ((A == C && B == D) || (A == D && B == C))
+        return BinaryOperator::CreateAnd(A, B);
+    }
+    // (A | B)^(A ^ B) -> A & B
+    if (match(Op0I, m_Or(m_Value(A), m_Value(B))) &&
+        match(Op1I, m_Xor(m_Value(C), m_Value(D)))) {
+      if ((A == C && B == D) || (A == D && B == C))
+        return BinaryOperator::CreateAnd(A, B);
+    }
     // (A & B) ^ (A ^ B) -> (A | B)
     if (match(Op0I, m_And(m_Value(A), m_Value(B))) &&
         match(Op1I, m_Xor(m_Specific(A), m_Specific(B))))
```

================
Comment at: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp:2452-2460
@@ -2450,2 +2451,11 @@
         std::swap(Op0, Op1);
+      } else if (Op0I && match(Op0I, m_Xor(m_Value(A1), m_Value(B1)))) {
+        if (A1 == A && B1 == B) {
+          I.swapOperands();    // (A^B)^(A|B) == (A|B)^(A^B)
+          std::swap(Op0, Op1); // Simplified below.
+        } else if (A1 == B && B1 == A) {
+          Op1I->swapOperands(); // (A^B)^(B|A) == (A|B)^(A^B)
+          I.swapOperands();     // Simplied below.
+          std::swap(Op0, Op1);
+        }
       }
----------------
I think this would be simpler as:
  } else if (match(Op0, m_Xor(m_Specific(A), m_Specific(B)))) {
    I.swapOperands();    // (A^B)^(A|B) == (A|B)^(A^B)
    std::swap(Op0, Op1); // Simplified below.
  } else if (match(Op0, m_Xor(m_Specific(B), m_Specific(A)))) {
    Op1I->swapOperands(); // (A^B)^(B|A) == (A|B)^(A^B)
    I.swapOperands();     // Simplied below.
    std::swap(Op0, Op1);

You would avoid needing `A1` and `B1` *and* you could avoid hoisting `Op0I`.

================
Comment at: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp:2492-2493
@@ -2476,1 +2491,4 @@
+      }
+    } else if (Op0I && match(Op0I, m_And(m_Value(A), m_Value(B))) &&
+               Op0I->hasOneUse()) {
       if (A == Op1)                                        // (A&B)^A -> (B&A)^A
----------------
This code shouldn't have been changed. `Op0I` is already checked for `null`.

================
Comment at: test/Transforms/InstCombine/or-xor.ll:140
@@ +139,3 @@
+
+define i32 @test15(i32 %x, i32 %y) #0 {
+  %1 = xor i32 %y, %x
----------------
Kill the reference to `#0`.

http://reviews.llvm.org/D4866






More information about the llvm-commits mailing list