mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add equivalent function combiner as Yul optimizer step.
This commit is contained in:
parent
6146c59a1a
commit
81f24f24e6
@ -275,4 +275,10 @@ std::string getChecksummedAddress(std::string const& _addr);
|
||||
bool isValidHex(std::string const& _string);
|
||||
bool isValidDecimal(std::string const& _string);
|
||||
|
||||
template<typename Container, typename Compare>
|
||||
bool containerEqual(Container const& _lhs, Container const& _rhs, Compare&& _compare)
|
||||
{
|
||||
return std::equal(std::begin(_lhs), std::end(_lhs), std::begin(_rhs), std::end(_rhs), std::forward<Compare>(_compare));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,6 +44,10 @@ add_library(yul
|
||||
optimiser/DataFlowAnalyzer.h
|
||||
optimiser/Disambiguator.cpp
|
||||
optimiser/Disambiguator.h
|
||||
optimiser/EquivalentFunctionDetector.cpp
|
||||
optimiser/EquivalentFunctionDetector.h
|
||||
optimiser/EquivalentFunctionCombiner.cpp
|
||||
optimiser/EquivalentFunctionCombiner.h
|
||||
optimiser/ExpressionInliner.cpp
|
||||
optimiser/ExpressionInliner.h
|
||||
optimiser/ExpressionJoiner.cpp
|
||||
|
@ -74,7 +74,7 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
|
||||
{
|
||||
assertThrow(var.second, OptimizerException, "");
|
||||
assertThrow(inScope(var.first), OptimizerException, "");
|
||||
if (SyntacticalEqualityChecker::equal(_e, *var.second))
|
||||
if (SyntacticallyEqual{}(_e, *var.second))
|
||||
{
|
||||
_e = Identifier{locationOf(_e), var.first};
|
||||
break;
|
||||
|
41
libyul/optimiser/EquivalentFunctionCombiner.cpp
Normal file
41
libyul/optimiser/EquivalentFunctionCombiner.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Optimiser component that combines syntactically equivalent functions.
|
||||
*/
|
||||
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace yul;
|
||||
using namespace dev::solidity;
|
||||
|
||||
void EquivalentFunctionCombiner::run(Block& _ast)
|
||||
{
|
||||
EquivalentFunctionCombiner{EquivalentFunctionDetector::run(_ast)}(_ast);
|
||||
}
|
||||
|
||||
void EquivalentFunctionCombiner::operator()(FunctionCall& _funCall)
|
||||
{
|
||||
auto it = m_duplicates.find(_funCall.functionName.name);
|
||||
if (it != m_duplicates.end())
|
||||
_funCall.functionName.name = it->second->name;
|
||||
ASTModifier::operator()(_funCall);
|
||||
}
|
49
libyul/optimiser/EquivalentFunctionCombiner.h
Normal file
49
libyul/optimiser/EquivalentFunctionCombiner.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Optimiser component that combines syntactically equivalent functions.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionDetector.h>
|
||||
#include <libyul/AsmDataForward.h>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
|
||||
/**
|
||||
* Optimiser component that detects syntactically equivalent functions and replaces all calls to any of them by calls
|
||||
* to one particular of them.
|
||||
*
|
||||
* Prerequisite: Disambiguator, Function Hoister
|
||||
*/
|
||||
class EquivalentFunctionCombiner: public ASTModifier
|
||||
{
|
||||
public:
|
||||
static void run(Block& _ast);
|
||||
|
||||
using ASTModifier::operator();
|
||||
void operator()(FunctionCall& _funCall) override;
|
||||
|
||||
private:
|
||||
EquivalentFunctionCombiner(std::map<YulString, FunctionDefinition const*> _duplicates): m_duplicates(std::move(_duplicates)) {}
|
||||
std::map<YulString, FunctionDefinition const*> m_duplicates;
|
||||
};
|
||||
|
||||
|
||||
}
|
63
libyul/optimiser/EquivalentFunctionDetector.cpp
Normal file
63
libyul/optimiser/EquivalentFunctionDetector.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Optimiser component that combines syntactically equivalent functions.
|
||||
*/
|
||||
|
||||
#include <libyul/optimiser/EquivalentFunctionDetector.h>
|
||||
#include <libyul/optimiser/SyntacticalEquality.h>
|
||||
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/optimiser/Metrics.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace yul;
|
||||
using namespace solidity;
|
||||
|
||||
void EquivalentFunctionDetector::operator()(FunctionDefinition const& _fun)
|
||||
{
|
||||
RoughHeuristic heuristic(_fun);
|
||||
auto& candidates = m_candidates[heuristic];
|
||||
for (auto const& candidate: candidates)
|
||||
if (SyntacticallyEqual{}.statementEqual(_fun, *candidate))
|
||||
{
|
||||
m_duplicates[_fun.name] = candidate;
|
||||
return;
|
||||
}
|
||||
candidates.push_back(&_fun);
|
||||
}
|
||||
|
||||
bool EquivalentFunctionDetector::RoughHeuristic::operator<(EquivalentFunctionDetector::RoughHeuristic const& _rhs) const
|
||||
{
|
||||
if (
|
||||
std::make_tuple(m_fun.parameters.size(), m_fun.returnVariables.size()) ==
|
||||
std::make_tuple(_rhs.m_fun.parameters.size(), _rhs.m_fun.returnVariables.size())
|
||||
)
|
||||
return codeSize() < _rhs.codeSize();
|
||||
else
|
||||
return
|
||||
std::make_tuple(m_fun.parameters.size(), m_fun.returnVariables.size()) <
|
||||
std::make_tuple(_rhs.m_fun.parameters.size(), _rhs.m_fun.returnVariables.size());
|
||||
}
|
||||
|
||||
size_t EquivalentFunctionDetector::RoughHeuristic::codeSize() const
|
||||
{
|
||||
if (!m_codeSize)
|
||||
m_codeSize = CodeSize::codeSize(m_fun.body);
|
||||
return *m_codeSize;
|
||||
}
|
71
libyul/optimiser/EquivalentFunctionDetector.h
Normal file
71
libyul/optimiser/EquivalentFunctionDetector.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Optimiser component that combines syntactically equivalent functions.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/AsmDataForward.h>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
|
||||
/**
|
||||
* Optimiser component that detects syntactically equivalent functions.
|
||||
*
|
||||
* Prerequisite: Disambiguator
|
||||
*/
|
||||
class EquivalentFunctionDetector: public ASTWalker
|
||||
{
|
||||
public:
|
||||
static std::map<YulString, FunctionDefinition const*> run(Block& _block)
|
||||
{
|
||||
EquivalentFunctionDetector detector{};
|
||||
detector(_block);
|
||||
return std::move(detector.m_duplicates);
|
||||
}
|
||||
|
||||
using ASTWalker::operator();
|
||||
void operator()(FunctionDefinition const& _fun) override;
|
||||
|
||||
private:
|
||||
EquivalentFunctionDetector() = default;
|
||||
/**
|
||||
* Fast heuristic to detect distinct, resp. potentially equal functions.
|
||||
*
|
||||
* Defines a partial order on function definitions. If two functions
|
||||
* are comparable (one is "less" than the other), they are distinct.
|
||||
* If not (neither is "less" than the other), they are *potentially* equal.
|
||||
*/
|
||||
class RoughHeuristic
|
||||
{
|
||||
public:
|
||||
RoughHeuristic(FunctionDefinition const& _fun): m_fun(_fun) {}
|
||||
bool operator<(RoughHeuristic const& _rhs) const;
|
||||
private:
|
||||
std::size_t codeSize() const;
|
||||
FunctionDefinition const& m_fun;
|
||||
mutable boost::optional<std::size_t> m_codeSize;
|
||||
// In case the heuristic doesn't turn out to be good enough, we might want to define a hash function for code blocks.
|
||||
};
|
||||
std::map<RoughHeuristic, std::vector<FunctionDefinition const*>> m_candidates;
|
||||
std::map<YulString, FunctionDefinition const*> m_duplicates;
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -171,7 +171,7 @@ bool Pattern::matches(
|
||||
Expression const* firstMatch = (*m_matchGroups)[m_matchGroup];
|
||||
assertThrow(firstMatch, OptimizerException, "Match set but to null.");
|
||||
return
|
||||
SyntacticalEqualityChecker::equal(*firstMatch, _expr) &&
|
||||
SyntacticallyEqual{}(*firstMatch, _expr) &&
|
||||
MovableChecker(_dialect, _expr).movable();
|
||||
}
|
||||
else if (m_kind == PatternKind::Any)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <libyul/optimiser/BlockFlattener.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/FunctionHoister.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
#include <libyul/optimiser/ExpressionSplitter.h>
|
||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||
#include <libyul/optimiser/ExpressionInliner.h>
|
||||
@ -62,6 +63,8 @@ void OptimiserSuite::run(
|
||||
(FunctionHoister{})(ast);
|
||||
(BlockFlattener{})(ast);
|
||||
(FunctionGrouper{})(ast);
|
||||
EquivalentFunctionCombiner::run(ast);
|
||||
UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers);
|
||||
(ForLoopInitRewriter{})(ast);
|
||||
(BlockFlattener{})(ast);
|
||||
StructuralSimplifier{_dialect}(ast);
|
||||
@ -101,6 +104,7 @@ void OptimiserSuite::run(
|
||||
CommonSubexpressionEliminator{_dialect}(ast);
|
||||
|
||||
(FunctionGrouper{})(ast);
|
||||
EquivalentFunctionCombiner::run(ast);
|
||||
FullInliner{ast, dispenser}.run();
|
||||
|
||||
SSATransform::run(ast, dispenser);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <libyul/Exceptions.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/Utilities.h>
|
||||
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
@ -29,48 +30,166 @@ using namespace std;
|
||||
using namespace dev;
|
||||
using namespace yul;
|
||||
|
||||
bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const& _e2)
|
||||
bool SyntacticallyEqual::operator()(Expression const& _lhs, Expression const& _rhs)
|
||||
{
|
||||
if (_e1.type() != _e2.type())
|
||||
return false;
|
||||
// TODO This somehow calls strcmp - WHERE?
|
||||
return boost::apply_visitor([this](auto&& _lhsExpr, auto&& _rhsExpr) -> bool {
|
||||
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
|
||||
return this->expressionEqual(_lhsExpr, _rhsExpr);
|
||||
}, _lhs, _rhs);
|
||||
}
|
||||
|
||||
// TODO This should be replaced by some kind of AST walker as soon as it gets
|
||||
// more complex.
|
||||
if (_e1.type() == typeid(FunctionalInstruction))
|
||||
bool SyntacticallyEqual::operator()(Statement const& _lhs, Statement const& _rhs)
|
||||
{
|
||||
return boost::apply_visitor([this](auto&& _lhsStmt, auto&& _rhsStmt) -> bool {
|
||||
// ``this->`` is redundant, but required to work around a bug present in gcc 6.x.
|
||||
return this->statementEqual(_lhsStmt, _rhsStmt);
|
||||
}, _lhs, _rhs);
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::expressionEqual(FunctionalInstruction const& _lhs, FunctionalInstruction const& _rhs)
|
||||
{
|
||||
auto const& e1 = boost::get<FunctionalInstruction>(_e1);
|
||||
auto const& e2 = boost::get<FunctionalInstruction>(_e2);
|
||||
return
|
||||
e1.instruction == e2.instruction &&
|
||||
equalVector(e1.arguments, e2.arguments);
|
||||
_lhs.instruction == _rhs.instruction &&
|
||||
containerEqual(_lhs.arguments, _rhs.arguments, [this](Expression const& _lhsExpr, Expression const& _rhsExpr) -> bool {
|
||||
return (*this)(_lhsExpr, _rhsExpr);
|
||||
});
|
||||
}
|
||||
else if (_e1.type() == typeid(FunctionCall))
|
||||
|
||||
bool SyntacticallyEqual::expressionEqual(FunctionCall const& _lhs, FunctionCall const& _rhs)
|
||||
{
|
||||
auto const& e1 = boost::get<FunctionCall>(_e1);
|
||||
auto const& e2 = boost::get<FunctionCall>(_e2);
|
||||
return
|
||||
equal(e1.functionName, e2.functionName) &&
|
||||
equalVector(e1.arguments, e2.arguments);
|
||||
expressionEqual(_lhs.functionName, _rhs.functionName) &&
|
||||
containerEqual(_lhs.arguments, _rhs.arguments, [this](Expression const& _lhsExpr, Expression const& _rhsExpr) -> bool {
|
||||
return (*this)(_lhsExpr, _rhsExpr);
|
||||
});
|
||||
}
|
||||
else if (_e1.type() == typeid(Identifier))
|
||||
return boost::get<Identifier>(_e1).name == boost::get<Identifier>(_e2).name;
|
||||
else if (_e1.type() == typeid(Literal))
|
||||
|
||||
bool SyntacticallyEqual::expressionEqual(Identifier const& _lhs, Identifier const& _rhs)
|
||||
{
|
||||
auto const& e1 = boost::get<Literal>(_e1);
|
||||
auto const& e2 = boost::get<Literal>(_e2);
|
||||
return e1.kind == e2.kind && e1.value == e2.value && e1.type == e2.type;
|
||||
auto lhsIt = m_identifiersLHS.find(_lhs.name);
|
||||
auto rhsIt = m_identifiersRHS.find(_rhs.name);
|
||||
return
|
||||
(lhsIt == m_identifiersLHS.end() && rhsIt == m_identifiersRHS.end() && _lhs.name == _rhs.name) ||
|
||||
(lhsIt != m_identifiersLHS.end() && rhsIt != m_identifiersRHS.end() && lhsIt->second == rhsIt->second);
|
||||
}
|
||||
bool SyntacticallyEqual::expressionEqual(Literal const& _lhs, Literal const& _rhs)
|
||||
{
|
||||
if (_lhs.kind != _rhs.kind || _lhs.type != _rhs.type)
|
||||
return false;
|
||||
if (_lhs.kind == LiteralKind::Number)
|
||||
return valueOfNumberLiteral(_lhs) == valueOfNumberLiteral(_rhs);
|
||||
else
|
||||
{
|
||||
assertThrow(false, OptimizerException, "Invalid expression");
|
||||
return _lhs.value == _rhs.value;
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(ExpressionStatement const& _lhs, ExpressionStatement const& _rhs)
|
||||
{
|
||||
return (*this)(_lhs.expression, _rhs.expression);
|
||||
}
|
||||
bool SyntacticallyEqual::statementEqual(Assignment const& _lhs, Assignment const& _rhs)
|
||||
{
|
||||
return containerEqual(
|
||||
_lhs.variableNames,
|
||||
_rhs.variableNames,
|
||||
[this](Identifier const& _lhsVarName, Identifier const& _rhsVarName) -> bool {
|
||||
return this->expressionEqual(_lhsVarName, _rhsVarName);
|
||||
}
|
||||
) && (*this)(*_lhs.value, *_rhs.value);
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(VariableDeclaration const& _lhs, VariableDeclaration const& _rhs)
|
||||
{
|
||||
// first visit expression, then variable declarations
|
||||
if (!compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.value, _rhs.value))
|
||||
return false;
|
||||
return containerEqual(_lhs.variables, _rhs.variables, [this](TypedName const& _lhsVarName, TypedName const& _rhsVarName) -> bool {
|
||||
return this->visitDeclaration(_lhsVarName, _rhsVarName);
|
||||
});
|
||||
}
|
||||
|
||||
bool SyntacticalEqualityChecker::equalVector(vector<Expression> const& _e1, vector<Expression> const& _e2)
|
||||
bool SyntacticallyEqual::statementEqual(FunctionDefinition const& _lhs, FunctionDefinition const& _rhs)
|
||||
{
|
||||
return _e1.size() == _e2.size() &&
|
||||
std::equal(begin(_e1), end(_e1), begin(_e2), SyntacticalEqualityChecker::equal);
|
||||
|
||||
auto compare = [this](TypedName const& _lhsVarName, TypedName const& _rhsVarName) -> bool {
|
||||
return this->visitDeclaration(_lhsVarName, _rhsVarName);
|
||||
};
|
||||
// first visit parameter declarations, then body
|
||||
if (!containerEqual(_lhs.parameters, _rhs.parameters, compare))
|
||||
return false;
|
||||
if (!containerEqual(_lhs.returnVariables, _rhs.returnVariables, compare))
|
||||
return false;
|
||||
return statementEqual(_lhs.body, _rhs.body);
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(If const& _lhs, If const& _rhs)
|
||||
{
|
||||
return
|
||||
compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.condition, _rhs.condition) &&
|
||||
statementEqual(_lhs.body, _rhs.body);
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(Switch const& _lhs, Switch const& _rhs)
|
||||
{
|
||||
static auto const sortCasesByValue = [](Case const* _lhsCase, Case const* _rhsCase) -> bool {
|
||||
return Less<Literal*>{}(_lhsCase->value.get(), _rhsCase->value.get());
|
||||
};
|
||||
std::set<Case const*, decltype(sortCasesByValue)> lhsCases(sortCasesByValue);
|
||||
std::set<Case const*, decltype(sortCasesByValue)> rhsCases(sortCasesByValue);
|
||||
for (auto const& lhsCase: _lhs.cases)
|
||||
lhsCases.insert(&lhsCase);
|
||||
for (auto const& rhsCase: _rhs.cases)
|
||||
rhsCases.insert(&rhsCase);
|
||||
return
|
||||
compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.expression, _rhs.expression) &&
|
||||
containerEqual(lhsCases, rhsCases, [this](Case const* _lhsCase, Case const* _rhsCase) -> bool {
|
||||
return this->switchCaseEqual(*_lhsCase, *_rhsCase);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool SyntacticallyEqual::switchCaseEqual(Case const& _lhs, Case const& _rhs)
|
||||
{
|
||||
return
|
||||
compareSharedPtr<Literal, &SyntacticallyEqual::expressionEqual>(_lhs.value, _rhs.value) &&
|
||||
statementEqual(_lhs.body, _rhs.body);
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(ForLoop const& _lhs, ForLoop const& _rhs)
|
||||
{
|
||||
return
|
||||
statementEqual(_lhs.pre, _rhs.pre) &&
|
||||
compareSharedPtr<Expression, &SyntacticallyEqual::operator()>(_lhs.condition, _rhs.condition) &&
|
||||
statementEqual(_lhs.body, _rhs.body) &&
|
||||
statementEqual(_lhs.post, _rhs.post);
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(Instruction const&, Instruction const&)
|
||||
{
|
||||
assertThrow(false, OptimizerException, "");
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(Label const&, Label const&)
|
||||
{
|
||||
assertThrow(false, OptimizerException, "");
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(StackAssignment const&, StackAssignment const&)
|
||||
{
|
||||
assertThrow(false, OptimizerException, "");
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::statementEqual(Block const& _lhs, Block const& _rhs)
|
||||
{
|
||||
return containerEqual(_lhs.statements, _rhs.statements, [this](Statement const& _lhsStmt, Statement const& _rhsStmt) -> bool {
|
||||
return (*this)(_lhsStmt, _rhsStmt);
|
||||
});
|
||||
}
|
||||
|
||||
bool SyntacticallyEqual::visitDeclaration(TypedName const& _lhs, TypedName const& _rhs)
|
||||
{
|
||||
if (_lhs.type != _rhs.type)
|
||||
return false;
|
||||
std::size_t id = m_idsUsed++;
|
||||
m_identifiersLHS[_lhs.name] = id;
|
||||
m_identifiersRHS[_rhs.name] = id;
|
||||
return true;
|
||||
}
|
||||
|
@ -21,27 +21,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <libyul/AsmDataForward.h>
|
||||
#include <libyul/YulString.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Component that can compare ASTs for equality on a syntactic basis.
|
||||
* Ignores source locations but requires exact matches otherwise.
|
||||
* Ignores source locations and allows for different variable names but requires exact matches otherwise.
|
||||
*
|
||||
* TODO: Only implemented for Expressions for now.
|
||||
* A future version might also recognize renamed variables and thus could be used to
|
||||
* remove duplicate functions.
|
||||
* Prerequisite: Disambiguator (unless only expressions are compared)
|
||||
*/
|
||||
class SyntacticalEqualityChecker
|
||||
class SyntacticallyEqual
|
||||
{
|
||||
public:
|
||||
static bool equal(Expression const& _e1, Expression const& _e2);
|
||||
bool operator()(Expression const& _lhs, Expression const& _rhs);
|
||||
bool operator()(Statement const& _lhs, Statement const& _rhs);
|
||||
|
||||
protected:
|
||||
static bool equalVector(std::vector<Expression> const& _e1, std::vector<Expression> const& _e2);
|
||||
bool expressionEqual(FunctionalInstruction const& _lhs, FunctionalInstruction const& _rhs);
|
||||
bool expressionEqual(FunctionCall const& _lhs, FunctionCall const& _rhs);
|
||||
bool expressionEqual(Identifier const& _lhs, Identifier const& _rhs);
|
||||
bool expressionEqual(Literal const& _lhs, Literal const& _rhs);
|
||||
|
||||
bool statementEqual(ExpressionStatement const& _lhs, ExpressionStatement const& _rhs);
|
||||
bool statementEqual(Assignment const& _lhs, Assignment const& _rhs);
|
||||
bool statementEqual(VariableDeclaration const& _lhs, VariableDeclaration const& _rhs);
|
||||
bool statementEqual(FunctionDefinition const& _lhs, FunctionDefinition const& _rhs);
|
||||
bool statementEqual(If const& _lhs, If const& _rhs);
|
||||
bool statementEqual(Switch const& _lhs, Switch const& _rhs);
|
||||
bool switchCaseEqual(Case const& _lhs, Case const& _rhs);
|
||||
bool statementEqual(ForLoop const& _lhs, ForLoop const& _rhs);
|
||||
bool statementEqual(Block const& _lhs, Block const& _rhs);
|
||||
private:
|
||||
bool statementEqual(Instruction const& _lhs, Instruction const& _rhs);
|
||||
bool statementEqual(Label const& _lhs, Label const& _rhs);
|
||||
bool statementEqual(StackAssignment const& _lhs, StackAssignment const& _rhs);
|
||||
|
||||
bool visitDeclaration(TypedName const& _lhs, TypedName const& _rhs);
|
||||
|
||||
template<typename U, typename V>
|
||||
bool expressionEqual(U const&, V const&, std::enable_if_t<!std::is_same<U, V>::value>* = nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename U, typename V>
|
||||
bool statementEqual(U const&, V const&, std::enable_if_t<!std::is_same<U, V>::value>* = nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, bool (SyntacticallyEqual::*CompareMember)(T const&, T const&)>
|
||||
bool compareSharedPtr(std::shared_ptr<T> const& _lhs, std::shared_ptr<T> const& _rhs)
|
||||
{
|
||||
return (_lhs == _rhs) || (_lhs && _rhs && (this->*CompareMember)(*_lhs, *_rhs));
|
||||
}
|
||||
|
||||
std::size_t m_idsUsed = 0;
|
||||
std::map<YulString, std::size_t> m_identifiersLHS;
|
||||
std::map<YulString, std::size_t> m_identifiersRHS;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <libyul/optimiser/Disambiguator.h>
|
||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||
#include <libyul/optimiser/NameCollector.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
#include <libyul/optimiser/ExpressionSplitter.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/FunctionHoister.h>
|
||||
@ -217,6 +218,11 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
|
||||
disambiguate();
|
||||
StructuralSimplifier{*m_dialect}(*m_ast);
|
||||
}
|
||||
else if (m_optimizerStep == "equivalentFunctionCombiner")
|
||||
{
|
||||
disambiguate();
|
||||
EquivalentFunctionCombiner::run(*m_ast);
|
||||
}
|
||||
else if (m_optimizerStep == "fullSuite")
|
||||
OptimiserSuite::run(*m_dialect, *m_ast, *m_analysisInfo);
|
||||
else
|
||||
|
@ -0,0 +1,114 @@
|
||||
{
|
||||
pop(f(1,2,3))
|
||||
pop(g(4,5,6))
|
||||
pop(h(7,8,9))
|
||||
function f(f1, f2, f3) -> rf
|
||||
{
|
||||
switch f1
|
||||
case 0 {
|
||||
if f2
|
||||
{
|
||||
rf := f3
|
||||
}
|
||||
if not(f2)
|
||||
{
|
||||
rf := f1
|
||||
}
|
||||
}
|
||||
default {
|
||||
rf := 3
|
||||
}
|
||||
}
|
||||
function g(g1, g2, g3) -> rg
|
||||
{
|
||||
switch g1
|
||||
case 0 {
|
||||
if g2
|
||||
{
|
||||
rg := g3
|
||||
}
|
||||
if not(g2)
|
||||
{
|
||||
rg := g1
|
||||
}
|
||||
}
|
||||
default {
|
||||
rg := 3
|
||||
}
|
||||
}
|
||||
function h(h1, h2, h3) -> rh
|
||||
{
|
||||
switch h1
|
||||
case 1 {
|
||||
if h2
|
||||
{
|
||||
rh := h3
|
||||
}
|
||||
if not(h2)
|
||||
{
|
||||
rh := h1
|
||||
}
|
||||
}
|
||||
default {
|
||||
rh := 3
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// equivalentFunctionCombiner
|
||||
// {
|
||||
// pop(f(1, 2, 3))
|
||||
// pop(f(4, 5, 6))
|
||||
// pop(h(7, 8, 9))
|
||||
// function f(f1, f2, f3) -> rf
|
||||
// {
|
||||
// switch f1
|
||||
// case 0 {
|
||||
// if f2
|
||||
// {
|
||||
// rf := f3
|
||||
// }
|
||||
// if not(f2)
|
||||
// {
|
||||
// rf := f1
|
||||
// }
|
||||
// }
|
||||
// default {
|
||||
// rf := 3
|
||||
// }
|
||||
// }
|
||||
// function g(g1, g2, g3) -> rg
|
||||
// {
|
||||
// switch g1
|
||||
// case 0 {
|
||||
// if g2
|
||||
// {
|
||||
// rg := g3
|
||||
// }
|
||||
// if not(g2)
|
||||
// {
|
||||
// rg := g1
|
||||
// }
|
||||
// }
|
||||
// default {
|
||||
// rg := 3
|
||||
// }
|
||||
// }
|
||||
// function h(h1, h2, h3) -> rh
|
||||
// {
|
||||
// switch h1
|
||||
// case 1 {
|
||||
// if h2
|
||||
// {
|
||||
// rh := h3
|
||||
// }
|
||||
// if not(h2)
|
||||
// {
|
||||
// rh := h1
|
||||
// }
|
||||
// }
|
||||
// default {
|
||||
// rh := 3
|
||||
// }
|
||||
// }
|
||||
// }
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
f()
|
||||
g()
|
||||
function f() { mstore(1, mload(0)) }
|
||||
function g() { mstore(1, mload(0)) }
|
||||
}
|
||||
// ----
|
||||
// equivalentFunctionCombiner
|
||||
// {
|
||||
// f()
|
||||
// f()
|
||||
// function f()
|
||||
// {
|
||||
// mstore(1, mload(0))
|
||||
// }
|
||||
// function g()
|
||||
// {
|
||||
// mstore(1, mload(0))
|
||||
// }
|
||||
// }
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
pop(f())
|
||||
pop(g())
|
||||
function f() -> b { let a := mload(0) b := a }
|
||||
function g() -> a { let b := mload(0) a := b }
|
||||
}
|
||||
// ----
|
||||
// equivalentFunctionCombiner
|
||||
// {
|
||||
// pop(f())
|
||||
// pop(f())
|
||||
// function f() -> b
|
||||
// {
|
||||
// let a := mload(0)
|
||||
// b := a
|
||||
// }
|
||||
// function g() -> a_1
|
||||
// {
|
||||
// let b_2 := mload(0)
|
||||
// a_1 := b_2
|
||||
// }
|
||||
// }
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
f(0)
|
||||
g(1)
|
||||
function f(x) { switch x case 0 { mstore(0, 42) } case 1 { mstore(1, 42) } }
|
||||
function g(x) { switch x case 1 { mstore(1, 42) } case 0 { mstore(0, 42) } }
|
||||
}
|
||||
// ----
|
||||
// equivalentFunctionCombiner
|
||||
// {
|
||||
// f(0)
|
||||
// f(1)
|
||||
// function f(x)
|
||||
// {
|
||||
// switch x
|
||||
// case 0 {
|
||||
// mstore(0, 42)
|
||||
// }
|
||||
// case 1 {
|
||||
// mstore(1, 42)
|
||||
// }
|
||||
// }
|
||||
// function g(x_1)
|
||||
// {
|
||||
// switch x_1
|
||||
// case 1 {
|
||||
// mstore(1, 42)
|
||||
// }
|
||||
// case 0 {
|
||||
// mstore(0, 42)
|
||||
// }
|
||||
// }
|
||||
// }
|
@ -1073,12 +1073,12 @@
|
||||
// fullSuite
|
||||
// {
|
||||
// let _2 := mload(1)
|
||||
// let _1042 := mload(0)
|
||||
// if slt(sub(_2, _1042), 64)
|
||||
// let _172 := mload(0)
|
||||
// if slt(sub(_2, _172), 64)
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// sstore(0, and(calldataload(_1042), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
|
||||
// sstore(0, and(calldataload(_172), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
|
||||
// let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8))
|
||||
// sstore(x1, x0)
|
||||
// sstore(x3, x2)
|
||||
@ -1093,40 +1093,40 @@
|
||||
// value0_57 := and(calldataload(add(headStart_55, value4)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
|
||||
// value1_58 := calldataload(add(headStart_55, 32))
|
||||
// let offset_62 := calldataload(add(headStart_55, 64))
|
||||
// let _1090 := 0xffffffffffffffff
|
||||
// if gt(offset_62, _1090)
|
||||
// let _220 := 0xffffffffffffffff
|
||||
// if gt(offset_62, _220)
|
||||
// {
|
||||
// revert(value4, value4)
|
||||
// }
|
||||
// let _1092 := add(headStart_55, offset_62)
|
||||
// if iszero(slt(add(_1092, 0x1f), dataEnd_56))
|
||||
// let _222 := add(headStart_55, offset_62)
|
||||
// if iszero(slt(add(_222, 0x1f), dataEnd_56))
|
||||
// {
|
||||
// revert(value4, value4)
|
||||
// }
|
||||
// let abi_decode_length_15_689 := calldataload(_1092)
|
||||
// if gt(abi_decode_length_15_689, _1090)
|
||||
// let abi_decode_length_15_116 := calldataload(_222)
|
||||
// if gt(abi_decode_length_15_116, _220)
|
||||
// {
|
||||
// revert(value4, value4)
|
||||
// }
|
||||
// if gt(add(add(_1092, abi_decode_length_15_689), 0x20), dataEnd_56)
|
||||
// if gt(add(add(_222, abi_decode_length_15_116), 32), dataEnd_56)
|
||||
// {
|
||||
// revert(value4, value4)
|
||||
// }
|
||||
// value2_59 := add(_1092, 0x20)
|
||||
// value3 := abi_decode_length_15_689
|
||||
// let _1095 := calldataload(add(headStart_55, 96))
|
||||
// if iszero(lt(_1095, 3))
|
||||
// value2_59 := add(_222, 32)
|
||||
// value3 := abi_decode_length_15_116
|
||||
// let _225 := calldataload(add(headStart_55, 96))
|
||||
// if iszero(lt(_225, 3))
|
||||
// {
|
||||
// revert(value4, value4)
|
||||
// }
|
||||
// value4 := _1095
|
||||
// value4 := _225
|
||||
// }
|
||||
// function abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(headStart_252, value10_253, value9_254, value8_255, value7_256, value6_257, value5_258, value4_259, value3_260, value2_261, value1_262, value0_263) -> tail_264
|
||||
// {
|
||||
// tail_264 := add(headStart_252, 352)
|
||||
// mstore(headStart_252, value0_263)
|
||||
// let _1307 := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
// mstore(add(headStart_252, 32), and(value1_262, _1307))
|
||||
// let _439 := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
// mstore(add(headStart_252, 32), and(value1_262, _439))
|
||||
// mstore(add(headStart_252, 64), value2_261)
|
||||
// mstore(add(headStart_252, 96), value3_260)
|
||||
// if iszero(lt(value4_259, 3))
|
||||
@ -1137,8 +1137,8 @@
|
||||
// mstore(add(headStart_252, 160), value5_258)
|
||||
// mstore(add(headStart_252, 192), value6_257)
|
||||
// mstore(add(headStart_252, 224), value7_256)
|
||||
// mstore(add(headStart_252, 256), and(value8_255, _1307))
|
||||
// mstore(add(headStart_252, 288), and(value9_254, _1307))
|
||||
// mstore(add(headStart_252, 256), and(value8_255, _439))
|
||||
// mstore(add(headStart_252, 288), and(value9_254, _439))
|
||||
// mstore(add(headStart_252, 320), value10_253)
|
||||
// }
|
||||
// }
|
||||
|
@ -458,13 +458,14 @@
|
||||
// ----
|
||||
// fullSuite
|
||||
// {
|
||||
// let _1 := 0x20
|
||||
// let _2 := 0
|
||||
// let _485 := mload(_2)
|
||||
// let abi_encode_pos := 0x20
|
||||
// let abi_encode_length_68 := mload(_485)
|
||||
// mstore(0x20, abi_encode_length_68)
|
||||
// let _268 := mload(_2)
|
||||
// let abi_encode_pos := _1
|
||||
// let abi_encode_length_68 := mload(_268)
|
||||
// mstore(_1, abi_encode_length_68)
|
||||
// abi_encode_pos := 64
|
||||
// let abi_encode_srcPtr := add(_485, 0x20)
|
||||
// let abi_encode_srcPtr := add(_268, _1)
|
||||
// let abi_encode_i_69 := _2
|
||||
// for {
|
||||
// }
|
||||
@ -473,31 +474,45 @@
|
||||
// abi_encode_i_69 := add(abi_encode_i_69, 1)
|
||||
// }
|
||||
// {
|
||||
// abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(mload(abi_encode_srcPtr), abi_encode_pos)
|
||||
// abi_encode_srcPtr := add(abi_encode_srcPtr, 0x20)
|
||||
// let _668 := mload(abi_encode_srcPtr)
|
||||
// let abi_encode_pos_71_760 := abi_encode_pos
|
||||
// let abi_encode_srcPtr_73_762 := _668
|
||||
// let abi_encode_i_74_763 := _2
|
||||
// for {
|
||||
// }
|
||||
// lt(abi_encode_i_74_763, 0x3)
|
||||
// {
|
||||
// abi_encode_i_74_763 := add(abi_encode_i_74_763, 1)
|
||||
// }
|
||||
// {
|
||||
// mstore(abi_encode_pos_71_760, and(mload(abi_encode_srcPtr_73_762), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
|
||||
// abi_encode_srcPtr_73_762 := add(abi_encode_srcPtr_73_762, _1)
|
||||
// abi_encode_pos_71_760 := add(abi_encode_pos_71_760, _1)
|
||||
// }
|
||||
// abi_encode_srcPtr := add(abi_encode_srcPtr, _1)
|
||||
// abi_encode_pos := add(abi_encode_pos, 0x60)
|
||||
// }
|
||||
// let _487 := mload(0x40)
|
||||
// let _488 := mload(0x20)
|
||||
// if slt(sub(_487, _488), 128)
|
||||
// let _270 := mload(64)
|
||||
// let _271 := mload(_1)
|
||||
// if slt(sub(_270, _271), 128)
|
||||
// {
|
||||
// revert(_2, _2)
|
||||
// }
|
||||
// let abi_decode_offset_64 := calldataload(add(_488, 64))
|
||||
// let abi_decode__165 := 0xffffffffffffffff
|
||||
// if gt(abi_decode_offset_64, abi_decode__165)
|
||||
// let abi_decode_offset_64 := calldataload(add(_271, 64))
|
||||
// let abi_decode__74 := 0xffffffffffffffff
|
||||
// if gt(abi_decode_offset_64, abi_decode__74)
|
||||
// {
|
||||
// revert(_2, _2)
|
||||
// }
|
||||
// let abi_decode_value2_587 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_488, abi_decode_offset_64), _487)
|
||||
// let abi_decode_offset_65 := calldataload(add(_488, 96))
|
||||
// if gt(abi_decode_offset_65, abi_decode__165)
|
||||
// let abi_decode_value2_367 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_271, abi_decode_offset_64), _270)
|
||||
// let abi_decode_offset_65 := calldataload(add(_271, 96))
|
||||
// if gt(abi_decode_offset_65, abi_decode__74)
|
||||
// {
|
||||
// revert(_2, _2)
|
||||
// }
|
||||
// let abi_decode_value3_588 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_488, abi_decode_offset_65), _487)
|
||||
// sstore(calldataload(_488), calldataload(add(_488, 32)))
|
||||
// sstore(abi_decode_value2_587, abi_decode_value3_588)
|
||||
// let abi_decode_value3_368 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_271, abi_decode_offset_65), _270)
|
||||
// sstore(calldataload(_271), calldataload(add(_271, _1)))
|
||||
// sstore(abi_decode_value2_367, abi_decode_value3_368)
|
||||
// sstore(_2, abi_encode_pos)
|
||||
// function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset_3, end_4) -> array_5
|
||||
// {
|
||||
@ -506,23 +521,19 @@
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// let length_6 := calldataload(offset_3)
|
||||
// if gt(length_6, 0xffffffffffffffff)
|
||||
// let array_5_115 := allocateMemory(array_allocation_size_t_array$_t_address_$dyn_memory(length_6))
|
||||
// array_5 := array_5_115
|
||||
// let dst_7 := array_5_115
|
||||
// mstore(array_5_115, length_6)
|
||||
// let _16 := 0x20
|
||||
// dst_7 := add(array_5_115, _16)
|
||||
// let src_8 := add(offset_3, _16)
|
||||
// if gt(add(add(offset_3, mul(length_6, 0x40)), _16), end_4)
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// let array_allo__217 := 0x20
|
||||
// let array_5_254 := allocateMemory(add(mul(length_6, array_allo__217), array_allo__217))
|
||||
// array_5 := array_5_254
|
||||
// let dst_7 := array_5_254
|
||||
// mstore(array_5_254, length_6)
|
||||
// dst_7 := add(array_5_254, array_allo__217)
|
||||
// let src_8 := add(offset_3, array_allo__217)
|
||||
// if gt(add(add(offset_3, mul(length_6, 0x40)), array_allo__217), end_4)
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// let i_9_566 := 0
|
||||
// let i_9 := i_9_566
|
||||
// let i_9_346 := 0
|
||||
// let i_9 := i_9_346
|
||||
// for {
|
||||
// }
|
||||
// lt(i_9, length_6)
|
||||
@ -532,16 +543,17 @@
|
||||
// {
|
||||
// if iszero(slt(add(src_8, 0x1f), end_4))
|
||||
// {
|
||||
// revert(i_9_566, i_9_566)
|
||||
// revert(i_9_346, i_9_346)
|
||||
// }
|
||||
// let abi_decode_array_13_263 := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(0x2))
|
||||
// let abi_decode_dst_15 := abi_decode_array_13_263
|
||||
// let abi_decode_array_13_124 := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(0x2))
|
||||
// let abi_decode_dst_15 := abi_decode_array_13_124
|
||||
// let abi_decode_src_16 := src_8
|
||||
// if gt(add(src_8, 64), end_4)
|
||||
// let abi_decode__289 := add(src_8, 0x40)
|
||||
// if gt(abi_decode__289, end_4)
|
||||
// {
|
||||
// revert(i_9_566, i_9_566)
|
||||
// revert(i_9_346, i_9_346)
|
||||
// }
|
||||
// let abi_decode_i_17 := i_9_566
|
||||
// let abi_decode_i_17 := i_9_346
|
||||
// for {
|
||||
// }
|
||||
// lt(abi_decode_i_17, 0x2)
|
||||
@ -550,12 +562,12 @@
|
||||
// }
|
||||
// {
|
||||
// mstore(abi_decode_dst_15, calldataload(abi_decode_src_16))
|
||||
// abi_decode_dst_15 := add(abi_decode_dst_15, array_allo__217)
|
||||
// abi_decode_src_16 := add(abi_decode_src_16, array_allo__217)
|
||||
// abi_decode_dst_15 := add(abi_decode_dst_15, _16)
|
||||
// abi_decode_src_16 := add(abi_decode_src_16, _16)
|
||||
// }
|
||||
// mstore(dst_7, abi_decode_array_13_263)
|
||||
// dst_7 := add(dst_7, array_allo__217)
|
||||
// src_8 := add(src_8, 0x40)
|
||||
// mstore(dst_7, abi_decode_array_13_124)
|
||||
// dst_7 := add(dst_7, _16)
|
||||
// src_8 := abi_decode__289
|
||||
// }
|
||||
// }
|
||||
// function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset_27, end_28) -> array_29
|
||||
@ -565,19 +577,14 @@
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// let length_30 := calldataload(offset_27)
|
||||
// if gt(length_30, 0xffffffffffffffff)
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// let array_allo__234 := 0x20
|
||||
// let array_allo__560 := mul(length_30, array_allo__234)
|
||||
// let array_29_279 := allocateMemory(add(array_allo__560, array_allo__234))
|
||||
// array_29 := array_29_279
|
||||
// let dst_31 := array_29_279
|
||||
// mstore(array_29_279, length_30)
|
||||
// dst_31 := add(array_29_279, array_allo__234)
|
||||
// let src_32 := add(offset_27, array_allo__234)
|
||||
// if gt(add(add(offset_27, array_allo__560), array_allo__234), end_28)
|
||||
// let array_29_131 := allocateMemory(array_allocation_size_t_array$_t_address_$dyn_memory(length_30))
|
||||
// array_29 := array_29_131
|
||||
// let dst_31 := array_29_131
|
||||
// mstore(array_29_131, length_30)
|
||||
// let _52 := 0x20
|
||||
// dst_31 := add(array_29_131, _52)
|
||||
// let src_32 := add(offset_27, _52)
|
||||
// if gt(add(add(offset_27, mul(length_30, _52)), _52), end_28)
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
@ -590,37 +597,29 @@
|
||||
// }
|
||||
// {
|
||||
// mstore(dst_31, calldataload(src_32))
|
||||
// dst_31 := add(dst_31, array_allo__234)
|
||||
// src_32 := add(src_32, array_allo__234)
|
||||
// }
|
||||
// }
|
||||
// function abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(value_70, pos_71)
|
||||
// {
|
||||
// let srcPtr_73 := value_70
|
||||
// let i_74 := 0
|
||||
// for {
|
||||
// }
|
||||
// lt(i_74, 0x3)
|
||||
// {
|
||||
// i_74 := add(i_74, 1)
|
||||
// }
|
||||
// {
|
||||
// mstore(pos_71, and(mload(srcPtr_73), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
|
||||
// srcPtr_73 := add(srcPtr_73, 0x20)
|
||||
// pos_71 := add(pos_71, 0x20)
|
||||
// dst_31 := add(dst_31, _52)
|
||||
// src_32 := add(src_32, _52)
|
||||
// }
|
||||
// }
|
||||
// function allocateMemory(size) -> memPtr
|
||||
// {
|
||||
// let memPtr_315 := mload(64)
|
||||
// memPtr := memPtr_315
|
||||
// let newFreePtr := add(memPtr_315, size)
|
||||
// if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_315))
|
||||
// let memPtr_157 := mload(64)
|
||||
// memPtr := memPtr_157
|
||||
// let newFreePtr := add(memPtr_157, size)
|
||||
// if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_157))
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// mstore(64, newFreePtr)
|
||||
// }
|
||||
// function array_allocation_size_t_array$_t_address_$dyn_memory(length_90) -> size_91
|
||||
// {
|
||||
// if gt(length_90, 0xffffffffffffffff)
|
||||
// {
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// size_91 := add(mul(length_90, 0x20), 0x20)
|
||||
// }
|
||||
// function array_allocation_size_t_array$_t_uint256_$2_memory(length_94) -> size_95
|
||||
// {
|
||||
// if gt(length_94, 0xffffffffffffffff)
|
||||
|
@ -264,10 +264,10 @@
|
||||
// }
|
||||
// {
|
||||
// let validateJo__34 := 0x20
|
||||
// let validateJo__376 := add(validateJo__10, mul(validateJo_i, 0xc0))
|
||||
// let validateJo_noteIndex := add(validateJo__376, 36)
|
||||
// let validateJo__373 := add(validateJo__10, mul(validateJo_i, 0xc0))
|
||||
// let validateJo_noteIndex := add(validateJo__373, 0x24)
|
||||
// let validateJo_k := validateJo_i_290
|
||||
// let validateJo_a_292 := calldataload(add(validateJo__376, 68))
|
||||
// let validateJo_a_292 := calldataload(add(validateJo__373, 0x44))
|
||||
// let validateJo_a := validateJo_a_292
|
||||
// let validateJo_c := validateJo_challenge
|
||||
// let validateJo__39 := add(validateJo_i, 0x01)
|
||||
@ -286,18 +286,18 @@
|
||||
// switch gt(validateJo__39, validateJo_m)
|
||||
// case 1 {
|
||||
// validateJo_kn := addmod(validateJo_kn, sub(validateJo_gen_order, validateJo_k), validateJo_gen_order)
|
||||
// let validateJo_x := mod(mload(0x00), validateJo_gen_order)
|
||||
// let validateJo_x := mod(mload(validateJo_i_290), validateJo_gen_order)
|
||||
// validateJo_k := mulmod(validateJo_k, validateJo_x, validateJo_gen_order)
|
||||
// validateJo_a := mulmod(validateJo_a_292, validateJo_x, validateJo_gen_order)
|
||||
// validateJo_c := mulmod(validateJo_challenge, validateJo_x, validateJo_gen_order)
|
||||
// mstore(0x00, keccak256(0x00, validateJo__34))
|
||||
// mstore(validateJo_i_290, keccak256(validateJo_i_290, validateJo__34))
|
||||
// }
|
||||
// case 0 {
|
||||
// validateJo_kn := addmod(validateJo_kn, validateJo_k, validateJo_gen_order)
|
||||
// }
|
||||
// let validateJo__52 := 0x40
|
||||
// calldatacopy(0xe0, add(validateJo__376, 164), validateJo__52)
|
||||
// calldatacopy(validateJo__34, add(validateJo__376, 100), validateJo__52)
|
||||
// calldatacopy(0xe0, add(validateJo__373, 164), validateJo__52)
|
||||
// calldatacopy(validateJo__34, add(validateJo__373, 100), validateJo__52)
|
||||
// let validateJo__61 := 0x120
|
||||
// mstore(validateJo__61, sub(validateJo_gen_order, validateJo_c))
|
||||
// let validateJo__62 := 0x60
|
||||
@ -329,8 +329,8 @@
|
||||
// }
|
||||
// if iszero(validateJo_result)
|
||||
// {
|
||||
// mstore(0x00, 400)
|
||||
// revert(0x00, validateJo__34)
|
||||
// mstore(validateJo_i_290, 400)
|
||||
// revert(validateJo_i_290, validateJo__34)
|
||||
// }
|
||||
// validateJo_b := add(validateJo_b, validateJo__52)
|
||||
// }
|
||||
@ -340,13 +340,13 @@
|
||||
// }
|
||||
// if iszero(eq(mod(keccak256(validateJo__24, add(validateJo_b, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60)), validateJo_gen_order), validateJo_challenge))
|
||||
// {
|
||||
// mstore(0x00, 404)
|
||||
// revert(0x00, 0x20)
|
||||
// mstore(validateJo_i_290, 404)
|
||||
// revert(validateJo_i_290, 0x20)
|
||||
// }
|
||||
// mstore(0x00, 0x01)
|
||||
// return(0x00, 0x20)
|
||||
// mstore(0x00, 404)
|
||||
// revert(0x00, 0x20)
|
||||
// mstore(validateJo_i_290, 0x01)
|
||||
// return(validateJo_i_290, 0x20)
|
||||
// mstore(validateJo_i_290, 404)
|
||||
// revert(validateJo_i_290, 0x20)
|
||||
// function validatePairing(t2)
|
||||
// {
|
||||
// let t2_x_1 := calldataload(t2)
|
||||
@ -379,8 +379,8 @@
|
||||
// let success := call(gas(), 8, 0, _165, _216, _165, _165)
|
||||
// if or(iszero(success), iszero(mload(_165)))
|
||||
// {
|
||||
// mstore(0x00, 400)
|
||||
// revert(0x00, _165)
|
||||
// mstore(0, 400)
|
||||
// revert(0, _165)
|
||||
// }
|
||||
// }
|
||||
// function validateCommitment(note, k_1, a_2)
|
||||
@ -409,6 +409,6 @@
|
||||
// {
|
||||
// calldatacopy(add(0x300, mul(i_7, 0x80)), add(add(notes_5, mul(i_7, 0xc0)), 0x60), 0x80)
|
||||
// }
|
||||
// mstore(0x00, keccak256(0x300, mul(n_6, 0x80)))
|
||||
// mstore(0, keccak256(0x300, mul(n_6, 0x80)))
|
||||
// }
|
||||
// }
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <libyul/optimiser/Disambiguator.h>
|
||||
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
|
||||
#include <libyul/optimiser/NameCollector.h>
|
||||
#include <libyul/optimiser/EquivalentFunctionCombiner.h>
|
||||
#include <libyul/optimiser/ExpressionSplitter.h>
|
||||
#include <libyul/optimiser/FunctionGrouper.h>
|
||||
#include <libyul/optimiser/FunctionHoister.h>
|
||||
@ -128,7 +129,7 @@ public:
|
||||
cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl;
|
||||
cout << " (e)xpr inline/(i)nline/(s)implify/(u)nusedprune/ss(a) transform/" << endl;
|
||||
cout << " (r)edundant assign elim./re(m)aterializer/f(o)r-loop-pre-rewriter/" << endl;
|
||||
cout << " s(t)ructural simplifier? " << endl;
|
||||
cout << " s(t)ructural simplifier/equi(v)alent function combiner? " << endl;
|
||||
cout.flush();
|
||||
int option = readStandardInputChar();
|
||||
cout << ' ' << char(option) << endl;
|
||||
@ -184,6 +185,9 @@ public:
|
||||
case 'm':
|
||||
Rematerialiser::run(*m_dialect, *m_ast);
|
||||
break;
|
||||
case 'v':
|
||||
EquivalentFunctionCombiner::run(*m_ast);
|
||||
break;
|
||||
default:
|
||||
cout << "Unknown option." << endl;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user