diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 72408f773840..8f87b58fe736 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -30,7 +30,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/ConstantRange.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include namespace llvm { @@ -250,6 +250,9 @@ namespace llvm { /// ValueExprMapType ValueExprMap; + /// Mark predicate values currently being processed by isImpliedCond. + DenseSet PendingLoopPredicates; + /// ExitLimit - Information about the number of loop iterations for /// which a loop exit's branch condition evaluates to the not-taken path. /// This is a temporary pair of exact and max expressions that are diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index d1ad8e02d6a0..4e3dc60ed501 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -6039,12 +6039,34 @@ ScalarEvolution::isLoopEntryGuardedByCond(const Loop *L, return false; } +/// RAII wrapper to prevent recursive application of isImpliedCond. +/// ScalarEvolution's PendingLoopPredicates set must be empty unless we are +/// currently evaluating isImpliedCond. +struct MarkPendingLoopPredicate { + Value *Cond; + DenseSet &LoopPreds; + bool Pending; + + MarkPendingLoopPredicate(Value *C, DenseSet &LP) + : Cond(C), LoopPreds(LP) { + Pending = !LoopPreds.insert(Cond).second; + } + ~MarkPendingLoopPredicate() { + if (!Pending) + LoopPreds.erase(Cond); + } +}; + /// isImpliedCond - Test whether the condition described by Pred, LHS, /// and RHS is true whenever the given Cond value evaluates to true. bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, Value *FoundCondValue, bool Inverse) { + MarkPendingLoopPredicate Mark(FoundCondValue, PendingLoopPredicates); + if (Mark.Pending) + return false; + // Recursively handle And and Or conditions. if (BinaryOperator *BO = dyn_cast(FoundCondValue)) { if (BO->getOpcode() == Instruction::And) { @@ -6571,6 +6593,8 @@ void ScalarEvolution::releaseMemory() { I->second.clear(); } + assert(PendingLoopPredicates.empty() && "isImpliedCond garbage"); + BackedgeTakenCounts.clear(); ConstantEvolutionLoopExitValue.clear(); ValuesAtScopes.clear(); diff --git a/llvm/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll b/llvm/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll new file mode 100644 index 000000000000..52e6683c9f01 --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/2012-05-18-LoopPredRecurse.ll @@ -0,0 +1,30 @@ +; RUN: opt < %s -iv-users -S -disable-output +; +; PR12868: Infinite recursion: +; getUDivExpr()->getZeroExtendExpr()->isLoopBackedgeGuardedBy() +; +; We actually want SCEV simplification to fail gracefully in this +; case, so there's no output to check, just the absense of stack overflow. + +@c = common global i8 0, align 1 + +define i32 @func() { +entry: + br label %for.cond + +for.cond: ; preds = %for.body, %entry + %storemerge = phi i8 [ -1, %entry ], [ %inc, %for.body ] + %ui.0 = phi i32 [ undef, %entry ], [ %div, %for.body ] + %tobool = icmp eq i8 %storemerge, 0 + br i1 %tobool, label %for.end, label %for.body + +for.body: ; preds = %for.cond + %conv = sext i8 %storemerge to i32 + %div = lshr i32 %conv, 1 + %tobool2 = icmp eq i32 %div, 0 + %inc = add i8 %storemerge, 1 + br i1 %tobool2, label %for.cond, label %for.end + +for.end: ; preds = %for.body, %for.cond + ret i32 0 +}