From a683ea764656b9c81fb7e5e33184d2a3f877d9e2 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Sep 2021 15:55:17 +0200 Subject: [PATCH] Remove the expression callback from the code generator functions of Yul builtins. --- libyul/backends/evm/EVMCodeTransform.cpp | 10 ++- libyul/backends/evm/EVMDialect.cpp | 83 +++++++----------------- libyul/backends/evm/EVMDialect.h | 7 +- libyul/backends/evm/NoOutputAssembly.cpp | 17 ++--- 4 files changed, 38 insertions(+), 79 deletions(-) diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index c837c8b1a..947e8d091 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -239,9 +239,13 @@ void CodeTransform::operator()(FunctionCall const& _call) m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) - builtin->generateCode(_call, m_assembly, m_builtinContext, [&](Expression const& _expression) { - visitExpression(_expression); - }); + { + for (auto&& [i, arg]: _call.arguments | ranges::views::enumerate | ranges::views::reverse) + if (!builtin->literalArgument(i)) + visitExpression(arg); + m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); + builtin->generateCode(_call, m_assembly, m_builtinContext); + } else { AbstractAssembly::LabelID returnLabel = m_assembly.newLabelId(); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 86202e378..c90784a03 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -26,8 +26,8 @@ #include #include #include +#include #include - #include #include @@ -46,19 +46,6 @@ using namespace solidity::util; namespace { -void visitArguments( - AbstractAssembly& _assembly, - FunctionCall const& _call, - function _visitExpression -) -{ - for (auto const& arg: _call.arguments | ranges::views::reverse) - _visitExpression(arg); - - _assembly.setSourceLocation(_call.debugData->location); -} - - pair createEVMFunction( string const& _name, evmasm::Instruction _instruction @@ -76,12 +63,10 @@ pair createEVMFunction( f.literalArguments.clear(); f.instruction = _instruction; f.generateCode = [_instruction]( - FunctionCall const& _call, + FunctionCall const&, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { - visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(_instruction); }; @@ -94,7 +79,7 @@ pair createFunction( size_t _returns, SideEffects _sideEffects, vector> _literalArguments, - std::function)> _generateCode + std::function _generateCode ) { yulAssert(_literalArguments.size() == _params || _literalArguments.empty(), ""); @@ -166,12 +151,10 @@ map createBuiltins(langutil::EVMVersion _evmVe builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - function + BuiltinContext& ) { yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendLinkerSymbol(std::get(arg).value.str()); })); @@ -184,24 +167,24 @@ map createBuiltins(langutil::EVMVersion _evmVe []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - function _visitExpression + BuiltinContext& ) { - visitArguments(_assembly, _call, _visitExpression); + yulAssert(_call.arguments.size() == 1, ""); + Literal const* literal = get_if(&_call.arguments.front()); + yulAssert(literal, ""); + _assembly.appendConstant(valueOfLiteral(*literal)); }) ); builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext& _context, - std::function const& + BuiltinContext& _context ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); YulString dataName = std::get(arg).value; - _assembly.setSourceLocation(_call.debugData->location); if (_context.currentObject->name == dataName) _assembly.appendAssemblySize(); else @@ -217,14 +200,12 @@ map createBuiltins(langutil::EVMVersion _evmVe builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext& _context, - std::function const& + BuiltinContext& _context ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); YulString dataName = std::get(arg).value; - _assembly.setSourceLocation(_call.debugData->location); if (_context.currentObject->name == dataName) _assembly.appendConstant(0); else @@ -244,12 +225,10 @@ map createBuiltins(langutil::EVMVersion _evmVe SideEffects{false, true, false, false, true, SideEffects::None, SideEffects::None, SideEffects::Write}, {}, []( - FunctionCall const& _call, + FunctionCall const&, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { - visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(evmasm::Instruction::CODECOPY); } )); @@ -262,15 +241,10 @@ map createBuiltins(langutil::EVMVersion _evmVe []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { yulAssert(_call.arguments.size() == 3, ""); - - _visitExpression(_call.arguments[2]); YulString identifier = std::get(_call.arguments[1]).value; - _visitExpression(_call.arguments[0]); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendImmutableAssignment(identifier.str()); } )); @@ -283,11 +257,9 @@ map createBuiltins(langutil::EVMVersion _evmVe []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - std::function + BuiltinContext& ) { yulAssert(_call.arguments.size() == 1, ""); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendImmutable(std::get(_call.arguments.front()).value.str()); } )); @@ -387,15 +359,11 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz [=]( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { yulAssert(_call.arguments.size() == (1 + _arguments), ""); - for (Expression const& arg: _call.arguments | ranges::views::tail | ranges::views::reverse) - _visitExpression(arg); Expression const& bytecode = _call.arguments.front(); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendVerbatim( asBytes(std::get(bytecode).value.str()), _arguments, @@ -456,24 +424,19 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA m_functions["popbool"_yulstring].name = "popbool"_yulstring; m_functions["popbool"_yulstring].parameters = {"bool"_yulstring}; m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, {}, []( - FunctionCall const& _call, - AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression - ) { - visitArguments(_assembly, _call, _visitExpression); - })); + FunctionCall const&, + AbstractAssembly&, + BuiltinContext& + ) {})); m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring}; m_functions["bool_to_u256"_yulstring].returns = {"u256"_yulstring}; m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, {}, []( - FunctionCall const& _call, + FunctionCall const&, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { // TODO this should use a Panic. // A value larger than 1 causes an invalid instruction. - visitArguments(_assembly, _call, _visitExpression); _assembly.appendConstant(2); _assembly.appendInstruction(evmasm::Instruction::DUP2); _assembly.appendInstruction(evmasm::Instruction::LT); diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index b79c558be..28649f3e5 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -52,9 +52,10 @@ struct BuiltinFunctionForEVM: public BuiltinFunction { std::optional instruction; /// Function to generate code for the given function call and append it to the abstract - /// assembly. The fourth parameter is called to visit (and generate code for) the given - /// argument. - std::function)> generateCode; + /// assembly. Expects all non-literal arguments of the call to be on stack in reverse order + /// (i.e. right-most argument pushed first). + /// Expects the caller to set the source location. + std::function generateCode; }; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index c8016d4a5..62c0ad119 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -26,6 +26,7 @@ #include +#include using namespace std; using namespace solidity; @@ -135,21 +136,11 @@ NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): for (auto& fun: m_functions) { size_t returns = fun.second.returns.size(); - fun.second.generateCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, std::function _visitExpression) + fun.second.generateCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&) { - size_t visited = 0; - for (size_t j = 0; j < _call.arguments.size(); j++) - { - size_t const i = _call.arguments.size() - j - 1; + for (size_t i: ranges::views::iota(0u, _call.arguments.size())) if (!fun.second.literalArgument(i)) - { - _visitExpression(_call.arguments[i]); - visited++; - } - } - - for (size_t i = 0; i < visited; i++) - _assembly.appendInstruction(evmasm::Instruction::POP); + _assembly.appendInstruction(evmasm::Instruction::POP); for (size_t i = 0; i < returns; i++) _assembly.appendConstant(u256(0));