summaryrefslogtreecommitdiff
path: root/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
diff options
context:
space:
mode:
authorBenjamin Kramer <benny.kra@googlemail.com>2011-02-20 13:23:43 +0000
committerBenjamin Kramer <benny.kra@googlemail.com>2011-02-20 13:23:43 +0000
commit91e37ef278779c3c8700bbddbb5c9d37739b1716 (patch)
tree8af592d9d6408992eb6af45dc74fcb3efca98aba /lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
parented9b934f65d82324506f03e2db2834682c7a8914 (diff)
downloadllvm-91e37ef278779c3c8700bbddbb5c9d37739b1716.tar.gz
llvm-91e37ef278779c3c8700bbddbb5c9d37739b1716.tar.bz2
llvm-91e37ef278779c3c8700bbddbb5c9d37739b1716.tar.xz
InstCombine: Add a bunch of combines of the form x | (y ^ z).
We usually catch this kind of optimization through InstSimplify's distributive magic, but or doesn't distribute over xor in general. "A | ~(A | B) -> A | ~B" hits 24 times on gcc.c. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@126081 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/InstCombine/InstCombineAndOrXor.cpp')
-rw-r--r--lib/Transforms/InstCombine/InstCombineAndOrXor.cpp41
1 files changed, 41 insertions, 0 deletions
diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index b6b6b84d96..07069ada9a 100644
--- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1897,6 +1897,47 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
return BinaryOperator::CreateNot(And);
}
+ // Canonicalize xor to the RHS.
+ if (match(Op0, m_Xor(m_Value(), m_Value())))
+ std::swap(Op0, Op1);
+
+ // A | ( A ^ B) -> A | B
+ // A | (~A ^ B) -> A | ~B
+ if (match(Op1, m_Xor(m_Value(A), m_Value(B)))) {
+ if (Op0 == A || Op0 == B)
+ return BinaryOperator::CreateOr(A, B);
+
+ if (Op1->hasOneUse() && match(A, m_Not(m_Specific(Op0)))) {
+ Value *Not = Builder->CreateNot(B, B->getName()+".not");
+ return BinaryOperator::CreateOr(Not, Op0);
+ }
+ if (Op1->hasOneUse() && match(B, m_Not(m_Specific(Op0)))) {
+ Value *Not = Builder->CreateNot(A, A->getName()+".not");
+ return BinaryOperator::CreateOr(Not, Op0);
+ }
+ }
+
+ // A | ~(A | B) -> A | ~B
+ // A | ~(A ^ B) -> A | ~B
+ // A | ~(A & B) -> -1
+ if (match(Op1, m_Not(m_Value(A))))
+ if (BinaryOperator *B = dyn_cast<BinaryOperator>(A))
+ if (Op0 == B->getOperand(0) || Op0 == B->getOperand(1))
+ switch (B->getOpcode()) {
+ default: break;
+ case Instruction::Or:
+ case Instruction::Xor:
+ if (Op1->hasOneUse()) {
+ Value *NotOp = Op0 == B->getOperand(0) ? B->getOperand(1) :
+ B->getOperand(0);
+ Value *Not = Builder->CreateNot(NotOp, NotOp->getName()+".not");
+ return BinaryOperator::CreateOr(Not, Op0);
+ }
+ break;
+ case Instruction::And:
+ return ReplaceInstUsesWith(I, Constant::getAllOnesValue(I.getType()));
+ }
+
if (ICmpInst *RHS = dyn_cast<ICmpInst>(I.getOperand(1)))
if (ICmpInst *LHS = dyn_cast<ICmpInst>(I.getOperand(0)))
if (Value *Res = FoldOrOfICmps(LHS, RHS))