diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp index 02b5a7179..155c80d1e 100644 --- a/libyul/optimiser/Metrics.cpp +++ b/libyul/optimiser/Metrics.cpp @@ -22,10 +22,13 @@ #include #include +#include #include +#include #include +#include using namespace std; using namespace dev; @@ -151,6 +154,54 @@ void CodeCost::visit(Expression const& _expression) ASTWalker::visit(_expression); } +pair GasMeter::gasCosts( + Expression const& _expression, + langutil::EVMVersion _evmVersion, + bool _isCreation +) +{ + GasMeter gm(_evmVersion, _isCreation); + gm.visit(_expression); + return {gm.m_runGas, gm.m_dataGas}; +} + +void GasMeter::operator()(FunctionCall const&) +{ + yulAssert(false, "Functions not implemented."); +} + +void GasMeter::operator()(FunctionalInstruction const& _fun) +{ + ASTWalker::operator()(_fun); + if (_fun.instruction == eth::Instruction::EXP) + m_runGas += dev::eth::GasCosts::expGas + dev::eth::GasCosts::expByteGas(m_evmVersion); + else + m_runGas += dev::eth::GasMeter::runGas(_fun.instruction); + m_dataGas += singleByteDataGas(); +} + +void GasMeter::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 GasMeter::operator()(Identifier const&) +{ + m_runGas += dev::eth::GasMeter::runGas(dev::eth::Instruction::DUP1); + m_dataGas += singleByteDataGas(); +} + +size_t GasMeter::singleByteDataGas() const +{ + if (m_isCreation) + return dev::eth::GasCosts::txDataNonZeroGas; + else + return dev::eth::GasCosts::createDataGas; +} + 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 1620d4d33..1ea8f7d7d 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -21,6 +21,7 @@ #pragma once #include +#include namespace yul { @@ -84,6 +85,42 @@ 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. + */ +class GasMeter: public ASTWalker +{ +public: + /// @returns the runtime costs and the data cost of + /// evaluating the given expression. + static std::pair gasCosts( + Expression const& _expression, + langutil::EVMVersion _evmVersion, + bool _isCreation = false + ); + +private: + GasMeter(langutil::EVMVersion _evmVersion, bool _isCreation): + m_evmVersion(_evmVersion), + 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; + + langutil::EVMVersion m_evmVersion; + 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.