From 6cb6fe35efdb186562024979a736944a43b9cb02 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 May 2019 12:57:15 +0200 Subject: [PATCH] Make Yul optimizer not fail for wasm. --- Changelog.md | 1 + libsolidity/codegen/CompilerContext.cpp | 2 +- libyul/AssemblyStack.cpp | 21 +-- libyul/CMakeLists.txt | 6 +- libyul/CompilabilityChecker.cpp | 44 ++++--- libyul/Dialect.h | 3 + .../evm}/ConstantOptimiser.cpp | 6 +- .../evm}/ConstantOptimiser.h | 0 libyul/backends/evm/EVMDialect.h | 3 + libyul/backends/evm/EVMMetrics.cpp | 123 ++++++++++++++++++ libyul/backends/evm/EVMMetrics.h | 101 ++++++++++++++ libyul/backends/wasm/WasmDialect.h | 2 + libyul/optimiser/ControlFlowSimplifier.cpp | 51 ++++++-- libyul/optimiser/Metrics.cpp | 87 ------------- libyul/optimiser/Metrics.h | 72 ---------- libyul/optimiser/Suite.cpp | 5 +- test/libyul/YulOptimizerTest.cpp | 4 +- 17 files changed, 321 insertions(+), 210 deletions(-) rename libyul/{optimiser => backends/evm}/ConstantOptimiser.cpp (97%) rename libyul/{optimiser => backends/evm}/ConstantOptimiser.h (100%) create mode 100644 libyul/backends/evm/EVMMetrics.cpp create mode 100644 libyul/backends/evm/EVMMetrics.h diff --git a/Changelog.md b/Changelog.md index 994cff927..71b1378d0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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. diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index e208a8c3c..851038421 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -32,8 +32,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index dec7d21e8..1723e1fc2 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -146,15 +147,17 @@ void AssemblyStack::optimize(Object& _object, bool _isCreation) for (auto& subNode: _object.subObjects) if (auto subObject = dynamic_cast(subNode.get())) optimize(*subObject, false); - EVMDialect const& dialect = dynamic_cast(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(&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 diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 12a31c2bb..bf09207b6 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -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 diff --git a/libyul/CompilabilityChecker.cpp b/libyul/CompilabilityChecker.cpp index 7f065e884..c25b33c98 100644 --- a/libyul/CompilabilityChecker.cpp +++ b/libyul/CompilabilityChecker.cpp @@ -43,27 +43,31 @@ map CompilabilityChecker::run( solAssert(_dialect.flavour == AsmFlavour::Strict, ""); - solAssert(dynamic_cast(&_dialect), ""); - NoOutputEVMDialect noOutputDialect(dynamic_cast(_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(&_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 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 functions; + for (StackTooDeepError const& error: transform.stackErrors()) + functions[error.functionName] = max(error.depth, functions[error.functionName]); + + return functions; + } + else + return {}; } diff --git a/libyul/Dialect.h b/libyul/Dialect.h index 4fc33edbc..6e2fb6585 100644 --- a/libyul/Dialect.h +++ b/libyul/Dialect.h @@ -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; diff --git a/libyul/optimiser/ConstantOptimiser.cpp b/libyul/backends/evm/ConstantOptimiser.cpp similarity index 97% rename from libyul/optimiser/ConstantOptimiser.cpp rename to libyul/backends/evm/ConstantOptimiser.cpp index 2fa200e73..f8b4854d8 100644 --- a/libyul/optimiser/ConstantOptimiser.cpp +++ b/libyul/backends/evm/ConstantOptimiser.cpp @@ -18,14 +18,12 @@ * Optimisation stage that replaces constants by expressions that compute them. */ -#include +#include #include -#include +#include #include -#include #include -#include #include diff --git a/libyul/optimiser/ConstantOptimiser.h b/libyul/backends/evm/ConstantOptimiser.h similarity index 100% rename from libyul/optimiser/ConstantOptimiser.h rename to libyul/backends/evm/ConstantOptimiser.h diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index 56dc99f87..bcea185f4 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -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); diff --git a/libyul/backends/evm/EVMMetrics.cpp b/libyul/backends/evm/EVMMetrics.cpp new file mode 100644 index 000000000..5211e5132 --- /dev/null +++ b/libyul/backends/evm/EVMMetrics.cpp @@ -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 . +*/ +/** +* Module providing metrics for the EVM optimizer. +*/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +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 _costs) const +{ + return _costs.first * m_runs + _costs.second; +} + + +pair 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 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(); +} diff --git a/libyul/backends/evm/EVMMetrics.h b/libyul/backends/evm/EVMMetrics.h new file mode 100644 index 000000000..8a8987b94 --- /dev/null +++ b/libyul/backends/evm/EVMMetrics.h @@ -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 . +*/ +/** + * Module providing metrics for the optimizer. + */ + +#pragma once + +#include +#include +#include + +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 _costs) const; + + EVMDialect const& m_dialect; + bool m_isCreation = false; + size_t m_runs; +}; + +class GasMeterVisitor: public ASTWalker +{ +public: + static std::pair costs( + Expression const& _expression, + EVMDialect const& _dialect, + bool _isCreation + ); + + static std::pair 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; +}; + +} diff --git a/libyul/backends/wasm/WasmDialect.h b/libyul/backends/wasm/WasmDialect.h index 0948a8049..4ade0be54 100644 --- a/libyul/backends/wasm/WasmDialect.h +++ b/libyul/backends/wasm/WasmDialect.h @@ -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(); diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index ccd88051f..7c826aa28 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -33,11 +34,16 @@ using OptionalStatements = boost::optional>; 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(makePopExpressionStatement(loc, std::move(*_switchStmt.expression))); + return make_vector(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(If{ std::move(_switchStmt.location), make_unique(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( - 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& _statements) { GenericFallbackReturnsVisitor const visitor( [&](If& _ifStmt) -> OptionalStatements { - if (_ifStmt.body.statements.empty()) + if (_ifStmt.body.statements.empty() && m_dialect.discardFunction()) { OptionalStatements s = vector{}; - 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& _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 {}; } diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp index a8f9807df..dfc8d98b5 100644 --- a/libyul/optimiser/Metrics.cpp +++ b/libyul/optimiser/Metrics.cpp @@ -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 _costs) const -{ - return _costs.first * m_runs + _costs.second; -} - - -pair 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 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) diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h index 51c6df9a7..5fe3eef7b 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -22,9 +22,6 @@ #include #include -#include - -#include 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 _costs) const; - - EVMDialect const& m_dialect; - bool m_isCreation = false; - size_t m_runs; -}; - -class GasMeterVisitor: public ASTWalker -{ -public: - static std::pair costs( - Expression const& _expression, - EVMDialect const& _dialect, - bool _isCreation - ); - - static std::pair 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. diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 4772bbb3a..05b4b1b40 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -45,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -209,7 +209,8 @@ void OptimiserSuite::run( FunctionGrouper{}(ast); - ConstantOptimiser{dynamic_cast(_dialect), _meter}(ast); + if (EVMDialect const* dialect = dynamic_cast(&_dialect)) + ConstantOptimiser{*dialect, _meter}(ast); VarNameCleaner{ast, _dialect, reservedIdentifiers}(ast); yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast); diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 3d2cd50eb..496f0837c 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -47,8 +46,9 @@ #include #include #include -#include +#include #include +#include #include #include #include