From 852ae99a0cd4b8042c961649985124a5472439a7 Mon Sep 17 00:00:00 2001 From: clonker <1685266+clonker@users.noreply.github.com> Date: Wed, 15 Apr 2026 09:25:22 +0200 Subject: [PATCH 1/3] ssa stack shuffler gets target args range helper --- libyul/backends/evm/ssa/StackShuffler.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libyul/backends/evm/ssa/StackShuffler.h b/libyul/backends/evm/ssa/StackShuffler.h index 70c381a899dc..2fd661331a97 100644 --- a/libyul/backends/evm/ssa/StackShuffler.h +++ b/libyul/backends/evm/ssa/StackShuffler.h @@ -41,6 +41,11 @@ struct Target { Target(StackData const& _args, LivenessAnalysis::LivenessData const& _liveOut, std::size_t _targetSize); + auto argsRange() const + { + return ranges::views::iota(tailSize, size) | ranges::views::transform([](auto _i) { return StackOffset{_i}; }); + } + StackData const& args; LivenessAnalysis::LivenessData const& liveOut; std::size_t const size; @@ -525,7 +530,7 @@ class StackShuffler // if we can't directly produce targetOffset, take the deepest arg that we don't have enough of and dup/push that // First, prioritize duping args that are on the stack over pushing freely-generatable ones - for (StackOffset offset{_state.target().tailSize}; offset < _state.target().size; ++offset.value) + for (StackOffset const offset: _state.target().argsRange()) { Slot const& arg = _state.targetArg(offset); if (!arg.isJunk() && (_state.count(arg) < _state.targetMinCount(arg) || _state.countInArgs(arg) < _state.targetArgsCount(arg))) @@ -792,7 +797,7 @@ class StackShuffler static std::optional allNecessarySlotsReachableOrFinal(Stack const& _stack, detail::State const& _state) { // check that args are either in position or reachable - for (StackOffset offset{_state.target().tailSize}; offset < _state.target().size; ++offset.value) + for (StackOffset const offset: _state.target().argsRange()) { if (_state.isArgsCompatible(offset, offset)) continue; From c5b6900e1eaf7b8850ed17981b1026e37d425d97 Mon Sep 17 00:00:00 2001 From: clonker <1685266+clonker@users.noreply.github.com> Date: Wed, 15 Apr 2026 10:19:14 +0200 Subject: [PATCH 2/3] pushes and dups in the ssa stack shuffler are gated by reachability checks --- libyul/backends/evm/ssa/StackShuffler.h | 62 +++++++++++++------ .../externalContracts/FixedFeeRegistrar.sol | 4 +- .../externalContracts/deposit_contract.sol | 12 ++-- .../externalContracts/prbmath_signed.sol | 4 +- .../externalContracts/prbmath_unsigned.sol | 4 +- .../externalContracts/ramanujan_pi.sol | 4 +- .../semanticTests/externalContracts/snark.sol | 4 +- .../externalContracts/strings.sol | 6 +- .../ssa/stackLayoutGenerator/function.yul | 10 +-- .../deep_values_grow_to_args.stack | 41 ++++-------- .../dup_value_into_args_with_grow_1.stack | 19 +++--- .../dup_value_into_tail_and_args.stack | 21 +++---- .../multi_dup_with_phi_in_tail.stack | 21 +++---- .../return_label_with_dup_and_grow.stack | 19 +++--- .../stackShuffler/superfluous_top_slots.stack | 5 +- .../ssa/stackShuffler/triple_dup_no_phi.stack | 21 +++---- .../stackShuffler/triple_dup_with_phi.stack | 21 +++---- 17 files changed, 137 insertions(+), 141 deletions(-) diff --git a/libyul/backends/evm/ssa/StackShuffler.h b/libyul/backends/evm/ssa/StackShuffler.h index 2fd661331a97..fa96e3df2b3c 100644 --- a/libyul/backends/evm/ssa/StackShuffler.h +++ b/libyul/backends/evm/ssa/StackShuffler.h @@ -263,7 +263,6 @@ class StackShuffler // if there are no args, we should be done now if (_state.target().args.empty()) return {StackShufflerResult::Status::Admissible}; - yulAssert(_stack.size() == _state.target().size); // check whether we are done if (_state.admissible()) @@ -510,23 +509,37 @@ class StackShuffler if (auto result = dupDeepSlotIfRequired(_stack, _state); result.status != ShuffleHelperResult::Status::NoAction) return result; + // depth of an args-region offset `_o` after the next grow, clamped from below to zero + auto const depthFromNewTop = [&](StackOffset _o) -> std::size_t { - StackOffset const targetOffset{_stack.size()}; - if (_state.count(_state.targetArg(targetOffset)) < _state.targetMinCount(_state.targetArg(targetOffset))) + if (_o.value >= _stack.size()) + return 0u; + return _stack.offsetToDepth(_o).value + 1; + }; + // duping up `_arg` only makes progress if some target args-region offset wanting `_arg` is still + // unfilled and reachable from the new top + auto const canReachSomeUnfilledTarget = [&](Slot const& _arg) + { + for (auto offset: _state.target().argsRange()) { - auto const sourceDepth = _stack.findSlotDepth(_state.targetArg(targetOffset)); - if (!sourceDepth) - { - _stack.push(_state.targetArg(targetOffset)); - return {ShuffleHelperResult::Status::StackModified}; - } - - if (!_stack.dupReachable(*sourceDepth)) - return {ShuffleHelperResult::Status::StackTooDeep, _state.targetArg(targetOffset)}; - _stack.dup(*sourceDepth); - return {ShuffleHelperResult::Status::StackModified}; + if (_state.targetArg(offset) != _arg) + continue; + if (_state.isArgsCompatible(offset, offset)) + continue; + if (depthFromNewTop(offset) <= ReachableStackDepth) + return true; } - } + return false; + }; + // after the grow, every misaligned args-region offset below the new top must still + // be swap-reachable, otherwise we'd strand it + bool const prefixReachable = [&] + { + for (StackOffset p: _state.stackArgsRange()) + if (!_state.isArgsCompatible(p, p) && depthFromNewTop(p) > ReachableStackDepth) + return false; + return true; + }(); // if we can't directly produce targetOffset, take the deepest arg that we don't have enough of and dup/push that // First, prioritize duping args that are on the stack over pushing freely-generatable ones @@ -537,7 +550,7 @@ class StackShuffler { if (auto sourceDepth = _stack.findSlotDepth(arg)) { - if (_stack.dupReachable(*sourceDepth)) + if (_stack.dupReachable(*sourceDepth) && canReachSomeUnfilledTarget(arg)) { _stack.dup(*sourceDepth); return {ShuffleHelperResult::Status::StackModified}; @@ -545,6 +558,12 @@ class StackShuffler if (!_stack.canBeFreelyGenerated(arg)) return {ShuffleHelperResult::Status::StackTooDeep, arg}; } + if (!prefixReachable) + continue; + if (!canReachSomeUnfilledTarget(arg)) + // Pushing this arg would land it at an offset from which none of its target + // positions are reachable + continue; yulAssert(_stack.canBeFreelyGenerated(arg)); _stack.push(arg); return {ShuffleHelperResult::Status::StackModified}; @@ -553,10 +572,15 @@ class StackShuffler // Try to dup the optimal slot based on liveness analysis if (auto slotToDup = selectOptimalSlotToDup(_stack, _state)) + { _stack.dup(*slotToDup); - else - // If no suitable slot found, push junk - _stack.push(Slot::makeJunk()); + return {ShuffleHelperResult::Status::StackModified}; + } + // Growing would strand a misaligned prefix slot + if (!prefixReachable) + return {ShuffleHelperResult::Status::NoAction}; + // If no suitable slot found, push junk + _stack.push(Slot::makeJunk()); return {ShuffleHelperResult::Status::StackModified}; } diff --git a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol index 9ac85f9c8d8e..95a424096359 100644 --- a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol +++ b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol @@ -83,8 +83,8 @@ contract FixedFeeRegistrar is Registrar { // gas legacy code: 792400 // gas legacyOptimized: 84598 // gas legacyOptimized code: 388000 -// gas ssaCFGOptimized: 78844 -// gas ssaCFGOptimized code: 321800 +// gas ssaCFGOptimized: 78940 +// gas ssaCFGOptimized code: 323000 // reserve(string), 69 ether: 0x20, 3, "abc" -> // ~ emit Changed(string): #0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 // gas irOptimized: 45741 diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index baa951e71040..c977eaeb4446 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: 809663 -// gas ssaCFGOptimized code: 570000 +// gas ssaCFGOptimized: 809919 +// gas ssaCFGOptimized code: 573200 // supportsInterface(bytes4): 0x0 -> 0 // supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 # // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # @@ -195,14 +195,14 @@ contract DepositContract is IDepositContract, ERC165 { // gas irOptimized: 109178 // gas legacy: 142741 // gas legacyOptimized: 117558 -// gas ssaCFGOptimized: 109748 +// gas ssaCFGOptimized: 109949 // get_deposit_count() -> 0x20, 8, 0 # TODO: check balance and logs after each deposit # // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0 -> FAILURE # Empty input # // get_deposit_root() -> 0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e // gas irOptimized: 109178 // gas legacy: 142741 // gas legacyOptimized: 117558 -// gas ssaCFGOptimized: 109748 +// gas ssaCFGOptimized: 109949 // get_deposit_count() -> 0x20, 8, 0 // deposit(bytes,bytes,bytes,bytes32), 1 ether: 0x80, 0xe0, 0x120, 0xaa4a8d0b7d9077248630f1a4701ae9764e42271d7f22b7838778411857fd349e, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0x00f50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8 -> # txhash: 0x7085c586686d666e8bb6e9477a0f0b09565b2060a11f1c4209d3a52295033832 # // ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0xf50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x08, 0xca9a3b00000000000000000000000000000000000000000000000000000000, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8, 0x08, 0x00 @@ -210,7 +210,7 @@ contract DepositContract is IDepositContract, ERC165 { // gas irOptimized: 109174 // gas legacy: 142750 // gas legacyOptimized: 117570 -// gas ssaCFGOptimized: 109744 +// gas ssaCFGOptimized: 109942 // get_deposit_count() -> 0x20, 8, 0x0100000000000000000000000000000000000000000000000000000000000000 // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0x80, 0xe0, 0x120, 0xdbd986dc85ceb382708cf90a3500f500f0a393c5ece76963ac3ed72eccd2c301, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x00344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d -> # txhash: 0x404d8e109822ce448e68f45216c12cb051b784d068fbe98317ab8e50c58304ac # // ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x08, 0x40597307000000000000000000000000000000000000000000000000000000, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d, 0x08, 0x0100000000000000000000000000000000000000000000000000000000000000 @@ -218,5 +218,5 @@ contract DepositContract is IDepositContract, ERC165 { // gas irOptimized: 109174 // gas legacy: 142750 // gas legacyOptimized: 117570 -// gas ssaCFGOptimized: 109744 +// gas ssaCFGOptimized: 109942 // get_deposit_count() -> 0x20, 8, 0x0200000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol index ad32fdc15adb..3bf8da5d0fbe 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol @@ -57,8 +57,8 @@ contract test { // gas legacy code: 2205000 // gas legacyOptimized: 178012 // gas legacyOptimized code: 1669600 -// gas ssaCFGOptimized: 175048 -// gas ssaCFGOptimized code: 1639600 +// gas ssaCFGOptimized: 175208 +// gas ssaCFGOptimized code: 1641600 // div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22045 // gas legacy: 22736 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index 2f681baa435d..b4f5d9d58f36 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -57,8 +57,8 @@ contract test { // gas legacy code: 1999000 // gas legacyOptimized: 168857 // gas legacyOptimized code: 1556200 -// gas ssaCFGOptimized: 167611 -// gas ssaCFGOptimized code: 1544800 +// gas ssaCFGOptimized: 167659 +// gas ssaCFGOptimized code: 1545400 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 21912 // gas legacy: 22475 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 44208308acab..69ede3bd18ff 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: 78122 +// gas ssaCFGOptimized code: 315400 // 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..a94f79b6f8b7 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: 275876 // verifyTx() -> true // ~ emit Verified(string): 0x20, 0x16, "Successfully verified." // gas irOptimized: 818076 // gas legacy: 904397 // gas legacyOptimized: 816770 -// gas ssaCFGOptimized: 820130 +// gas ssaCFGOptimized: 820658 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index 9bd1f39a0f92..1206f2eb2e72 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: 96160 -// gas ssaCFGOptimized code: 532200 +// gas ssaCFGOptimized: 96272 +// gas ssaCFGOptimized code: 533600 // 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: 1882355 +// gas ssaCFGOptimized: 1898814 diff --git a/test/libyul/ssa/stackLayoutGenerator/function.yul b/test/libyul/ssa/stackLayoutGenerator/function.yul index 8ea0f691bbc5..028f4687e7cd 100644 --- a/test/libyul/ssa/stackLayoutGenerator/function.yul +++ b/test/libyul/ssa/stackLayoutGenerator/function.yul @@ -81,15 +81,15 @@ // Block3_0 [label="\ // IN: [v0]\l\ // \l\ -// [FunctionCallReturnLabel[0], lit0, v0]\l\ +// [v0, FunctionCallReturnLabel[0], lit0, v0]\l\ // f\l\ -// [FunctionCallReturnLabel[0], v1]\l\ +// [v0, FunctionCallReturnLabel[0], v1]\l\ // \l\ -// [v1]\l\ +// [JUNK, v1]\l\ // h\l\ -// []\l\ +// [JUNK]\l\ // \l\ -// OUT: []\l\ +// OUT: [JUNK]\l\ // "]; // Block3_0Exit [label="Terminated"]; // Block3_0 -> Block3_0Exit; diff --git a/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack b/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack index e84310023a51..ce28dccd01c9 100644 --- a/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack +++ b/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack @@ -6,35 +6,16 @@ targetStackTop: [JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, // +-------------------------------------------------------------------------------------------------------------------------------------------- // (initial)| * * * * * * * * * * * * * v1 v2 * // POP| * * * * * * * * * * * * * v1 v2 -// PUSH lit2| * * * * * * * * * * * * * v1 v2 lit2 -// DUP2| * * * * * * * * * * * * * v1 v2 lit2 v2 -// PUSH lit3| * * * * * * * * * * * * * v1 v2 lit2 v2 lit3 -// DUP2| * * * * * * * * * * * * * v1 v2 lit2 v2 lit3 v2 -// PUSH lit1| * * * * * * * * * * * * * v1 v2 lit2 v2 lit3 v2 lit1 -// SWAP6| * * * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v2 v1 -// SWAP1| * * * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP7| * * * * * * * * * * * * v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * * * * * * * v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * * * * * * * v2 lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP8| * * * * * * * * * * * v2 v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * * * * * * v2 v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * * * * * * v2 v2 lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP9| * * * * * * * * * * v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * * * * * v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * * * * * v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP10| * * * * * * * * * v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * * * * v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * * * * v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP11| * * * * * * * * v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * * * v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * * * v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP12| * * * * * * * v2 v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * * v2 v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * * v2 v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 v2 -// SWAP13| * * * * * * v2 v2 v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 * -// POP| * * * * * * v2 v2 v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 -// DUP3| * * * * * * v2 v2 v2 v2 v2 v2 v2 lit1 v2 lit2 v2 lit3 v1 v2 -// ...| +// DUP1| * * * * * * * * * * * * * v1 v2 v2 +// SWAP14| * v2 * * * * * * * * * * * v1 v2 * +// DUP2| * v2 * * * * * * * * * * * v1 v2 * v2 +// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 * v2 lit1 +// SWAP4| * v2 * * * * * * * * * * * lit1 v2 * v2 v1 +// PUSH lit2| * v2 * * * * * * * * * * * lit1 v2 * v2 v1 lit2 +// SWAP3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 * +// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 * lit3 +// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 * v1 +// SWAP1| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 * // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 * -// Status: MaxIterationsReached +// Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack b/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack index 0b81b635f176..ce68f30f413d 100644 --- a/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack +++ b/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack @@ -7,17 +7,14 @@ targetStackTop: [v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, phi1, // (initial)| * * * * * * * * * * phi1 * v1 v2 v3 // SWAP14| v3 * * * * * * * * * phi1 * v1 v2 * // POP| v3 * * * * * * * * * phi1 * v1 v2 -// PUSH lit2| v3 * * * * * * * * * phi1 * v1 v2 lit2 -// DUP2| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 -// PUSH lit1| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 lit1 -// DUP2| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 lit1 v2 -// SWAP1| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 v2 lit1 -// POP| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 v2 -// SWAP16| v2 * * * * * * * * * phi1 * v1 v2 lit2 v2 v3 -// PUSH lit1| v2 * * * * * * * * * phi1 * v1 v2 lit2 v2 v3 lit1 -// SWAP5| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 v3 v1 -// DUP6| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 v3 v1 lit1 -// SWAP2| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 lit1 v1 v3 +// DUP1| v3 * * * * * * * * * phi1 * v1 v2 v2 +// SWAP14| v2 * * * * * * * * * phi1 * v1 v2 v3 +// DUP2| v2 * * * * * * * * * phi1 * v1 v2 v3 v2 +// PUSH lit1| v2 * * * * * * * * * phi1 * v1 v2 v3 v2 lit1 +// DUP1| v2 * * * * * * * * * phi1 * v1 v2 v3 v2 lit1 lit1 +// SWAP5| v2 * * * * * * * * * phi1 * lit1 v2 v3 v2 lit1 v1 +// PUSH lit2| v2 * * * * * * * * * phi1 * lit1 v2 v3 v2 lit1 v1 lit2 +// SWAP4| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 lit1 v1 v3 // +------------------------------------------------------------------------------------------------------------------------------------- // (target)| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 lit1 v1 v3 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack b/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack index 287ba86cf2a2..f8c964f0e872 100644 --- a/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack +++ b/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack @@ -7,17 +7,16 @@ targetStackTop: [JUNK, JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, // (initial)| * * * * * * * * * * * * * * v1 v2 v3 // SWAP14| * * v3 * * * * * * * * * * * v1 v2 * // POP| * * v3 * * * * * * * * * * * v1 v2 -// PUSH lit2| * * v3 * * * * * * * * * * * v1 v2 lit2 -// DUP2| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 -// PUSH lit3| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 lit3 -// DUP2| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 lit3 v2 -// SWAP1| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 lit3 -// POP| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 -// SWAP16| * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 -// PUSH lit1| * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 lit1 -// SWAP5| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 -// PUSH lit3| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 lit3 -// SWAP2| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 +// DUP1| * * v3 * * * * * * * * * * * v1 v2 v2 +// SWAP14| * * v2 * * * * * * * * * * * v1 v2 v3 +// DUP2| * * v2 * * * * * * * * * * * v1 v2 v3 v2 +// PUSH lit1| * * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 +// SWAP4| * * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 +// PUSH lit2| * * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 lit2 +// SWAP3| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 +// PUSH lit3| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 lit3 +// SWAP2| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v3 v1 +// SWAP1| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // +--------------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack b/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack index aa563e6f9f2b..2f8912e8b492 100644 --- a/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack +++ b/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack @@ -7,17 +7,16 @@ targetStackTop: [JUNK, v5, JUNK, v1, v2, JUNK, JUNK, JUNK, JUNK, phi1, JUNK, v3, // (initial)| * * * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 // SWAP14| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 * // POP| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 -// PUSH lit2| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 -// DUP2| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 -// PUSH lit3| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 lit3 -// DUP2| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 lit3 v5 -// SWAP1| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v5 lit3 -// POP| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v5 -// SWAP16| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v6 -// PUSH lit1| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v6 lit1 -// SWAP5| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v6 v4 -// PUSH lit3| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v6 v4 lit3 -// SWAP2| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v4 v6 +// DUP1| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v5 +// SWAP14| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 +// DUP2| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 v5 +// PUSH lit1| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 v5 lit1 +// SWAP4| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 v6 v5 v4 +// PUSH lit2| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 v6 v5 v4 lit2 +// SWAP3| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v4 v6 +// PUSH lit3| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v4 v6 lit3 +// SWAP2| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v6 v4 +// SWAP1| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v4 v6 // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v4 v6 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack b/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack index 571ed4a24269..039c6eec2c16 100644 --- a/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack +++ b/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack @@ -18,17 +18,14 @@ targetStackTop: [ReturnLabel[1], JUNK, JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, J // POP| ReturnLabel[1] * * * * * * * * * * * * * * v1 v2 v3 // SWAP14| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 * // POP| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 -// PUSH lit2| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 -// DUP2| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 -// PUSH lit1| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 lit1 -// DUP2| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 lit1 v2 -// SWAP1| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 lit1 -// POP| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 -// SWAP16| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 -// PUSH lit1| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 lit1 -// SWAP5| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 -// DUP6| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 lit1 -// SWAP2| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit1 v1 v3 +// DUP1| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 v2 +// SWAP14| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 +// DUP2| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 v2 +// PUSH lit1| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 +// DUP1| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 lit1 +// SWAP5| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 v3 v2 lit1 v1 +// PUSH lit2| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 v3 v2 lit1 v1 lit2 +// SWAP4| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit1 v1 v3 // +------------------------------------------------------------------------------------------------------------------------------------------------------------------ +------- // (target)| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit1 v1 v3 | // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack b/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack index 775a2d782735..d86b13fde1af 100644 --- a/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack +++ b/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack @@ -7,8 +7,9 @@ targetStackTop: [JUNK, JUNK, v56, v57, lit0, v56, lit11] // (initial)| * * v56 v57 * * // POP| * * v56 v57 * // POP| * * v56 v57 -// PUSH lit0| * * v56 v57 lit0 -// DUP3| * * v56 v57 lit0 v56 +// DUP2| * * v56 v57 v56 +// PUSH lit0| * * v56 v57 v56 lit0 +// SWAP1| * * v56 v57 lit0 v56 // PUSH lit11| * * v56 v57 lit0 v56 lit11 // +------------------------------------------------- // (target)| * * v56 v57 lit0 v56 lit11 diff --git a/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack b/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack index 845095016f9d..66f904bd0976 100644 --- a/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack +++ b/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack @@ -7,17 +7,16 @@ targetStackTop: [JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, // (initial)| * * * * * * * * * * * * * v1 v2 v3 // SWAP14| * v3 * * * * * * * * * * * v1 v2 * // POP| * v3 * * * * * * * * * * * v1 v2 -// PUSH lit2| * v3 * * * * * * * * * * * v1 v2 lit2 -// DUP2| * v3 * * * * * * * * * * * v1 v2 lit2 v2 -// PUSH lit3| * v3 * * * * * * * * * * * v1 v2 lit2 v2 lit3 -// DUP2| * v3 * * * * * * * * * * * v1 v2 lit2 v2 lit3 v2 -// SWAP1| * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 lit3 -// POP| * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 -// SWAP16| * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 -// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 lit1 -// SWAP5| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 -// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 lit3 -// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 +// DUP1| * v3 * * * * * * * * * * * v1 v2 v2 +// SWAP14| * v2 * * * * * * * * * * * v1 v2 v3 +// DUP2| * v2 * * * * * * * * * * * v1 v2 v3 v2 +// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 +// SWAP4| * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 +// PUSH lit2| * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 lit2 +// SWAP3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 +// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 lit3 +// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v3 v1 +// SWAP1| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack b/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack index 3d28212bd91f..40d20f43b5c1 100644 --- a/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack +++ b/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack @@ -7,17 +7,16 @@ targetStackTop: [JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, phi1, JUNK, JUNK, // (initial)| * * * * * * * * phi1 * * * * v1 v2 v3 // SWAP14| * v3 * * * * * * phi1 * * * * v1 v2 * // POP| * v3 * * * * * * phi1 * * * * v1 v2 -// PUSH lit2| * v3 * * * * * * phi1 * * * * v1 v2 lit2 -// DUP2| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 -// PUSH lit3| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 lit3 -// DUP2| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 lit3 v2 -// SWAP1| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 v2 lit3 -// POP| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 v2 -// SWAP16| * v2 * * * * * * phi1 * * * * v1 v2 lit2 v2 v3 -// PUSH lit1| * v2 * * * * * * phi1 * * * * v1 v2 lit2 v2 v3 lit1 -// SWAP5| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v3 v1 -// PUSH lit3| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v3 v1 lit3 -// SWAP2| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v1 v3 +// DUP1| * v3 * * * * * * phi1 * * * * v1 v2 v2 +// SWAP14| * v2 * * * * * * phi1 * * * * v1 v2 v3 +// DUP2| * v2 * * * * * * phi1 * * * * v1 v2 v3 v2 +// PUSH lit1| * v2 * * * * * * phi1 * * * * v1 v2 v3 v2 lit1 +// SWAP4| * v2 * * * * * * phi1 * * * * lit1 v2 v3 v2 v1 +// PUSH lit2| * v2 * * * * * * phi1 * * * * lit1 v2 v3 v2 v1 lit2 +// SWAP3| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v1 v3 +// PUSH lit3| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v1 v3 lit3 +// SWAP2| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v3 v1 +// SWAP1| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v1 v3 // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v1 v3 // Status: Admissible From 41d19bb30facfa6942041373cfd39a6e414a174f Mon Sep 17 00:00:00 2001 From: clonker <1685266+clonker@users.noreply.github.com> Date: Wed, 15 Apr 2026 10:48:06 +0200 Subject: [PATCH 3/3] ssa shuffler properly guards fast path in fix args grow branch --- libyul/backends/evm/ssa/StackShuffler.h | 84 +++++++++++++++---- .../externalContracts/FixedFeeRegistrar.sol | 4 +- .../externalContracts/base64.sol | 6 +- .../externalContracts/deposit_contract.sol | 12 +-- .../externalContracts/prbmath_signed.sol | 4 +- .../externalContracts/prbmath_unsigned.sol | 4 +- .../externalContracts/ramanujan_pi.sol | 4 +- .../semanticTests/externalContracts/snark.sol | 4 +- .../externalContracts/strings.sol | 6 +- .../ssa/stackLayoutGenerator/function.yul | 10 +-- .../ssa/stackLayoutGenerator/nested_for.yul | 6 +- .../deep_values_grow_to_args.stack | 18 ++-- .../dup_value_into_args_with_grow_1.stack | 16 ++-- .../dup_value_into_tail_and_args.stack | 18 ++-- .../multi_dup_with_phi_in_tail.stack | 18 ++-- .../return_label_with_dup_and_grow.stack | 16 ++-- .../satisfy_tail_requirements.stack | 34 ++++---- .../stackShuffler/superfluous_top_slots.stack | 5 +- .../stackShuffler/swap_junk_over_pop.stack | 8 +- .../ssa/stackShuffler/triple_dup_no_phi.stack | 18 ++-- .../stackShuffler/triple_dup_with_phi.stack | 18 ++-- 21 files changed, 179 insertions(+), 134 deletions(-) diff --git a/libyul/backends/evm/ssa/StackShuffler.h b/libyul/backends/evm/ssa/StackShuffler.h index fa96e3df2b3c..9d9d8b0ab451 100644 --- a/libyul/backends/evm/ssa/StackShuffler.h +++ b/libyul/backends/evm/ssa/StackShuffler.h @@ -541,35 +541,83 @@ class StackShuffler return true; }(); - // if we can't directly produce targetOffset, take the deepest arg that we don't have enough of and dup/push that - // First, prioritize duping args that are on the stack over pushing freely-generatable ones - for (StackOffset const offset: _state.target().argsRange()) + // stricter gate for the fast path: every misaligned prefix offset must remain swap-reachable + // after the grow AND after one more placement op (so the prefix can still be fixed later) + bool const pushKeepsDeepPrefixReachable = [&] { - Slot const& arg = _state.targetArg(offset); - if (!arg.isJunk() && (_state.count(arg) < _state.targetMinCount(arg) || _state.countInArgs(arg) < _state.targetArgsCount(arg))) + for (StackOffset p: _state.stackArgsRange()) + if (!_state.isArgsCompatible(p, p) && depthFromNewTop(p) + 1 > ReachableStackDepth) + return false; + return true; + }(); + + // fast path: if the arg the target wants at the new top is under-supplied, place it directly there. + // Skip when growing would push a misaligned prefix offset out of swap range for subsequent fixups; + // otherwise we'd push and then immediately shrink back, oscillating + if (pushKeepsDeepPrefixReachable) + { + // the slot we're about to create lives at the current stack size (i.e. the post-grow top) + StackOffset const targetOffset{_stack.size()}; + Slot const& targetArg = _state.targetArg(targetOffset); + if ( + !targetArg.isJunk() && + ( + _state.count(targetArg) < _state.targetMinCount(targetArg) || + _state.countInArgs(targetArg) < _state.targetArgsCount(targetArg) + ) + ) { - if (auto sourceDepth = _stack.findSlotDepth(arg)) + // prefer duping an existing copy over generating a fresh one + if (auto sourceDepth = _stack.findSlotDepth(targetArg)) { - if (_stack.dupReachable(*sourceDepth) && canReachSomeUnfilledTarget(arg)) + if (_stack.dupReachable(*sourceDepth)) { _stack.dup(*sourceDepth); return {ShuffleHelperResult::Status::StackModified}; } - if (!_stack.canBeFreelyGenerated(arg)) - return {ShuffleHelperResult::Status::StackTooDeep, arg}; + // existing copy is out of dup range; if we also can't regenerate it, bail + if (!_stack.canBeFreelyGenerated(targetArg)) + return {ShuffleHelperResult::Status::StackTooDeep, targetArg}; + } + // no reachable copy (or none at all), push a fresh instance if the slot allows it + if (_stack.canBeFreelyGenerated(targetArg)) + { + _stack.push(targetArg); + return {ShuffleHelperResult::Status::StackModified}; } - if (!prefixReachable) - continue; - if (!canReachSomeUnfilledTarget(arg)) - // Pushing this arg would land it at an offset from which none of its target - // positions are reachable - continue; - yulAssert(_stack.canBeFreelyGenerated(arg)); - _stack.push(arg); - return {ShuffleHelperResult::Status::StackModified}; } } + // if we can't directly produce targetOffset, take the deepest arg that we don't have enough of and dup/push that + // First, prioritize duping args that are on the stack over pushing freely-generatable ones + for (StackOffset const offset: _state.target().argsRange()) + { + Slot const& arg = _state.targetArg(offset); + if (arg.isJunk()) + continue; + if (_state.count(arg) >= _state.targetMinCount(arg) && _state.countInArgs(arg) >= _state.targetArgsCount(arg)) + continue; + // If none of this arg's unfilled targets are reachable from the new top, growing for it + // won't help — skip and let another arg or a later step (e.g. the tail loop) handle it. + if (!canReachSomeUnfilledTarget(arg)) + continue; + if (auto sourceDepth = _stack.findSlotDepth(arg)) + { + if (_stack.dupReachable(*sourceDepth)) + { + _stack.dup(*sourceDepth); + return {ShuffleHelperResult::Status::StackModified}; + } + if (!_stack.canBeFreelyGenerated(arg)) + return {ShuffleHelperResult::Status::StackTooDeep, arg}; + } + if (!prefixReachable) + continue; + yulAssert(_stack.canBeFreelyGenerated(arg)); + _stack.push(arg); + return {ShuffleHelperResult::Status::StackModified}; + } + // Try to dup the optimal slot based on liveness analysis if (auto slotToDup = selectOptimalSlotToDup(_stack, _state)) { diff --git a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol index 95a424096359..9ac85f9c8d8e 100644 --- a/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol +++ b/test/libsolidity/semanticTests/externalContracts/FixedFeeRegistrar.sol @@ -83,8 +83,8 @@ contract FixedFeeRegistrar is Registrar { // gas legacy code: 792400 // gas legacyOptimized: 84598 // gas legacyOptimized code: 388000 -// gas ssaCFGOptimized: 78940 -// gas ssaCFGOptimized code: 323000 +// gas ssaCFGOptimized: 78844 +// gas ssaCFGOptimized code: 321800 // reserve(string), 69 ether: 0x20, 3, "abc" -> // ~ emit Changed(string): #0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 // gas irOptimized: 45741 diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol index 93799e936df4..39292cb8071a 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: 79931 -// gas ssaCFGOptimized code: 332600 +// gas ssaCFGOptimized: 79883 +// gas ssaCFGOptimized code: 332000 // 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=" @@ -66,4 +66,4 @@ contract test { // gas irOptimized: 3512081 // gas legacy: 4600082 // gas legacyOptimized: 2813075 -// gas ssaCFGOptimized: 3089081 +// gas ssaCFGOptimized: 3078081 diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index c977eaeb4446..d3a9834a82bd 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: 809919 -// gas ssaCFGOptimized code: 573200 +// gas ssaCFGOptimized: 809667 +// gas ssaCFGOptimized code: 570200 // supportsInterface(bytes4): 0x0 -> 0 // supportsInterface(bytes4): 0xffffffff00000000000000000000000000000000000000000000000000000000 -> false # defined to be false by ERC-165 # // supportsInterface(bytes4): 0x01ffc9a700000000000000000000000000000000000000000000000000000000 -> true # ERC-165 id # @@ -195,14 +195,14 @@ contract DepositContract is IDepositContract, ERC165 { // gas irOptimized: 109178 // gas legacy: 142741 // gas legacyOptimized: 117558 -// gas ssaCFGOptimized: 109949 +// gas ssaCFGOptimized: 109751 // get_deposit_count() -> 0x20, 8, 0 # TODO: check balance and logs after each deposit # // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0 -> FAILURE # Empty input # // get_deposit_root() -> 0xd70a234731285c6804c2a4f56711ddb8c82c99740f207854891028af34e27e5e // gas irOptimized: 109178 // gas legacy: 142741 // gas legacyOptimized: 117558 -// gas ssaCFGOptimized: 109949 +// gas ssaCFGOptimized: 109751 // get_deposit_count() -> 0x20, 8, 0 // deposit(bytes,bytes,bytes,bytes32), 1 ether: 0x80, 0xe0, 0x120, 0xaa4a8d0b7d9077248630f1a4701ae9764e42271d7f22b7838778411857fd349e, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0x00f50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8 -> # txhash: 0x7085c586686d666e8bb6e9477a0f0b09565b2060a11f1c4209d3a52295033832 # // ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0xf50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x08, 0xca9a3b00000000000000000000000000000000000000000000000000000000, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8, 0x08, 0x00 @@ -210,7 +210,7 @@ contract DepositContract is IDepositContract, ERC165 { // gas irOptimized: 109174 // gas legacy: 142750 // gas legacyOptimized: 117570 -// gas ssaCFGOptimized: 109942 +// gas ssaCFGOptimized: 109747 // get_deposit_count() -> 0x20, 8, 0x0100000000000000000000000000000000000000000000000000000000000000 // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0x80, 0xe0, 0x120, 0xdbd986dc85ceb382708cf90a3500f500f0a393c5ece76963ac3ed72eccd2c301, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x00344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d -> # txhash: 0x404d8e109822ce448e68f45216c12cb051b784d068fbe98317ab8e50c58304ac # // ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x08, 0x40597307000000000000000000000000000000000000000000000000000000, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d, 0x08, 0x0100000000000000000000000000000000000000000000000000000000000000 @@ -218,5 +218,5 @@ contract DepositContract is IDepositContract, ERC165 { // gas irOptimized: 109174 // gas legacy: 142750 // gas legacyOptimized: 117570 -// gas ssaCFGOptimized: 109942 +// gas ssaCFGOptimized: 109747 // get_deposit_count() -> 0x20, 8, 0x0200000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol index 3bf8da5d0fbe..ad32fdc15adb 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_signed.sol @@ -57,8 +57,8 @@ contract test { // gas legacy code: 2205000 // gas legacyOptimized: 178012 // gas legacyOptimized code: 1669600 -// gas ssaCFGOptimized: 175208 -// gas ssaCFGOptimized code: 1641600 +// gas ssaCFGOptimized: 175048 +// gas ssaCFGOptimized code: 1639600 // div(int256,int256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 22045 // gas legacy: 22736 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index b4f5d9d58f36..2f681baa435d 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -57,8 +57,8 @@ contract test { // gas legacy code: 1999000 // gas legacyOptimized: 168857 // gas legacyOptimized code: 1556200 -// gas ssaCFGOptimized: 167659 -// gas ssaCFGOptimized code: 1545400 +// gas ssaCFGOptimized: 167611 +// gas ssaCFGOptimized code: 1544800 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 // gas irOptimized: 21912 // gas legacy: 22475 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 69ede3bd18ff..37359ebeb8bb 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: 78122 -// gas ssaCFGOptimized code: 315400 +// gas ssaCFGOptimized: 77804 +// gas ssaCFGOptimized code: 311200 // 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 a94f79b6f8b7..d28869c77206 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: 275876 +// gas ssaCFGOptimized: 275791 // verifyTx() -> true // ~ emit Verified(string): 0x20, 0x16, "Successfully verified." // gas irOptimized: 818076 // gas legacy: 904397 // gas legacyOptimized: 816770 -// gas ssaCFGOptimized: 820658 +// gas ssaCFGOptimized: 820120 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index 1206f2eb2e72..999ead07b92f 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: 96272 -// gas ssaCFGOptimized code: 533600 +// gas ssaCFGOptimized: 95989 +// gas ssaCFGOptimized code: 530000 // 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: 1898814 +// gas ssaCFGOptimized: 1841235 diff --git a/test/libyul/ssa/stackLayoutGenerator/function.yul b/test/libyul/ssa/stackLayoutGenerator/function.yul index 028f4687e7cd..8ea0f691bbc5 100644 --- a/test/libyul/ssa/stackLayoutGenerator/function.yul +++ b/test/libyul/ssa/stackLayoutGenerator/function.yul @@ -81,15 +81,15 @@ // Block3_0 [label="\ // IN: [v0]\l\ // \l\ -// [v0, FunctionCallReturnLabel[0], lit0, v0]\l\ +// [FunctionCallReturnLabel[0], lit0, v0]\l\ // f\l\ -// [v0, FunctionCallReturnLabel[0], v1]\l\ +// [FunctionCallReturnLabel[0], v1]\l\ // \l\ -// [JUNK, v1]\l\ +// [v1]\l\ // h\l\ -// [JUNK]\l\ +// []\l\ // \l\ -// OUT: [JUNK]\l\ +// OUT: []\l\ // "]; // Block3_0Exit [label="Terminated"]; // Block3_0 -> Block3_0Exit; 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/deep_values_grow_to_args.stack b/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack index ce28dccd01c9..848d246fe619 100644 --- a/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack +++ b/test/libyul/ssa/stackShuffler/deep_values_grow_to_args.stack @@ -6,16 +6,14 @@ targetStackTop: [JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, // +-------------------------------------------------------------------------------------------------------------------------------------------- // (initial)| * * * * * * * * * * * * * v1 v2 * // POP| * * * * * * * * * * * * * v1 v2 -// DUP1| * * * * * * * * * * * * * v1 v2 v2 -// SWAP14| * v2 * * * * * * * * * * * v1 v2 * -// DUP2| * v2 * * * * * * * * * * * v1 v2 * v2 -// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 * v2 lit1 -// SWAP4| * v2 * * * * * * * * * * * lit1 v2 * v2 v1 -// PUSH lit2| * v2 * * * * * * * * * * * lit1 v2 * v2 v1 lit2 -// SWAP3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 * -// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 * lit3 -// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 * v1 -// SWAP1| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 * +// PUSH lit2| * * * * * * * * * * * * * v1 v2 lit2 +// DUP2| * * * * * * * * * * * * * v1 v2 lit2 v2 +// DUP1| * * * * * * * * * * * * * v1 v2 lit2 v2 v2 +// SWAP16| * v2 * * * * * * * * * * * v1 v2 lit2 v2 * +// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 lit2 v2 * lit1 +// SWAP5| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 * v1 +// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 * v1 lit3 +// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 * // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 * // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack b/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack index ce68f30f413d..4f27cf720971 100644 --- a/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack +++ b/test/libyul/ssa/stackShuffler/dup_value_into_args_with_grow_1.stack @@ -7,14 +7,14 @@ targetStackTop: [v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, phi1, // (initial)| * * * * * * * * * * phi1 * v1 v2 v3 // SWAP14| v3 * * * * * * * * * phi1 * v1 v2 * // POP| v3 * * * * * * * * * phi1 * v1 v2 -// DUP1| v3 * * * * * * * * * phi1 * v1 v2 v2 -// SWAP14| v2 * * * * * * * * * phi1 * v1 v2 v3 -// DUP2| v2 * * * * * * * * * phi1 * v1 v2 v3 v2 -// PUSH lit1| v2 * * * * * * * * * phi1 * v1 v2 v3 v2 lit1 -// DUP1| v2 * * * * * * * * * phi1 * v1 v2 v3 v2 lit1 lit1 -// SWAP5| v2 * * * * * * * * * phi1 * lit1 v2 v3 v2 lit1 v1 -// PUSH lit2| v2 * * * * * * * * * phi1 * lit1 v2 v3 v2 lit1 v1 lit2 -// SWAP4| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 lit1 v1 v3 +// PUSH lit2| v3 * * * * * * * * * phi1 * v1 v2 lit2 +// DUP2| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 +// DUP1| v3 * * * * * * * * * phi1 * v1 v2 lit2 v2 v2 +// SWAP16| v2 * * * * * * * * * phi1 * v1 v2 lit2 v2 v3 +// PUSH lit1| v2 * * * * * * * * * phi1 * v1 v2 lit2 v2 v3 lit1 +// SWAP5| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 v3 v1 +// DUP6| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 v3 v1 lit1 +// SWAP2| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 lit1 v1 v3 // +------------------------------------------------------------------------------------------------------------------------------------- // (target)| v2 * * * * * * * * * phi1 * lit1 v2 lit2 v2 lit1 v1 v3 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack b/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack index f8c964f0e872..ae4266c6b18b 100644 --- a/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack +++ b/test/libyul/ssa/stackShuffler/dup_value_into_tail_and_args.stack @@ -7,16 +7,14 @@ targetStackTop: [JUNK, JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, // (initial)| * * * * * * * * * * * * * * v1 v2 v3 // SWAP14| * * v3 * * * * * * * * * * * v1 v2 * // POP| * * v3 * * * * * * * * * * * v1 v2 -// DUP1| * * v3 * * * * * * * * * * * v1 v2 v2 -// SWAP14| * * v2 * * * * * * * * * * * v1 v2 v3 -// DUP2| * * v2 * * * * * * * * * * * v1 v2 v3 v2 -// PUSH lit1| * * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 -// SWAP4| * * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 -// PUSH lit2| * * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 lit2 -// SWAP3| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 -// PUSH lit3| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 lit3 -// SWAP2| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v3 v1 -// SWAP1| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 +// PUSH lit2| * * v3 * * * * * * * * * * * v1 v2 lit2 +// DUP2| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 +// DUP1| * * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 +// SWAP16| * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 +// PUSH lit1| * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 lit1 +// SWAP5| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 +// PUSH lit3| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 lit3 +// SWAP2| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // +--------------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack b/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack index 2f8912e8b492..f608f4b7f1cd 100644 --- a/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack +++ b/test/libyul/ssa/stackShuffler/multi_dup_with_phi_in_tail.stack @@ -7,16 +7,14 @@ targetStackTop: [JUNK, v5, JUNK, v1, v2, JUNK, JUNK, JUNK, JUNK, phi1, JUNK, v3, // (initial)| * * * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 // SWAP14| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 * // POP| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 -// DUP1| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v5 -// SWAP14| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 -// DUP2| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 v5 -// PUSH lit1| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 v6 v5 lit1 -// SWAP4| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 v6 v5 v4 -// PUSH lit2| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 v6 v5 v4 lit2 -// SWAP3| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v4 v6 -// PUSH lit3| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v4 v6 lit3 -// SWAP2| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v6 v4 -// SWAP1| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v4 v6 +// PUSH lit2| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 +// DUP2| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 +// DUP1| * v6 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v5 +// SWAP16| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v6 +// PUSH lit1| * v5 * v1 v2 * * * * phi1 * v3 phi2 v4 v5 lit2 v5 v6 lit1 +// SWAP5| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v6 v4 +// PUSH lit3| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 v6 v4 lit3 +// SWAP2| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v4 v6 // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v5 * v1 v2 * * * * phi1 * v3 phi2 lit1 v5 lit2 v5 lit3 v4 v6 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack b/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack index 039c6eec2c16..d583b0d6d503 100644 --- a/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack +++ b/test/libyul/ssa/stackShuffler/return_label_with_dup_and_grow.stack @@ -18,14 +18,14 @@ targetStackTop: [ReturnLabel[1], JUNK, JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, J // POP| ReturnLabel[1] * * * * * * * * * * * * * * v1 v2 v3 // SWAP14| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 * // POP| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 -// DUP1| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 v2 -// SWAP14| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 -// DUP2| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 v2 -// PUSH lit1| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 -// DUP1| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 lit1 -// SWAP5| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 v3 v2 lit1 v1 -// PUSH lit2| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 v3 v2 lit1 v1 lit2 -// SWAP4| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit1 v1 v3 +// PUSH lit2| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 +// DUP2| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 +// DUP1| ReturnLabel[1] * * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 +// SWAP16| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 +// PUSH lit1| ReturnLabel[1] * * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 lit1 +// SWAP5| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 +// DUP6| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 lit1 +// SWAP2| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit1 v1 v3 // +------------------------------------------------------------------------------------------------------------------------------------------------------------------ +------- // (target)| ReturnLabel[1] * * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit1 v1 v3 | // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/satisfy_tail_requirements.stack b/test/libyul/ssa/stackShuffler/satisfy_tail_requirements.stack index a97447af9235..fb0927f0126d 100644 --- a/test/libyul/ssa/stackShuffler/satisfy_tail_requirements.stack +++ b/test/libyul/ssa/stackShuffler/satisfy_tail_requirements.stack @@ -8,20 +8,26 @@ targetStackSize: 17 // +------------------------------------------------- +---------------------------------------------------------------------- // (initial)| v2 v3 v4 v5 v6 v7 v8 | v9 v10 // SWAP8| v10 v3 v4 v5 v6 v7 v8 | v9 v2 -// PUSH lit3| v10 v3 v4 v5 v6 v7 v8 | v9 v2 lit3 -// SWAP2| v10 v3 v4 v5 v6 v7 v8 | lit3 v2 v9 -// SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v2 -// DUP4| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v2 v8 -// SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v2 -// DUP6| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v2 v7 -// SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v2 -// DUP8| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v2 v6 -// SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v2 -// DUP10| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v2 v5 -// SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v2 -// DUP12| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v2 v4 -// SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v4 v2 -// DUP14| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v4 v2 v3 +// DUP3| v10 v3 v4 v5 v6 v7 v8 | v9 v2 v8 +// SWAP2| v10 v3 v4 v5 v6 v7 v8 | v8 v2 v9 +// SWAP1| v10 v3 v4 v5 v6 v7 v8 | v8 v9 v2 +// DUP5| v10 v3 v4 v5 v6 v7 v8 | v8 v9 v2 v7 +// SWAP3| v10 v3 v4 v5 v6 v7 v8 | v7 v9 v2 v8 +// SWAP1| v10 v3 v4 v5 v6 v7 v8 | v7 v9 v8 v2 +// DUP7| v10 v3 v4 v5 v6 v7 v8 | v7 v9 v8 v2 v6 +// SWAP4| v10 v3 v4 v5 v6 v7 v8 | v6 v9 v8 v2 v7 +// SWAP1| v10 v3 v4 v5 v6 v7 v8 | v6 v9 v8 v7 v2 +// DUP9| v10 v3 v4 v5 v6 v7 v8 | v6 v9 v8 v7 v2 v5 +// SWAP5| v10 v3 v4 v5 v6 v7 v8 | v5 v9 v8 v7 v2 v6 +// SWAP1| v10 v3 v4 v5 v6 v7 v8 | v5 v9 v8 v7 v6 v2 +// DUP11| v10 v3 v4 v5 v6 v7 v8 | v5 v9 v8 v7 v6 v2 v4 +// SWAP6| v10 v3 v4 v5 v6 v7 v8 | v4 v9 v8 v7 v6 v2 v5 +// SWAP1| v10 v3 v4 v5 v6 v7 v8 | v4 v9 v8 v7 v6 v5 v2 +// DUP13| v10 v3 v4 v5 v6 v7 v8 | v4 v9 v8 v7 v6 v5 v2 v3 +// SWAP7| v10 v3 v4 v5 v6 v7 v8 | v3 v9 v8 v7 v6 v5 v2 v4 +// SWAP1| v10 v3 v4 v5 v6 v7 v8 | v3 v9 v8 v7 v6 v5 v4 v2 +// PUSH lit3| v10 v3 v4 v5 v6 v7 v8 | v3 v9 v8 v7 v6 v5 v4 v2 lit3 +// SWAP8| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v4 v2 v3 // SWAP1| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v4 v3 v2 // DUP16| v10 v3 v4 v5 v6 v7 v8 | lit3 v9 v8 v7 v6 v5 v4 v3 v2 v10 // +------------------------------------------------- +---------------------------------------------------------------------- diff --git a/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack b/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack index d86b13fde1af..775a2d782735 100644 --- a/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack +++ b/test/libyul/ssa/stackShuffler/superfluous_top_slots.stack @@ -7,9 +7,8 @@ targetStackTop: [JUNK, JUNK, v56, v57, lit0, v56, lit11] // (initial)| * * v56 v57 * * // POP| * * v56 v57 * // POP| * * v56 v57 -// DUP2| * * v56 v57 v56 -// PUSH lit0| * * v56 v57 v56 lit0 -// SWAP1| * * v56 v57 lit0 v56 +// PUSH lit0| * * v56 v57 lit0 +// DUP3| * * v56 v57 lit0 v56 // PUSH lit11| * * v56 v57 lit0 v56 lit11 // +------------------------------------------------- // (target)| * * v56 v57 lit0 v56 lit11 diff --git a/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack b/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack index b83cef92f7ef..5c51427d171f 100644 --- a/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack +++ b/test/libyul/ssa/stackShuffler/swap_junk_over_pop.stack @@ -6,9 +6,11 @@ targetStackSize: 4 // | 0 | 1 2 3 // +------- +--------------------- // (initial)| v0 | * v2 -// PUSH lit2| v0 | * v2 lit2 -// SWAP2| v0 | lit2 v2 * -// SWAP3| * | lit2 v2 v0 +// DUP3| v0 | * v2 v0 +// SWAP2| v0 | v0 v2 * +// POP| v0 | v0 v2 +// PUSH lit2| v0 | v0 v2 lit2 +// SWAP2| v0 | lit2 v2 v0 // +------- +--------------------- // (target)| {} | lit2 v2 v0 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack b/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack index 66f904bd0976..46dde8a40333 100644 --- a/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack +++ b/test/libyul/ssa/stackShuffler/triple_dup_no_phi.stack @@ -7,16 +7,14 @@ targetStackTop: [JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, // (initial)| * * * * * * * * * * * * * v1 v2 v3 // SWAP14| * v3 * * * * * * * * * * * v1 v2 * // POP| * v3 * * * * * * * * * * * v1 v2 -// DUP1| * v3 * * * * * * * * * * * v1 v2 v2 -// SWAP14| * v2 * * * * * * * * * * * v1 v2 v3 -// DUP2| * v2 * * * * * * * * * * * v1 v2 v3 v2 -// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 v3 v2 lit1 -// SWAP4| * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 -// PUSH lit2| * v2 * * * * * * * * * * * lit1 v2 v3 v2 v1 lit2 -// SWAP3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 -// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v1 v3 lit3 -// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v3 v1 -// SWAP1| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 +// PUSH lit2| * v3 * * * * * * * * * * * v1 v2 lit2 +// DUP2| * v3 * * * * * * * * * * * v1 v2 lit2 v2 +// DUP1| * v3 * * * * * * * * * * * v1 v2 lit2 v2 v2 +// SWAP16| * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 +// PUSH lit1| * v2 * * * * * * * * * * * v1 v2 lit2 v2 v3 lit1 +// SWAP5| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 +// PUSH lit3| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 v3 v1 lit3 +// SWAP2| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v2 * * * * * * * * * * * lit1 v2 lit2 v2 lit3 v1 v3 // Status: Admissible diff --git a/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack b/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack index 40d20f43b5c1..60f890972dcc 100644 --- a/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack +++ b/test/libyul/ssa/stackShuffler/triple_dup_with_phi.stack @@ -7,16 +7,14 @@ targetStackTop: [JUNK, v2, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, phi1, JUNK, JUNK, // (initial)| * * * * * * * * phi1 * * * * v1 v2 v3 // SWAP14| * v3 * * * * * * phi1 * * * * v1 v2 * // POP| * v3 * * * * * * phi1 * * * * v1 v2 -// DUP1| * v3 * * * * * * phi1 * * * * v1 v2 v2 -// SWAP14| * v2 * * * * * * phi1 * * * * v1 v2 v3 -// DUP2| * v2 * * * * * * phi1 * * * * v1 v2 v3 v2 -// PUSH lit1| * v2 * * * * * * phi1 * * * * v1 v2 v3 v2 lit1 -// SWAP4| * v2 * * * * * * phi1 * * * * lit1 v2 v3 v2 v1 -// PUSH lit2| * v2 * * * * * * phi1 * * * * lit1 v2 v3 v2 v1 lit2 -// SWAP3| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v1 v3 -// PUSH lit3| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v1 v3 lit3 -// SWAP2| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v3 v1 -// SWAP1| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v1 v3 +// PUSH lit2| * v3 * * * * * * phi1 * * * * v1 v2 lit2 +// DUP2| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 +// DUP1| * v3 * * * * * * phi1 * * * * v1 v2 lit2 v2 v2 +// SWAP16| * v2 * * * * * * phi1 * * * * v1 v2 lit2 v2 v3 +// PUSH lit1| * v2 * * * * * * phi1 * * * * v1 v2 lit2 v2 v3 lit1 +// SWAP5| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v3 v1 +// PUSH lit3| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 v3 v1 lit3 +// SWAP2| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v1 v3 // +-------------------------------------------------------------------------------------------------------------------------------------------- // (target)| * v2 * * * * * * phi1 * * * * lit1 v2 lit2 v2 lit3 v1 v3 // Status: Admissible