aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/LoopPeel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Utils/LoopPeel.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/LoopPeel.cpp86
1 files changed, 63 insertions, 23 deletions
diff --git a/llvm/lib/Transforms/Utils/LoopPeel.cpp b/llvm/lib/Transforms/Utils/LoopPeel.cpp
index f76fa3b..e251693 100644
--- a/llvm/lib/Transforms/Utils/LoopPeel.cpp
+++ b/llvm/lib/Transforms/Utils/LoopPeel.cpp
@@ -351,6 +351,21 @@ static unsigned countToEliminateCompares(Loop &L, unsigned MaxPeelCount,
MaxPeelCount =
std::min((unsigned)SC->getAPInt().getLimitedValue() - 1, MaxPeelCount);
+ // Increase PeelCount while (IterVal Pred BoundSCEV) condition is satisfied;
+ // return true if inversed condition become known before reaching the
+ // MaxPeelCount limit.
+ auto PeelWhilePredicateIsKnown =
+ [&](unsigned &PeelCount, const SCEV *&IterVal, const SCEV *BoundSCEV,
+ const SCEV *Step, ICmpInst::Predicate Pred) {
+ while (PeelCount < MaxPeelCount &&
+ SE.isKnownPredicate(Pred, IterVal, BoundSCEV)) {
+ IterVal = SE.getAddExpr(IterVal, Step);
+ ++PeelCount;
+ }
+ return SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), IterVal,
+ BoundSCEV);
+ };
+
const unsigned MaxDepth = 4;
std::function<void(Value *, unsigned)> ComputePeelCount =
[&](Value *Condition, unsigned Depth) -> void {
@@ -411,48 +426,73 @@ static unsigned countToEliminateCompares(Loop &L, unsigned MaxPeelCount,
Pred = ICmpInst::getInversePredicate(Pred);
const SCEV *Step = LeftAR->getStepRecurrence(SE);
- const SCEV *NextIterVal = SE.getAddExpr(IterVal, Step);
- auto PeelOneMoreIteration = [&IterVal, &NextIterVal, &SE, Step,
- &NewPeelCount]() {
- IterVal = NextIterVal;
- NextIterVal = SE.getAddExpr(IterVal, Step);
- NewPeelCount++;
- };
-
- auto CanPeelOneMoreIteration = [&NewPeelCount, &MaxPeelCount]() {
- return NewPeelCount < MaxPeelCount;
- };
-
- while (CanPeelOneMoreIteration() &&
- SE.isKnownPredicate(Pred, IterVal, RightSCEV))
- PeelOneMoreIteration();
-
- // With *that* peel count, does the predicate !Pred become known in the
- // first iteration of the loop body after peeling?
- if (!SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), IterVal,
- RightSCEV))
- return; // If not, give up.
+ if (!PeelWhilePredicateIsKnown(NewPeelCount, IterVal, RightSCEV, Step,
+ Pred))
+ return;
// However, for equality comparisons, that isn't always sufficient to
// eliminate the comparsion in loop body, we may need to peel one more
// iteration. See if that makes !Pred become unknown again.
+ const SCEV *NextIterVal = SE.getAddExpr(IterVal, Step);
if (ICmpInst::isEquality(Pred) &&
!SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), NextIterVal,
RightSCEV) &&
!SE.isKnownPredicate(Pred, IterVal, RightSCEV) &&
SE.isKnownPredicate(Pred, NextIterVal, RightSCEV)) {
- if (!CanPeelOneMoreIteration())
+ if (NewPeelCount >= MaxPeelCount)
return; // Need to peel one more iteration, but can't. Give up.
- PeelOneMoreIteration(); // Great!
+ ++NewPeelCount; // Great!
}
DesiredPeelCount = std::max(DesiredPeelCount, NewPeelCount);
};
+ auto ComputePeelCountMinMax = [&](MinMaxIntrinsic *MinMax) {
+ if (!MinMax->getType()->isIntegerTy())
+ return;
+ Value *LHS = MinMax->getLHS(), *RHS = MinMax->getRHS();
+ const SCEV *BoundSCEV, *IterSCEV;
+ if (L.isLoopInvariant(LHS)) {
+ BoundSCEV = SE.getSCEV(LHS);
+ IterSCEV = SE.getSCEV(RHS);
+ } else if (L.isLoopInvariant(RHS)) {
+ BoundSCEV = SE.getSCEV(RHS);
+ IterSCEV = SE.getSCEV(LHS);
+ } else
+ return;
+ const auto *AddRec = dyn_cast<SCEVAddRecExpr>(IterSCEV);
+ // For simplicity, we support only affine recurrences.
+ if (!AddRec || !AddRec->isAffine() || AddRec->getLoop() != &L)
+ return;
+ const SCEV *Step = AddRec->getStepRecurrence(SE);
+ bool IsSigned = MinMax->isSigned();
+ // To minimize number of peeled iterations, we use strict relational
+ // predicates here.
+ ICmpInst::Predicate Pred;
+ if (SE.isKnownPositive(Step))
+ Pred = IsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT;
+ else if (SE.isKnownNegative(Step))
+ Pred = IsSigned ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT;
+ else
+ return;
+ // Check that AddRec is not wrapping.
+ if (!(IsSigned ? AddRec->hasNoSignedWrap() : AddRec->hasNoUnsignedWrap()))
+ return;
+ unsigned NewPeelCount = DesiredPeelCount;
+ const SCEV *IterVal = AddRec->evaluateAtIteration(
+ SE.getConstant(AddRec->getType(), NewPeelCount), SE);
+ if (!PeelWhilePredicateIsKnown(NewPeelCount, IterVal, BoundSCEV, Step,
+ Pred))
+ return;
+ DesiredPeelCount = NewPeelCount;
+ };
+
for (BasicBlock *BB : L.blocks()) {
for (Instruction &I : *BB) {
if (SelectInst *SI = dyn_cast<SelectInst>(&I))
ComputePeelCount(SI->getCondition(), 0);
+ if (MinMaxIntrinsic *MinMax = dyn_cast<MinMaxIntrinsic>(&I))
+ ComputePeelCountMinMax(MinMax);
}
auto *BI = dyn_cast<BranchInst>(BB->getTerminator());