diff options
author | chriseth <chris@ethereum.org> | 2018-12-13 22:57:49 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-13 22:57:49 +0800 |
commit | 1d274a8924a9a26f75adbea6dfed7883e1aaa029 (patch) | |
tree | beb14b1f3b73ab3811cc7c5e69ce1c4f7f647306 /libyul | |
parent | 1c4caaa0a20336509802966a1663752cf11697f2 (diff) | |
parent | 60a368244ac4a92836fc64054ad7ee6130b386eb (diff) | |
download | dexon-solidity-1d274a8924a9a26f75adbea6dfed7883e1aaa029.tar.gz dexon-solidity-1d274a8924a9a26f75adbea6dfed7883e1aaa029.tar.zst dexon-solidity-1d274a8924a9a26f75adbea6dfed7883e1aaa029.zip |
Merge pull request #5644 from ethereum/noInlineIntoLarge
[Yul] Do not inline into already big functions.
Diffstat (limited to 'libyul')
-rw-r--r-- | libyul/optimiser/FullInliner.cpp | 19 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.h | 7 | ||||
-rw-r--r-- | libyul/optimiser/Metrics.cpp | 3 | ||||
-rw-r--r-- | libyul/optimiser/Metrics.h | 12 |
4 files changed, 31 insertions, 10 deletions
diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index f69f7cdd..04005847 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -49,6 +49,8 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): if (ssaValue.second && ssaValue.second->type() == typeid(Literal)) m_constants.emplace(ssaValue.first); + // Store size of global statements. + m_functionSizes[YulString{}] = CodeSize::codeSize(_ast); map<YulString, size_t> references = ReferencesCounter::countReferences(m_ast); for (auto& statement: m_ast.statements) { @@ -58,7 +60,7 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser): m_functions[fun.name] = &fun; // Always inline functions that are only called once. if (references[fun.name] == 1) - m_alwaysInline.emplace(fun.name); + m_singleUse.emplace(fun.name); updateCodeSize(fun); } } @@ -98,7 +100,11 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) if (!calledFunction) return false; - if (m_alwaysInline.count(calledFunction->name)) + // Do not inline into already big functions. + if (m_functionSizes.at(_callSite) > 100) + return false; + + if (m_singleUse.count(calledFunction->name)) return true; // Constant arguments might provide a means for further optimization, so they cause a bonus. @@ -114,7 +120,12 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) } size_t size = m_functionSizes.at(calledFunction->name); - return (size < 10 || (constantArg && size < 50)); + return (size < 10 || (constantArg && size < 30)); +} + +void FullInliner::tentativelyUpdateCodeSize(YulString _function, YulString _callSite) +{ + m_functionSizes.at(_callSite) += m_functionSizes.at(_function); } @@ -155,6 +166,8 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC FunctionDefinition* function = m_driver.function(_funCall.functionName.name); assertThrow(!!function, OptimizerException, "Attempt to inline invalid function."); + m_driver.tentativelyUpdateCodeSize(function->name, m_currentFunction); + // helper function to create a new variable that is supposed to model // an existing variable. auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) { diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index 8f6211c8..d2dd3229 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -85,6 +85,11 @@ public: return nullptr; } + /// Adds the size of _funCall to the size of _callSite. This is just + /// a rough estimate that is done during inlining. The proper size + /// should be determined after inlining is completed. + void tentativelyUpdateCodeSize(YulString _function, YulString _callSite); + private: void updateCodeSize(FunctionDefinition& fun); void handleBlock(YulString _currentFunctionName, Block& _block); @@ -94,7 +99,7 @@ private: Block& m_ast; std::map<YulString, FunctionDefinition*> m_functions; /// Names of functions to always inline. - std::set<YulString> m_alwaysInline; + std::set<YulString> m_singleUse; /// Variables that are constants (used for inlining heuristic) std::set<YulString> m_constants; std::map<YulString, size_t> m_functionSizes; diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp index a5557fb3..8fc9476e 100644 --- a/libyul/optimiser/Metrics.cpp +++ b/libyul/optimiser/Metrics.cpp @@ -48,6 +48,9 @@ size_t CodeSize::codeSize(Block const& _block) void CodeSize::visit(Statement const& _statement) { + if (_statement.type() == typeid(FunctionDefinition)) + return; + ++m_size; ASTWalker::visit(_statement); } diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h index ca244600..d26ecbd9 100644 --- a/libyul/optimiser/Metrics.h +++ b/libyul/optimiser/Metrics.h @@ -25,17 +25,17 @@ namespace yul { +/** + * Metric for the size of code. + * More specifically, the number of AST nodes. + * Ignores function definitions while traversing the AST. + * If you want to know the size of a function, you have to invoke this on its body. + */ class CodeSize: public ASTWalker { public: - /// Returns a metric for the code size of an AST element. - /// More specifically, it returns the number of AST nodes. static size_t codeSize(Statement const& _statement); - /// Returns a metric for the code size of an AST element. - /// More specifically, it returns the number of AST nodes. static size_t codeSize(Expression const& _expression); - /// Returns a metric for the code size of an AST element. - /// More specifically, it returns the number of AST nodes. static size_t codeSize(Block const& _block); private: |