summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2018-05-03 21:58:44 +0000
committerSanjay Patel <spatel@rotateright.com>2018-05-03 21:58:44 +0000
commite7b665471135e63955bbc102cb5ac457726849e4 (patch)
tree0f52533637946d077e702b54c9096ee1c4a4cd34 /llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
parentabc9871d6099d154dcab127b3676f015f76accec (diff)
downloadbcm5719-llvm-e7b665471135e63955bbc102cb5ac457726849e4.tar.gz
bcm5719-llvm-e7b665471135e63955bbc102cb5ac457726849e4.zip
[InstCombine] refine select-of-constants to bitwise ops
Add logic for the special case when a cmp+select can clearly be reduced to just a bitwise logic instruction, and remove an over-reaching chunk of general purpose bit magic. The primary goal is to remove cases where we are not improving the IR instruction count when doing these select transforms, and in all cases here that is true. In the motivating 3-way compare tests, there are further improvements because we can combine/propagate select values (not sure if that belongs in instcombine, but it's there for now). DAGCombiner has folds to turn some of these selects into bit magic, so there should be no difference in the end result in those cases. Not all constant combinations are handled there yet, however, so it is possible that some targets will see more cmov/csel codegen with this change in IR canonicalization. Ideally, we'll go further to *not* turn selects into multiple logic/math ops in instcombine, and we'll canonicalize to selects. But we should make sure that this step does not result in regressions first (and if it does, we should fix those in the backend). The general direction for this change was discussed here: http://lists.llvm.org/pipermail/llvm-dev/2016-September/105373.html http://lists.llvm.org/pipermail/llvm-dev/2017-July/114885.html Alive proofs for the new bit magic: https://rise4fun.com/Alive/XG7 Differential Revision: https://reviews.llvm.org/D46086 llvm-svn: 331486
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp91
1 files changed, 34 insertions, 57 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index affeb740f27..b4db091a439 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -100,23 +100,41 @@ static Value *foldSelectICmpAnd(SelectInst &Sel, ICmpInst *Cmp,
return nullptr;
}
- // If both select arms are non-zero see if we have a select of the form
- // 'x ? 2^n + TC : FC'. Then we can offset both arms by C, use the logic
- // for 'x ? 2^n : 0' and fix the thing up at the end.
+ // In general, when both constants are non-zero, we would need an offset to
+ // replace the select. This would require more instructions than we started
+ // with. But there's one special-case that we handle here because it can
+ // simplify/reduce the instructions.
APInt TC = *SelTC;
APInt FC = *SelFC;
- APInt Offset(TC.getBitWidth(), 0);
if (!TC.isNullValue() && !FC.isNullValue()) {
- if ((TC - FC).isPowerOf2())
- Offset = FC;
- else if ((FC - TC).isPowerOf2())
- Offset = TC;
- else
+ // If the select constants differ by exactly one bit and that's the same
+ // bit that is masked and checked by the select condition, the select can
+ // be replaced by bitwise logic to set/clear one bit of the constant result.
+ if (TC.getBitWidth() != AndMask.getBitWidth() || (TC ^ FC) != AndMask)
return nullptr;
-
- // Adjust TC and FC by the offset.
- TC -= Offset;
- FC -= Offset;
+ if (CreateAnd) {
+ // If we have to create an 'and', then we must kill the cmp to not
+ // increase the instruction count.
+ if (!Cmp->hasOneUse())
+ return nullptr;
+ V = Builder.CreateAnd(V, ConstantInt::get(SelType, AndMask));
+ }
+ bool ExtraBitInTC = TC.ugt(FC);
+ if (Pred == ICmpInst::ICMP_EQ) {
+ // If the masked bit in V is clear, clear or set the bit in the result:
+ // (V & AndMaskC) == 0 ? TC : FC --> (V & AndMaskC) ^ TC
+ // (V & AndMaskC) == 0 ? TC : FC --> (V & AndMaskC) | TC
+ Constant *C = ConstantInt::get(SelType, TC);
+ return ExtraBitInTC ? Builder.CreateXor(V, C) : Builder.CreateOr(V, C);
+ }
+ if (Pred == ICmpInst::ICMP_NE) {
+ // If the masked bit in V is set, set or clear the bit in the result:
+ // (V & AndMaskC) != 0 ? TC : FC --> (V & AndMaskC) | FC
+ // (V & AndMaskC) != 0 ? TC : FC --> (V & AndMaskC) ^ FC
+ Constant *C = ConstantInt::get(SelType, FC);
+ return ExtraBitInTC ? Builder.CreateOr(V, C) : Builder.CreateXor(V, C);
+ }
+ llvm_unreachable("Only expecting equality predicates");
}
// Make sure one of the select arms is a power-of-2.
@@ -152,9 +170,6 @@ static Value *foldSelectICmpAnd(SelectInst &Sel, ICmpInst *Cmp,
if (ShouldNotVal)
V = Builder.CreateXor(V, ValC);
- // Apply an offset if needed.
- if (!Offset.isNullValue())
- V = Builder.CreateAdd(V, ConstantInt::get(V->getType(), Offset));
return V;
}
@@ -790,51 +805,13 @@ Instruction *InstCombiner::foldSelectInstWithICmp(SelectInst &SI,
bool Changed = adjustMinMax(SI, *ICI);
- ICmpInst::Predicate Pred = ICI->getPredicate();
- Value *CmpLHS = ICI->getOperand(0);
- Value *CmpRHS = ICI->getOperand(1);
-
- // Transform (X >s -1) ? C1 : C2 --> ((X >>s 31) & (C2 - C1)) + C1
- // and (X <s 0) ? C2 : C1 --> ((X >>s 31) & (C2 - C1)) + C1
- // FIXME: Type and constness constraints could be lifted, but we have to
- // watch code size carefully. We should consider xor instead of
- // sub/add when we decide to do that.
- // TODO: Merge this with foldSelectICmpAnd somehow.
- if (CmpLHS->getType()->isIntOrIntVectorTy() &&
- CmpLHS->getType() == TrueVal->getType()) {
- const APInt *C1, *C2;
- if (match(TrueVal, m_APInt(C1)) && match(FalseVal, m_APInt(C2))) {
- ICmpInst::Predicate Pred = ICI->getPredicate();
- Value *X;
- APInt Mask;
- if (decomposeBitTestICmp(CmpLHS, CmpRHS, Pred, X, Mask, false)) {
- if (Mask.isSignMask()) {
- assert(X == CmpLHS && "Expected to use the compare input directly");
- assert(ICmpInst::isEquality(Pred) && "Expected equality predicate");
-
- if (Pred == ICmpInst::ICMP_NE)
- std::swap(C1, C2);
-
- // This shift results in either -1 or 0.
- Value *AShr = Builder.CreateAShr(X, Mask.getBitWidth() - 1);
-
- // Check if we can express the operation with a single or.
- if (C2->isAllOnesValue())
- return replaceInstUsesWith(SI, Builder.CreateOr(AShr, *C1));
-
- Value *And = Builder.CreateAnd(AShr, *C2 - *C1);
- return replaceInstUsesWith(SI, Builder.CreateAdd(And,
- ConstantInt::get(And->getType(), *C1)));
- }
- }
- }
- }
-
if (Value *V = foldSelectICmpAnd(SI, ICI, Builder))
return replaceInstUsesWith(SI, V);
// NOTE: if we wanted to, this is where to detect integer MIN/MAX
-
+ ICmpInst::Predicate Pred = ICI->getPredicate();
+ Value *CmpLHS = ICI->getOperand(0);
+ Value *CmpRHS = ICI->getOperand(1);
if (CmpRHS != CmpLHS && isa<Constant>(CmpRHS)) {
if (CmpLHS == TrueVal && Pred == ICmpInst::ICMP_EQ) {
// Transform (X == C) ? X : Y -> (X == C) ? C : Y
OpenPOWER on IntegriCloud