Prototype of a full SSA transformation.

This commit is contained in:
Daniel Kirchner 2021-01-06 20:21:42 +01:00
parent 591f04e41c
commit dab68e6254
36 changed files with 1263 additions and 3 deletions

View File

@ -125,6 +125,10 @@ add_library(yul
optimiser/ForLoopInitRewriter.h
optimiser/FullInliner.cpp
optimiser/FullInliner.h
optimiser/FullSSAReverse.cpp
optimiser/FullSSAReverse.h
optimiser/FullSSATransform.cpp
optimiser/FullSSATransform.h
optimiser/FunctionCallFinder.cpp
optimiser/FunctionCallFinder.h
optimiser/FunctionGrouper.cpp

View File

@ -150,6 +150,38 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
builtins.emplace(createEVMFunction(name, opcode));
}
builtins.emplace(createFunction(
"phi_store",
2,
0,
SideEffects{false, false, false, false, true, SideEffects::None, SideEffects::None, SideEffects::None},
{LiteralKind::String, nullopt},
[](
FunctionCall const&,
AbstractAssembly&,
BuiltinContext&,
std::function<void(Expression const&)>
) {
yulAssert(false, "leftover phi_store");
}
));
builtins.emplace(createFunction(
"phi_load",
1,
1,
SideEffects{},
{LiteralKind::String},
[](
FunctionCall const&,
AbstractAssembly&,
BuiltinContext&,
std::function<void(Expression const&)>
) {
yulAssert(false, "leftover phi_load");
}
));
if (_objectAccess)
{
builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, [](

View File

@ -1,4 +1,4 @@
/*(
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify

View File

@ -0,0 +1,134 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libyul/optimiser/FullSSAReverse.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/NameDispenser.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/AST.h>
#include <libyul/Dialect.h>
#include <libyul/Exceptions.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/Visitor.h>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
#include <variant>
using namespace std;
using namespace solidity;
using namespace solidity::util;
using namespace solidity::yul;
class FullSSAReverseLoad: public ASTCopier
{
public:
FullSSAReverseLoad(std::map<YulString, YulString> const& _variableNames): m_variableNames(_variableNames) {}
Expression operator()(FunctionCall const& _funCall) override
{
if (_funCall.functionName.name == "phi_load"_yulstring)
{
yulAssert(_funCall.arguments.size() == 1, "");
Literal const* literal = std::get_if<Literal>(&_funCall.arguments.front());
yulAssert(literal && literal->kind == LiteralKind::String, "");
yulAssert(m_variableNames.count(literal->value), "");
return Identifier{
_funCall.location,
m_variableNames.at(literal->value)
};
}
return ASTCopier::operator()(_funCall);
}
private:
map<YulString, YulString> const& m_variableNames;
};
void FullSSAReverse::run(OptimiserStepContext& _context, Block& _ast)
{
FullSSAReverse fullSSAReverse{_context.dispenser};
fullSSAReverse(_ast);
_ast = FullSSAReverseLoad{fullSSAReverse.m_variableNames}.translate(_ast);
}
void FullSSAReverse::operator()(Block& _block)
{
util::iterateReplacing(
_block.statements,
[&](Statement& _stmt) -> std::optional<vector<Statement>>
{
if (auto* expressionStatement = std::get_if<ExpressionStatement>(&_stmt))
if (auto* functionCall = std::get_if<FunctionCall>(&expressionStatement->expression))
if (functionCall->functionName.name == "phi_store"_yulstring)
{
yulAssert(functionCall->arguments.size() == 2, "");
Literal const* literal = std::get_if<Literal>(&functionCall->arguments.front());
yulAssert(literal && literal->kind == LiteralKind::String, "");
vector<Statement> result;
if (m_variableNames.count(literal->value))
result.emplace_back(Assignment{
functionCall->location,
{Identifier{literal->location, m_variableNames.at(literal->value)}},
make_unique<Expression>(move(functionCall->arguments.back()))
});
else
{
YulString newName = m_nameDispenser.newName(literal->value);
m_variableNames[literal->value] = newName;
result.emplace_back(VariableDeclaration{
functionCall->location,
{TypedName{literal->location, newName, YulString{}}},
make_unique<Expression>(move(functionCall->arguments.back()))
});
}
return result;
}
visit(_stmt);
return {};
}
);
}
void FullSSAReverse::operator()(FunctionDefinition& _funDef)
{
set<YulString> oldFunctionReturns;
swap(m_currentFunctionReturns, oldFunctionReturns);
vector<Statement> bodyPrefix;
for (auto& var: _funDef.returnVariables)
{
YulString newName = m_nameDispenser.newName(var.name);
m_variableNames[var.name] = newName;
m_currentFunctionReturns.emplace(var.name);
bodyPrefix.emplace_back(VariableDeclaration{
var.location,
{var},
make_unique<Expression>(Identifier{var.location, newName})
});
var.name = newName;
}
bodyPrefix += std::move(_funDef.body.statements);
_funDef.body.statements = std::move(bodyPrefix);
ASTModifier::operator()(_funDef);
swap(m_currentFunctionReturns, oldFunctionReturns);
}

View File

@ -0,0 +1,52 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#pragma once
#include <libyul/optimiser/ASTWalker.h>
#include <libyul/optimiser/KnowledgeBase.h>
#include <libyul/optimiser/OptimiserStep.h>
#include <libyul/YulString.h>
#include <libyul/AST.h>
#include <libyul/SideEffects.h>
#include <libsolutil/InvertibleMap.h>
#include <map>
#include <set>
namespace solidity::yul
{
struct Dialect;
class FullSSAReverse: public ASTModifier
{
public:
static constexpr char const* name{"FullSSAReverse"};
static void run(OptimiserStepContext& _context, Block& _ast);
using ASTModifier::operator();
void operator()(Block& _block) override;
void operator()(FunctionDefinition& _funDef) override;
private:
FullSSAReverse(NameDispenser& _nameDispenser): m_nameDispenser(_nameDispenser) {}
NameDispenser& m_nameDispenser;
std::map<YulString, YulString> m_variableNames;
std::set<YulString> m_currentFunctionReturns;
};
}

View File

@ -0,0 +1,300 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libyul/optimiser/FullSSATransform.h>
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/NameDispenser.h>
#include <libyul/AST.h>
#include <libyul/Exceptions.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/Visitor.h>
#include <variant>
using namespace std;
using namespace solidity;
using namespace solidity::util;
using namespace solidity::yul;
void FullSSATransform::run(OptimiserStepContext& _context, Block& _ast)
{
FullSSATransform transform{_context};
transform(_ast);
}
FullSSATransform::FullSSATransform(OptimiserStepContext& _context): m_nameDispenser(_context.dispenser)
{
}
void FullSSATransform::operator()(VariableDeclaration& _varDecl)
{
ASTModifier::operator()(_varDecl);
for (auto const& _var: _varDecl.variables)
{
yulAssert(!m_currentSSANames.count(_var.name), "");
m_currentSSANames[_var.name] = _var.name;
}
}
void FullSSATransform::operator()(Identifier& _identifier)
{
yulAssert(m_currentSSANames.count(_identifier.name), "");
_identifier.name = m_currentSSANames[_identifier.name];
}
void FullSSATransform::operator()(FunctionDefinition& _functionDefinition)
{
vector<YulString> oldFunctionReturnVariables;
swap(oldFunctionReturnVariables, m_currentFunctionReturnVariables);
for (auto const& var: _functionDefinition.returnVariables)
m_currentFunctionReturnVariables.emplace_back(var.name);
for (auto const& argument: _functionDefinition.parameters + _functionDefinition.returnVariables)
{
yulAssert(!m_currentSSANames.count(argument.name), "");
m_currentSSANames[argument.name] = argument.name;
}
(*this)(_functionDefinition.body);
for (auto const& var: _functionDefinition.returnVariables)
_functionDefinition.body.statements.emplace_back(makePhiStore(var.name, m_currentSSANames[var.name]));
swap(m_currentFunctionReturnVariables, oldFunctionReturnVariables);
}
Statement FullSSATransform::makePhiStore(YulString _var, YulString _value)
{
return ExpressionStatement{
langutil::SourceLocation{}, // TODO
FunctionCall{
langutil::SourceLocation{}, // TODO
Identifier{
langutil::SourceLocation{},
YulString{"phi_store"}
},
{
Literal{
langutil::SourceLocation{}, // TODO
LiteralKind::String,
_var,
YulString{} // TODO
},
Identifier{
langutil::SourceLocation{}, // TODO
_value
}
}
}
};
}
Expression FullSSATransform::makePhiLoad(YulString _var)
{
return FunctionCall{
langutil::SourceLocation{}, // TODO
Identifier{
langutil::SourceLocation{},
YulString{"phi_load"}
},
{
Literal{
langutil::SourceLocation{}, // TODO
LiteralKind::String,
_var,
YulString{} // TODO
}
}
};
}
void FullSSATransform::operator()(Block& _block)
{
auto addReloads = [&](map<YulString, YulString> const& _variables, vector<Statement>& _statements) {
for (auto [origName, oldName]: _variables)
{
YulString newName = m_nameDispenser.newName(origName);
_statements.emplace_back(
VariableDeclaration{
langutil::SourceLocation{},
{TypedName{langutil::SourceLocation{}, newName, YulString{}}},
make_unique<Expression>(makePhiLoad(oldName))
}
);
m_currentSSANames[origName] = newName;
}
};
auto saveAssignedVariables = [&](auto const& _names, vector<Statement>& _result) {
map<YulString, YulString> storedNames;
for (YulString var: _names)
if (m_currentSSANames.count(var))
{
YulString currentName = m_currentSSANames[var];
_result.emplace_back(makePhiStore(currentName, currentName));
storedNames[var] = currentName;
}
return storedNames;
};
auto restoreAssignedVariables = [&](map<YulString, YulString> const& _storedNames, vector<Statement>& _result) {
for (auto [origName, oldName]: _storedNames)
{
yulAssert(m_currentSSANames.count(origName), "");
YulString currentName = m_currentSSANames[origName];
_result.emplace_back(makePhiStore(oldName, currentName));
}
};
using OptionalStatements = optional<vector<Statement>>;
util::iterateReplacing(
_block.statements,
[&](Statement& _stmt) -> OptionalStatements
{
return std::visit(util::GenericVisitor{
[&](Assignment& _assignment) -> OptionalStatements {
visit(*_assignment.value);
vector<Statement> result;
VariableDeclaration varDecl{
_assignment.location,
{},
std::move(_assignment.value)
};
for (auto& var: _assignment.variableNames)
{
yulAssert(m_currentSSANames.count(var.name), "");
YulString newName = m_nameDispenser.newName(var.name);
varDecl.variables.emplace_back(TypedName{
var.location,
newName,
YulString{}
});
m_currentSSANames[var.name] = newName;
}
result.emplace_back(move(varDecl));
return result;
},
[&](If& _if) -> OptionalStatements {
Assignments assignments;
assignments(_if);
vector<Statement> result;
auto storedAssignedVariables = saveAssignedVariables(assignments.names(), result);
(*this)(_if);
restoreAssignedVariables(storedAssignedVariables, _if.body.statements);
result.emplace_back(std::move(_if));
addReloads(storedAssignedVariables, result);
return result;
},
[&](Switch& _switch) -> OptionalStatements {
Assignments assignments;
assignments(_switch);
vector<Statement> result;
auto storedAssignedVariables = saveAssignedVariables(assignments.names(), result);
visit(*_switch.expression);
auto saved = m_currentSSANames;
for (auto& switchCase: _switch.cases)
{
m_currentSSANames = saved;
if (switchCase.value)
(*this)(*switchCase.value);
(*this)(switchCase.body);
restoreAssignedVariables(storedAssignedVariables, switchCase.body.statements);
}
result.emplace_back(std::move(_switch));
addReloads(storedAssignedVariables, result);
return result;
},
[&](ForLoop& _loop) -> OptionalStatements {
yulAssert(_loop.pre.statements.empty(), "");
std::map<YulString, YulString> oldLoopAssignments;
swap(oldLoopAssignments, m_currentLoopAssignments);
Assignments assignments;
assignments(_loop);
vector<Statement> result;
if (auto* identifier = std::get_if<Identifier>(_loop.condition.get()))
{
if (assignments.names().count(identifier->name))
{
yulAssert(m_currentSSANames.count(identifier->name), "");
_loop.condition = make_unique<Expression>(makePhiLoad(m_currentSSANames[identifier->name]));
}
}
else
yulAssert(holds_alternative<Literal>(*_loop.condition), "for loop into body required");
m_currentLoopAssignments = saveAssignedVariables(assignments.names(), result);
vector<Statement> newBody;
addReloads(m_currentLoopAssignments, newBody);
(*this)(_loop.body);
newBody += std::move(_loop.body.statements);
_loop.body.statements = std::move(newBody);
restoreAssignedVariables(m_currentLoopAssignments, _loop.body.statements);
vector<Statement> newPost;
addReloads(m_currentLoopAssignments, newPost);
(*this)(_loop.post);
restoreAssignedVariables(m_currentLoopAssignments, _loop.post.statements);
newPost += std::move(_loop.post.statements);
_loop.post.statements = std::move(newPost);
result.emplace_back(move(_loop));
addReloads(m_currentLoopAssignments, result);
swap(m_currentLoopAssignments, oldLoopAssignments);
return result;
},
[&](Continue& _continue) -> OptionalStatements {
vector<Statement> result;
restoreAssignedVariables(m_currentLoopAssignments, result);
result.emplace_back(std::move(_continue));
return result;
},
[&](Break& _break) -> OptionalStatements {
vector<Statement> result;
restoreAssignedVariables(m_currentLoopAssignments, result);
result.emplace_back(std::move(_break));
return result;
},
[&](Leave& _leaveStatement) -> OptionalStatements {
vector<Statement> result;
for (YulString var: m_currentFunctionReturnVariables)
{
yulAssert(m_currentSSANames.count(var), "");
result.emplace_back(makePhiStore(var, m_currentSSANames[var]));
}
result.emplace_back(std::move(_leaveStatement));
return result;
},
[&](auto& _stmt) -> OptionalStatements { (*this)(_stmt); return std::nullopt; }
}, _stmt);
}
);
}

View File

@ -0,0 +1,59 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#pragma once
#include <libyul/optimiser/ASTWalker.h>
#include <libyul/optimiser/KnowledgeBase.h>
#include <libyul/optimiser/OptimiserStep.h>
#include <libyul/YulString.h>
#include <libyul/AST.h>
#include <libyul/SideEffects.h>
#include <libsolutil/InvertibleMap.h>
#include <map>
#include <set>
namespace solidity::yul
{
struct Dialect;
class FullSSATransform: public ASTModifier
{
public:
static constexpr char const* name{"FullSSATransform"};
static void run(OptimiserStepContext& _context, Block& _ast);
explicit FullSSATransform(OptimiserStepContext& _context);
using ASTModifier::operator();
void operator()(VariableDeclaration& _varDecl) override;
void operator()(Identifier& _varDecl) override;
void operator()(FunctionDefinition& _functionDefinition) override;
void operator()(Block& _block) override;
private:
std::map<YulString, YulString> m_currentSSANames;
NameDispenser& m_nameDispenser;
std::vector<YulString> m_currentFunctionReturnVariables;
std::map<YulString, YulString> m_currentLoopAssignments;
static Statement makePhiStore(YulString _var, YulString _value);
static Expression makePhiLoad(YulString _var);
};
}

View File

@ -44,6 +44,18 @@ void NameCollector::operator ()(FunctionDefinition const& _funDef)
ASTWalker::operator ()(_funDef);
}
void NameCollector::operator()(FunctionCall const& _funCall)
{
if (_funCall.functionName.name == "phi_store"_yulstring || _funCall.functionName.name == "phi_load"_yulstring)
{
yulAssert(!_funCall.arguments.empty(), "");
auto const* literal = std::get_if<Literal>(&_funCall.arguments.front());
yulAssert(literal && literal->kind == LiteralKind::String, "");
m_names.emplace(literal->value);
}
ASTWalker::operator ()(_funCall);
}
void ReferencesCounter::operator()(Identifier const& _identifier)
{
++m_references[_identifier.name];

View File

@ -43,6 +43,7 @@ public:
using ASTWalker::operator ();
void operator()(VariableDeclaration const& _varDecl) override;
void operator()(FunctionDefinition const& _funDef) override;
void operator()(FunctionCall const& _funCall) override;
std::set<YulString> names() const { return m_names; }
private:

View File

@ -308,7 +308,19 @@ void RedundantAssignEliminator::finalize(YulString _variable, RedundantAssignEli
void AssignmentRemover::operator()(Block& _block)
{
boost::range::remove_erase_if(_block.statements, [&](Statement const& _statement) -> bool {
return holds_alternative<Assignment>(_statement) && m_toRemove.count(&std::get<Assignment>(_statement));
if (auto const* assignment = std::get_if<Assignment>(&_statement))
{
if (m_toRemove.count(assignment))
return true;
// TODO: hack to generally get rid of assignments like a := a
if (assignment->variableNames.size() == 1)
{
if (auto const* identifier = std::get_if<Identifier>(assignment->value.get()))
if (identifier->name == assignment->variableNames.front().name)
return true;
}
}
return false;
});
ASTModifier::operator()(_block);

View File

@ -37,6 +37,8 @@
#include <libyul/optimiser/ExpressionJoiner.h>
#include <libyul/optimiser/ExpressionInliner.h>
#include <libyul/optimiser/FullInliner.h>
#include <libyul/optimiser/FullSSAReverse.h>
#include <libyul/optimiser/FullSSATransform.h>
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
#include <libyul/optimiser/ForLoopConditionOutOfBody.h>
#include <libyul/optimiser/ForLoopInitRewriter.h>
@ -190,6 +192,8 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
ForLoopConditionOutOfBody,
ForLoopInitRewriter,
FullInliner,
FullSSAReverse,
FullSSATransform,
FunctionGrouper,
FunctionHoister,
LiteralRematerialiser,
@ -229,6 +233,8 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
{ForLoopConditionOutOfBody::name, 'O'},
{ForLoopInitRewriter::name, 'o'},
{FullInliner::name, 'i'},
{FullSSAReverse::name, 'Z'},
{FullSSATransform::name, 'z'},
{FunctionGrouper::name, 'g'},
{FunctionHoister::name, 'h'},
{LiteralRematerialiser::name, 'T'},

View File

@ -40,6 +40,8 @@
#include <libyul/optimiser/FunctionHoister.h>
#include <libyul/optimiser/ExpressionInliner.h>
#include <libyul/optimiser/FullInliner.h>
#include <libyul/optimiser/FullSSAReverse.h>
#include <libyul/optimiser/FullSSATransform.h>
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
#include <libyul/optimiser/ForLoopConditionOutOfBody.h>
#include <libyul/optimiser/ForLoopInitRewriter.h>
@ -168,6 +170,38 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
disambiguate();
ForLoopInitRewriter::run(*m_context, *m_object->code);
}
else if (m_optimizerStep == "fullSSATransform")
{
disambiguate();
ForLoopInitRewriter::run(*m_context, *m_object->code);
ForLoopConditionIntoBody::run(*m_context, *m_object->code);
FullSSATransform::run(*m_context, *m_object->code);
}
else if (m_optimizerStep == "fullSSAReverse")
{
disambiguate();
FullSSAReverse::run(*m_context, *m_object->code);
ForLoopConditionOutOfBody::run(*m_context, *m_object->code);
}
else if (m_optimizerStep == "fullSSAandBack")
{
disambiguate();
ForLoopInitRewriter::run(*m_context, *m_object->code);
ForLoopConditionIntoBody::run(*m_context, *m_object->code);
FullSSATransform::run(*m_context, *m_object->code);
UnusedPruner::run(*m_context, *m_object->code);
FullSSAReverse::run(*m_context, *m_object->code);
RedundantAssignEliminator::run(*m_context, *m_object->code);
CommonSubexpressionEliminator::run(*m_context, *m_object->code);
Rematerialiser::run(*m_context, *m_object->code);
UnusedPruner::run(*m_context, *m_object->code);
RedundantAssignEliminator::run(*m_context, *m_object->code);
ForLoopConditionOutOfBody::run(*m_context, *m_object->code);
}
else if (m_optimizerStep == "commonSubexpressionEliminator")
{
disambiguate();

View File

@ -0,0 +1,13 @@
{
phi_store("a", 23)
let a := 42
sstore(0, phi_load("a"))
}
// ----
// step: fullSSAReverse
//
// {
// let a_1 := 23
// let a := 42
// sstore(0, a_1)
// }

View File

@ -0,0 +1,13 @@
{
phi_store("a", 42)
let b := 0
phi_store("b", 23)
}
// ----
// step: fullSSAReverse
//
// {
// let a_1 := 42
// let b := 0
// let b_2 := 23
// }

View File

@ -0,0 +1,28 @@
{
let a := calldataload(42)
for {} a { sstore(1, a) } {
a := sub(a,1)
}
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := calldataload(42)
// phi_store("a", a)
// for { }
// phi_load("a")
// {
// let a_3 := phi_load("a")
// sstore(1, a_3)
// phi_store("a", a_3)
// }
// {
// let a_1 := phi_load("a")
// let a_2 := sub(a_1, 1)
// phi_store("a", a_2)
// }
// let a_4 := phi_load("a")
// sstore(0, a_4)
// }

View File

@ -0,0 +1,40 @@
{
let a := calldataload(42)
for {} a { sstore(1, a) } {
a := sub(a,1)
if lt(a,4) { continue }
if eq(a,42) { break }
}
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := calldataload(42)
// phi_store("a", a)
// for { }
// phi_load("a")
// {
// let a_3 := phi_load("a")
// sstore(1, a_3)
// phi_store("a", a_3)
// }
// {
// let a_1 := phi_load("a")
// let a_2 := sub(a_1, 1)
// if lt(a_2, 4)
// {
// phi_store("a", a_2)
// continue
// }
// if eq(a_2, 42)
// {
// phi_store("a", a_2)
// break
// }
// phi_store("a", a_2)
// }
// let a_4 := phi_load("a")
// sstore(0, a_4)
// }

View File

@ -0,0 +1,36 @@
{
let a := 0
for {} lt(a, 10) {
// checked increment
if eq(a, sub(0, 1)) { revert(0, 0) }
a := add(a, 1)
} {
sstore(a, 42)
}
}
// ----
// step: fullSSATransform
//
// {
// let a := 0
// phi_store("a", a)
// for { }
// true
// {
// let a_2 := phi_load("a")
// if eq(a_2, sub(0, 1)) { revert(0, 0) }
// let a_3 := add(a_2, 1)
// phi_store("a", a_3)
// }
// {
// let a_1 := phi_load("a")
// if iszero(lt(a_1, 10))
// {
// phi_store("a", a_1)
// break
// }
// sstore(a_1, 42)
// phi_store("a", a_1)
// }
// let a_4 := phi_load("a")
// }

View File

@ -0,0 +1,41 @@
{
let a := calldataload(42)
for {} a { for {} a { a := sub(a, 1) } { sstore(1, a) }} {
a := sub(a,1)
}
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := calldataload(42)
// phi_store("a", a)
// for { }
// phi_load("a")
// {
// let a_3 := phi_load("a")
// phi_store("a_3", a_3)
// for { }
// phi_load("a_3")
// {
// let a_5 := phi_load("a_3")
// let a_6 := sub(a_5, 1)
// phi_store("a_3", a_6)
// }
// {
// let a_4 := phi_load("a_3")
// sstore(1, a_4)
// phi_store("a_3", a_4)
// }
// let a_7 := phi_load("a_3")
// phi_store("a", a_7)
// }
// {
// let a_1 := phi_load("a")
// let a_2 := sub(a_1, 1)
// phi_store("a", a_2)
// }
// let a_8 := phi_load("a")
// sstore(0, a_8)
// }

View File

@ -0,0 +1,25 @@
{
function f(a, b) -> c {
c := calldataload(0)
sstore(0, a)
a := b
sstore(1, b)
c := calldataload(1)
}
sstore(2, f(calldataload(2), calldataload(3)))
}
// ----
// step: fullSSATransform
//
// {
// function f(a, b) -> c
// {
// let c_1 := calldataload(0)
// sstore(0, a)
// let a_2 := b
// sstore(1, b)
// let c_3 := calldataload(1)
// phi_store("c", c_3)
// }
// sstore(2, f(calldataload(2), calldataload(3)))
// }

View File

@ -0,0 +1,48 @@
{
function f(a, b) -> c {
c := calldataload(0)
for {} gt(a,0) { a := sub(a,b) } {
c := calldataload(a)
}
c := calldataload(c)
}
sstore(2, f(calldataload(2), calldataload(3)))
}
// ----
// step: fullSSATransform
//
// {
// function f(a, b) -> c
// {
// let c_1 := calldataload(0)
// phi_store("c_1", c_1)
// phi_store("a", a)
// for { }
// true
// {
// let c_5 := phi_load("c_1")
// let a_6 := phi_load("a")
// let a_7 := sub(a_6, b)
// phi_store("c_1", c_5)
// phi_store("a", a_7)
// }
// {
// let c_2 := phi_load("c_1")
// let a_3 := phi_load("a")
// if iszero(gt(a_3, 0))
// {
// phi_store("c_1", c_2)
// phi_store("a", a_3)
// break
// }
// let c_4 := calldataload(a_3)
// phi_store("c_1", c_4)
// phi_store("a", a_3)
// }
// let c_8 := phi_load("c_1")
// let a_9 := phi_load("a")
// let c_10 := calldataload(c_8)
// phi_store("c", c_10)
// }
// sstore(2, f(calldataload(2), calldataload(3)))
// }

View File

@ -0,0 +1,56 @@
{
function f(a, b) -> c {
c := calldataload(0)
for {} gt(a,0) { a := sub(a,b) } {
c := calldataload(a)
if lt(c, add(b, a)) {
leave
}
}
c := calldataload(c)
}
sstore(2, f(calldataload(2), calldataload(3)))
}
// ----
// step: fullSSATransform
//
// {
// function f(a, b) -> c
// {
// let c_1 := calldataload(0)
// phi_store("c_1", c_1)
// phi_store("a", a)
// for { }
// true
// {
// let c_5 := phi_load("c_1")
// let a_6 := phi_load("a")
// let a_7 := sub(a_6, b)
// phi_store("c_1", c_5)
// phi_store("a", a_7)
// }
// {
// let c_2 := phi_load("c_1")
// let a_3 := phi_load("a")
// if iszero(gt(a_3, 0))
// {
// phi_store("c_1", c_2)
// phi_store("a", a_3)
// break
// }
// let c_4 := calldataload(a_3)
// if lt(c_4, add(b, a_3))
// {
// phi_store("c", c_4)
// leave
// }
// phi_store("c_1", c_4)
// phi_store("a", a_3)
// }
// let c_8 := phi_load("c_1")
// let a_9 := phi_load("a")
// let c_10 := calldataload(c_8)
// phi_store("c", c_10)
// }
// sstore(2, f(calldataload(2), calldataload(3)))
// }

View File

@ -0,0 +1,21 @@
{
let a := 1
if calldataload(42) {
a := 2
}
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := 1
// phi_store("a", a)
// if calldataload(42)
// {
// let a_1 := 2
// phi_store("a", a_1)
// }
// let a_2 := phi_load("a")
// sstore(0, a_2)
// }

View File

@ -0,0 +1,19 @@
{
let a := 42
if calldataload(42) { a := 23 }
sstore(0, 42)
}
// ----
// step: fullSSATransform
//
// {
// let a := 42
// phi_store("a", a)
// if calldataload(42)
// {
// let a_1 := 23
// phi_store("a", a_1)
// }
// let a_2 := phi_load("a")
// sstore(0, 42)
// }

View File

@ -0,0 +1,31 @@
{
let a := 1
if calldataload(42) {
a := 2
}
if calldataload(a) {
a := add(a, 4)
}
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := 1
// phi_store("a", a)
// if calldataload(42)
// {
// let a_1 := 2
// phi_store("a", a_1)
// }
// let a_2 := phi_load("a")
// phi_store("a_2", a_2)
// if calldataload(a_2)
// {
// let a_3 := add(a_2, 4)
// phi_store("a_2", a_3)
// }
// let a_4 := phi_load("a_2")
// sstore(0, a_4)
// }

View File

@ -0,0 +1,13 @@
{
let a := 1
a := 2
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := 1
// let a_1 := 2
// sstore(0, a_1)
// }

View File

@ -0,0 +1,35 @@
{
let a := 1
switch a
case 1
{
a := calldataload(1)
}
case 2
{
a := calldataload(a)
}
default
{
}
sstore(0, a)
}
// ----
// step: fullSSATransform
//
// {
// let a := 1
// phi_store("a", a)
// switch a
// case 1 {
// let a_1 := calldataload(1)
// phi_store("a", a_1)
// }
// case 2 {
// let a_2 := calldataload(a)
// phi_store("a", a_2)
// }
// default { phi_store("a", a) }
// let a_3 := phi_load("a")
// sstore(0, a_3)
// }

View File

@ -0,0 +1,16 @@
{
let a := calldataload(42)
for {} a { sstore(1, a) } {
a := sub(a,1)
}
sstore(0, a)
}
// ----
// step: fullSSAandBack
//
// {
// let a_5 := calldataload(42)
// for { } a_5 { sstore(1, a_5) }
// { a_5 := sub(a_5, 1) }
// sstore(0, a_5)
// }

View File

@ -0,0 +1,31 @@
{
let a := calldataload(42)
for {} a { sstore(1, a) } {
a := sub(a,1)
if lt(a,4) { continue }
if eq(a,42) { break }
}
sstore(0, a)
}
// ----
// step: fullSSAandBack
//
// {
// let a_5 := calldataload(42)
// for { } a_5 { sstore(1, a_5) }
// {
// let a_2 := sub(a_5, 1)
// if lt(a_2, 4)
// {
// a_5 := a_2
// continue
// }
// if eq(a_2, 42)
// {
// a_5 := a_2
// break
// }
// a_5 := a_2
// }
// sstore(0, a_5)
// }

View File

@ -0,0 +1,23 @@
{
let a := calldataload(42)
for {} a { for {} a { a := sub(a, 1) } { sstore(1, a) }} {
a := sub(a,1)
}
sstore(0, a)
}
// ----
// step: fullSSAandBack
//
// {
// let a_9 := calldataload(42)
// for { }
// a_9
// {
// let a_3_10 := a_9
// for { } a_3_10 { a_3_10 := sub(a_3_10, 1) }
// { sstore(1, a_3_10) }
// a_9 := a_3_10
// }
// { a_9 := sub(a_9, 1) }
// sstore(0, a_9)
// }

View File

@ -0,0 +1,22 @@
{
function f(a, b) -> c {
c := calldataload(0)
sstore(0, a)
a := b
sstore(1, b)
c := calldataload(1)
}
sstore(2, f(calldataload(2), calldataload(3)))
}
// ----
// step: fullSSAandBack
//
// {
// function f(a, b) -> c_4
// {
// sstore(0, a)
// sstore(1, b)
// c_4 := calldataload(1)
// }
// sstore(2, f(calldataload(2), calldataload(3)))
// }

View File

@ -0,0 +1,24 @@
{
function f(a, b) -> c {
c := calldataload(0)
for {} gt(a,0) { a := sub(a,b) } {
c := calldataload(a)
}
c := calldataload(c)
}
sstore(2, f(calldataload(2), calldataload(3)))
}
// ----
// step: fullSSAandBack
//
// {
// function f(a, b) -> c_11
// {
// let c_1_12 := calldataload(0)
// let a_13 := a
// for { } gt(a_13, c_11) { a_13 := sub(a_13, b) }
// { c_1_12 := calldataload(a_13) }
// c_11 := calldataload(c_1_12)
// }
// sstore(2, f(calldataload(2), calldataload(3)))
// }

View File

@ -0,0 +1,35 @@
{
function f(a, b) -> c {
c := calldataload(0)
for {} gt(a,0) { a := sub(a,b) } {
c := calldataload(a)
if lt(c, add(b, a)) {
leave
}
}
c := calldataload(c)
}
sstore(2, f(calldataload(2), calldataload(3)))
}
// ----
// step: fullSSAandBack
//
// {
// function f(a, b) -> c_11
// {
// let c_1_12 := calldataload(0)
// let a_13 := a
// for { } gt(a_13, 0) { a_13 := sub(a_13, b) }
// {
// let c_4 := calldataload(a_13)
// if lt(c_4, add(b, a_13))
// {
// c_11 := c_4
// leave
// }
// c_1_12 := c_4
// }
// c_11 := calldataload(c_1_12)
// }
// sstore(2, f(calldataload(2), calldataload(3)))
// }

View File

@ -0,0 +1,15 @@
{
let a := 1
if calldataload(42) {
a := 2
}
sstore(0, a)
}
// ----
// step: fullSSAandBack
//
// {
// let a_3 := 1
// if calldataload(42) { a_3 := 2 }
// sstore(0, a_3)
// }

View File

@ -0,0 +1,20 @@
{
let a := 1
if calldataload(42) {
a := 2
}
if calldataload(a) {
a := add(a, 4)
}
sstore(0, a)
}
// ----
// step: fullSSAandBack
//
// {
// let a_5 := 1
// if calldataload(42) { a_5 := 2 }
// let a_2_6 := a_5
// if calldataload(a_5) { a_2_6 := add(a_5, 4) }
// sstore(0, a_2_6)
// }

View File

@ -0,0 +1,9 @@
{
let a := calldataload(0)
a := calldataload(1)
sstore(0, a)
}
// ----
// step: fullSSAandBack
//
// { sstore(0, calldataload(1)) }

View File

@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_strin
BOOST_TEST(chromosome.length() == allSteps.size());
BOOST_TEST(chromosome.optimisationSteps() == allSteps);
BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoighTLMRrmVatpud");
BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoiZzghTLMRrmVatpud");
}
BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_optimisation_step_names)