Yul] RedundantAssignEliminator: Implements break/continue handling within ForLoop.

This commit is contained in:
Christian Parpart 2019-03-18 17:43:28 +01:00 committed by chriseth
parent d8c42a0270
commit a1ec49409d
6 changed files with 160 additions and 2 deletions

View File

@ -133,9 +133,14 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
visit(*_forLoop.condition);
ForLoopInfo outerForLoopInfo;
swap(outerForLoopInfo, m_forLoopInfo);
TrackedAssignments zeroRuns{m_assignments};
(*this)(_forLoop.body);
merge(m_assignments, move(m_forLoopInfo.pendingContinueStmts));
m_forLoopInfo.pendingContinueStmts = {};
(*this)(_forLoop.post);
visit(*_forLoop.condition);
@ -143,6 +148,8 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
TrackedAssignments oneRun{m_assignments};
(*this)(_forLoop.body);
merge(m_assignments, move(m_forLoopInfo.pendingContinueStmts));
(*this)(_forLoop.post);
visit(*_forLoop.condition);
@ -150,16 +157,20 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
// Order does not matter because "max" is commutative and associative.
merge(m_assignments, move(oneRun));
merge(m_assignments, move(zeroRuns));
merge(m_assignments, move(m_forLoopInfo.pendingBreakStmts));
// Oestore potential outer for-loop states.
swap(m_forLoopInfo, outerForLoopInfo);
}
void RedundantAssignEliminator::operator()(Break const&)
{
yulAssert(false, "Not implemented yet.");
m_forLoopInfo.pendingBreakStmts.push_back(m_assignments);
}
void RedundantAssignEliminator::operator()(Continue const&)
{
yulAssert(false, "Not implemented yet.");
m_forLoopInfo.pendingContinueStmts.push_back(m_assignments);
}
void RedundantAssignEliminator::operator()(Block const& _block)
@ -218,6 +229,13 @@ void RedundantAssignEliminator::merge(TrackedAssignments& _target, TrackedAssign
});
}
void RedundantAssignEliminator::merge(TrackedAssignments& _target, vector<TrackedAssignments>&& _source)
{
for (TrackedAssignments& ts: _source)
merge(_target, move(ts));
_source.clear();
}
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
{
for (auto& assignment: m_assignments[_variable])

View File

@ -25,6 +25,7 @@
#include <libyul/optimiser/ASTWalker.h>
#include <map>
#include <vector>
namespace yul
{
@ -171,6 +172,7 @@ private:
/// above.
/// Will destroy @a _source.
static void merge(TrackedAssignments& _target, TrackedAssignments&& _source);
static void merge(TrackedAssignments& _target, std::vector<TrackedAssignments>&& _source);
void changeUndecidedTo(YulString _variable, State _newState);
void finalize(YulString _variable);
@ -178,6 +180,16 @@ private:
std::set<YulString> m_declaredVariables;
std::set<Assignment const*> m_pendingRemovals;
TrackedAssignments m_assignments;
/// Working data for traversing for-loops.
struct ForLoopInfo
{
/// Tracked assignment states for each break statement.
std::vector<TrackedAssignments> pendingBreakStmts;
/// Tracked assignment states for each continue statement.
std::vector<TrackedAssignments> pendingContinueStmts;
};
ForLoopInfo m_forLoopInfo;
};
class AssignmentRemover: public ASTModifier

View File

@ -0,0 +1,32 @@
{
// Cannot be removed, because we might run the loop only once
let x := 1
for { } calldataload(0) { }
{
if callvalue() {
x := 2 // is preserved because of break stmt below.
break
}
x := 3
}
mstore(x, 0x42)
}
// ----
// redundantAssignEliminator
// {
// let x := 1
// for {
// }
// calldataload(0)
// {
// }
// {
// if callvalue()
// {
// x := 2
// break
// }
// x := 3
// }
// mstore(x, 0x42)
// }

View File

@ -0,0 +1,33 @@
{
// Cannot be removed, because we might run the loop only once
let x := 1
for { } calldataload(0) { }
{
x := 2 // Will not be removed as if-condition can be false.
if callvalue() {
x := 3
continue
}
mstore(x, 2)
}
x := 3
}
// ----
// redundantAssignEliminator
// {
// let x := 1
// for {
// }
// calldataload(0)
// {
// }
// {
// x := 2
// if callvalue()
// {
// x := 3
// continue
// }
// mstore(x, 2)
// }
// }

View File

@ -0,0 +1,32 @@
{
// Cannot be removed, because we might run the loop only once
let x := 1
for { } calldataload(0) { }
{
if callvalue() {
x := 2 // is preserved because of continue stmt below.
continue
}
x := 3
}
mstore(x, 0x42)
}
// ----
// redundantAssignEliminator
// {
// let x := 1
// for {
// }
// calldataload(0)
// {
// }
// {
// if callvalue()
// {
// x := 2
// continue
// }
// x := 3
// }
// mstore(x, 0x42)
// }

View File

@ -0,0 +1,31 @@
{
// Cannot be removed, because we might run the loop only once
let x := 1
for { } calldataload(0) { mstore(x, 0x42) }
{
if callvalue() {
x := 2 // is preserved because of continue stmt below.
continue
}
x := 3
}
}
// ----
// redundantAssignEliminator
// {
// let x := 1
// for {
// }
// calldataload(0)
// {
// mstore(x, 0x42)
// }
// {
// if callvalue()
// {
// x := 2
// continue
// }
// x := 3
// }
// }