Disable redundent assign eliminator for deeply nested loops.

This commit is contained in:
chriseth 2019-04-23 09:49:16 +02:00
parent 4312f6ec23
commit aad4373da4
4 changed files with 202 additions and 10 deletions

View File

@ -117,13 +117,13 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
{
ForLoopInfo outerForLoopInfo;
swap(outerForLoopInfo, m_forLoopInfo);
++m_forLoopNestingDepth;
// If the pre block was not empty,
// we would have to deal with more complicated scoping rules.
assertThrow(_forLoop.pre.statements.empty(), OptimizerException, "");
// We just run the loop twice to account for the
// back edge.
// We just run the loop twice to account for the back edge.
// There need not be more runs because we only have three different states.
visit(*_forLoop.condition);
@ -137,24 +137,46 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
visit(*_forLoop.condition);
TrackedAssignments oneRun{m_assignments};
if (m_forLoopNestingDepth < 6)
{
// Do the second run only for small nesting depths to avoid horrible runtime.
TrackedAssignments oneRun{m_assignments};
(*this)(_forLoop.body);
(*this)(_forLoop.body);
merge(m_assignments, move(m_forLoopInfo.pendingContinueStmts));
m_forLoopInfo.pendingContinueStmts.clear();
(*this)(_forLoop.post);
merge(m_assignments, move(m_forLoopInfo.pendingContinueStmts));
m_forLoopInfo.pendingContinueStmts.clear();
(*this)(_forLoop.post);
visit(*_forLoop.condition);
visit(*_forLoop.condition);
// Order of merging does not matter because "max" is commutative and associative.
merge(m_assignments, move(oneRun));
}
else
{
// Shortcut to avoid horrible runtime:
// Change all assignments that were newly introduced in the for loop to "used".
// We do not have to do that with the "break" or "continue" paths, because
// they will be joined later anyway.
// TODO parallel traversal might be more efficient here.
for (auto& var: m_assignments)
for (auto& assignment: var.second)
{
auto zeroIt = zeroRuns.find(var.first);
if (zeroIt != zeroRuns.end() && zeroIt->second.count(assignment.first))
continue;
assignment.second = State::Value::Used;
}
}
// Order does not matter because "max" is commutative and associative.
merge(m_assignments, move(oneRun));
// Order of merging does not matter because "max" is commutative and associative.
merge(m_assignments, move(zeroRuns));
merge(m_assignments, move(m_forLoopInfo.pendingBreakStmts));
m_forLoopInfo.pendingBreakStmts.clear();
// Restore potential outer for-loop states.
swap(m_forLoopInfo, outerForLoopInfo);
--m_forLoopNestingDepth;
}
void RedundantAssignEliminator::operator()(Break const&)

View File

@ -82,6 +82,11 @@ struct Dialect;
* one run and two runs and then combine them at the end.
* Running at most twice is enough because there are only three different states.
*
* Since this algorithm has exponential runtime in the nesting depth of for loops,
* a shortcut is taken at a certain nesting level: We only use the zero- and
* once-run of the for loop and change any assignment that was newly introduced
* in the for loop from to "used".
*
* For switch statements that have a "default"-case, there is no control-flow
* part that skips the switch.
*
@ -168,6 +173,7 @@ private:
std::vector<TrackedAssignments> pendingContinueStmts;
};
ForLoopInfo m_forLoopInfo;
size_t m_forLoopNestingDepth = 0;
};
class AssignmentRemover: public ASTModifier

View File

@ -0,0 +1,88 @@
{
let x := 1
let y := 2
let a := 3
let b := 4
for {} 1 {} {
for {} 1 {} {
for {} 1 {} {
// Here, the nesting is not yet too deep, so the assignment
// should be removed.
for {} 1 { x := 9 } {
y := 10
for {} 1 {} {
for {} 1 {} {
// Now we are too deep, assignments stay.
for {} 1 { a := 10 } {
b := 12
b := 11
}
}
}
}
}
}
}
x := 13
}
// ====
// step: redundantAssignEliminator
// ----
// {
// let x := 1
// let y := 2
// let a := 3
// let b := 4
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// a := 10
// }
// {
// b := 12
// b := 11
// }
// }
// }
// }
// }
// }
// }
// }

View File

@ -0,0 +1,76 @@
{
for {} 1 {} {
for {} 1 {} {
for {} 1 {} {
for {} 1 {} {
for {} 1 {} {
for {} 1 {} {
for {} 1 { let a := 1 a := 2 a := 3 } {
// Declarations inside body and post should be handled as normal.
let b := 1
b := 2
b := 3
}
}
}
}
}
}
}
}
// ====
// step: redundantAssignEliminator
// ----
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// }
// {
// for {
// }
// 1
// {
// let a := 1
// }
// {
// let b := 1
// }
// }
// }
// }
// }
// }
// }
// }