@@ -82,25 +82,29 @@ void declareJunk(StackType& _stack, LivenessAnalysis::LivenessData const& _live)
8282
8383}
8484
85- SSACFGStackLayout StackLayoutGenerator::generate (
85+ StackLayoutGenerator::Result StackLayoutGenerator::generate (
8686 LivenessAnalysis const & _liveness,
8787 CallSites const & _callSites,
88- ControlFlowGraphs::FunctionGraphID const _graphID
88+ ControlFlowGraphs::FunctionGraphID const _graphID,
89+ bool const _spillingAllowed
8990)
9091{
91- return StackLayoutGenerator (_liveness, _callSites, _graphID).m_resultLayout ;
92+ StackLayoutGenerator generator (_liveness, _callSites, _graphID, _spillingAllowed);
93+ return Result{std::move (generator.m_resultLayout ), std::move (generator.m_spillSet )};
9294}
9395
9496StackLayoutGenerator::StackLayoutGenerator (
9597 LivenessAnalysis const & _liveness,
9698 CallSites const & _callSites,
97- ControlFlowGraphs::FunctionGraphID const _graphID
99+ ControlFlowGraphs::FunctionGraphID const _graphID,
100+ bool const _spillingAllowed
98101):
99102 m_cfg(_liveness.cfg()),
100103 m_liveness(_liveness),
101104 m_callSites(_callSites),
102105 m_graphID(_graphID),
103106 m_hasFunctionReturnLabel(!_liveness.cfg().isMainGraph() && _liveness.cfg().canContinue),
107+ m_spillingAllowed(_spillingAllowed),
104108 m_junkAdmittingBlocksFinder(std::make_unique<JunkAdmittingBlocksFinder>(_liveness.cfg(), _liveness.topologicalSort())),
105109 m_inputStackProposalsPerBlock(m_cfg.numBlocks()),
106110 m_resultLayout(m_cfg.numBlocks())
@@ -199,7 +203,8 @@ void StackLayoutGenerator::defineStackIn(SSACFG::BlockId const& _blockId)
199203 stack,
200204 proposals[i],
201205 {},
202- proposals[i].size ()
206+ proposals[i].size (),
207+ &m_spillSet
203208 );
204209 yulAssert (shuffleResult.status == StackShufflerResult::Status::Admissible);
205210 cumulativeCost += stack.callbacks ().opGas ;
@@ -258,15 +263,20 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
258263
259264 StackSlotLiveness const opLiveOutSlots = toStackSlotLiveness (m_cfg, opLiveOutWithoutOutputs);
260265 {
261- StackData const target = findOptimalTarget (
266+ auto [ target, plannedSpillSet] = findOptimalTarget (
262267 stack.data (),
263268 requiredStackTop,
264269 opLiveOutSlots,
265270 junkCanBeAdded,
266- m_hasFunctionReturnLabel
271+ m_hasFunctionReturnLabel,
272+ m_spillSet,
273+ m_spillingAllowed
267274 );
268- auto const shuffleResult = StackShuffler<StackType::Callbacks>::shuffle (stack, target);
275+ auto const spillCountBefore = m_spillSet.numSpilled ();
276+ m_spillSet = std::move (plannedSpillSet);
277+ auto const shuffleResult = shuffleWithSpillDiscovery (currentStackData, target, m_spillSet);
269278 yulAssert (shuffleResult.status == StackShufflerResult::Status::Admissible);
279+ yulAssert (m_spillingAllowed || m_spillSet.numSpilled () == spillCountBefore, " Spilling not allowed, stack too deep." );
270280 }
271281
272282 blockLayout.operationIn .push_back (currentStackData);
@@ -293,15 +303,20 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
293303 {
294304 auto const condition = Slot::makeValue (m_cfg, _cJump.condition );
295305 StackSlotLiveness const blockLiveOutSlots = toStackSlotLiveness (m_cfg, blockLiveOut);
296- StackData const target = findOptimalTarget (
306+ auto [ target, plannedSpillSet] = findOptimalTarget (
297307 stack.data (),
298308 {condition},
299309 blockLiveOutSlots,
300310 false ,
301- m_hasFunctionReturnLabel
311+ m_hasFunctionReturnLabel,
312+ m_spillSet,
313+ m_spillingAllowed
302314 );
303- auto const shuffleResult = StackShuffler<StackType::Callbacks>::shuffle (stack, target);
315+ auto const spillCountBefore = m_spillSet.numSpilled ();
316+ m_spillSet = std::move (plannedSpillSet);
317+ auto const shuffleResult = shuffleWithSpillDiscovery (currentStackData, target, m_spillSet);
304318 yulAssert (shuffleResult.status == StackShufflerResult::Status::Admissible);
319+ yulAssert (m_spillingAllowed || m_spillSet.numSpilled () == spillCountBefore, " Spilling not allowed, stack too deep." );
305320 }
306321
307322 yulAssert (!stack.empty () && stack.top ().isValue () && stack.top ().value () == _cJump.condition );
@@ -322,8 +337,10 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
322337 // in case there are return values, let's bring the function return label to the top
323338 StackData returnStack = _functionReturn.returnValues | ranges::views::transform ([this ](InstId const _id) { return StackSlot::makeValue (m_cfg, _id); }) | ranges::to<std::vector>;
324339 returnStack.push_back (StackSlot::makeFunctionReturnLabel (m_graphID));
325- auto const shuffleResult = StackShuffler<StackType::Callbacks>::shuffle (stack, returnStack);
340+ auto const spillCountBefore = m_spillSet.numSpilled ();
341+ auto const shuffleResult = shuffleWithSpillDiscovery (currentStackData, returnStack, m_spillSet);
326342 yulAssert (shuffleResult.status == StackShufflerResult::Status::Admissible);
343+ yulAssert (m_spillingAllowed || m_spillSet.numSpilled () == spillCountBefore, " Spilling not allowed, stack too deep." );
327344 blockLayout.exitIn = currentStackData;
328345 },
329346 [&](SSACFG ::BasicBlock::Jump const & _jump) {
0 commit comments