This is an archive of the discontinued LLVM Phabricator instance.

Instcombine (A|B) ^(A^B) to A&B
ClosedPublic

Authored by karthikthecool on Aug 12 2014, 7:03 AM.

Details

Summary

Hi All,
This patch implements transform for pattern (A|B) ^(A^B) to A&B.

Please find the correctness proof of the transform using CVC3 -

$ cat t.cvc
A, B : BITVECTOR(32);
QUERY BVXOR(A | B, BVXOR(A,B) ) = A & B;

$ cvc3 t.cvc
Valid.

Please let me know if this is good to commit.

Thanks
Karthik Bhat

Diff Detail

Event Timeline

karthikthecool retitled this revision from to Instcombine (A|B) ^(A^B) to A&B.
karthikthecool updated this object.
karthikthecool edited the test plan for this revision. (Show Details)
karthikthecool added a subscriber: Unknown Object (MLST).
majnemer edited edge metadata.Aug 12 2014, 9:10 AM

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))))
lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
2451–2459

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.

2483–2484

This code shouldn't have been changed. Op0I is already checked for null.

test/Transforms/InstCombine/or-xor.ll
140

Kill the reference to #0.

karthikthecool edited edge metadata.

Hi David,
Thanks for the review. Yes the newer version is definetly more simple and correct place to do this transform.
Updated the patch as per review comments.

Thanks
Karthik Bhat

majnemer accepted this revision.Aug 12 2014, 9:44 PM
majnemer edited edge metadata.

LGTM with comments addressed.

test/Transforms/InstCombine/or-xor.ll
141–147

All the other tests use names for their instructions, can you please do the same?

This revision is now accepted and ready to land.Aug 12 2014, 9:44 PM

Thanks David. Comitted as r215524 after test case modifications.