1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 04:02:41 +01:00

[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
This commit is contained in:
Carl Ritson 2021-06-24 09:36:58 +09:00
parent e702056af0
commit 45b4219826

View File

@ -1151,20 +1151,20 @@ static ValueLatticeElement getValueFromOverflowCondition(
return ValueLatticeElement::getRange(NWR); return ValueLatticeElement::getRange(NWR);
} }
static ValueLatticeElement static Optional<ValueLatticeElement>
getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest,
SmallDenseMap<Value*, ValueLatticeElement> &Visited);
static ValueLatticeElement
getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest, getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
SmallDenseMap<Value*, ValueLatticeElement> &Visited) { bool isRevisit,
if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond)) SmallDenseMap<Value *, ValueLatticeElement> &Visited,
return getValueFromICmpCondition(Val, ICI, isTrueDest); SmallVectorImpl<Value *> &Worklist) {
if (!isRevisit) {
if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
return getValueFromICmpCondition(Val, ICI, isTrueDest);
if (auto *EVI = dyn_cast<ExtractValueInst>(Cond)) if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand())) if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1) if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
return getValueFromOverflowCondition(Val, WO, isTrueDest); return getValueFromOverflowCondition(Val, WO, isTrueDest);
}
Value *L, *R; Value *L, *R;
bool IsAnd; bool IsAnd;
@ -1175,44 +1175,63 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
else else
return ValueLatticeElement::getOverdefined(); 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)) -> 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 (!(L && R)) -> union L and R // if (!(L && R)) -> union L and R
if (isTrueDest ^ IsAnd) { if ((isTrueDest ^ IsAnd) && (LV != Visited.end())) {
ValueLatticeElement V = getValueFromCondition(Val, L, isTrueDest, Visited); ValueLatticeElement V = LV->second;
if (V.isOverdefined()) if (V.isOverdefined())
return V; return V;
V.mergeIn(getValueFromCondition(Val, R, isTrueDest, Visited)); if (RV != Visited.end()) {
return V; V.mergeIn(RV->second);
return V;
}
} }
return intersect(getValueFromCondition(Val, L, isTrueDest, Visited), if (LV == Visited.end() || RV == Visited.end()) {
getValueFromCondition(Val, R, isTrueDest, Visited)); assert(!isRevisit);
} if (LV == Visited.end())
Worklist.push_back(L);
if (RV == Visited.end())
Worklist.push_back(R);
return None;
}
static ValueLatticeElement return intersect(LV->second, RV->second);
getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest,
SmallDenseMap<Value*, ValueLatticeElement> &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;
} }
ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond, ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond,
bool isTrueDest) { bool isTrueDest) {
assert(Cond && "precondition"); assert(Cond && "precondition");
SmallDenseMap<Value*, ValueLatticeElement> Visited; SmallDenseMap<Value*, ValueLatticeElement> Visited;
return getValueFromCondition(Val, Cond, isTrueDest, Visited); SmallVector<Value *> 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<ValueLatticeElement> 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. // Return true if Usr has Op as an operand, otherwise false.