From 476ee898b117ab5f5e15212491c454a4b888b474 Mon Sep 17 00:00:00 2001 From: clonker <1685266+clonker@users.noreply.github.com> Date: Thu, 16 Apr 2026 21:24:32 +0200 Subject: [PATCH] in the ssa shuffler fix args slot, when offset is already top no swap-up is needed, so it doesn't have to be a valid swap target itself --- libyul/backends/evm/ssa/Stack.h | 1 + libyul/backends/evm/ssa/StackShuffler.h | 3 +- .../ssa/stackShuffler/loop-fuzzer.stack | 34 ++----------------- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/libyul/backends/evm/ssa/Stack.h b/libyul/backends/evm/ssa/Stack.h index d4342426f09d..50f58aeb46a1 100644 --- a/libyul/backends/evm/ssa/Stack.h +++ b/libyul/backends/evm/ssa/Stack.h @@ -252,6 +252,7 @@ class Stack bool dupReachable(Depth const& _depth) const noexcept { return _depth < size() && _depth.value + 1 <= reachableStackDepth; } bool isValidSwapTarget(Offset const& _offset) const noexcept { return isValidSwapTarget(offsetToDepth(_offset)); } bool isValidSwapTarget(Depth const& _depth) const noexcept { return _depth < size() && 1 <= _depth.value && _depth.value <= reachableStackDepth; } + bool isBeyondSwapRange(Offset const& _offset) const noexcept { return isBeyondSwapRange(offsetToDepth(_offset)); } bool isBeyondSwapRange(Depth const& _depth) const noexcept { return _depth > reachableStackDepth; } void declareJunk(Offset const& _offset) { (*m_data)[_offset.value] = Slot::makeJunk(); } diff --git a/libyul/backends/evm/ssa/StackShuffler.h b/libyul/backends/evm/ssa/StackShuffler.h index 14c136a142ae..80d57c560f31 100644 --- a/libyul/backends/evm/ssa/StackShuffler.h +++ b/libyul/backends/evm/ssa/StackShuffler.h @@ -471,7 +471,8 @@ class StackShuffler // swap up any slot in args that is out of position and has a slot available in args that it can occupy for (StackOffset offset: _state.stackArgsRange()) { - bool const reachable = _stack.isValidSwapTarget(offset); + // when offset is already top no swap-up is needed, so it doesn't have to be a valid swap target itself + bool const reachable = !_stack.isBeyondSwapRange(offset); bool const identical = _state.isArgsCompatible(offset, stackTop) && !_state.targetArbitrary(stackTop); if ( reachable && diff --git a/test/libyul/ssa/stackShuffler/loop-fuzzer.stack b/test/libyul/ssa/stackShuffler/loop-fuzzer.stack index 49e6cf8192b8..7ea19fd61dbf 100644 --- a/test/libyul/ssa/stackShuffler/loop-fuzzer.stack +++ b/test/libyul/ssa/stackShuffler/loop-fuzzer.stack @@ -6,36 +6,8 @@ targetStackSize: 7 // | 0 1 | 2 3 4 5 6 // +-------------- +----------------------------------- // (initial)| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// POP| v0 phi0 | phi0 lit0 v0 v0 -// DUP4| v0 phi0 | phi0 lit0 v0 v0 phi0 -// ...| +// SWAP2| v0 phi0 | phi0 v0 v0 lit0 +// DUP4| v0 phi0 | phi0 v0 v0 lit0 phi0 // +-------------- +----------------------------------- // (target)| {v0} | phi0 v0 v0 * phi0 -// Status: MaxIterationsReached +// Status: Admissible