@@ -56,7 +56,6 @@ inline std::string stackToString(Stack const& _stack, Dialect const& _dialect)
5656}
5757
5858
59- // Abstraction of stack shuffling operations. Can be defined as actual concept once we switch to C++20.
6059// Used as an interface for the stack shuffler below.
6160// The shuffle operation class is expected to internally keep track of a current stack layout (the "source layout")
6261// that the shuffler is supposed to shuffle to a fixed target stack layout.
@@ -65,7 +64,6 @@ inline std::string stackToString(Stack const& _stack, Dialect const& _dialect)
6564// in the interface below.
6665// Based on that information the shuffler decides which is the next optimal operation to perform on the stack
6766// and calls the corresponding entry point in the shuffling operations (swap, pushOrDupTarget or pop).
68- /*
6967template <typename ShuffleOperations>
7068concept ShuffleOperationConcept = requires (ShuffleOperations ops, size_t sourceOffset, size_t targetOffset, size_t depth) {
7169 // Returns true, iff the current slot at sourceOffset in source layout is a suitable slot at targetOffset.
@@ -98,11 +96,13 @@ concept ShuffleOperationConcept = requires(ShuffleOperations ops, size_t sourceO
9896 { ops.pop () };
9997 // Dups or pushes the slot that is supposed to end up at the given target offset.
10098 { ops.pushOrDupTarget (targetOffset) };
99+ // Maximum reachable depth with swaps and dups.
100+ { ops.reachableStackDepth } -> std::convertible_to<size_t >;
101101};
102- */
102+
103103// / Helper class that can perform shuffling of a source stack layout to a target stack layout via
104104// / abstracted shuffle operations.
105- template </* ShuffleOperationConcept*/ typename ShuffleOperations>
105+ template <ShuffleOperationConcept ShuffleOperations>
106106class Shuffler
107107{
108108public:
@@ -128,10 +128,10 @@ class Shuffler
128128 static bool dupDeepSlotIfRequired (ShuffleOperations& _ops)
129129 {
130130 // Check if the stack is large enough for anything to potentially become unreachable.
131- if (_ops.sourceSize () < 15 )
131+ if (_ops.sourceSize () < (_ops. reachableStackDepth - 1 ) )
132132 return false ;
133133 // Check whether any deep slot might still be needed later (i.e. we still need to reach it with a DUP or SWAP).
134- for (size_t sourceOffset: ranges::views::iota (0u , _ops.sourceSize () - 15 ))
134+ for (size_t sourceOffset: ranges::views::iota (0u , _ops.sourceSize () - (_ops. reachableStackDepth - 1 ) ))
135135 {
136136 // This slot needs to be moved.
137137 if (!_ops.isCompatible (sourceOffset, sourceOffset))
@@ -256,10 +256,10 @@ class Shuffler
256256 )
257257 {
258258 // We cannot swap that deep.
259- if (ops.sourceSize () - offset - 1 > 16 )
259+ if (ops.sourceSize () - offset - 1 > ops. reachableStackDepth )
260260 {
261261 // If there is a reachable slot to be removed, park the current top there.
262- for (size_t swapDepth: ranges::views::iota (1u , 17u ) | ranges::views::reverse)
262+ for (size_t swapDepth: ranges::views::iota (1u , ops. reachableStackDepth + 1u ) | ranges::views::reverse)
263263 if (ops.sourceMultiplicity (ops.sourceSize () - 1 - swapDepth) < 0 )
264264 {
265265 ops.swap (swapDepth);
@@ -327,7 +327,7 @@ class Shuffler
327327 yulAssert (ops.sourceMultiplicity (i) == 0 && (ops.targetIsArbitrary (i) || ops.targetMultiplicity (i) == 0 ), " " );
328328 yulAssert (ops.isCompatible (sourceTop, sourceTop), " " );
329329
330- auto swappableOffsets = ranges::views::iota (size > 17 ? size - 17 : 0u , size);
330+ auto swappableOffsets = ranges::views::iota (size > ops. reachableStackDepth + 1u ? size - (ops. reachableStackDepth + 1u ) : 0u , size);
331331
332332 // If we find a lower slot that is out of position, but also compatible with the top, swap that up.
333333 for (size_t offset: swappableOffsets)
@@ -431,7 +431,14 @@ class Multiplicity
431431// / its argument to the stack top.
432432// / @a _pop is a function with signature void() that is called when the top most slot is popped.
433433template <typename Swap, typename PushOrDup, typename Pop>
434- void createStackLayout (Stack& _currentStack, Stack const & _targetStack, Swap _swap, PushOrDup _pushOrDup, Pop _pop)
434+ void createStackLayout (
435+ Stack& _currentStack,
436+ Stack const & _targetStack,
437+ Swap _swap,
438+ PushOrDup _pushOrDup,
439+ Pop _pop,
440+ size_t _reachableStackDepth
441+ )
435442{
436443 struct ShuffleOperations
437444 {
@@ -441,18 +448,21 @@ void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _sw
441448 PushOrDup pushOrDupCallback;
442449 Pop popCallback;
443450 Multiplicity multiplicity;
451+ size_t reachableStackDepth;
444452 ShuffleOperations (
445453 Stack& _currentStack,
446454 Stack const & _targetStack,
447455 Swap _swap,
448456 PushOrDup _pushOrDup,
449- Pop _pop
457+ Pop _pop,
458+ size_t _reachableStackDepth
450459 ):
451460 currentStack (_currentStack),
452461 targetStack (_targetStack),
453462 swapCallback (_swap),
454463 pushOrDupCallback (_pushOrDup),
455- popCallback (_pop)
464+ popCallback (_pop),
465+ reachableStackDepth (_reachableStackDepth)
456466 {
457467 for (auto const & slot: currentStack)
458468 --multiplicity[slot];
@@ -499,7 +509,7 @@ void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _sw
499509 }
500510 };
501511
502- Shuffler<ShuffleOperations>::shuffle (_currentStack, _targetStack, _swap, _pushOrDup, _pop);
512+ Shuffler<ShuffleOperations>::shuffle (_currentStack, _targetStack, _swap, _pushOrDup, _pop, _reachableStackDepth );
503513
504514 yulAssert (_currentStack.size () == _targetStack.size (), " " );
505515 for (auto && [current, target]: ranges::zip_view (_currentStack, _targetStack))
0 commit comments