[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 ab244db1fa
commit ae266e743c
1 changed files with 54 additions and 35 deletions

View File

@ -1151,20 +1151,20 @@ static ValueLatticeElement getValueFromOverflowCondition(
return ValueLatticeElement::getRange(NWR);
}
static ValueLatticeElement
getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest,
SmallDenseMap<Value*, ValueLatticeElement> &Visited);
static ValueLatticeElement
static Optional<ValueLatticeElement>
getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
SmallDenseMap<Value*, ValueLatticeElement> &Visited) {
if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
return getValueFromICmpCondition(Val, ICI, isTrueDest);
bool isRevisit,
SmallDenseMap<Value *, ValueLatticeElement> &Visited,
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 *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
return getValueFromOverflowCondition(Val, WO, isTrueDest);
if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
if (auto *WO = dyn_cast<WithOverflowInst>(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<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;
return intersect(LV->second, RV->second);
}
ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond,
bool isTrueDest) {
assert(Cond && "precondition");
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.