3232
3333#include < libsolutil/Numeric.h>
3434
35+ #include < range/v3/range/concepts.hpp>
3536#include < range/v3/range/conversion.hpp>
37+ #include < range/v3/range/traits.hpp>
3638#include < range/v3/view/iota.hpp>
37- #include < range/v3/view/subrange.hpp>
3839#include < range/v3/view/transform.hpp>
3940
4041#include < concepts>
@@ -47,6 +48,9 @@ namespace solidity::yul::ssa
4748class LivenessAnalysis ;
4849struct ControlFlowGraphs ;
4950
51+ template <typename R, typename T>
52+ concept InputRangeOf = ranges::input_range<R> && std::same_as<ranges::range_value_t <R>, T>;
53+
5054class SSACFG
5155{
5256public:
@@ -316,7 +320,7 @@ class SSACFG
316320 // / View over the contiguous trailing Projections of `_producer` in `m_insts`. Empty for ops with <= 1 returns.
317321 // / Note this relies on the m_insts-contiguity invariant established by `make(Builtin)CallWithProjections`:
318322 // / projections live at `m_insts[_producer.value+1..+numReturns]`.
319- auto projectionsOf (InstId const _producer) const
323+ InputRangeOf<InstId> auto projectionsOf (InstId const _producer) const
320324 {
321325 std::size_t const n = numReturnsOf (_producer);
322326 std::size_t const count = n >= 2 ? n : 0 ;
@@ -341,26 +345,33 @@ class SSACFG
341345 }
342346 return
343347 ranges::views::iota (static_cast <InstId::ValueType>(firstIdx), static_cast <InstId::ValueType>(lastIdx)) |
344- ranges::views::transform ([](InstId::ValueType const _idVal) { return InstId{_idVal}; });
348+ ranges::views::transform (&toInstId);
349+ }
350+
351+ // / View over the logical outputs of `_producer` in stack order: the producer itself if it has a single return,
352+ // / the trailing Projections if it has multiple, and an empty range otherwise.
353+ InputRangeOf<InstId> auto outputsOf (InstId const _producer) const
354+ {
355+ std::size_t const n = numReturnsOf (_producer);
356+ if (n >= 2 )
357+ return projectionsOf (_producer);
358+ auto const firstIdx = static_cast <InstId::ValueType>(_producer.value );
359+ return
360+ ranges::views::iota (firstIdx, static_cast <InstId::ValueType>(firstIdx + n)) |
361+ ranges::views::transform (&toInstId);
345362 }
346363
347364 // / Invokes `_fn(InstId)` once per logical output of `_producer` in stack order.
348365 template <std::invocable<InstId> Fn>
349366 void forEachOutput (InstId const _producer, Fn&& _fn) const
350367 {
351- auto const n = numReturnsOf (_producer);
352- if (n == 0 )
353- return ;
354- if (n == 1 )
355- {
356- _fn (_producer);
357- return ;
358- }
359- for (InstId const id: projectionsOf (_producer))
368+ for (InstId const id: outputsOf (_producer))
360369 _fn (id);
361370 }
362371
363372private:
373+ static InstId toInstId (InstId::ValueType const _v) { return InstId{_v}; }
374+
364375 InstId makeBuiltinCall (
365376 BlockId const _block,
366377 BuiltinCall _payload,
0 commit comments