Skip to content

Commit 45030f0

Browse files
authored
Merge pull request #12731 from ethereum/removeInliningConstraint
Remove inlining constraint for large functions when targetting the new code transform.
2 parents df7bfd1 + 77038aa commit 45030f0

File tree

161 files changed

+1183
-1134
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+1183
-1134
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Language Features:
77

88
Compiler Features:
99
* LSP: Add rudimentary support for semantic highlighting.
10+
* Yul Optimizer: Improve inlining heuristics for via IR code generation and pure Yul compilation.
1011

1112

1213
Bugfixes:

libyul/optimiser/FullInliner.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
#include <libyul/optimiser/FullInliner.h>
2323

2424
#include <libyul/optimiser/ASTCopier.h>
25+
#include <libyul/optimiser/CallGraphGenerator.h>
26+
#include <libyul/optimiser/FunctionCallFinder.h>
2527
#include <libyul/optimiser/NameCollector.h>
2628
#include <libyul/optimiser/Metrics.h>
2729
#include <libyul/optimiser/SSAValueTracker.h>
2830
#include <libyul/optimiser/Semantics.h>
2931
#include <libyul/optimiser/CallGraphGenerator.h>
32+
#include <libyul/backends/evm/EVMDialect.h>
3033
#include <libyul/Exceptions.h>
3134
#include <libyul/AST.h>
3235
#include <libyul/Dialect.h>
@@ -46,8 +49,12 @@ void FullInliner::run(OptimiserStepContext& _context, Block& _ast)
4649
}
4750

4851
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect):
49-
m_ast(_ast), m_nameDispenser(_dispenser), m_dialect(_dialect)
52+
m_ast(_ast),
53+
m_recursiveFunctions(CallGraphGenerator::callGraph(_ast).recursiveFunctions()),
54+
m_nameDispenser(_dispenser),
55+
m_dialect(_dialect)
5056
{
57+
5158
// Determine constants
5259
SSAValueTracker tracker;
5360
tracker(m_ast);
@@ -71,6 +78,15 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const&
7178
m_singleUse.emplace(fun.name);
7279
updateCodeSize(fun);
7380
}
81+
82+
// Check for memory guard.
83+
vector<FunctionCall*> memoryGuardCalls = FunctionCallFinder::run(
84+
_ast,
85+
"memoryguard"_yulstring
86+
);
87+
// We will perform less aggressive inlining, if no ``memoryguard`` call is found.
88+
if (!memoryGuardCalls.empty())
89+
m_hasMemoryGuard = true;
7490
}
7591

7692
void FullInliner::run(Pass _pass)
@@ -177,8 +193,20 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
177193
if (m_pass == Pass::InlineTiny)
178194
return false;
179195

180-
// Do not inline into already big functions.
181-
if (m_functionSizes.at(_callSite) > 45)
196+
bool aggressiveInlining = true;
197+
198+
if (
199+
EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect);
200+
!evmDialect || !evmDialect->providesObjectAccess() || evmDialect->evmVersion() <= langutil::EVMVersion::homestead()
201+
)
202+
// No aggressive inlining with the old code transform.
203+
aggressiveInlining = false;
204+
205+
// No aggressive inlining, if we cannot perform stack-to-memory.
206+
if (!m_hasMemoryGuard || m_recursiveFunctions.count(_callSite))
207+
aggressiveInlining = false;
208+
209+
if (!aggressiveInlining && m_functionSizes.at(_callSite) > 45)
182210
return false;
183211

184212
if (m_singleUse.count(calledFunction->name))
@@ -196,7 +224,7 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
196224
break;
197225
}
198226

199-
return (size < 6 || (constantArg && size < 12));
227+
return (size < (aggressiveInlining ? 8 : 6) || (constantArg && size < (aggressiveInlining ? 16 : 12)));
200228
}
201229

202230
void FullInliner::tentativelyUpdateCodeSize(YulString _function, YulString _callSite)

libyul/optimiser/FullInliner.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ class FullInliner: public ASTModifier
111111
std::map<YulString, FunctionDefinition*> m_functions;
112112
/// Functions not to be inlined (because they contain the ``leave`` statement).
113113
std::set<YulString> m_noInlineFunctions;
114+
/// True, if the code contains a ``memoryguard`` and we can expect to be able to move variables to memory later.
115+
bool m_hasMemoryGuard = false;
116+
/// Set of recursive functions.
117+
std::set<YulString> m_recursiveFunctions;
114118
/// Names of functions to always inline.
115119
std::set<YulString> m_singleUse;
116120
/// Variables that are constants (used for inlining heuristic)

test/cmdlineTests/debug_info_in_yul_snippet_escaping/output

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -434,77 +434,77 @@ object "D_27" {
434434
{
435435
/// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..."
436436
let _1 := memoryguard(0x80)
437-
mstore(64, _1)
437+
let _2 := 64
438+
mstore(_2, _1)
438439
if iszero(lt(calldatasize(), 4))
439440
{
440-
let _2 := 0
441-
if eq(0x26121ff0, shr(224, calldataload(_2)))
441+
let _3 := 0
442+
if eq(0x26121ff0, shr(224, calldataload(_3)))
442443
{
443-
if callvalue() { revert(_2, _2) }
444-
if slt(add(calldatasize(), not(3)), _2) { revert(_2, _2) }
444+
if callvalue() { revert(_3, _3) }
445+
if slt(add(calldatasize(), not(3)), _3) { revert(_3, _3) }
445446
/// @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..."
446-
let _3 := datasize("C_2")
447-
let _4 := add(_1, _3)
448-
if or(gt(_4, 0xffffffffffffffff), lt(_4, _1)) { panic_error_0x41() }
449-
datacopy(_1, dataoffset("C_2"), _3)
450-
if iszero(create(/** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ _2, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ _1, sub(_4, _1)))
447+
let _4 := datasize("C_2")
448+
let _5 := add(_1, _4)
449+
let _6 := 0xffffffffffffffff
450+
if or(gt(_5, _6), lt(_5, _1))
451451
{
452452
/// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..."
453-
let pos := mload(64)
454-
returndatacopy(pos, _2, returndatasize())
453+
mstore(_3, shl(224, 0x4e487b71))
454+
mstore(4, 0x41)
455+
revert(_3, 0x24)
456+
}
457+
/// @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..."
458+
datacopy(_1, dataoffset("C_2"), _4)
459+
if iszero(create(/** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ _3, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ _1, sub(_5, _1)))
460+
{
461+
/// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..."
462+
let pos := mload(_2)
463+
returndatacopy(pos, _3, returndatasize())
455464
revert(pos, returndatasize())
456465
}
457-
mstore(add(allocate_memory_array_string(), 32), "/*")
458-
let memPtr := allocate_memory_array_string_546()
459-
mstore(add(memPtr, 32), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b)
460-
mstore(add(memPtr, 64), shl(200, 0x2e2e2e22202a2f))
461-
let memPos := mload(64)
462-
return(memPos, sub(abi_encode_string(memPos, memPtr), memPos))
466+
let memPtr := mload(_2)
467+
let newFreePtr := add(memPtr, _2)
468+
if or(gt(newFreePtr, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ _6), /** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ lt(newFreePtr, memPtr))
469+
{
470+
mstore(_3, shl(224, 0x4e487b71))
471+
mstore(4, 0x41)
472+
revert(_3, 0x24)
473+
}
474+
mstore(_2, newFreePtr)
475+
mstore(memPtr, 2)
476+
let _7 := 32
477+
mstore(add(memPtr, _7), "/*")
478+
let memPtr_1 := mload(_2)
479+
let newFreePtr_1 := add(memPtr_1, 96)
480+
if or(gt(newFreePtr_1, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ _6), /** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ lt(newFreePtr_1, memPtr_1))
481+
{
482+
mstore(_3, shl(224, 0x4e487b71))
483+
mstore(4, 0x41)
484+
revert(_3, 0x24)
485+
}
486+
mstore(_2, newFreePtr_1)
487+
mstore(memPtr_1, 39)
488+
mstore(add(memPtr_1, _7), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b)
489+
mstore(add(memPtr_1, _2), shl(200, 0x2e2e2e22202a2f))
490+
let memPos := mload(_2)
491+
mstore(memPos, _7)
492+
let length := mload(memPtr_1)
493+
mstore(add(memPos, _7), length)
494+
let i := _3
495+
for { } lt(i, length) { i := add(i, _7) }
496+
{
497+
mstore(add(add(memPos, i), _2), mload(add(add(memPtr_1, i), _7)))
498+
}
499+
if gt(i, length)
500+
{
501+
mstore(add(add(memPos, length), _2), _3)
502+
}
503+
return(memPos, add(sub(add(memPos, and(add(length, 31), not(31))), memPos), _2))
463504
}
464505
}
465506
revert(0, 0)
466507
}
467-
function abi_encode_string(headStart, value0) -> tail
468-
{
469-
let _1 := 32
470-
mstore(headStart, _1)
471-
let length := mload(value0)
472-
mstore(add(headStart, _1), length)
473-
let i := 0
474-
for { } lt(i, length) { i := add(i, _1) }
475-
{
476-
mstore(add(add(headStart, i), 64), mload(add(add(value0, i), _1)))
477-
}
478-
if gt(i, length)
479-
{
480-
mstore(add(add(headStart, length), 64), 0)
481-
}
482-
tail := add(add(headStart, and(add(length, 31), not(31))), 64)
483-
}
484-
function panic_error_0x41()
485-
{
486-
mstore(0, shl(224, 0x4e487b71))
487-
mstore(4, 0x41)
488-
revert(0, 0x24)
489-
}
490-
function allocate_memory_array_string() -> memPtr
491-
{
492-
let memPtr_1 := mload(64)
493-
let newFreePtr := add(memPtr_1, 64)
494-
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_1)) { panic_error_0x41() }
495-
mstore(64, newFreePtr)
496-
memPtr := memPtr_1
497-
mstore(memPtr_1, 2)
498-
}
499-
function allocate_memory_array_string_546() -> memPtr
500-
{
501-
let memPtr_1 := mload(64)
502-
let newFreePtr := add(memPtr_1, 96)
503-
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_1)) { panic_error_0x41() }
504-
mstore(64, newFreePtr)
505-
memPtr := memPtr_1
506-
mstore(memPtr_1, 39)
507-
}
508508
}
509509
/// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol"
510510
object "C_2" {

test/cmdlineTests/function_debug_info_via_yul/output

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,7 @@
44
"function_debug_info_via_yul/input.sol:C":
55
{
66
"function-debug": {},
7-
"function-debug-runtime":
8-
{
9-
"abi_encode_uint256":
10-
{
11-
"parameterSlots": 2,
12-
"returnSlots": 1
13-
},
14-
"calldata_array_index_access_uint256_dyn_calldata":
15-
{
16-
"entryPoint": 144,
17-
"parameterSlots": 2,
18-
"returnSlots": 1
19-
}
20-
}
7+
"function-debug-runtime": {}
218
}
229
},
2310
"version": "<VERSION REMOVED>"

0 commit comments

Comments
 (0)