return true;
}
+ struct ClearWalkingBEDominatingCondsOnExit {
+ ScalarEvolution &SE;
+
+ explicit ClearWalkingBEDominatingCondsOnExit(ScalarEvolution &SE)
+ : SE(SE){};
+
+ ~ClearWalkingBEDominatingCondsOnExit() {
+ SE.WalkingBEDominatingConds = false;
+ }
+ };
+
+ // We don't want more than one activation of the following loop on the stack
+ // -- that can lead to O(n!) time complexity.
+ if (WalkingBEDominatingConds)
+ return false;
+
+ WalkingBEDominatingConds = true;
+ ClearWalkingBEDominatingCondsOnExit ClearOnExit(*this);
+
+ // If the loop is not reachable from the entry block, we risk running into an
+ // infinite loop as we walk up into the dom tree. These loops do not matter
+ // anyway, so we just return a conservative answer when we see them.
+ if (!DT->isReachableFromEntry(L->getHeader()))
+ return false;
+
+ for (DomTreeNode *DTN = (*DT)[Latch], *HeaderDTN = (*DT)[L->getHeader()];
+ DTN != HeaderDTN;
+ DTN = DTN->getIDom()) {
+
+ assert(DTN && "should reach the loop header before reaching the root!");
+
+ BasicBlock *BB = DTN->getBlock();
+ BasicBlock *PBB = BB->getSinglePredecessor();
+ if (!PBB)
+ continue;
+
+ BranchInst *ContinuePredicate = dyn_cast<BranchInst>(PBB->getTerminator());
+ if (!ContinuePredicate || !ContinuePredicate->isConditional())
+ continue;
+
+ Value *Condition = ContinuePredicate->getCondition();
+
+ // If we have an edge `E` within the loop body that dominates the only
+ // latch, the condition guarding `E` also guards the backedge. This
+ // reasoning works only for loops with a single latch.
+
+ BasicBlockEdge DominatingEdge(PBB, BB);
+ if (DominatingEdge.isSingleEdge()) {
+ // We're constructively (and conservatively) enumerating edges within the
+ // loop body that dominate the latch. The dominator tree better agree
+ // with us on this:
+ assert(DT->dominates(DominatingEdge, Latch) && "should be!");
+
+ if (isImpliedCond(Pred, LHS, RHS, Condition,
+ BB != ContinuePredicate->getSuccessor(0)))
+ return true;
+ }
+ }
+
return false;
}
//===----------------------------------------------------------------------===//
ScalarEvolution::ScalarEvolution()
- : FunctionPass(ID), ValuesAtScopes(64), LoopDispositions(64),
- BlockDispositions(64), FirstUnknown(nullptr) {
+ : FunctionPass(ID), WalkingBEDominatingConds(false), ValuesAtScopes(64),
+ LoopDispositions(64), BlockDispositions(64), FirstUnknown(nullptr) {
initializeScalarEvolutionPass(*PassRegistry::getPassRegistry());
}
}
assert(PendingLoopPredicates.empty() && "isImpliedCond garbage");
+ assert(!WalkingBEDominatingConds && "isLoopBackedgeGuardedByCond garbage!");
BackedgeTakenCounts.clear();
ConstantEvolutionLoopExitValue.clear();
--- /dev/null
+; RUN: opt -S -indvars < %s | FileCheck %s
+
+declare void @side_effect(i1)
+
+define void @latch_dominating_0(i8 %start) {
+; CHECK-LABEL: latch_dominating_0
+ entry:
+ %e = icmp slt i8 %start, 42
+ br i1 %e, label %loop, label %exit
+
+ loop:
+; CHECK-LABEL: loop
+ %idx = phi i8 [ %start, %entry ], [ %idx.inc, %be ]
+ %idx.inc = add i8 %idx, 1
+ %folds.to.true = icmp slt i8 %idx, 42
+; CHECK: call void @side_effect(i1 true)
+ call void @side_effect(i1 %folds.to.true)
+ %c0 = icmp slt i8 %idx.inc, 42
+ br i1 %c0, label %be, label %exit
+
+ be:
+; CHECK: call void @side_effect(i1 true)
+ call void @side_effect(i1 %folds.to.true)
+ %c1 = icmp slt i8 %idx.inc, 100
+ br i1 %c1, label %loop, label %exit
+
+ exit:
+ ret void
+}
+
+define void @latch_dominating_1(i8 %start) {
+; CHECK-LABEL: latch_dominating_1
+ entry:
+ %e = icmp slt i8 %start, 42
+ br i1 %e, label %loop, label %exit
+
+ loop:
+; CHECK-LABEL: loop
+ %idx = phi i8 [ %start, %entry ], [ %idx.inc, %be ]
+ %idx.inc = add i8 %idx, 1
+ %does.not.fold.to.true = icmp slt i8 %idx, 42
+; CHECK: call void @side_effect(i1 %does.not.fold.to.true)
+ call void @side_effect(i1 %does.not.fold.to.true)
+ %c0 = icmp slt i8 %idx.inc, 42
+ br i1 %c0, label %be, label %be
+
+ be:
+; CHECK: call void @side_effect(i1 %does.not.fold.to.true)
+ call void @side_effect(i1 %does.not.fold.to.true)
+ %c1 = icmp slt i8 %idx.inc, 100
+ br i1 %c1, label %loop, label %exit
+
+ exit:
+ ret void
+}