summaryrefslogtreecommitdiff
path: root/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
diff options
context:
space:
mode:
authorOwen Anderson <resistor@mac.com>2010-09-11 05:48:06 +0000
committerOwen Anderson <resistor@mac.com>2010-09-11 05:48:06 +0000
commit26c5663283f89f1624304723ebe8c25d253463a3 (patch)
tree896fb72e24c4e16fdfd238c9044e13789e7916db /lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
parent1c4e934666b3fa672a3dd8f933671da4b95447db (diff)
downloadllvm-26c5663283f89f1624304723ebe8c25d253463a3.tar.gz
llvm-26c5663283f89f1624304723ebe8c25d253463a3.tar.bz2
llvm-26c5663283f89f1624304723ebe8c25d253463a3.tar.xz
Invert and-of-or into or-of-and when doing so would allow us to clear bits of the and's mask.
This can result in increased opportunities for store narrowing in code generation. Update a number of tests for this change. This fixes <rdar://problem/8285027>. Additionally, because this inverts the order of ors and ands, some patterns for optimizing or-of-and-of-or no longer fire in instances where they did originally. Add a simple transform which recaptures most of these opportunities: if we have an or-of-constant-or and have failed to fold away the inner or, commute the order of the two ors, to give the non-constant or a chance for simplification instead. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@113679 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/InstCombine/InstCombineAndOrXor.cpp')
-rw-r--r--lib/Transforms/InstCombine/InstCombineAndOrXor.cpp35
1 files changed, 30 insertions, 5 deletions
diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 3dc8779879..d30655f985 100644
--- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -207,12 +207,26 @@ Instruction *InstCombiner::OptAndOp(Instruction *Op,
}
break;
case Instruction::Or:
- if (Op->hasOneUse() && Together != OpRHS) {
- // (X | C1) & C2 --> (X | (C1&C2)) & C2
- Value *Or = Builder->CreateOr(X, Together);
- Or->takeName(Op);
- return BinaryOperator::CreateAnd(Or, AndRHS);
+ if (Op->hasOneUse()){
+ if (Together != OpRHS) {
+ // (X | C1) & C2 --> (X | (C1&C2)) & C2
+ Value *Or = Builder->CreateOr(X, Together);
+ Or->takeName(Op);
+ return BinaryOperator::CreateAnd(Or, AndRHS);
+ }
+
+ ConstantInt *TogetherCI = dyn_cast<ConstantInt>(Together);
+ if (TogetherCI && !TogetherCI->isZero()){
+ // (X | C1) & C2 --> (X & (C2^(C1&C2))) | C1
+ // NOTE: This reduces the number of bits set in the & mask, which
+ // can expose opportunities for store narrowing.
+ Together = ConstantExpr::getXor(AndRHS, Together);
+ Value *And = Builder->CreateAnd(X, Together);
+ And->takeName(Op);
+ return BinaryOperator::CreateOr(And, OpRHS);
+ }
}
+
break;
case Instruction::Add:
if (Op->hasOneUse()) {
@@ -1943,6 +1957,17 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
}
}
+ // Note: If we've gotten to the point of visiting the outer OR, then the
+ // inner one couldn't be simplified. If it was a constant, then it won't
+ // be simplified by a later pass either, so we try swapping the inner/outer
+ // ORs in the hopes that we'll be able to simplify it this way.
+ // (X|C) | V --> (X|V) | C
+ if (Op0->hasOneUse() && match(Op0, m_Or(m_Value(A), m_ConstantInt(C1)))) {
+ Value *Inner = Builder->CreateOr(Op0, Op1);
+ Inner->takeName(Op0);
+ return BinaryOperator::CreateOr(Inner, C1);
+ }
+
return Changed ? &I : 0;
}