diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index d5469911e..16f456e88 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -179,6 +179,7 @@ add_library(yul optimiser/UnusedFunctionParameterPruner.cpp optimiser/UnusedFunctionParameterPruner.h optimiser/UnusedFunctionsCommon.h + optimiser/UnusedFunctionsCommon.cpp optimiser/UnusedPruner.cpp optimiser/UnusedPruner.h optimiser/VarDeclInitializer.cpp diff --git a/libyul/optimiser/UnusedFunctionsCommon.cpp b/libyul/optimiser/UnusedFunctionsCommon.cpp new file mode 100644 index 000000000..db2ca5dee --- /dev/null +++ b/libyul/optimiser/UnusedFunctionsCommon.cpp @@ -0,0 +1,77 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +#include + +#include + +using namespace solidity; +using namespace solidity::util; +using namespace solidity::yul; +using namespace solidity::yul::unusedFunctionsCommon; + +FunctionDefinition unusedFunctionsCommon::createLinkingFunction( + FunctionDefinition const& _original, + std::pair, std::vector> const& _usedParametersAndReturns, + YulString const& _originalFunctionName, + YulString const& _linkingFunctionName, + NameDispenser& _nameDispenser +) +{ + auto generateTypedName = [&](TypedName t) + { + return TypedName{ + t.location, + _nameDispenser.newName(t.name), + t.type + }; + }; + + langutil::SourceLocation loc = _original.location; + + FunctionDefinition linkingFunction{ + loc, + _linkingFunctionName, + util::applyMap(_original.parameters, generateTypedName), + util::applyMap(_original.returnVariables, generateTypedName), + {loc, {}} // body + }; + + FunctionCall call{loc, Identifier{loc, _originalFunctionName}, {}}; + for (auto const& p: filter(linkingFunction.parameters, _usedParametersAndReturns.first)) + call.arguments.emplace_back(Identifier{loc, p.name}); + + Assignment assignment{loc, {}, nullptr}; + + for (auto const& r: filter(linkingFunction.returnVariables, _usedParametersAndReturns.second)) + assignment.variableNames.emplace_back(Identifier{loc, r.name}); + + if (assignment.variableNames.empty()) + linkingFunction.body.statements.emplace_back(ExpressionStatement{loc, std::move(call)}); + else + { + assignment.value = std::make_unique(std::move(call)); + linkingFunction.body.statements.emplace_back(std::move(assignment)); + } + + return linkingFunction; +} diff --git a/libyul/optimiser/UnusedFunctionsCommon.h b/libyul/optimiser/UnusedFunctionsCommon.h index dcf9ca55b..2cf4c3114 100644 --- a/libyul/optimiser/UnusedFunctionsCommon.h +++ b/libyul/optimiser/UnusedFunctionsCommon.h @@ -19,15 +19,8 @@ #include #include + #include -#include -#include - -#include - -#include - -#include namespace solidity::yul::unusedFunctionsCommon { @@ -48,56 +41,34 @@ std::vector filter(std::vector const& _vec, std::vector const& _mask /// Returns true if applying UnusedFunctionParameterPruner is not helpful or redundant because the /// inliner will be able to handle it anyway. -bool tooSimpleToBePruned(FunctionDefinition const& _f) +inline bool tooSimpleToBePruned(FunctionDefinition const& _f) { return _f.body.statements.size() <= 1 && CodeSize::codeSize(_f.body) <= 1; } +/// Given a function definition `_original`, this function returns a 'linking' function that calls +/// `_originalFunctionName` (with reduced parameters and return values). +/// +/// The parameter `_usedParametersAndReturnVariables` is a pair of boolean-vectors. Its `.first` +/// corresponds to function parameters and its `.second` corresponds to function return-variables. A +/// false value at index `i` means that the corresponding function parameter / return-variable at +/// index `i` is unused. +/// +/// Example: +/// +/// Let `_original` be the function `function f_1() -> y { }`. (In practice, this function usually cannot +/// be inlined and has parameters / return-variables that are unused.) +/// Let `_usedParametersAndReturnVariables` be `({}, {false})` +/// Let `_originalFunctionName` be `f`. +/// Let `_linkingFunctionName` be `f_1`. +/// +/// Then the returned linking function would be `function f_1() -> y_1 { f() }` FunctionDefinition createLinkingFunction( FunctionDefinition const& _original, std::pair, std::vector> const& _usedParametersAndReturns, YulString const& _originalFunctionName, YulString const& _linkingFunctionName, NameDispenser& _nameDispenser -) -{ - auto generateTypedName = [&](TypedName t) - { - return TypedName{ - t.location, - _nameDispenser.newName(t.name), - t.type - }; - }; - - langutil::SourceLocation loc = _original.location; - - FunctionDefinition linkingFunction{ - loc, - _linkingFunctionName, - util::applyMap(_original.parameters, generateTypedName), - util::applyMap(_original.returnVariables, generateTypedName), - {loc, {}} // body - }; - - FunctionCall call{loc, Identifier{loc, _originalFunctionName}, {}}; - for (auto const& p: filter(linkingFunction.parameters, _usedParametersAndReturns.first)) - call.arguments.emplace_back(Identifier{loc, p.name}); - - Assignment assignment{loc, {}, nullptr}; - - for (auto const& r: filter(linkingFunction.returnVariables, _usedParametersAndReturns.second)) - assignment.variableNames.emplace_back(Identifier{loc, r.name}); - - if (assignment.variableNames.empty()) - linkingFunction.body.statements.emplace_back(ExpressionStatement{loc, std::move(call)}); - else - { - assignment.value = std::make_unique(std::move(call)); - linkingFunction.body.statements.emplace_back(std::move(assignment)); - } - - return linkingFunction; -} +); }