summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2018-09-04 21:00:13 +0000
committerSanjay Patel <spatel@rotateright.com>2018-09-04 21:00:13 +0000
commita89f183253624c4552dce67c5928214a38bb1daf (patch)
tree7454998e61b40692ca659a2e8acb53e9644393f7 /llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
parent4c08654b17118106919500a51e9623fbc8470b3a (diff)
downloadbcm5719-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.cpp63
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;
OpenPOWER on IntegriCloud