diff options
author | Sanjay Patel <spatel@rotateright.com> | 2018-09-04 21:00:13 +0000 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2018-09-04 21:00:13 +0000 |
commit | a89f183253624c4552dce67c5928214a38bb1daf (patch) | |
tree | 7454998e61b40692ca659a2e8acb53e9644393f7 /llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | |
parent | 4c08654b17118106919500a51e9623fbc8470b3a (diff) | |
download | bcm5719-llvm-a89f183253624c4552dce67c5928214a38bb1daf.tar.gz bcm5719-llvm-a89f183253624c4552dce67c5928214a38bb1daf.zip |
[InstCombine] simplify code for xor folds; NFCI
This is just a cleanup step. The TODO comments show
what is wrong with the 'and' version of the fold.
Fixing this should be part of recommitting:
rL300977
llvm-svn: 341405
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp')
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 63 |
1 files changed, 23 insertions, 40 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 8fa012d214e..19322dd6f5b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2769,46 +2769,29 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I)) return FoldedLogic; - { - Value *A, *B; - if (match(Op1, m_OneUse(m_Or(m_Value(A), m_Value(B))))) { - if (A == Op0) { // A^(A|B) == A^(B|A) - cast<BinaryOperator>(Op1)->swapOperands(); - std::swap(A, B); - } - if (B == Op0) { // A^(B|A) == (B|A)^A - I.swapOperands(); // Simplified below. - std::swap(Op0, Op1); - } - } else if (match(Op1, m_OneUse(m_And(m_Value(A), m_Value(B))))) { - if (A == Op0) { // A^(A&B) -> A^(B&A) - cast<BinaryOperator>(Op1)->swapOperands(); - std::swap(A, B); - } - if (B == Op0) { // A^(B&A) -> (B&A)^A - I.swapOperands(); // Simplified below. - std::swap(Op0, Op1); - } - } - } - - { - Value *A, *B; - if (match(Op0, m_OneUse(m_Or(m_Value(A), m_Value(B))))) { - if (A == Op1) // (B|A)^B == (A|B)^B - std::swap(A, B); - if (B == Op1) // (A|B)^B == A & ~B - return BinaryOperator::CreateAnd(A, Builder.CreateNot(Op1)); - } else if (match(Op0, m_OneUse(m_And(m_Value(A), m_Value(B))))) { - if (A == Op1) // (A&B)^A -> (B&A)^A - std::swap(A, B); - const APInt *C; - if (B == Op1 && // (B&A)^A == ~B & A - !match(Op1, m_APInt(C))) { // Canonical form is (B&C)^C - return BinaryOperator::CreateAnd(Builder.CreateNot(A), Op1); - } - } - } + // Y ^ (X | Y) --> X & ~Y + // Y ^ (Y | X) --> X & ~Y + if (match(Op1, m_OneUse(m_c_Or(m_Value(X), m_Specific(Op0))))) + return BinaryOperator::CreateAnd(X, Builder.CreateNot(Op0)); + // (X | Y) ^ Y --> X & ~Y + // (Y | X) ^ Y --> X & ~Y + if (match(Op0, m_OneUse(m_c_Or(m_Value(X), m_Specific(Op1))))) + return BinaryOperator::CreateAnd(X, Builder.CreateNot(Op1)); + + // Y ^ (X & Y) --> ~X & Y + // Y ^ (Y & X) --> ~X & Y + if (match(Op1, m_OneUse(m_c_And(m_Value(X), m_Specific(Op0))))) + return BinaryOperator::CreateAnd(Op0, Builder.CreateNot(X)); + // (X & Y) ^ Y --> ~X & Y + // (Y & X) ^ Y --> ~X & Y + // Canonical form with a non-splat constant is (X & C) ^ C; don't touch that. + // TODO: Why do we treat arbitrary vector constants differently? + // TODO: A 'not' op is better for analysis and codegen, but demanded bits must + // be fixed to prefer that (otherwise we get infinite looping). + const APInt *Unused; + if (!match(Op1, m_APInt(Unused)) && + 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; |