Make Yul optimizer not fail for wasm.

This commit is contained in:
chriseth 2019-05-28 12:57:15 +02:00
parent 8260ae1397
commit 6cb6fe35ef
17 changed files with 321 additions and 210 deletions

View File

@ -7,6 +7,7 @@ Language Features:
Compiler Features:
* Optimizer: Add rule to simplify SUB(~0, X) to NOT(X).
* Commandline Interface: Experimental parser error recovery via the ``--error-recovery`` commandline switch.
* Yul Optimizer: Make the optimizer work for all dialects of Yul including eWasm.

View File

@ -32,8 +32,8 @@
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/backends/evm/AsmCodeGen.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/optimiser/Suite.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/YulString.h>
#include <liblangutil/ErrorReporter.h>

View File

@ -31,6 +31,7 @@
#include <libyul/backends/evm/EVMCodeTransform.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/evm/EVMObjectCompiler.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/wasm/WasmDialect.h>
#include <libyul/backends/wasm/EWasmObjectCompiler.h>
#include <libyul/optimiser/Metrics.h>
@ -146,15 +147,17 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation)
for (auto& subNode: _object.subObjects)
if (auto subObject = dynamic_cast<Object*>(subNode.get()))
optimize(*subObject, false);
EVMDialect const& dialect = dynamic_cast<EVMDialect const&>(languageToDialect(m_language, m_evmVersion));
GasMeter meter(dialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
OptimiserSuite::run(
dialect,
meter,
*_object.code,
*_object.analysisInfo,
m_optimiserSettings.optimizeStackAllocation
);
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&languageToDialect(m_language, m_evmVersion)))
{
GasMeter meter(*dialect, _isCreation, m_optimiserSettings.expectedExecutionsPerDeployment);
OptimiserSuite::run(
*dialect,
meter,
*_object.code,
*_object.analysisInfo,
m_optimiserSettings.optimizeStackAllocation
);
}
}
MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const

View File

@ -28,6 +28,8 @@ add_library(yul
backends/evm/AbstractAssembly.h
backends/evm/AsmCodeGen.h
backends/evm/AsmCodeGen.cpp
backends/evm/ConstantOptimiser.cpp
backends/evm/ConstantOptimiser.h
backends/evm/EVMAssembly.cpp
backends/evm/EVMAssembly.h
backends/evm/EVMCodeTransform.cpp
@ -36,6 +38,8 @@ add_library(yul
backends/evm/EVMDialect.h
backends/evm/EVMObjectCompiler.cpp
backends/evm/EVMObjectCompiler.h
backends/evm/EVMMetrics.cpp
backends/evm/EVMMetrics.h
backends/evm/NoOutputAssembly.h
backends/evm/NoOutputAssembly.cpp
backends/wasm/EWasmCodeTransform.cpp
@ -58,8 +62,6 @@ add_library(yul
optimiser/BlockHasher.h
optimiser/CommonSubexpressionEliminator.cpp
optimiser/CommonSubexpressionEliminator.h
optimiser/ConstantOptimiser.cpp
optimiser/ConstantOptimiser.h
optimiser/ControlFlowSimplifier.cpp
optimiser/ControlFlowSimplifier.h
optimiser/DataFlowAnalyzer.cpp

View File

@ -43,27 +43,31 @@ map<YulString, int> CompilabilityChecker::run(
solAssert(_dialect.flavour == AsmFlavour::Strict, "");
solAssert(dynamic_cast<EVMDialect const*>(&_dialect), "");
NoOutputEVMDialect noOutputDialect(dynamic_cast<EVMDialect const&>(_dialect));
BuiltinContext builtinContext;
yul::AsmAnalysisInfo analysisInfo =
yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _ast);
NoOutputAssembly assembly;
CodeTransform transform(assembly, analysisInfo, _ast, noOutputDialect, builtinContext, _optimizeStackAllocation);
try
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
{
transform(_ast);
}
catch (StackTooDeepError const&)
{
solAssert(!transform.stackErrors().empty(), "Got stack too deep exception that was not stored.");
}
NoOutputEVMDialect noOutputDialect(*evmDialect);
BuiltinContext builtinContext;
std::map<YulString, int> functions;
for (StackTooDeepError const& error: transform.stackErrors())
functions[error.functionName] = max(error.depth, functions[error.functionName]);
yul::AsmAnalysisInfo analysisInfo =
yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _ast);
return functions;
NoOutputAssembly assembly;
CodeTransform transform(assembly, analysisInfo, _ast, noOutputDialect, builtinContext, _optimizeStackAllocation);
try
{
transform(_ast);
}
catch (StackTooDeepError const&)
{
solAssert(!transform.stackErrors().empty(), "Got stack too deep exception that was not stored.");
}
std::map<YulString, int> functions;
for (StackTooDeepError const& error: transform.stackErrors())
functions[error.functionName] = max(error.depth, functions[error.functionName]);
return functions;
}
else
return {};
}

View File

@ -66,6 +66,9 @@ struct Dialect: boost::noncopyable
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
virtual BuiltinFunction const* builtin(YulString /*_name*/) const { return nullptr; }
virtual BuiltinFunction const* discardFunction() const { return nullptr; }
virtual BuiltinFunction const* equalityFunction() const { return nullptr; }
Dialect(AsmFlavour _flavour): flavour(_flavour) {}
virtual ~Dialect() = default;

View File

@ -18,14 +18,12 @@
* Optimisation stage that replaces constants by expressions that compute them.
*/
#include <libyul/optimiser/ConstantOptimiser.h>
#include <libyul/backends/evm/ConstantOptimiser.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/AsmData.h>
#include <libyul/AsmPrinter.h>
#include <libyul/Utilities.h>
#include <libyul/AsmParser.h>
#include <libdevcore/CommonData.h>

View File

@ -68,6 +68,9 @@ struct EVMDialect: public Dialect
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
BuiltinFunctionForEVM const* builtin(YulString _name) const override;
BuiltinFunctionForEVM const* discardFunction() const override { return builtin("pop"_yulstring); }
BuiltinFunctionForEVM const* equalityFunction() const override { return builtin("eq"_yulstring); }
static EVMDialect const& looseAssemblyForEVM(langutil::EVMVersion _version);
static EVMDialect const& strictAssemblyForEVM(langutil::EVMVersion _version);
static EVMDialect const& strictAssemblyForEVMObjects(langutil::EVMVersion _version);

View File

@ -0,0 +1,123 @@
/*
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/>.
*/
/**
* Module providing metrics for the EVM optimizer.
*/
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/AsmData.h>
#include <libyul/Exceptions.h>
#include <libyul/Utilities.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libevmasm/Instruction.h>
#include <libevmasm/GasMeter.h>
#include <libdevcore/Visitor.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
using namespace yul;
size_t GasMeter::costs(Expression const& _expression) const
{
return combineCosts(GasMeterVisitor::costs(_expression, m_dialect, m_isCreation));
}
size_t GasMeter::instructionCosts(eth::Instruction _instruction) const
{
return combineCosts(GasMeterVisitor::instructionCosts(_instruction, m_dialect, m_isCreation));
}
size_t GasMeter::combineCosts(std::pair<size_t, size_t> _costs) const
{
return _costs.first * m_runs + _costs.second;
}
pair<size_t, size_t> GasMeterVisitor::costs(
Expression const& _expression,
EVMDialect const& _dialect,
bool _isCreation
)
{
GasMeterVisitor gmv(_dialect, _isCreation);
gmv.visit(_expression);
return {gmv.m_runGas, gmv.m_dataGas};
}
pair<size_t, size_t> GasMeterVisitor::instructionCosts(
dev::eth::Instruction _instruction,
EVMDialect const& _dialect,
bool _isCreation
)
{
GasMeterVisitor gmv(_dialect, _isCreation);
gmv.instructionCostsInternal(_instruction);
return {gmv.m_runGas, gmv.m_dataGas};
}
void GasMeterVisitor::operator()(FunctionCall const& _funCall)
{
ASTWalker::operator()(_funCall);
if (BuiltinFunctionForEVM const* f = m_dialect.builtin(_funCall.functionName.name))
if (f->instruction)
{
instructionCostsInternal(*f->instruction);
return;
}
yulAssert(false, "Functions not implemented.");
}
void GasMeterVisitor::operator()(FunctionalInstruction const& _fun)
{
ASTWalker::operator()(_fun);
instructionCostsInternal(_fun.instruction);
}
void GasMeterVisitor::operator()(Literal const& _lit)
{
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1);
m_dataGas +=
singleByteDataGas() +
size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation));
}
void GasMeterVisitor::operator()(Identifier const&)
{
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::DUP1);
m_dataGas += singleByteDataGas();
}
size_t GasMeterVisitor::singleByteDataGas() const
{
if (m_isCreation)
return dev::eth::GasCosts::txDataNonZeroGas;
else
return dev::eth::GasCosts::createDataGas;
}
void GasMeterVisitor::instructionCostsInternal(dev::eth::Instruction _instruction)
{
if (_instruction == eth::Instruction::EXP)
m_runGas += dev::eth::GasCosts::expGas + dev::eth::GasCosts::expByteGas(m_dialect.evmVersion());
else
m_runGas += dev::eth::GasMeter::runGas(_instruction);
m_dataGas += singleByteDataGas();
}

View File

@ -0,0 +1,101 @@
/*
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/>.
*/
/**
* Module providing metrics for the optimizer.
*/
#pragma once
#include <libyul/optimiser/ASTWalker.h>
#include <liblangutil/EVMVersion.h>
#include <libevmasm/Instruction.h>
namespace yul
{
struct EVMDialect;
/**
* Gas meter for expressions only involving literals, identifiers and
* EVM instructions.
*
* Assumes that EXP is not used with exponents larger than a single byte.
* Is not particularly exact for anything apart from arithmetic.
*/
class GasMeter
{
public:
GasMeter(EVMDialect const& _dialect, bool _isCreation, size_t _runs):
m_dialect(_dialect),
m_isCreation{_isCreation},
m_runs(_runs)
{}
/// @returns the full combined costs of deploying and evaluating the expression.
size_t costs(Expression const& _expression) const;
/// @returns the combined costs of deploying and running the instruction, not including
/// the costs for its arguments.
size_t instructionCosts(dev::eth::Instruction _instruction) const;
private:
size_t combineCosts(std::pair<size_t, size_t> _costs) const;
EVMDialect const& m_dialect;
bool m_isCreation = false;
size_t m_runs;
};
class GasMeterVisitor: public ASTWalker
{
public:
static std::pair<size_t, size_t> costs(
Expression const& _expression,
EVMDialect const& _dialect,
bool _isCreation
);
static std::pair<size_t, size_t> instructionCosts(
dev::eth::Instruction _instruction,
EVMDialect const& _dialect,
bool _isCreation = false
);
public:
GasMeterVisitor(EVMDialect const& _dialect, bool _isCreation):
m_dialect(_dialect),
m_isCreation{_isCreation}
{}
void operator()(FunctionCall const& _funCall) override;
void operator()(FunctionalInstruction const& _instr) override;
void operator()(Literal const& _literal) override;
void operator()(Identifier const& _identifier) override;
private:
size_t singleByteDataGas() const;
/// Computes the cost of storing and executing the single instruction (excluding its arguments).
/// For EXP, it assumes that the exponent is at most 255.
/// Does not work particularly exact for anything apart from arithmetic.
void instructionCostsInternal(dev::eth::Instruction _instruction);
EVMDialect const& m_dialect;
bool m_isCreation = false;
size_t m_runGas = 0;
size_t m_dataGas = 0;
};
}

View File

@ -45,6 +45,8 @@ struct WasmDialect: public Dialect
WasmDialect();
BuiltinFunction const* builtin(YulString _name) const override;
BuiltinFunction const* discardFunction() const override { return builtin("drop"_yulstring); }
BuiltinFunction const* equalityFunction() const override { return builtin("i64.eq"_yulstring); }
static WasmDialect const& instance();

View File

@ -18,6 +18,7 @@
#include <libyul/optimiser/Semantics.h>
#include <libyul/AsmData.h>
#include <libyul/Utilities.h>
#include <libyul/Dialect.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/Visitor.h>
@ -33,11 +34,16 @@ using OptionalStatements = boost::optional<vector<Statement>>;
namespace
{
ExpressionStatement makePopExpressionStatement(langutil::SourceLocation const& _location, Expression&& _expression)
ExpressionStatement makeDiscardCall(
langutil::SourceLocation const& _location,
Dialect const& _dialect,
Expression&& _expression
)
{
yulAssert(_dialect.discardFunction(), "No discard function available.");
return {_location, FunctionCall{
_location,
Identifier{_location, "pop"_yulstring},
Identifier{_location, _dialect.discardFunction()->name},
{std::move(_expression)}
}};
}
@ -66,36 +72,55 @@ void removeEmptyCasesFromSwitch(Switch& _switchStmt)
);
}
OptionalStatements reduceNoCaseSwitch(Switch& _switchStmt)
OptionalStatements reduceNoCaseSwitch(Dialect const& _dialect, Switch& _switchStmt)
{
yulAssert(_switchStmt.cases.empty(), "Expected no case!");
if (!_dialect.discardFunction())
return {};
auto loc = locationOf(*_switchStmt.expression);
return make_vector<Statement>(makePopExpressionStatement(loc, std::move(*_switchStmt.expression)));
return make_vector<Statement>(makeDiscardCall(
loc,
_dialect,
std::move(*_switchStmt.expression)
));
}
OptionalStatements reduceSingleCaseSwitch(Switch& _switchStmt)
OptionalStatements reduceSingleCaseSwitch(Dialect const& _dialect, Switch& _switchStmt)
{
yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!");
auto& switchCase = _switchStmt.cases.front();
auto loc = locationOf(*_switchStmt.expression);
if (switchCase.value)
{
if (!_dialect.equalityFunction())
return {};
return make_vector<Statement>(If{
std::move(_switchStmt.location),
make_unique<Expression>(FunctionCall{
loc,
Identifier{loc, "eq"_yulstring},
Identifier{loc, _dialect.equalityFunction()->name},
{std::move(*switchCase.value), std::move(*_switchStmt.expression)}
}),
std::move(switchCase.body)
});
}
else
{
if (!_dialect.discardFunction())
return {};
return make_vector<Statement>(
makePopExpressionStatement(loc, std::move(*_switchStmt.expression)),
makeDiscardCall(
loc,
_dialect,
std::move(*_switchStmt.expression)
),
std::move(switchCase.body)
);
}
}
}
@ -151,10 +176,14 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
{
GenericFallbackReturnsVisitor<OptionalStatements, If, Switch> const visitor(
[&](If& _ifStmt) -> OptionalStatements {
if (_ifStmt.body.statements.empty())
if (_ifStmt.body.statements.empty() && m_dialect.discardFunction())
{
OptionalStatements s = vector<Statement>{};
s->emplace_back(makePopExpressionStatement(_ifStmt.location, std::move(*_ifStmt.condition)));
s->emplace_back(makeDiscardCall(
_ifStmt.location,
m_dialect,
std::move(*_ifStmt.condition)
));
return s;
}
return {};
@ -164,9 +193,9 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
removeEmptyCasesFromSwitch(_switchStmt);
if (_switchStmt.cases.empty())
return reduceNoCaseSwitch(_switchStmt);
return reduceNoCaseSwitch(m_dialect, _switchStmt);
else if (_switchStmt.cases.size() == 1)
return reduceSingleCaseSwitch(_switchStmt);
return reduceSingleCaseSwitch(m_dialect, _switchStmt);
return {};
}

View File

@ -169,93 +169,6 @@ void CodeCost::addInstructionCost(eth::Instruction _instruction)
m_cost += 49;
}
size_t GasMeter::costs(Expression const& _expression) const
{
return combineCosts(GasMeterVisitor::costs(_expression, m_dialect, m_isCreation));
}
size_t GasMeter::instructionCosts(eth::Instruction _instruction) const
{
return combineCosts(GasMeterVisitor::instructionCosts(_instruction, m_dialect, m_isCreation));
}
size_t GasMeter::combineCosts(std::pair<size_t, size_t> _costs) const
{
return _costs.first * m_runs + _costs.second;
}
pair<size_t, size_t> GasMeterVisitor::costs(
Expression const& _expression,
EVMDialect const& _dialect,
bool _isCreation
)
{
GasMeterVisitor gmv(_dialect, _isCreation);
gmv.visit(_expression);
return {gmv.m_runGas, gmv.m_dataGas};
}
pair<size_t, size_t> GasMeterVisitor::instructionCosts(
dev::eth::Instruction _instruction,
EVMDialect const& _dialect,
bool _isCreation
)
{
GasMeterVisitor gmv(_dialect, _isCreation);
gmv.instructionCostsInternal(_instruction);
return {gmv.m_runGas, gmv.m_dataGas};
}
void GasMeterVisitor::operator()(FunctionCall const& _funCall)
{
ASTWalker::operator()(_funCall);
if (BuiltinFunctionForEVM const* f = m_dialect.builtin(_funCall.functionName.name))
if (f->instruction)
{
instructionCostsInternal(*f->instruction);
return;
}
yulAssert(false, "Functions not implemented.");
}
void GasMeterVisitor::operator()(FunctionalInstruction const& _fun)
{
ASTWalker::operator()(_fun);
instructionCostsInternal(_fun.instruction);
}
void GasMeterVisitor::operator()(Literal const& _lit)
{
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::PUSH1);
m_dataGas +=
singleByteDataGas() +
size_t(dev::eth::GasMeter::dataGas(dev::toCompactBigEndian(valueOfLiteral(_lit), 1), m_isCreation));
}
void GasMeterVisitor::operator()(Identifier const&)
{
m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::DUP1);
m_dataGas += singleByteDataGas();
}
size_t GasMeterVisitor::singleByteDataGas() const
{
if (m_isCreation)
return dev::eth::GasCosts::txDataNonZeroGas;
else
return dev::eth::GasCosts::createDataGas;
}
void GasMeterVisitor::instructionCostsInternal(dev::eth::Instruction _instruction)
{
if (_instruction == eth::Instruction::EXP)
m_runGas += dev::eth::GasCosts::expGas + dev::eth::GasCosts::expByteGas(m_dialect.evmVersion());
else
m_runGas += dev::eth::GasMeter::runGas(_instruction);
m_dataGas += singleByteDataGas();
}
void AssignmentCounter::operator()(Assignment const& _assignment)
{
for (auto const& variable: _assignment.variableNames)

View File

@ -22,9 +22,6 @@
#include <libyul/optimiser/ASTWalker.h>
#include <liblangutil/EVMVersion.h>
#include <libevmasm/Instruction.h>
#include <libevmasm/Instruction.h>
namespace yul
{
@ -96,75 +93,6 @@ private:
size_t m_cost = 0;
};
/**
* Gas meter for expressions only involving literals, identifiers and
* EVM instructions.
*
* Assumes that EXP is not used with exponents larger than a single byte.
* Is not particularly exact for anything apart from arithmetic.
*/
class GasMeter
{
public:
GasMeter(EVMDialect const& _dialect, bool _isCreation, size_t _runs):
m_dialect(_dialect),
m_isCreation{_isCreation},
m_runs(_runs)
{}
/// @returns the full combined costs of deploying and evaluating the expression.
size_t costs(Expression const& _expression) const;
/// @returns the combined costs of deploying and running the instruction, not including
/// the costs for its arguments.
size_t instructionCosts(dev::eth::Instruction _instruction) const;
private:
size_t combineCosts(std::pair<size_t, size_t> _costs) const;
EVMDialect const& m_dialect;
bool m_isCreation = false;
size_t m_runs;
};
class GasMeterVisitor: public ASTWalker
{
public:
static std::pair<size_t, size_t> costs(
Expression const& _expression,
EVMDialect const& _dialect,
bool _isCreation
);
static std::pair<size_t, size_t> instructionCosts(
dev::eth::Instruction _instruction,
EVMDialect const& _dialect,
bool _isCreation = false
);
public:
GasMeterVisitor(EVMDialect const& _dialect, bool _isCreation):
m_dialect(_dialect),
m_isCreation{_isCreation}
{}
void operator()(FunctionCall const& _funCall) override;
void operator()(FunctionalInstruction const& _instr) override;
void operator()(Literal const& _literal) override;
void operator()(Identifier const& _identifier) override;
private:
size_t singleByteDataGas() const;
/// Computes the cost of storing and executing the single instruction (excluding its arguments).
/// For EXP, it assumes that the exponent is at most 255.
/// Does not work particularly exact for anything apart from arithmetic.
void instructionCostsInternal(dev::eth::Instruction _instruction);
EVMDialect const& m_dialect;
bool m_isCreation = false;
size_t m_runGas = 0;
size_t m_dataGas = 0;
};
/**
* Counts the number of assignments to every variable.
* Only works after running the Disambiguator.

View File

@ -24,7 +24,6 @@
#include <libyul/optimiser/VarDeclInitializer.h>
#include <libyul/optimiser/BlockFlattener.h>
#include <libyul/optimiser/ControlFlowSimplifier.h>
#include <libyul/optimiser/ConstantOptimiser.h>
#include <libyul/optimiser/DeadCodeEliminator.h>
#include <libyul/optimiser/FunctionGrouper.h>
#include <libyul/optimiser/FunctionHoister.h>
@ -45,6 +44,7 @@
#include <libyul/optimiser/RedundantAssignEliminator.h>
#include <libyul/optimiser/VarNameCleaner.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/backends/evm/ConstantOptimiser.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/AsmData.h>
@ -209,7 +209,8 @@ void OptimiserSuite::run(
FunctionGrouper{}(ast);
ConstantOptimiser{dynamic_cast<EVMDialect const&>(_dialect), _meter}(ast);
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&_dialect))
ConstantOptimiser{*dialect, _meter}(ast);
VarNameCleaner{ast, _dialect, reservedIdentifiers}(ast);
yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast);

View File

@ -23,7 +23,6 @@
#include <libyul/optimiser/VarDeclInitializer.h>
#include <libyul/optimiser/VarNameCleaner.h>
#include <libyul/optimiser/ControlFlowSimplifier.h>
#include <libyul/optimiser/ConstantOptimiser.h>
#include <libyul/optimiser/DeadCodeEliminator.h>
#include <libyul/optimiser/Disambiguator.h>
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
@ -47,8 +46,9 @@
#include <libyul/optimiser/StructuralSimplifier.h>
#include <libyul/optimiser/StackCompressor.h>
#include <libyul/optimiser/Suite.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/backends/evm/ConstantOptimiser.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/backends/evm/EVMMetrics.h>
#include <libyul/backends/wasm/WordSizeTransform.h>
#include <libyul/AsmPrinter.h>
#include <libyul/AsmParser.h>