aboutsummaryrefslogtreecommitdiffstats
path: root/libyul
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-12-13 22:57:49 +0800
committerGitHub <noreply@github.com>2018-12-13 22:57:49 +0800
commit1d274a8924a9a26f75adbea6dfed7883e1aaa029 (patch)
treebeb14b1f3b73ab3811cc7c5e69ce1c4f7f647306 /libyul
parent1c4caaa0a20336509802966a1663752cf11697f2 (diff)
parent60a368244ac4a92836fc64054ad7ee6130b386eb (diff)
downloaddexon-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.cpp19
-rw-r--r--libyul/optimiser/FullInliner.h7
-rw-r--r--libyul/optimiser/Metrics.cpp3
-rw-r--r--libyul/optimiser/Metrics.h12
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: