Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libyul/backends/evm/ssa/Stack.h
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
19
#pragma once
20
21
#include <libyul/backends/evm/ssa/ControlFlowGraphs.h>
22
#include <libyul/backends/evm/ssa/SSACFG.h>
23
24
#include <range/v3/algorithm/find.hpp>
25
#include <range/v3/view/reverse.hpp>
26
27
#include <cstdint>
28
#include <type_traits>
29
30
namespace solidity::yul::ssa
31
{
32
33
/// Registry for tracking function call sites.
34
///
35
/// Maps user-function-call operations to unique numeric IDs. These IDs are used
36
/// to generate return labels for function calls in the EVM bytecode.
37
class CallSites
38
{
39
public:
40
  using CallSiteID = std::uint32_t;
41
42
  std::optional<CallSiteID> callSiteID(InstId _instId) const
43
0
  {
44
0
    if (auto const it = ranges::find(m_data, _instId); it != m_data.end())
45
0
      return static_cast<CallSiteID>(std::distance(m_data.begin(), it));
46
0
    return std::nullopt;
47
0
  }
48
49
  InstId instId(CallSiteID _callSite) const
50
0
  {
51
0
    yulAssert(_callSite < m_data.size());
52
0
    return m_data[_callSite];
53
0
  }
54
55
  CallSiteID addCallSite(InstId _instId)
56
0
  {
57
0
    if (auto const id = callSiteID(_instId))
58
0
      return *id;
59
0
    yulAssert(_instId.hasValue());
60
0
    m_data.emplace_back(_instId);
61
0
    return static_cast<CallSiteID>(m_data.size() - 1);
62
0
  }
63
private:
64
  std::vector<InstId> m_data;
65
};
66
67
/// A discriminated union corresponding to a single EVM stack slot.
68
/// Can represent:
69
///   - ValueID: SSA values (including literals)
70
///   - Junk: Placeholder/unused values
71
///     - FunctionCallReturnLabel: Return addresses for function calls
72
///     - FunctionReturnLabel: Identifies the calling function's graph
73
///
74
/// Memory layout is optimized: 8 bytes size for cache efficiency, trivially copyable, standard layout, trivial
75
class StackSlot
76
{
77
public:
78
  enum struct Kind: std::uint8_t
79
  {
80
    Value, // u32 InstId
81
    Junk, // empty
82
    FunctionCallReturnLabel, // index into corresponding stack layout's call sites
83
    FunctionReturnLabel // identifying the function graph via ControlFlowGraphs
84
  };
85
86
  constexpr StackSlot() = default;
87
  constexpr StackSlot(StackSlot const&) = default;
88
  constexpr StackSlot(StackSlot&&) = default;
89
  constexpr StackSlot& operator=(StackSlot const&) = default;
90
  constexpr StackSlot& operator=(StackSlot&&) = default;
91
92
0
  constexpr bool isValue() const noexcept { return kind() == Kind::Value; }
93
0
  constexpr bool isLiteralValue() const noexcept { return m_valueOpcode == InstOpcode::Const; }
94
0
  constexpr bool isPhiValue() const noexcept { return m_valueOpcode == InstOpcode::Phi; }
95
0
  constexpr bool isFunctionReturnLabel() const noexcept { return kind() == Kind::FunctionReturnLabel; }
96
0
  constexpr bool isFunctionCallReturnLabel() const noexcept { return kind() == Kind::FunctionCallReturnLabel; }
97
0
  constexpr bool isJunk() const noexcept { return kind() == Kind::Junk; }
98
0
  constexpr Kind kind() const noexcept { return m_kind; }
99
100
0
  ControlFlowGraphs::FunctionGraphID functionReturnLabel() const { yulAssert(isFunctionReturnLabel()); return m_payload; }
101
0
  CallSites::CallSiteID functionCallReturnLabel() const { yulAssert(isFunctionCallReturnLabel()); return m_payload; }
102
  InstId value() const
103
0
  {
104
0
    yulAssert(isValue());
105
0
    return InstId{m_payload};
106
0
  }
107
108
0
  static constexpr StackSlot makeJunk() { return {0, Kind::Junk}; }
109
  static StackSlot makeValue(SSACFG const& _cfg, InstId _value)
110
0
  {
111
0
    return {_value.value, Kind::Value, _cfg.kindOf(_value)};
112
0
  }
113
  static StackSlot makeValue(InstructionStore const& _store, InstId _value)
114
0
  {
115
0
    return {_value.value, Kind::Value, _store.kindOf(_value)};
116
0
  }
117
0
  static constexpr StackSlot makeFunctionReturnLabel(ControlFlowGraphs::FunctionGraphID const _graphID) { return {_graphID, Kind::FunctionReturnLabel}; }
118
0
  static constexpr StackSlot makeFunctionCallReturnLabel(CallSites::CallSiteID const _callSiteID) { return {_callSiteID, Kind::FunctionCallReturnLabel};  }
119
120
0
  auto operator<=>(StackSlot const&) const = default;
121
private:
122
  constexpr StackSlot(std::uint32_t const _payload, Kind const _kind, InstOpcode const _valueOpcode = InstOpcode::Unreachable):
123
0
    m_payload(_payload),
124
0
    m_kind(_kind),
125
0
    m_valueOpcode(_valueOpcode)
126
0
  {}
127
128
  /// interpretation depends on kind
129
  std::uint32_t m_payload;
130
  Kind m_kind;
131
  /// for Kind::Value: cached Opcode of the defining Inst
132
  InstOpcode m_valueOpcode;
133
};
134
static_assert(sizeof(StackSlot) == 8, "Want cache efficiency, benchmark this if you go beyond 8 bytes");
135
static_assert(std::is_trivially_copyable_v<StackSlot>, "Should be able to use memcpy semantics");
136
static_assert(std::is_standard_layout_v<StackSlot>, "Want to have a predictable layout");
137
static_assert(std::is_trivial_v<StackSlot>, "Want to have no init/cpy overhead");
138
139
using StackData = std::vector<StackSlot>;
140
std::string slotToString(StackSlot const& _slot);
141
std::string stackToString(StackData const& _stackData);
142
143
/// Array index into stack from the bottom (offset 0 = bottom).
144
/// Natural for array-like access and iteration; used when treating the stack as a data structure.
145
struct StackOffset
146
{
147
0
  explicit constexpr StackOffset(size_t _value) : value(_value) {}
148
  size_t value;
149
  auto operator<=>(StackOffset const&) const = default;
150
};
151
// comparison operations with size_t
152
0
constexpr auto operator<=>(StackOffset const lhs, size_t const rhs) noexcept { return lhs.value <=> rhs; }
153
0
constexpr auto operator<=>(size_t const lhs, StackOffset const rhs) noexcept { return lhs <=> rhs.value; }
154
155
/// Distance from the stack top (depth 0 = top).
156
/// Natural for stack operations (SWAP1 = swap with depth 1); used for operations that
157
/// conceptually work "from the top".
158
struct StackDepth
159
{
160
0
  explicit constexpr StackDepth(size_t _value) : value(_value) {}
161
  size_t value;
162
0
  auto operator<=>(StackDepth const&) const = default;
163
};
164
// comparison operations with size_t
165
0
constexpr auto operator<=>(StackDepth const lhs, size_t const rhs) noexcept { return lhs.value <=> rhs; }
166
0
constexpr auto operator<=>(size_t const lhs, StackDepth const rhs) noexcept { return lhs <=> rhs.value; }
167
168
template<typename StackManipulationCallback>
169
concept StackManipulationCallbackConcept = requires(
170
  StackManipulationCallback& _callback,
171
  StackSlot _slot,
172
  StackDepth _depth
173
)
174
{
175
  { _callback.swap(_depth) } -> std::same_as<void>;
176
  { _callback.dup(_depth) } -> std::same_as<void>;
177
  { _callback.push(_slot) } -> std::same_as<void>;
178
  { _callback.pop() } -> std::same_as<void>;
179
};
180
181
struct NoOpStackManipulationCallbacks
182
{
183
0
  static void swap(StackDepth) {}
184
0
  static void dup(StackDepth) {}
185
0
  static void push(StackSlot const&) {}
186
0
  static void pop() {}
187
};
188
static_assert(StackManipulationCallbackConcept<NoOpStackManipulationCallbacks>);
189
190
template<
191
  StackManipulationCallbackConcept CallbacksType = NoOpStackManipulationCallbacks
192
>
193
class Stack
194
{
195
  static size_t constexpr reachableStackDepth = 16;
196
public:
197
  using Callbacks = CallbacksType;
198
199
  using Slot = StackSlot;
200
  using Data = StackData;
201
  using Depth = StackDepth;
202
  using Offset = StackOffset;
203
204
  Stack(
205
    Data& _data,
206
    Callbacks _callbacks
207
  ):
208
0
    m_data(&_data),
209
0
    m_callbacks(std::move(_callbacks))
210
0
  {}
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::Stack(std::__1::vector<solidity::yul::ssa::StackSlot, std::__1::allocator<solidity::yul::ssa::StackSlot> >&, solidity::yul::ssa::AssemblyCallbacks)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::Stack(std::__1::vector<solidity::yul::ssa::StackSlot, std::__1::allocator<solidity::yul::ssa::StackSlot> >&, solidity::yul::ssa::NoOpStackManipulationCallbacks)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::Stack(std::__1::vector<solidity::yul::ssa::StackSlot, std::__1::allocator<solidity::yul::ssa::StackSlot> >&, solidity::yul::ssa::GasAccumulatingCallbacks)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::Stack(std::__1::vector<solidity::yul::ssa::StackSlot, std::__1::allocator<solidity::yul::ssa::StackSlot> >&, solidity::yul::ssa::OpsCountingCallbacks)
211
212
  Slot const& top() const
213
0
  {
214
0
    yulAssert(!m_data->empty());
215
0
    return m_data->back();
216
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::top() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::top() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::top() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::top() const
217
218
  void swap(Depth const& _depth) { swap(depthToOffset(_depth)); }
219
  void swap(Offset const& _offset)
220
0
  {
221
0
    yulAssert(isValidSwapTarget(_offset), "Stack too deep");
222
0
    std::swap((*m_data)[_offset.value], m_data->back());
223
    if constexpr (!std::is_same_v<Callbacks, NoOpStackManipulationCallbacks>)
224
0
      m_callbacks.swap(offsetToDepth(_offset));
225
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::swap(solidity::yul::ssa::StackOffset const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::swap(solidity::yul::ssa::StackOffset const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::swap(solidity::yul::ssa::StackOffset const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::swap(solidity::yul::ssa::StackOffset const&)
226
227
  /// if the stack state needs to be updated without notifying the callback, the template parameter can be set to false
228
  template<bool callback=true>
229
  void pop()
230
0
  {
231
0
    yulAssert(!m_data->empty());
232
0
    m_data->pop_back();
233
    if constexpr (callback && !std::is_same_v<Callbacks, NoOpStackManipulationCallbacks>)
234
0
      m_callbacks.pop();
235
0
  }
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::pop<true>()
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::pop<false>()
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::pop<true>()
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::pop<false>()
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::pop<true>()
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::pop<true>()
236
237
  /// if the stack state needs to be updated without notifying the callback, the template parameter can be set to false
238
  template<bool callback=true>
239
  void push(Slot const& _slot)
240
0
  {
241
0
    yulAssert(!_slot.isFunctionReturnLabel(), "Cannot push function return label");
242
0
    m_data->emplace_back(_slot);
243
    if constexpr (callback && !std::is_same_v<Callbacks, NoOpStackManipulationCallbacks>)
244
0
      m_callbacks.push(_slot);
245
0
  }
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::push<true>(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::push<false>(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::push<true>(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::push<true>(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::push<false>(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: void solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::push<true>(solidity::yul::ssa::StackSlot const&)
246
247
0
  void dup(Depth const& _depth) { dup(depthToOffset(_depth)); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::dup(solidity::yul::ssa::StackDepth const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::dup(solidity::yul::ssa::StackDepth const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::dup(solidity::yul::ssa::StackDepth const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::dup(solidity::yul::ssa::StackDepth const&)
248
  void dup(Offset const& _offset)
249
0
  {
250
0
    auto const depth = offsetToDepth(_offset);
251
0
    yulAssert(dupReachable(depth), "Stack too deep");
252
0
    auto const slot = (*m_data)[_offset.value];
253
0
    yulAssert(!slot.isFunctionReturnLabel(), "Cannot dup function return label");
254
0
    m_data->push_back(slot);
255
    if constexpr (!std::is_same_v<Callbacks, NoOpStackManipulationCallbacks>)
256
0
      m_callbacks.dup(StackDepth{depth.value + 1});
257
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::dup(solidity::yul::ssa::StackOffset const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::dup(solidity::yul::ssa::StackOffset const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::dup(solidity::yul::ssa::StackOffset const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::dup(solidity::yul::ssa::StackOffset const&)
258
259
0
  bool dupReachable(Offset const& _offset) const noexcept { return dupReachable(offsetToDepth(_offset)); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::dupReachable(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::dupReachable(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::dupReachable(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::dupReachable(solidity::yul::ssa::StackOffset const&) const
260
0
  bool dupReachable(Depth const& _depth) const noexcept { return _depth < size() && _depth.value + 1 <= reachableStackDepth; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::dupReachable(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::dupReachable(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::dupReachable(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::dupReachable(solidity::yul::ssa::StackDepth const&) const
261
0
  bool isValidSwapTarget(Offset const& _offset) const noexcept { return isValidSwapTarget(offsetToDepth(_offset)); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackOffset const&) const
262
0
  bool isValidSwapTarget(Depth const& _depth) const noexcept { return _depth < size() && 1 <= _depth.value && _depth.value <= reachableStackDepth; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::isValidSwapTarget(solidity::yul::ssa::StackDepth const&) const
263
0
  bool isBeyondSwapRange(Offset const& _offset) const noexcept { return isBeyondSwapRange(offsetToDepth(_offset)); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackOffset const&) const
264
0
  bool isBeyondSwapRange(Depth const& _depth) const noexcept { return _depth > reachableStackDepth; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::isBeyondSwapRange(solidity::yul::ssa::StackDepth const&) const
265
266
0
  void declareJunk(Offset const& _offset) { (*m_data)[_offset.value] = Slot::makeJunk(); }
267
  void declareJunk(Depth const& _depth) { declareJunk(depthToOffset(_depth)); }
268
269
0
  Slot const& slot(Depth const& _depth) const { return (*m_data)[depthToOffset(_depth).value]; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::slot(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::slot(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::slot(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::slot(solidity::yul::ssa::StackDepth const&) const
270
0
  Slot const& slot(Offset const& _offset) const { return slot(offsetToDepth(_offset)); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::slot(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::slot(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::slot(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::slot(solidity::yul::ssa::StackOffset const&) const
271
0
  bool empty() const noexcept { return size() == 0; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::empty() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::empty() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::empty() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::empty() const
272
0
  size_t size() const noexcept { return m_data->size(); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::size() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::size() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::size() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::size() const
273
274
  std::optional<Depth> findSlotDepth(Slot const& _value) const
275
0
  {
276
0
    auto rview = *this | ranges::views::reverse;
277
0
    auto it = ranges::find(rview, _value);
278
279
0
    if (it == ranges::end(rview))
280
0
      return std::nullopt;
281
282
0
    return Depth{static_cast<size_t>(std::distance(ranges::begin(rview), it))};
283
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::findSlotDepth(solidity::yul::ssa::StackSlot const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::findSlotDepth(solidity::yul::ssa::StackSlot const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::findSlotDepth(solidity::yul::ssa::StackSlot const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::findSlotDepth(solidity::yul::ssa::StackSlot const&) const
284
285
  static bool constexpr canBeFreelyGenerated(Slot const& _slot)
286
0
  {
287
0
    return _slot.isLiteralValue() || _slot.isJunk() || _slot.isFunctionCallReturnLabel();
288
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::canBeFreelyGenerated(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::canBeFreelyGenerated(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::canBeFreelyGenerated(solidity::yul::ssa::StackSlot const&)
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::canBeFreelyGenerated(solidity::yul::ssa::StackSlot const&)
289
290
0
  Slot const& operator[](Offset const& _index) const noexcept { return (*m_data)[_index.value]; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::operator[](solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::operator[](solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::operator[](solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::operator[](solidity::yul::ssa::StackOffset const&) const
291
0
  auto begin() const { return ranges::begin(*m_data); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::begin() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::begin() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::begin() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::begin() const
292
0
  auto end() const { return ranges::end(*m_data); }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::end() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::end() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::end() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::end() const
293
294
  Data const& data() const
295
0
  {
296
0
    return *m_data;
297
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::data() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::data() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::data() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::data() const
298
299
0
  Callbacks const& callbacks() const { return m_callbacks; }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::callbacks() const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::callbacks() const
300
301
  /// index scheme conversion offset -> depth
302
  Depth offsetToDepth(Offset const& _offset) const
303
0
  {
304
0
    yulAssert(_offset < size(), "Offset out of range");
305
0
    return Depth{size() - _offset.value - 1};
306
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::offsetToDepth(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::offsetToDepth(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::offsetToDepth(solidity::yul::ssa::StackOffset const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::offsetToDepth(solidity::yul::ssa::StackOffset const&) const
307
  /// index scheme conversion depth -> offset
308
  Offset depthToOffset(Depth const& _depth) const
309
0
  {
310
    yulAssert(_depth < size(), "Depth out of range");
311
0
    return Offset{size() - _depth.value - 1};
312
0
  }
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::AssemblyCallbacks>::depthToOffset(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::NoOpStackManipulationCallbacks>::depthToOffset(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::GasAccumulatingCallbacks>::depthToOffset(solidity::yul::ssa::StackDepth const&) const
Unexecuted instantiation: solidity::yul::ssa::Stack<solidity::yul::ssa::OpsCountingCallbacks>::depthToOffset(solidity::yul::ssa::StackDepth const&) const
313
314
private:
315
  Data* m_data;
316
  Callbacks m_callbacks;
317
};
318
319
}