1919#pragma once
2020
2121#include < libyul/backends/evm/StackHelpers.h>
22- #include < libyul/backends/evm/SSACFGStack.h>
22+
23+ #include < libyul/backends/evm/ssa/Stack.h>
2324
2425#include < range/v3/algorithm/find.hpp>
2526#include < range/v3/algorithm/find_end.hpp>
@@ -127,12 +128,12 @@ struct BubbleShuffler
127128
128129template <
129130 typename StackType,
130- auto SlotIsCompatible = [](typename StackType::Slot const & _source, typename StackType::Slot const & _target) { return std::holds_alternative<ssa::JunkSlot>( _target) || _source == _target; }
131+ auto SlotIsCompatible = [](StackSlot const & _source, typename StackType::Slot const & _target) { return _target. isJunk ( ) || _source == _target; }
131132>
132133struct DanielShuffler
133134{
134135 using Stack = StackType;
135- using StackSlot = typename Stack::Slot ;
136+ using StackSlot = ssa::StackSlot ;
136137 static void shuffle (Stack& _stack, std::set<StackSlot> const & _targetStackTail, std::vector<StackSlot> const & _targetStackTop)
137138 {
138139 struct ShuffleOperations
@@ -151,7 +152,7 @@ struct DanielShuffler
151152 for (auto const & x: currentStack)
152153 ++sourceCounts[x];
153154 for (auto const [i, x]: ranges::views::enumerate (targetStack))
154- if (i < currentStack.size () && std::holds_alternative<ssa::JunkSlot>( targetStack[i]))
155+ if (i < currentStack.size () && targetStack[i]. isJunk ( ))
155156 ++targetCounts[currentStack[i]];
156157 else
157158 ++targetCounts[x];
@@ -183,7 +184,7 @@ struct DanielShuffler
183184
184185 bool targetIsArbitrary (size_t _targetOffset) const
185186 {
186- return _targetOffset < targetStack.size () && std::holds_alternative<ssa::JunkSlot>( targetStack. at (_targetOffset) );
187+ return _targetOffset < targetStack.size () && targetStack[_targetOffset]. isJunk ( );
187188 }
188189
189190 size_t sourceSize () const { return currentStack.size (); }
@@ -335,7 +336,7 @@ struct GreedyForwardShuffler
335336{
336337 using Stack = StackType;
337338 using StackSlot = typename Stack::Slot;
338-
339+
339340 // / Simple, correct forward shuffler (INTENTIONALLY does NOT conform to SSACFGStackShuffler concept)
340341 // / Key insight: handle values that are both consumed AND live-out properly
341342 static Stack shuffle (
@@ -345,19 +346,19 @@ struct GreedyForwardShuffler
345346 )
346347 {
347348 Stack result = _sourceStack;
348-
349+
349350 // Safety check: don't create overly deep stacks
350351 if (result.size () + _requiredTop.size () > 1000 ) {
351352 // Fall back to Daniel shuffler for very deep stacks
352353 return DanielShuffler<Stack>::shuffle (_sourceStack, std::set<StackSlot>(_liveOut.begin (), _liveOut.end ()), _requiredTop);
353354 }
354-
355+
355356 // Phase 1: Ensure extra copies for values that are both consumed and live-out (with constraints)
356357 ensureExtraCopiesForConsumedLiveOuts (result, _liveOut, _requiredTop);
357-
358+
358359 // Phase 2: Build required top in correct order (simple approach)
359360 buildRequiredTop (result, _requiredTop);
360-
361+
361362 return result;
362363 }
363364
@@ -371,17 +372,17 @@ struct GreedyForwardShuffler
371372 for (auto const & requiredValue : _requiredTop) {
372373 // Is this value also live-out? (will be consumed but must survive)
373374 bool isAlsoLiveOut = ranges::find (_liveOut, requiredValue) != _liveOut.end ();
374-
375+
375376 if (isAlsoLiveOut) {
376377 // Count how many copies we have on stack
377378 auto copyCount = std::count (_stack.data ().begin (), _stack.data ().end (), requiredValue);
378-
379+
379380 if (copyCount < 2 ) {
380381 // Find the value's position from top of stack
381382 auto stackData = _stack.data ();
382383 auto reverseView = stackData | ranges::views::reverse;
383384 auto it = ranges::find (reverseView, requiredValue);
384-
385+
385386 if (it != reverseView.end ()) {
386387 auto distance = std::distance (reverseView.begin (), it);
387388 // Only dup if within EVM's 16-element reach
@@ -394,14 +395,14 @@ struct GreedyForwardShuffler
394395 }
395396 }
396397 }
397-
398+
398399 // / Phase 2: Build required top - respecting EVM depth constraints
399400 static void buildRequiredTop (Stack& _stack, std::vector<StackSlot> const & _requiredTop) {
400401 if (_requiredTop.empty ()) return ;
401-
402+
402403 // Fast path: check if already correct
403404 if (isTopAlreadyCorrect (_stack, _requiredTop)) return ;
404-
405+
405406 // Build top from bottom to top (iterate requiredTop in reverse)
406407 // Example: requiredTop=[v0,64] means final stack=[...,64,v0] (v0 at top)
407408 // So push 64 first (ends up deeper), then v0 (ends up at top)
@@ -410,16 +411,16 @@ struct GreedyForwardShuffler
410411 _stack.pushOrDup (*it);
411412 }
412413 }
413-
414+
414415 // / Check if required top is already correct (optimization)
415416 static bool isTopAlreadyCorrect (Stack const & _stack, std::vector<StackSlot> const & _requiredTop) {
416417 if (_requiredTop.size () > _stack.size ()) return false ;
417-
418+
418419 // Check if top of stack matches required top exactly
419420 for (size_t i = 0 ; i < _requiredTop.size (); ++i) {
420421 size_t stackIndex = _stack.size () - 1 - i; // Stack top = size-1
421422 size_t requiredIndex = _requiredTop.size () - 1 - i; // Required top = size-1
422-
423+
423424 if (_stack[stackIndex] != _requiredTop[requiredIndex]) {
424425 return false ;
425426 }
0 commit comments