Skip to content

Commit b0ff7b9

Browse files
committed
SSA CFG: Add outputsOf helper that returns a range over inst id
1 parent d25627f commit b0ff7b9

5 files changed

Lines changed: 33 additions & 26 deletions

File tree

libyul/backends/evm/ssa/CodeTransform.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -309,16 +309,14 @@ void CodeTransform::operator()(InstId _instId, StackData const& _operationInputL
309309
for (size_t i = 0; i < _inst.inputs.size(); ++i)
310310
m_stack.pop<false>();
311311
// simulate that the outputs are produced
312-
std::vector<InstId> outputs;
313-
outputs.reserve(m_cfg.numReturnsOf(_instId));
314-
m_cfg.forEachOutput(_instId, [&](InstId const id) { outputs.push_back(id); });
315-
for (InstId const id: outputs)
312+
auto const numOutputs = m_cfg.numReturnsOf(_instId);
313+
for (InstId const id: m_cfg.outputsOf(_instId))
316314
m_stack.push<false>(StackSlot::makeValue(m_cfg, id));
317315

318-
yulAssert(m_stack.size() == baseHeight + outputs.size());
316+
yulAssert(m_stack.size() == baseHeight + numOutputs);
319317
for (auto const& [stackEntry, output]: ranges::views::zip(
320-
m_stack.data() | ranges::views::take_last(outputs.size()),
321-
outputs
318+
m_stack.data() | ranges::views::take_last(numOutputs),
319+
m_cfg.outputsOf(_instId)
322320
))
323321
yulAssert(stackEntry.isValue() && stackEntry.value() == output);
324322
yulAssert(

libyul/backends/evm/ssa/SSACFG.h

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
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
4748
class LivenessAnalysis;
4849
struct 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+
5054
class SSACFG
5155
{
5256
public:
@@ -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

363372
private:
373+
static InstId toInstId(InstId::ValueType const _v) { return InstId{_v}; }
374+
364375
InstId makeBuiltinCall(
365376
BlockId const _block,
366377
BuiltinCall _payload,

libyul/backends/evm/ssa/SSACFGBuilder.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,10 +430,10 @@ void SSACFGBuilder::assign(std::vector<std::reference_wrapper<Scope::Variable co
430430
}
431431
else
432432
{
433-
std::vector<InstId> outputs;
434-
m_graph.forEachOutput(callId, [&](InstId const id) { outputs.push_back(id); });
433+
yulAssert(m_graph.numReturnsOf(callId) == _variables.size());
434+
auto const outputs = m_graph.outputsOf(callId);
435435
yulAssert(outputs.size() == _variables.size());
436-
for (auto const& [var, output]: ranges::zip_view(_variables, outputs))
436+
for (auto const& [var, output]: ranges::views::zip(_variables, outputs))
437437
writeVariable(var, m_currentBlock, output);
438438
}
439439
return;

libyul/backends/evm/ssa/StackLayoutGenerator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
231231
auto const& operationsLiveOut = m_liveness.operationsLiveOut(_blockId);
232232
blockLayout.operationIn.reserve(operationsLiveOut.size());
233233
std::size_t operationIndex = 0;
234-
m_cfg.forEachOperation(block, [&](InstId const _instId, SSACFG::Inst const& _inst){
234+
m_cfg.forEachOperation(block, [&](InstId const _instId, SSACFG::Inst const& _inst) {
235235
auto opLiveOutWithoutOutputs = operationsLiveOut[operationIndex];
236236
m_cfg.forEachOutput(_instId, [&](InstId const id) { opLiveOutWithoutOutputs.erase(id); });
237237

libyul/backends/evm/ssa/io/JSONExporter.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,7 @@ Json toJson(Json& _ret, SSACFG const& _cfg, InstId const _instId, ControlFlowGra
7070
}
7171

7272
opJson["in"] = toJson(_cfg, inst.inputs);
73-
std::vector<InstId> outputs;
74-
_cfg.forEachOutput(_instId, [&](InstId const id) { outputs.push_back(id); });
75-
opJson["out"] = toJson(_cfg, outputs);
73+
opJson["out"] = toJson(_cfg, _cfg.outputsOf(_instId));
7674

7775
return opJson;
7876
}

0 commit comments

Comments
 (0)