From 93cd9f79251cec0f2d758e736e758fbec634c5b0 Mon Sep 17 00:00:00 2001 From: blishko Date: Wed, 15 Apr 2026 15:14:31 +0200 Subject: [PATCH] SSA: Remove some shuffler logic This piece of logic was swapping top to the tail region if case the top is not in its right place and it wants to be in tail anyway. I don't have an explanation why this is useful, but it seems to improve code generation on most external benchmarks. --- libyul/backends/evm/ssa/StackShuffler.h | 17 ----------------- .../semanticTests/externalContracts/base64.sol | 8 ++++---- .../externalContracts/deposit_contract.sol | 4 ++-- .../externalContracts/ramanujan_pi.sol | 4 ++-- .../semanticTests/externalContracts/snark.sol | 4 ++-- .../semanticTests/externalContracts/strings.sol | 6 +++--- .../ssa/stackLayoutGenerator/nested_for.yul | 6 +++--- .../stackShuffler/shrink_lifting_deep_phi.stack | 3 ++- .../ssa/stackShuffler/swap_junk_over_pop.stack | 3 ++- 9 files changed, 20 insertions(+), 35 deletions(-) diff --git a/libyul/backends/evm/ssa/StackShuffler.h b/libyul/backends/evm/ssa/StackShuffler.h index 6ccb629cb1ad..825739b334a3 100644 --- a/libyul/backends/evm/ssa/StackShuffler.h +++ b/libyul/backends/evm/ssa/StackShuffler.h @@ -450,23 +450,6 @@ class StackShuffler _stack.swap(offset); return {ShuffleHelperResult::Status::StackModified}; } - - // try swapping top with a tail slot that has what we need at top - for (StackOffset tailOffset: _state.stackTailRange()) - if ( - _stack.isValidSwapTarget(tailOffset) && - _state.isArgsCompatible(tailOffset, stackTop) && - (!_state.requiredInTail(_stack[tailOffset]) || _state.countInTail(_stack[tailOffset]) > 1) && - // current top can safely go to tail (not needed in args, or we have excess) - ( - !_state.requiredInArgs(_stack[stackTop]) || - _state.countInArgs(_stack[stackTop]) > _state.targetArgsCount(_stack[stackTop]) - ) - ) - { - _stack.swap(tailOffset); - return {ShuffleHelperResult::Status::StackModified}; - } } // swap up any slot in args that is out of position and has a slot available in args that it can occupy diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol index 0efcda12d8f0..472892138ddc 100644 --- a/test/libsolidity/semanticTests/externalContracts/base64.sol +++ b/test/libsolidity/semanticTests/externalContracts/base64.sol @@ -41,8 +41,8 @@ contract test { // gas legacy code: 629800 // gas legacyOptimized: 87926 // gas legacyOptimized code: 429800 -// gas ssaCFGOptimized: 79879 -// gas ssaCFGOptimized code: 331800 +// gas ssaCFGOptimized: 79815 +// gas ssaCFGOptimized code: 331000 // encode_inline_asm(bytes): 0x20, 0 -> 0x20, 0 // encode_inline_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg==" // encode_inline_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8=" @@ -61,9 +61,9 @@ contract test { // gas irOptimized: 1406025 // gas legacy: 1554038 // gas legacyOptimized: 1132031 -// gas ssaCFGOptimized: 1388025 +// gas ssaCFGOptimized: 1386025 // encode_no_asm_large() // gas irOptimized: 3512081 // gas legacy: 4600082 // gas legacyOptimized: 2813075 -// gas ssaCFGOptimized: 3077081 +// gas ssaCFGOptimized: 3066081 diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index fb186b48148f..331a1672987b 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -185,8 +185,8 @@ contract DepositContract is IDepositContract, ERC165 { // gas legacy code: 1438800 // gas legacyOptimized: 848699 // gas legacyOptimized code: 878200 -// gas ssaCFGOptimized: 809592 -// gas ssaCFGOptimized code: 569200 +// gas ssaCFGOptimized: 809647 +// gas ssaCFGOptimized code: 569800 // supportsInterface(bytes4): 0x0 -> 0 // supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 # // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 44208308acab..b7c9829d3813 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -42,8 +42,8 @@ contract test { // gas legacy code: 523600 // gas legacyOptimized: 82667 // gas legacyOptimized code: 369200 -// gas ssaCFGOptimized: 77956 -// gas ssaCFGOptimized code: 313400 +// gas ssaCFGOptimized: 77772 +// gas ssaCFGOptimized code: 310800 // prb_pi() -> 3141592656369545286 // gas irOptimized: 55036 // gas legacy: 100657 diff --git a/test/libsolidity/semanticTests/externalContracts/snark.sol b/test/libsolidity/semanticTests/externalContracts/snark.sol index f7e450487310..763e9a049ac0 100644 --- a/test/libsolidity/semanticTests/externalContracts/snark.sol +++ b/test/libsolidity/semanticTests/externalContracts/snark.sol @@ -297,10 +297,10 @@ contract Test { // gas irOptimized: 275229 // gas legacy: 293579 // gas legacyOptimized: 276313 -// gas ssaCFGOptimized: 275795 +// gas ssaCFGOptimized: 275787 // verifyTx() -> true // ~ emit Verified(string): 0x20, 0x16, "Successfully verified." // gas irOptimized: 818076 // gas legacy: 904397 // gas legacyOptimized: 816770 -// gas ssaCFGOptimized: 820130 +// gas ssaCFGOptimized: 820110 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index 534b41710dbb..605aaee569b9 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -58,8 +58,8 @@ contract test { // gas legacy code: 932600 // gas legacyOptimized: 102639 // gas legacyOptimized code: 612400 -// gas ssaCFGOptimized: 96128 -// gas ssaCFGOptimized code: 531800 +// gas ssaCFGOptimized: 95933 +// gas ssaCFGOptimized code: 529600 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 // gas irOptimized: 22646 // gas legacy: 23168 @@ -80,4 +80,4 @@ contract test { // gas irOptimized: 1976778 // gas legacy: 4234020 // gas legacyOptimized: 2318668 -// gas ssaCFGOptimized: 1882325 +// gas ssaCFGOptimized: 1841205 diff --git a/test/libyul/ssa/stackLayoutGenerator/nested_for.yul b/test/libyul/ssa/stackLayoutGenerator/nested_for.yul index 0d37b16e503b..b26480b8bbac 100644 --- a/test/libyul/ssa/stackLayoutGenerator/nested_for.yul +++ b/test/libyul/ssa/stackLayoutGenerator/nested_for.yul @@ -107,11 +107,11 @@ // Block0_3 [label="\ // IN: [phi0, phi3, JUNK]\l\ // \l\ -// [JUNK, phi3, lit2, phi0]\l\ +// [phi3, lit2, phi0]\l\ // add\l\ -// [JUNK, phi3, v5]\l\ +// [phi3, v5]\l\ // \l\ -// OUT: [JUNK, phi3, v5]\l\ +// OUT: [phi3, v5]\l\ // "]; // Block0_3 -> Block0_3Exit [arrowhead=none]; // Block0_3Exit [label="Jump" shape=oval]; diff --git a/test/libyul/ssa/stackShuffler/shrink_lifting_deep_phi.stack b/test/libyul/ssa/stackShuffler/shrink_lifting_deep_phi.stack index 4dc9c74e981c..07504756b899 100644 --- a/test/libyul/ssa/stackShuffler/shrink_lifting_deep_phi.stack +++ b/test/libyul/ssa/stackShuffler/shrink_lifting_deep_phi.stack @@ -9,7 +9,8 @@ targetStackSize: 12 // POP| phi0 v0 lit0 | v0 lit0 v0 lit0 v0 v0 lit0 v0 // DUP11| phi0 v0 lit0 | v0 lit0 v0 lit0 v0 v0 lit0 v0 phi0 // SWAP5| phi0 v0 lit0 | v0 lit0 v0 phi0 v0 v0 lit0 v0 lit0 -// SWAP10| phi0 lit0 lit0 | v0 lit0 v0 phi0 v0 v0 lit0 v0 v0 +// POP| phi0 v0 lit0 | v0 lit0 v0 phi0 v0 v0 lit0 v0 +// DUP1| phi0 v0 lit0 | v0 lit0 v0 phi0 v0 v0 lit0 v0 v0 // +--------------------- +--------------------------------------------------------------- // (target)| {} | * lit0 v0 phi0 v0 v0 lit0 v0 v0 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack b/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack index b83cef92f7ef..f4479c610826 100644 --- a/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack +++ b/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack @@ -8,7 +8,8 @@ targetStackSize: 4 // (initial)| v0 | * v2 // PUSH lit2| v0 | * v2 lit2 // SWAP2| v0 | lit2 v2 * -// SWAP3| * | lit2 v2 v0 +// POP| v0 | lit2 v2 +// DUP3| v0 | lit2 v2 v0 // +------- +--------------------- // (target)| {} | lit2 v2 v0 // Status: Admissible