mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
More logic about control flow with continue and about finalize. Remove BlockScope.
This commit is contained in:
parent
a1ec49409d
commit
91f96c299e
@ -97,31 +97,30 @@ void RedundantAssignEliminator::operator()(FunctionDefinition const& _functionDe
|
|||||||
{
|
{
|
||||||
std::set<YulString> outerDeclaredVariables;
|
std::set<YulString> outerDeclaredVariables;
|
||||||
TrackedAssignments outerAssignments;
|
TrackedAssignments outerAssignments;
|
||||||
|
ForLoopInfo forLoopInfo;
|
||||||
swap(m_declaredVariables, outerDeclaredVariables);
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
swap(m_assignments, outerAssignments);
|
swap(m_assignments, outerAssignments);
|
||||||
|
swap(m_forLoopInfo, forLoopInfo);
|
||||||
|
|
||||||
(*this)(_functionDefinition.body);
|
(*this)(_functionDefinition.body);
|
||||||
|
|
||||||
for (auto const& param: _functionDefinition.parameters)
|
for (auto const& param: _functionDefinition.parameters)
|
||||||
{
|
finalize(param.name, State::Unused);
|
||||||
changeUndecidedTo(param.name, State::Unused);
|
|
||||||
finalize(param.name);
|
|
||||||
}
|
|
||||||
for (auto const& retParam: _functionDefinition.returnVariables)
|
for (auto const& retParam: _functionDefinition.returnVariables)
|
||||||
{
|
finalize(retParam.name, State::Used);
|
||||||
changeUndecidedTo(retParam.name, State::Used);
|
|
||||||
finalize(retParam.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
swap(m_declaredVariables, outerDeclaredVariables);
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
swap(m_assignments, outerAssignments);
|
swap(m_assignments, outerAssignments);
|
||||||
|
swap(m_forLoopInfo, forLoopInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
|
void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
|
||||||
{
|
{
|
||||||
// This will set all variables that are declared in this
|
ForLoopInfo outerForLoopInfo;
|
||||||
// block to "unused" when it is destroyed.
|
swap(outerForLoopInfo, m_forLoopInfo);
|
||||||
BlockScope scope(*this);
|
|
||||||
|
set<YulString> outerDeclaredVariables;
|
||||||
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
|
|
||||||
// We need to visit the statements directly because of the
|
// We need to visit the statements directly because of the
|
||||||
// scoping rules.
|
// scoping rules.
|
||||||
@ -133,9 +132,6 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
|
|||||||
|
|
||||||
visit(*_forLoop.condition);
|
visit(*_forLoop.condition);
|
||||||
|
|
||||||
ForLoopInfo outerForLoopInfo;
|
|
||||||
swap(outerForLoopInfo, m_forLoopInfo);
|
|
||||||
|
|
||||||
TrackedAssignments zeroRuns{m_assignments};
|
TrackedAssignments zeroRuns{m_assignments};
|
||||||
|
|
||||||
(*this)(_forLoop.body);
|
(*this)(_forLoop.body);
|
||||||
@ -150,6 +146,7 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
|
|||||||
(*this)(_forLoop.body);
|
(*this)(_forLoop.body);
|
||||||
|
|
||||||
merge(m_assignments, move(m_forLoopInfo.pendingContinueStmts));
|
merge(m_assignments, move(m_forLoopInfo.pendingContinueStmts));
|
||||||
|
m_forLoopInfo.pendingContinueStmts.clear();
|
||||||
(*this)(_forLoop.post);
|
(*this)(_forLoop.post);
|
||||||
|
|
||||||
visit(*_forLoop.condition);
|
visit(*_forLoop.condition);
|
||||||
@ -158,28 +155,39 @@ void RedundantAssignEliminator::operator()(ForLoop const& _forLoop)
|
|||||||
merge(m_assignments, move(oneRun));
|
merge(m_assignments, move(oneRun));
|
||||||
merge(m_assignments, move(zeroRuns));
|
merge(m_assignments, move(zeroRuns));
|
||||||
merge(m_assignments, move(m_forLoopInfo.pendingBreakStmts));
|
merge(m_assignments, move(m_forLoopInfo.pendingBreakStmts));
|
||||||
|
m_forLoopInfo.pendingBreakStmts.clear();
|
||||||
|
|
||||||
// Oestore potential outer for-loop states.
|
for (auto const& var: m_declaredVariables)
|
||||||
|
finalize(var, State::Unused);
|
||||||
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
|
|
||||||
|
// Restore potential outer for-loop states.
|
||||||
swap(m_forLoopInfo, outerForLoopInfo);
|
swap(m_forLoopInfo, outerForLoopInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Break const&)
|
void RedundantAssignEliminator::operator()(Break const&)
|
||||||
{
|
{
|
||||||
m_forLoopInfo.pendingBreakStmts.push_back(m_assignments);
|
m_forLoopInfo.pendingBreakStmts.emplace_back(move(m_assignments));
|
||||||
|
m_assignments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Continue const&)
|
void RedundantAssignEliminator::operator()(Continue const&)
|
||||||
{
|
{
|
||||||
m_forLoopInfo.pendingContinueStmts.push_back(m_assignments);
|
m_forLoopInfo.pendingContinueStmts.emplace_back(move(m_assignments));
|
||||||
|
m_assignments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::operator()(Block const& _block)
|
void RedundantAssignEliminator::operator()(Block const& _block)
|
||||||
{
|
{
|
||||||
// This will set all variables that are declared in this
|
set<YulString> outerDeclaredVariables;
|
||||||
// block to "unused" when it is destroyed.
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
BlockScope scope(*this);
|
|
||||||
|
|
||||||
ASTWalker::operator()(_block);
|
ASTWalker::operator()(_block);
|
||||||
|
|
||||||
|
for (auto const& var: m_declaredVariables)
|
||||||
|
finalize(var, State::Unused);
|
||||||
|
|
||||||
|
swap(m_declaredVariables, outerDeclaredVariables);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::run(Dialect const& _dialect, Block& _ast)
|
void RedundantAssignEliminator::run(Dialect const& _dialect, Block& _ast)
|
||||||
@ -239,21 +247,35 @@ void RedundantAssignEliminator::merge(TrackedAssignments& _target, vector<Tracke
|
|||||||
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
|
void RedundantAssignEliminator::changeUndecidedTo(YulString _variable, RedundantAssignEliminator::State _newState)
|
||||||
{
|
{
|
||||||
for (auto& assignment: m_assignments[_variable])
|
for (auto& assignment: m_assignments[_variable])
|
||||||
if (assignment.second == State{State::Undecided})
|
if (assignment.second == State::Undecided)
|
||||||
assignment.second = _newState;
|
assignment.second = _newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RedundantAssignEliminator::finalize(YulString _variable)
|
void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEliminator::State _finalState)
|
||||||
{
|
{
|
||||||
for (auto& assignment: m_assignments[_variable])
|
finalize(m_assignments, _variable, _finalState);
|
||||||
|
for (auto& assignments: m_forLoopInfo.pendingBreakStmts)
|
||||||
|
finalize(assignments, _variable, _finalState);
|
||||||
|
for (auto& assignments: m_forLoopInfo.pendingContinueStmts)
|
||||||
|
finalize(assignments, _variable, _finalState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RedundantAssignEliminator::finalize(
|
||||||
|
TrackedAssignments& _assignments,
|
||||||
|
YulString _variable,
|
||||||
|
RedundantAssignEliminator::State _finalState
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto const& assignment: _assignments[_variable])
|
||||||
{
|
{
|
||||||
assertThrow(assignment.second != State::Undecided, OptimizerException, "");
|
State const state = assignment.second == State::Undecided ? _finalState : assignment.second;
|
||||||
if (assignment.second == State{State::Unused} && MovableChecker{*m_dialect, *assignment.first->value}.movable())
|
|
||||||
|
if (state == State::Unused && MovableChecker{*m_dialect, *assignment.first->value}.movable())
|
||||||
// TODO the only point where we actually need this
|
// TODO the only point where we actually need this
|
||||||
// to be a set is for the for loop
|
// to be a set is for the for loop
|
||||||
m_pendingRemovals.insert(assignment.first);
|
m_pendingRemovals.insert(assignment.first);
|
||||||
}
|
}
|
||||||
m_assignments.erase(_variable);
|
_assignments.erase(_variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignmentRemover::operator()(Block& _block)
|
void AssignmentRemover::operator()(Block& _block)
|
||||||
|
@ -137,33 +137,6 @@ private:
|
|||||||
Value m_value = Undecided;
|
Value m_value = Undecided;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes care about storing the list of declared variables and
|
|
||||||
* sets them to "unused" when it is destroyed.
|
|
||||||
*/
|
|
||||||
class BlockScope
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit BlockScope(RedundantAssignEliminator& _rae): m_rae(_rae)
|
|
||||||
{
|
|
||||||
swap(m_rae.m_declaredVariables, m_outerDeclaredVariables);
|
|
||||||
}
|
|
||||||
~BlockScope()
|
|
||||||
{
|
|
||||||
// This should actually store all declared variables
|
|
||||||
// into a different mapping
|
|
||||||
for (auto const& var: m_rae.m_declaredVariables)
|
|
||||||
m_rae.changeUndecidedTo(var, State::Unused);
|
|
||||||
for (auto const& var: m_rae.m_declaredVariables)
|
|
||||||
m_rae.finalize(var);
|
|
||||||
swap(m_rae.m_declaredVariables, m_outerDeclaredVariables);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RedundantAssignEliminator& m_rae;
|
|
||||||
std::set<YulString> m_outerDeclaredVariables;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO check that this does not cause nondeterminism!
|
// TODO check that this does not cause nondeterminism!
|
||||||
// This could also be a pseudo-map from state to assignment.
|
// This could also be a pseudo-map from state to assignment.
|
||||||
using TrackedAssignments = std::map<YulString, std::map<Assignment const*, State>>;
|
using TrackedAssignments = std::map<YulString, std::map<Assignment const*, State>>;
|
||||||
@ -174,7 +147,12 @@ private:
|
|||||||
static void merge(TrackedAssignments& _target, TrackedAssignments&& _source);
|
static void merge(TrackedAssignments& _target, TrackedAssignments&& _source);
|
||||||
static void merge(TrackedAssignments& _target, std::vector<TrackedAssignments>&& _source);
|
static void merge(TrackedAssignments& _target, std::vector<TrackedAssignments>&& _source);
|
||||||
void changeUndecidedTo(YulString _variable, State _newState);
|
void changeUndecidedTo(YulString _variable, State _newState);
|
||||||
void finalize(YulString _variable);
|
/// Called when a variable goes out of scope. Sets the state of all still undecided
|
||||||
|
/// assignments to the final state. In this case, this also applies to pending
|
||||||
|
/// break and continue TrackedAssignments.
|
||||||
|
void finalize(YulString _variable, State _finalState);
|
||||||
|
/// Helper function for the above.
|
||||||
|
void finalize(TrackedAssignments& _assignments, YulString _variable, State _finalState);
|
||||||
|
|
||||||
Dialect const* m_dialect;
|
Dialect const* m_dialect;
|
||||||
std::set<YulString> m_declaredVariables;
|
std::set<YulString> m_declaredVariables;
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
{
|
{
|
||||||
// Cannot be removed, because we might run the loop only once
|
let x
|
||||||
let x := 1
|
// Cannot be removed, because we might skip the loop
|
||||||
for { } calldataload(0) { }
|
x := 1
|
||||||
{
|
for { } calldataload(0) { }
|
||||||
if callvalue() {
|
{
|
||||||
x := 2 // is preserved because of break stmt below.
|
if callvalue() {
|
||||||
break
|
x := 2 // is preserved because of break stmt below.
|
||||||
}
|
break
|
||||||
x := 3
|
}
|
||||||
}
|
x := 3
|
||||||
mstore(x, 0x42)
|
}
|
||||||
|
mstore(x, 0x42)
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// redundantAssignEliminator
|
// redundantAssignEliminator
|
||||||
// {
|
// {
|
||||||
// let x := 1
|
// let x
|
||||||
|
// x := 1
|
||||||
// for {
|
// for {
|
||||||
// }
|
// }
|
||||||
// calldataload(0)
|
// calldataload(0)
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
{
|
{
|
||||||
// Cannot be removed, because we might run the loop only once
|
let x
|
||||||
let x := 1
|
// Can be removed, because x is reassigned after the loop
|
||||||
for { } calldataload(0) { }
|
x := 1
|
||||||
{
|
for { } calldataload(0) { }
|
||||||
x := 2 // Will not be removed as if-condition can be false.
|
{
|
||||||
if callvalue() {
|
x := 2 // Will not be removed as if-condition can be false.
|
||||||
x := 3
|
if callvalue() {
|
||||||
continue
|
// This can be removed because x is overwritten both after the
|
||||||
}
|
// loop at at the start of the next iteration.
|
||||||
mstore(x, 2)
|
x := 3
|
||||||
}
|
continue
|
||||||
x := 3
|
}
|
||||||
|
mstore(x, 2)
|
||||||
|
}
|
||||||
|
x := 3
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// redundantAssignEliminator
|
// redundantAssignEliminator
|
||||||
// {
|
// {
|
||||||
// let x := 1
|
// let x
|
||||||
// for {
|
// for {
|
||||||
// }
|
// }
|
||||||
// calldataload(0)
|
// calldataload(0)
|
||||||
@ -25,7 +28,6 @@
|
|||||||
// x := 2
|
// x := 2
|
||||||
// if callvalue()
|
// if callvalue()
|
||||||
// {
|
// {
|
||||||
// x := 3
|
|
||||||
// continue
|
// continue
|
||||||
// }
|
// }
|
||||||
// mstore(x, 2)
|
// mstore(x, 2)
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
{
|
{
|
||||||
// Cannot be removed, because we might run the loop only once
|
let x
|
||||||
let x := 1
|
// Cannot be removed, because we might skip the loop
|
||||||
for { } calldataload(0) { }
|
x := 1
|
||||||
{
|
for { } calldataload(0) { }
|
||||||
if callvalue() {
|
{
|
||||||
x := 2 // is preserved because of continue stmt below.
|
if callvalue() {
|
||||||
continue
|
x := 2 // is preserved because of continue stmt below.
|
||||||
}
|
continue
|
||||||
x := 3
|
}
|
||||||
}
|
x := 3
|
||||||
mstore(x, 0x42)
|
}
|
||||||
|
mstore(x, 0x42)
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// redundantAssignEliminator
|
// redundantAssignEliminator
|
||||||
// {
|
// {
|
||||||
// let x := 1
|
// let x
|
||||||
|
// x := 1
|
||||||
// for {
|
// for {
|
||||||
// }
|
// }
|
||||||
// calldataload(0)
|
// calldataload(0)
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
{
|
{
|
||||||
// Cannot be removed, because we might run the loop only once
|
let x
|
||||||
let x := 1
|
// Can be removed, because x is not used after the loop.
|
||||||
for { } calldataload(0) { mstore(x, 0x42) }
|
x := 1
|
||||||
{
|
for { } calldataload(0) { mstore(x, 0x42) }
|
||||||
if callvalue() {
|
{
|
||||||
x := 2 // is preserved because of continue stmt below.
|
if callvalue() {
|
||||||
continue
|
x := 2 // is preserved because of continue stmt below.
|
||||||
}
|
continue
|
||||||
x := 3
|
}
|
||||||
}
|
x := 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// redundantAssignEliminator
|
// redundantAssignEliminator
|
||||||
// {
|
// {
|
||||||
// let x := 1
|
// let x
|
||||||
// for {
|
// for {
|
||||||
// }
|
// }
|
||||||
// calldataload(0)
|
// calldataload(0)
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
let x := 1
|
||||||
|
for { } calldataload(0) { }
|
||||||
|
{
|
||||||
|
// This will go out of scope at the end of the block,
|
||||||
|
// but the continue/break statements still refer to it.
|
||||||
|
{
|
||||||
|
let y := 9
|
||||||
|
if callvalue() {
|
||||||
|
y := 2 // will be removed
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if eq(callvalue(), 3) {
|
||||||
|
y := 12 // will be removed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mstore(x, 0x42)
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// redundantAssignEliminator
|
||||||
|
// {
|
||||||
|
// let x := 1
|
||||||
|
// for {
|
||||||
|
// }
|
||||||
|
// calldataload(0)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// {
|
||||||
|
// let y := 9
|
||||||
|
// if callvalue()
|
||||||
|
// {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// if eq(callvalue(), 3)
|
||||||
|
// {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// mstore(x, 0x42)
|
||||||
|
// }
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
let x := 1
|
||||||
|
let y := 1
|
||||||
|
let z := 1
|
||||||
|
for { } calldataload(0) { mstore(x, 2) mstore(z, 2) }
|
||||||
|
{
|
||||||
|
y := 3
|
||||||
|
switch callvalue()
|
||||||
|
case 0 {
|
||||||
|
x := 2
|
||||||
|
y := 2
|
||||||
|
z := 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 1 {
|
||||||
|
x := 3
|
||||||
|
y := 3
|
||||||
|
z := 3
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case 2 {
|
||||||
|
x := 4
|
||||||
|
y := 4
|
||||||
|
z := 4
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 3 {
|
||||||
|
x := 5
|
||||||
|
y := 5
|
||||||
|
z := 5
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mstore(y, 9)
|
||||||
|
}
|
||||||
|
mstore(x, 0x42)
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// redundantAssignEliminator
|
||||||
|
// {
|
||||||
|
// let x := 1
|
||||||
|
// let y := 1
|
||||||
|
// let z := 1
|
||||||
|
// for {
|
||||||
|
// }
|
||||||
|
// calldataload(0)
|
||||||
|
// {
|
||||||
|
// mstore(x, 2)
|
||||||
|
// mstore(z, 2)
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// y := 3
|
||||||
|
// switch callvalue()
|
||||||
|
// case 0 {
|
||||||
|
// x := 2
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// case 1 {
|
||||||
|
// x := 3
|
||||||
|
// z := 3
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// case 2 {
|
||||||
|
// x := 4
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// case 3 {
|
||||||
|
// x := 5
|
||||||
|
// z := 5
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// mstore(y, 9)
|
||||||
|
// }
|
||||||
|
// mstore(x, 0x42)
|
||||||
|
// }
|
@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
let x := 1
|
||||||
|
let y := 1
|
||||||
|
let a := 7
|
||||||
|
let b := 9
|
||||||
|
for { } calldataload(0) { }
|
||||||
|
{
|
||||||
|
y := 9
|
||||||
|
mstore(a, 7)
|
||||||
|
if callvalue() {
|
||||||
|
x := 2
|
||||||
|
for {} calldataload(1) {}
|
||||||
|
{
|
||||||
|
a := 2 // can be removed
|
||||||
|
if eq(x, 3) {
|
||||||
|
b := 3 // cannot be removed
|
||||||
|
y := 2 // will be removed
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mstore(b, 2)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if eq(callvalue(), 3) {
|
||||||
|
x := 12
|
||||||
|
y := 12
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
x := 3
|
||||||
|
mstore(y, 3)
|
||||||
|
}
|
||||||
|
mstore(x, 0x42)
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// redundantAssignEliminator
|
||||||
|
// {
|
||||||
|
// let x := 1
|
||||||
|
// let y := 1
|
||||||
|
// let a := 7
|
||||||
|
// let b := 9
|
||||||
|
// for {
|
||||||
|
// }
|
||||||
|
// calldataload(0)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// y := 9
|
||||||
|
// mstore(a, 7)
|
||||||
|
// if callvalue()
|
||||||
|
// {
|
||||||
|
// x := 2
|
||||||
|
// for {
|
||||||
|
// }
|
||||||
|
// calldataload(1)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// if eq(x, 3)
|
||||||
|
// {
|
||||||
|
// b := 3
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// mstore(b, 2)
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// if eq(callvalue(), 3)
|
||||||
|
// {
|
||||||
|
// x := 12
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// x := 3
|
||||||
|
// mstore(y, 3)
|
||||||
|
// }
|
||||||
|
// mstore(x, 0x42)
|
||||||
|
// }
|
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
let x := 1
|
||||||
|
let y := 1
|
||||||
|
for { } calldataload(0) { }
|
||||||
|
{
|
||||||
|
y := 9
|
||||||
|
if callvalue() {
|
||||||
|
x := 2
|
||||||
|
y := 2 // will be removed
|
||||||
|
break
|
||||||
|
x := 7 // after break, we start with fresh state.
|
||||||
|
}
|
||||||
|
if eq(callvalue(), 3) {
|
||||||
|
x := 12
|
||||||
|
y := 12 // will be removed
|
||||||
|
continue
|
||||||
|
x := 17 // after continue, we start with fresh state.
|
||||||
|
y := 9
|
||||||
|
}
|
||||||
|
x := 3
|
||||||
|
mstore(y, 3)
|
||||||
|
}
|
||||||
|
mstore(x, 0x42)
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// redundantAssignEliminator
|
||||||
|
// {
|
||||||
|
// let x := 1
|
||||||
|
// let y := 1
|
||||||
|
// for {
|
||||||
|
// }
|
||||||
|
// calldataload(0)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// {
|
||||||
|
// y := 9
|
||||||
|
// if callvalue()
|
||||||
|
// {
|
||||||
|
// x := 2
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// if eq(callvalue(), 3)
|
||||||
|
// {
|
||||||
|
// x := 12
|
||||||
|
// continue
|
||||||
|
// y := 9
|
||||||
|
// }
|
||||||
|
// x := 3
|
||||||
|
// mstore(y, 3)
|
||||||
|
// }
|
||||||
|
// mstore(x, 0x42)
|
||||||
|
// }
|
Loading…
Reference in New Issue
Block a user