mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Prototype of a full SSA transformation.
This commit is contained in:
parent
591f04e41c
commit
dab68e6254
@ -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
|
||||
|
@ -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}, [](
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*(
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
|
134
libyul/optimiser/FullSSAReverse.cpp
Normal file
134
libyul/optimiser/FullSSAReverse.cpp
Normal 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);
|
||||
}
|
52
libyul/optimiser/FullSSAReverse.h
Normal file
52
libyul/optimiser/FullSSAReverse.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
300
libyul/optimiser/FullSSATransform.cpp
Normal file
300
libyul/optimiser/FullSSATransform.cpp
Normal 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);
|
||||
}
|
||||
);
|
||||
}
|
59
libyul/optimiser/FullSSATransform.h
Normal file
59
libyul/optimiser/FullSSATransform.h
Normal 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);
|
||||
};
|
||||
|
||||
}
|
@ -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];
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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'},
|
||||
|
@ -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();
|
||||
|
13
test/libyul/yulOptimizerTests/fullSSAReverse/load.yul
Normal file
13
test/libyul/yulOptimizerTests/fullSSAReverse/load.yul
Normal 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)
|
||||
// }
|
13
test/libyul/yulOptimizerTests/fullSSAReverse/store.yul
Normal file
13
test/libyul/yulOptimizerTests/fullSSAReverse/store.yul
Normal 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
|
||||
// }
|
28
test/libyul/yulOptimizerTests/fullSSATransform/for.yul
Normal file
28
test/libyul/yulOptimizerTests/fullSSATransform/for.yul
Normal 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)
|
||||
// }
|
@ -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)
|
||||
// }
|
@ -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")
|
||||
// }
|
@ -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)
|
||||
// }
|
25
test/libyul/yulOptimizerTests/fullSSATransform/function.yul
Normal file
25
test/libyul/yulOptimizerTests/fullSSATransform/function.yul
Normal 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)))
|
||||
// }
|
@ -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)))
|
||||
// }
|
@ -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)))
|
||||
// }
|
21
test/libyul/yulOptimizerTests/fullSSATransform/if.yul
Normal file
21
test/libyul/yulOptimizerTests/fullSSATransform/if.yul
Normal 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)
|
||||
// }
|
@ -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)
|
||||
// }
|
31
test/libyul/yulOptimizerTests/fullSSATransform/if_twice.yul
Normal file
31
test/libyul/yulOptimizerTests/fullSSATransform/if_twice.yul
Normal 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)
|
||||
// }
|
@ -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)
|
||||
// }
|
35
test/libyul/yulOptimizerTests/fullSSATransform/switch.yul
Normal file
35
test/libyul/yulOptimizerTests/fullSSATransform/switch.yul
Normal 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)
|
||||
// }
|
16
test/libyul/yulOptimizerTests/fullSSAandBack/for.yul
Normal file
16
test/libyul/yulOptimizerTests/fullSSAandBack/for.yul
Normal 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)
|
||||
// }
|
@ -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)
|
||||
// }
|
23
test/libyul/yulOptimizerTests/fullSSAandBack/for_nested.yul
Normal file
23
test/libyul/yulOptimizerTests/fullSSAandBack/for_nested.yul
Normal 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)
|
||||
// }
|
22
test/libyul/yulOptimizerTests/fullSSAandBack/function.yul
Normal file
22
test/libyul/yulOptimizerTests/fullSSAandBack/function.yul
Normal 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)))
|
||||
// }
|
@ -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)))
|
||||
// }
|
@ -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)))
|
||||
// }
|
15
test/libyul/yulOptimizerTests/fullSSAandBack/if.yul
Normal file
15
test/libyul/yulOptimizerTests/fullSSAandBack/if.yul
Normal 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)
|
||||
// }
|
20
test/libyul/yulOptimizerTests/fullSSAandBack/if_twice.yul
Normal file
20
test/libyul/yulOptimizerTests/fullSSAandBack/if_twice.yul
Normal 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)
|
||||
// }
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
let a := calldataload(0)
|
||||
a := calldataload(1)
|
||||
sstore(0, a)
|
||||
}
|
||||
// ----
|
||||
// step: fullSSAandBack
|
||||
//
|
||||
// { sstore(0, calldataload(1)) }
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user