From 45b42198260f70a537efc791572a49a39ae9b676 Mon Sep 17 00:00:00 2001 From: Carl Ritson Date: Thu, 24 Jun 2021 09:36:58 +0900 Subject: [PATCH] [LVI] Remove recursion from getValueForCondition (NFCI) Convert getValueForCondition to a worklist model instead of using recursion. In pathological cases getValueForCondition recurses heavily. Stack frames are quite expensive on x86-64, and some operating systems (e.g. Windows) have relatively low stack size limits. Using a worklist avoids potential failures from stack overflow. Differential Revision: https://reviews.llvm.org/D104191 --- lib/Analysis/LazyValueInfo.cpp | 89 +++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/lib/Analysis/LazyValueInfo.cpp b/lib/Analysis/LazyValueInfo.cpp index 83d83f45c97..1dababafb8a 100644 --- a/lib/Analysis/LazyValueInfo.cpp +++ b/lib/Analysis/LazyValueInfo.cpp @@ -1151,20 +1151,20 @@ static ValueLatticeElement getValueFromOverflowCondition( return ValueLatticeElement::getRange(NWR); } -static ValueLatticeElement -getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest, - SmallDenseMap &Visited); - -static ValueLatticeElement +static Optional getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest, - SmallDenseMap &Visited) { - if (ICmpInst *ICI = dyn_cast(Cond)) - return getValueFromICmpCondition(Val, ICI, isTrueDest); + bool isRevisit, + SmallDenseMap &Visited, + SmallVectorImpl &Worklist) { + if (!isRevisit) { + if (ICmpInst *ICI = dyn_cast(Cond)) + return getValueFromICmpCondition(Val, ICI, isTrueDest); - if (auto *EVI = dyn_cast(Cond)) - if (auto *WO = dyn_cast(EVI->getAggregateOperand())) - if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1) - return getValueFromOverflowCondition(Val, WO, isTrueDest); + if (auto *EVI = dyn_cast(Cond)) + if (auto *WO = dyn_cast(EVI->getAggregateOperand())) + if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1) + return getValueFromOverflowCondition(Val, WO, isTrueDest); + } Value *L, *R; bool IsAnd; @@ -1175,44 +1175,63 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest, else return ValueLatticeElement::getOverdefined(); + auto LV = Visited.find(L); + auto RV = Visited.find(R); + // if (L && R) -> intersect L and R // if (!(L || R)) -> intersect L and R // if (L || R) -> union L and R // if (!(L && R)) -> union L and R - if (isTrueDest ^ IsAnd) { - ValueLatticeElement V = getValueFromCondition(Val, L, isTrueDest, Visited); + if ((isTrueDest ^ IsAnd) && (LV != Visited.end())) { + ValueLatticeElement V = LV->second; if (V.isOverdefined()) return V; - V.mergeIn(getValueFromCondition(Val, R, isTrueDest, Visited)); - return V; + if (RV != Visited.end()) { + V.mergeIn(RV->second); + return V; + } } - return intersect(getValueFromCondition(Val, L, isTrueDest, Visited), - getValueFromCondition(Val, R, isTrueDest, Visited)); -} + if (LV == Visited.end() || RV == Visited.end()) { + assert(!isRevisit); + if (LV == Visited.end()) + Worklist.push_back(L); + if (RV == Visited.end()) + Worklist.push_back(R); + return None; + } -static ValueLatticeElement -getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest, - SmallDenseMap &Visited) { - // Insert an Overdefined placeholder into the set to prevent - // infinite recursion if there exists IRs that use not - // dominated by its def as in this example: - // "%tmp3 = or i1 undef, %tmp4" - // "%tmp4 = or i1 undef, %tmp3" - auto Iter = Visited.try_emplace(Cond, ValueLatticeElement::getOverdefined()); - if (!Iter.second) - return Iter.first->getSecond(); - - auto Result = getValueFromConditionImpl(Val, Cond, isTrueDest, Visited); - Visited[Cond] = Result; - return Result; + return intersect(LV->second, RV->second); } ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest) { assert(Cond && "precondition"); SmallDenseMap Visited; - return getValueFromCondition(Val, Cond, isTrueDest, Visited); + SmallVector Worklist; + + Worklist.push_back(Cond); + do { + Value *CurrentCond = Worklist.back(); + // Insert an Overdefined placeholder into the set to prevent + // infinite recursion if there exists IRs that use not + // dominated by its def as in this example: + // "%tmp3 = or i1 undef, %tmp4" + // "%tmp4 = or i1 undef, %tmp3" + auto Iter = + Visited.try_emplace(CurrentCond, ValueLatticeElement::getOverdefined()); + bool isRevisit = !Iter.second; + Optional Result = getValueFromConditionImpl( + Val, CurrentCond, isTrueDest, isRevisit, Visited, Worklist); + if (Result) { + Visited[CurrentCond] = *Result; + Worklist.pop_back(); + } + } while (!Worklist.empty()); + + auto Result = Visited.find(Cond); + assert(Result != Visited.end()); + return Result->second; } // Return true if Usr has Op as an operand, otherwise false.