mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Relax inliner heuristics.
This commit is contained in:
parent
f08d349791
commit
7168c27f0d
@ -7,6 +7,7 @@ Language Features:
|
|||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
* LSP: Add rudimentary support for semantic highlighting.
|
* LSP: Add rudimentary support for semantic highlighting.
|
||||||
|
* Yul Optimizer: Improve inlining heuristics for via IR code generation and pure Yul compilation.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -22,11 +22,14 @@
|
|||||||
#include <libyul/optimiser/FullInliner.h>
|
#include <libyul/optimiser/FullInliner.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/ASTCopier.h>
|
#include <libyul/optimiser/ASTCopier.h>
|
||||||
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
|
#include <libyul/optimiser/FunctionCallFinder.h>
|
||||||
#include <libyul/optimiser/NameCollector.h>
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
#include <libyul/optimiser/Metrics.h>
|
#include <libyul/optimiser/Metrics.h>
|
||||||
#include <libyul/optimiser/SSAValueTracker.h>
|
#include <libyul/optimiser/SSAValueTracker.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/CallGraphGenerator.h>
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
#include <libyul/AST.h>
|
#include <libyul/AST.h>
|
||||||
#include <libyul/Dialect.h>
|
#include <libyul/Dialect.h>
|
||||||
@ -46,8 +49,12 @@ void FullInliner::run(OptimiserStepContext& _context, Block& _ast)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect):
|
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect):
|
||||||
m_ast(_ast), m_nameDispenser(_dispenser), m_dialect(_dialect)
|
m_ast(_ast),
|
||||||
|
m_recursiveFunctions(CallGraphGenerator::callGraph(_ast).recursiveFunctions()),
|
||||||
|
m_nameDispenser(_dispenser),
|
||||||
|
m_dialect(_dialect)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Determine constants
|
// Determine constants
|
||||||
SSAValueTracker tracker;
|
SSAValueTracker tracker;
|
||||||
tracker(m_ast);
|
tracker(m_ast);
|
||||||
@ -71,6 +78,15 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const&
|
|||||||
m_singleUse.emplace(fun.name);
|
m_singleUse.emplace(fun.name);
|
||||||
updateCodeSize(fun);
|
updateCodeSize(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for memory guard.
|
||||||
|
vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
|
||||||
|
_ast,
|
||||||
|
"memoryguard"_yulstring
|
||||||
|
);
|
||||||
|
// We will perform less aggressive inlining, if no ``memoryguard`` call is found.
|
||||||
|
if (!memoryGuardCalls.empty())
|
||||||
|
m_hasMemoryGuard = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullInliner::run(Pass _pass)
|
void FullInliner::run(Pass _pass)
|
||||||
@ -177,8 +193,20 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
|||||||
if (m_pass == Pass::InlineTiny)
|
if (m_pass == Pass::InlineTiny)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Do not inline into already big functions.
|
bool aggressiveInlining = true;
|
||||||
if (m_functionSizes.at(_callSite) > 45)
|
|
||||||
|
if (
|
||||||
|
EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect);
|
||||||
|
!evmDialect || !evmDialect->providesObjectAccess() || evmDialect->evmVersion() <= langutil::EVMVersion::homestead()
|
||||||
|
)
|
||||||
|
// No aggressive inlining with the old code transform.
|
||||||
|
aggressiveInlining = false;
|
||||||
|
|
||||||
|
// No aggressive inlining, if we cannot perform stack-to-memory.
|
||||||
|
if (!m_hasMemoryGuard || m_recursiveFunctions.count(_callSite))
|
||||||
|
aggressiveInlining = false;
|
||||||
|
|
||||||
|
if (!aggressiveInlining && m_functionSizes.at(_callSite) > 45)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (m_singleUse.count(calledFunction->name))
|
if (m_singleUse.count(calledFunction->name))
|
||||||
@ -196,7 +224,7 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (size < 6 || (constantArg && size < 12));
|
return (size < (aggressiveInlining ? 8 : 6) || (constantArg && size < (aggressiveInlining ? 16 : 12)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullInliner::tentativelyUpdateCodeSize(YulString _function, YulString _callSite)
|
void FullInliner::tentativelyUpdateCodeSize(YulString _function, YulString _callSite)
|
||||||
|
@ -111,6 +111,10 @@ private:
|
|||||||
std::map<YulString, FunctionDefinition*> m_functions;
|
std::map<YulString, FunctionDefinition*> m_functions;
|
||||||
/// Functions not to be inlined (because they contain the ``leave`` statement).
|
/// Functions not to be inlined (because they contain the ``leave`` statement).
|
||||||
std::set<YulString> m_noInlineFunctions;
|
std::set<YulString> m_noInlineFunctions;
|
||||||
|
/// True, if the code contains a ``memoryguard`` and we can expect to be able to move variables to memory later.
|
||||||
|
bool m_hasMemoryGuard = false;
|
||||||
|
/// Set of recursive functions.
|
||||||
|
std::set<YulString> m_recursiveFunctions;
|
||||||
/// Names of functions to always inline.
|
/// Names of functions to always inline.
|
||||||
std::set<YulString> m_singleUse;
|
std::set<YulString> m_singleUse;
|
||||||
/// Variables that are constants (used for inlining heuristic)
|
/// Variables that are constants (used for inlining heuristic)
|
||||||
|
Loading…
Reference in New Issue
Block a user