LLVM  14.0.0git
Sequence.h
Go to the documentation of this file.
1 //===- Sequence.h - Utility for producing sequences of values ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 /// Provides some synthesis utilities to produce sequences of values. The names
10 /// are intentionally kept very short as they tend to occur in common and
11 /// widely used contexts.
12 ///
13 /// The `seq(A, B)` function produces a sequence of values from `A` to up to
14 /// (but not including) `B`, i.e., [`A`, `B`), that can be safely iterated over.
15 /// `seq` supports both integral (e.g., `int`, `char`, `uint32_t`) and enum
16 /// types. `seq_inclusive(A, B)` produces a sequence of values from `A` to `B`,
17 /// including `B`.
18 ///
19 /// Examples with integral types:
20 /// ```
21 /// for (int x : seq(0, 3))
22 /// outs() << x << " ";
23 /// ```
24 ///
25 /// Prints: `0 1 2 `.
26 ///
27 /// ```
28 /// for (int x : seq_inclusive(0, 3))
29 /// outs() << x << " ";
30 /// ```
31 ///
32 /// Prints: `0 1 2 3 `.
33 ///
34 /// Similar to `seq` and `seq_inclusive`, the `enum_seq` and
35 /// `enum_seq_inclusive` functions produce sequences of enum values that can be
36 /// iterated over.
37 /// To enable iteration with enum types, you need to either mark enums as safe
38 /// to iterate on by specializing `enum_iteration_traits`, or opt into
39 /// potentially unsafe iteration at every callsite by passing
40 /// `force_iteration_on_noniterable_enum`.
41 ///
42 /// Examples with enum types:
43 /// ```
44 /// namespace X {
45 /// enum class MyEnum : unsigned {A = 0, B, C};
46 /// } // namespace X
47 ///
48 /// template <> struct enum_iteration_traits<X::MyEnum> {
49 /// static contexpr bool is_iterable = true;
50 /// };
51 ///
52 /// class MyClass {
53 /// public:
54 /// enum Safe { D = 3, E, F };
55 /// enum MaybeUnsafe { G = 1, H = 2, I = 4 };
56 /// };
57 ///
58 /// template <> struct enum_iteration_traits<MyClass::Safe> {
59 /// static contexpr bool is_iterable = true;
60 /// };
61 /// ```
62 ///
63 /// ```
64 /// for (auto v : enum_seq(MyClass::Safe::D, MyClass::Safe::F))
65 /// outs() << int(v) << " ";
66 /// ```
67 ///
68 /// Prints: `3 4 `.
69 ///
70 /// ```
71 /// for (auto v : enum_seq(MyClass::MaybeUnsafe::H, MyClass::MaybeUnsafe::I,
72 /// force_iteration_on_noniterable_enum))
73 /// outs() << int(v) << " ";
74 /// ```
75 ///
76 /// Prints: `2 3 `.
77 ///
78 //===----------------------------------------------------------------------===//
79 
80 #ifndef LLVM_ADT_SEQUENCE_H
81 #define LLVM_ADT_SEQUENCE_H
82 
83 #include <cassert> // assert
84 #include <iterator> // std::random_access_iterator_tag
85 #include <limits> // std::numeric_limits
86 #include <type_traits> // std::is_integral, std::is_enum, std::underlying_type,
87  // std::enable_if
88 
89 #include "llvm/Support/MathExtras.h" // AddOverflow / SubOverflow
90 
91 namespace llvm {
92 
93 // Enum traits that marks enums as safe or unsafe to iterate over.
94 // By default, enum types are *not* considered safe for iteration.
95 // To allow iteration for your enum type, provide a specialization with
96 // `is_iterable` set to `true` in the `llvm` namespace.
97 // Alternatively, you can pass the `force_iteration_on_noniterable_enum` tag
98 // to `enum_seq` or `enum_seq_inclusive`.
99 template <typename EnumT> struct enum_iteration_traits {
100  static constexpr bool is_iterable = false;
101 };
102 
104  explicit force_iteration_on_noniterable_enum_t() = default;
105 };
106 
107 // TODO: Make this `inline` once we update to C++17 to avoid ORD violations.
110 
111 namespace detail {
112 
113 // Returns whether a value of type U can be represented with type T.
114 template <typename T, typename U> bool canTypeFitValue(const U Value) {
115  const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
116  const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
117  const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
118  const uintmax_t TopU = uintmax_t(std::numeric_limits<U>::max());
119  return !((BotT > BotU && Value < static_cast<U>(BotT)) ||
120  (TopT < TopU && Value > static_cast<U>(TopT)));
121 }
122 
123 // An integer type that asserts when:
124 // - constructed from a value that doesn't fit into intmax_t,
125 // - casted to a type that cannot hold the current value,
126 // - its internal representation overflows.
127 struct CheckedInt {
128  // Integral constructor, asserts if Value cannot be represented as intmax_t.
129  template <typename Integral, typename std::enable_if_t<
130  std::is_integral<Integral>::value, bool> = 0>
131  static CheckedInt from(Integral FromValue) {
132  if (!canTypeFitValue<intmax_t>(FromValue))
133  assertOutOfBounds();
134  CheckedInt Result;
135  Result.Value = static_cast<intmax_t>(FromValue);
136  return Result;
137  }
138 
139  // Enum constructor, asserts if Value cannot be represented as intmax_t.
140  template <typename Enum,
141  typename std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
142  static CheckedInt from(Enum FromValue) {
143  using type = typename std::underlying_type<Enum>::type;
144  return from<type>(static_cast<type>(FromValue));
145  }
146 
147  // Equality
148  bool operator==(const CheckedInt &O) const { return Value == O.Value; }
149  bool operator!=(const CheckedInt &O) const { return Value != O.Value; }
150 
151  CheckedInt operator+(intmax_t Offset) const {
152  CheckedInt Result;
153  if (AddOverflow(Value, Offset, Result.Value))
154  assertOutOfBounds();
155  return Result;
156  }
157 
158  intmax_t operator-(CheckedInt Other) const {
159  intmax_t Result;
160  if (SubOverflow(Value, Other.Value, Result))
161  assertOutOfBounds();
162  return Result;
163  }
164 
165  // Convert to integral, asserts if Value cannot be represented as Integral.
166  template <typename Integral, typename std::enable_if_t<
167  std::is_integral<Integral>::value, bool> = 0>
168  Integral to() const {
169  if (!canTypeFitValue<Integral>(Value))
170  assertOutOfBounds();
171  return static_cast<Integral>(Value);
172  }
173 
174  // Convert to enum, asserts if Value cannot be represented as Enum's
175  // underlying type.
176  template <typename Enum,
177  typename std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
178  Enum to() const {
179  using type = typename std::underlying_type<Enum>::type;
180  return Enum(to<type>());
181  }
182 
183 private:
184  static void assertOutOfBounds() { assert(false && "Out of bounds"); }
185 
186  intmax_t Value;
187 };
188 
189 template <typename T, bool IsReverse> struct SafeIntIterator {
190  using iterator_category = std::random_access_iterator_tag;
191  using value_type = T;
192  using difference_type = intmax_t;
193  using pointer = T *;
194  using reference = T &;
195 
196  // Construct from T.
197  explicit SafeIntIterator(T Value) : SI(CheckedInt::from<T>(Value)) {}
198  // Construct from other direction.
200 
201  // Dereference
202  value_type operator*() const { return SI.to<T>(); }
203  // Indexing
204  value_type operator[](intmax_t Offset) const { return *(*this + Offset); }
205 
206  // Can be compared for equivalence using the equality/inequality operators.
207  bool operator==(const SafeIntIterator &O) const { return SI == O.SI; }
208  bool operator!=(const SafeIntIterator &O) const { return SI != O.SI; }
209  // Comparison
210  bool operator<(const SafeIntIterator &O) const { return (*this - O) < 0; }
211  bool operator>(const SafeIntIterator &O) const { return (*this - O) > 0; }
212  bool operator<=(const SafeIntIterator &O) const { return (*this - O) <= 0; }
213  bool operator>=(const SafeIntIterator &O) const { return (*this - O) >= 0; }
214 
215  // Pre Increment/Decrement
216  void operator++() { offset(1); }
217  void operator--() { offset(-1); }
218 
219  // Post Increment/Decrement
221  const auto Copy = *this;
222  ++*this;
223  return Copy;
224  }
226  const auto Copy = *this;
227  --*this;
228  return Copy;
229  }
230 
231  // Compound assignment operators
232  void operator+=(intmax_t Offset) { offset(Offset); }
233  void operator-=(intmax_t Offset) { offset(-Offset); }
234 
235  // Arithmetic
236  SafeIntIterator operator+(intmax_t Offset) const { return add(Offset); }
237  SafeIntIterator operator-(intmax_t Offset) const { return add(-Offset); }
238 
239  // Difference
240  intmax_t operator-(const SafeIntIterator &O) const {
241  return IsReverse ? O.SI - SI : SI - O.SI;
242  }
243 
244 private:
245  SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
246 
247  static intmax_t getOffset(intmax_t Offset) {
248  return IsReverse ? -Offset : Offset;
249  }
250 
251  CheckedInt add(intmax_t Offset) const { return SI + getOffset(Offset); }
252 
253  void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
254 
255  CheckedInt SI;
256 
257  // To allow construction from the other direction.
258  template <typename, bool> friend struct SafeIntIterator;
259 };
260 
261 } // namespace detail
262 
263 template <typename T> struct iota_range {
264  using value_type = T;
265  using reference = T &;
266  using const_reference = const T &;
271  using difference_type = intmax_t;
272  using size_type = std::size_t;
273 
274  explicit iota_range(T Begin, T End, bool Inclusive)
275  : BeginValue(Begin), PastEndValue(End) {
276  assert(Begin <= End && "Begin must be less or equal to End.");
277  if (Inclusive)
278  ++PastEndValue;
279  }
280 
281  size_t size() const { return PastEndValue - BeginValue; }
282  bool empty() const { return BeginValue == PastEndValue; }
283 
284  auto begin() const { return const_iterator(BeginValue); }
285  auto end() const { return const_iterator(PastEndValue); }
286 
287  auto rbegin() const { return const_reverse_iterator(PastEndValue - 1); }
288  auto rend() const { return const_reverse_iterator(BeginValue - 1); }
289 
290 private:
291  static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
292  "T must be an integral or enum type");
293  static_assert(std::is_same<T, std::remove_cv_t<T>>::value,
294  "T must not be const nor volatile");
295 
296  iterator BeginValue;
297  iterator PastEndValue;
298 };
299 
300 /// Iterate over an integral type from Begin up to - but not including - End.
301 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
302 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
303 /// iteration).
304 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
305  !std::is_enum<T>::value>>
306 auto seq(T Begin, T End) {
307  return iota_range<T>(Begin, End, false);
308 }
309 
310 /// Iterate over an integral type from Begin to End inclusive.
311 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
312 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
313 /// iteration).
314 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
315  !std::is_enum<T>::value>>
316 auto seq_inclusive(T Begin, T End) {
317  return iota_range<T>(Begin, End, true);
318 }
319 
320 /// Iterate over an enum type from Begin up to - but not including - End.
321 /// Note: `enum_seq` will generate each consecutive value, even if no
322 /// enumerator with that value exists.
323 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
324 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
325 /// iteration).
326 template <typename EnumT,
327  typename = std::enable_if_t<std::is_enum<EnumT>::value>>
328 auto enum_seq(EnumT Begin, EnumT End) {
330  "Enum type is not marked as iterable.");
331  return iota_range<EnumT>(Begin, End, false);
332 }
333 
334 /// Iterate over an enum type from Begin up to - but not including - End, even
335 /// when `EnumT` is not marked as safely iterable by `enum_iteration_traits`.
336 /// Note: `enum_seq` will generate each consecutive value, even if no
337 /// enumerator with that value exists.
338 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
339 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
340 /// iteration).
341 template <typename EnumT,
342  typename = std::enable_if_t<std::is_enum<EnumT>::value>>
343 auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
344  return iota_range<EnumT>(Begin, End, false);
345 }
346 
347 /// Iterate over an enum type from Begin to End inclusive.
348 /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
349 /// enumerator with that value exists.
350 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
351 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
352 /// iteration).
353 template <typename EnumT,
354  typename = std::enable_if_t<std::is_enum<EnumT>::value>>
355 auto enum_seq_inclusive(EnumT Begin, EnumT End) {
357  "Enum type is not marked as iterable.");
358  return iota_range<EnumT>(Begin, End, true);
359 }
360 
361 /// Iterate over an enum type from Begin to End inclusive, even when `EnumT`
362 /// is not marked as safely iterable by `enum_iteration_traits`.
363 /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
364 /// enumerator with that value exists.
365 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
366 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
367 /// iteration).
368 template <typename EnumT,
369  typename = std::enable_if_t<std::is_enum<EnumT>::value>>
370 auto enum_seq_inclusive(EnumT Begin, EnumT End,
372  return iota_range<EnumT>(Begin, End, true);
373 }
374 
375 } // end namespace llvm
376 
377 #endif // LLVM_ADT_SEQUENCE_H
llvm::iota_range::empty
bool empty() const
Definition: Sequence.h:282
llvm::detail::SafeIntIterator::operator-=
void operator-=(intmax_t Offset)
Definition: Sequence.h:233
llvm::enum_seq_inclusive
auto enum_seq_inclusive(EnumT Begin, EnumT End)
Iterate over an enum type from Begin to End inclusive.
Definition: Sequence.h:355
llvm::iota_range::size_type
std::size_t size_type
Definition: Sequence.h:272
llvm::iota_range::const_iterator
iterator const_iterator
Definition: Sequence.h:268
llvm::detail::SafeIntIterator::operator+
SafeIntIterator operator+(intmax_t Offset) const
Definition: Sequence.h:236
MathExtras.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::detail::SafeIntIterator::operator==
bool operator==(const SafeIntIterator &O) const
Definition: Sequence.h:207
llvm::detail::SafeIntIterator::operator--
void operator--()
Definition: Sequence.h:217
llvm::iota_range::rbegin
auto rbegin() const
Definition: Sequence.h:287
llvm::detail::SafeIntIterator::operator>
bool operator>(const SafeIntIterator &O) const
Definition: Sequence.h:211
llvm::detail::SafeIntIterator::operator--
SafeIntIterator operator--(int)
Definition: Sequence.h:225
llvm::detail::SafeIntIterator::operator>=
bool operator>=(const SafeIntIterator &O) const
Definition: Sequence.h:213
llvm::detail::SafeIntIterator< value_type, false >::iterator_category
std::random_access_iterator_tag iterator_category
Definition: Sequence.h:190
llvm::detail::CheckedInt::from
static CheckedInt from(Enum FromValue)
Definition: Sequence.h:142
llvm::iota_range::const_reverse_iterator
reverse_iterator const_reverse_iterator
Definition: Sequence.h:270
llvm::iota_range::const_reference
const T & const_reference
Definition: Sequence.h:266
llvm::detail::CheckedInt::operator+
CheckedInt operator+(intmax_t Offset) const
Definition: Sequence.h:151
llvm::enum_iteration_traits
Definition: Sequence.h:99
llvm::detail::SafeIntIterator
Definition: Sequence.h:189
llvm::detail::SafeIntIterator::SafeIntIterator
friend struct SafeIntIterator
Definition: Sequence.h:258
llvm::detail::SafeIntIterator::SafeIntIterator
SafeIntIterator(T Value)
Definition: Sequence.h:197
llvm::seq_inclusive
auto seq_inclusive(T Begin, T End)
Iterate over an integral type from Begin to End inclusive.
Definition: Sequence.h:316
T
#define T
Definition: Mips16ISelLowering.cpp:341
llvm::iota_range::iterator
detail::SafeIntIterator< value_type, false > iterator
Definition: Sequence.h:267
Offset
uint64_t Offset
Definition: ELFObjHandler.cpp:80
llvm::detail::SafeIntIterator::operator<
bool operator<(const SafeIntIterator &O) const
Definition: Sequence.h:210
llvm::detail::SafeIntIterator::operator[]
value_type operator[](intmax_t Offset) const
Definition: Sequence.h:204
llvm::force_iteration_on_noniterable_enum_t
Definition: Sequence.h:103
llvm::detail::SafeIntIterator::operator-
intmax_t operator-(const SafeIntIterator &O) const
Definition: Sequence.h:240
llvm::detail::CheckedInt
Definition: Sequence.h:127
llvm::detail::SafeIntIterator< value_type, false >::difference_type
intmax_t difference_type
Definition: Sequence.h:192
llvm::detail::SafeIntIterator::operator++
SafeIntIterator operator++(int)
Definition: Sequence.h:220
llvm::iota_range::value_type
T value_type
Definition: Sequence.h:264
llvm::seq
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition: Sequence.h:306
llvm::detail::SafeIntIterator::operator++
void operator++()
Definition: Sequence.h:216
llvm::AddOverflow
std::enable_if_t< std::is_signed< T >::value, T > AddOverflow(T X, T Y, T &Result)
Add two signed integers, computing the two's complement truncated result, returning true if overflow ...
Definition: MathExtras.h:884
llvm::detail::SafeIntIterator::operator*
value_type operator*() const
Definition: Sequence.h:202
llvm::detail::SafeIntIterator::operator!=
bool operator!=(const SafeIntIterator &O) const
Definition: Sequence.h:208
llvm::force_iteration_on_noniterable_enum_t::force_iteration_on_noniterable_enum_t
force_iteration_on_noniterable_enum_t()=default
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:206
type
AMD64 Optimization Manual has some nice information about optimizing integer multiplication by a constant How much of it applies to Intel s X86 implementation There are definite trade offs to xmm0 cvttss2siq rdx jb L3 subss xmm0 rax cvttss2siq rdx xorq rdx rax ret instead of xmm1 cvttss2siq rcx movaps xmm2 subss xmm2 cvttss2siq rax rdx xorq rax ucomiss xmm0 cmovb rax ret Seems like the jb branch has high likelihood of being taken It would have saved a few instructions It s not possible to reference and DH registers in an instruction requiring REX prefix divb and mulb both produce results in AH If isel emits a CopyFromReg which gets turned into a movb and that can be allocated a r8b r15b To get around isel emits a CopyFromReg from AX and then right shift it down by and truncate it It s not pretty but it works We need some register allocation magic to make the hack go which would often require a callee saved register Callees usually need to keep this value live for most of their body so it doesn t add a significant burden on them We currently implement this in however this is suboptimal because it means that it would be quite awkward to implement the optimization for callers A better implementation would be to relax the LLVM IR rules for sret arguments to allow a function with an sret argument to have a non void return type
Definition: README-X86-64.txt:70
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::detail::CheckedInt::operator-
intmax_t operator-(CheckedInt Other) const
Definition: Sequence.h:158
SI
StandardInstrumentations SI(Debug, VerifyEach)
llvm::detail::CheckedInt::to
Enum to() const
Definition: Sequence.h:178
llvm::detail::CheckedInt::operator==
bool operator==(const CheckedInt &O) const
Definition: Sequence.h:148
llvm::detail::SafeIntIterator::operator-
SafeIntIterator operator-(intmax_t Offset) const
Definition: Sequence.h:237
llvm::enum_iteration_traits::is_iterable
static constexpr bool is_iterable
Definition: Sequence.h:100
llvm::iota_range::size
size_t size() const
Definition: Sequence.h:281
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
llvm::iota_range::difference_type
intmax_t difference_type
Definition: Sequence.h:271
llvm::detail::SafeIntIterator< value_type, false >::pointer
value_type * pointer
Definition: Sequence.h:193
llvm::iota_range::end
auto end() const
Definition: Sequence.h:285
llvm::iota_range::begin
auto begin() const
Definition: Sequence.h:284
llvm::enum_seq
auto enum_seq(EnumT Begin, EnumT End)
Iterate over an enum type from Begin up to - but not including - End.
Definition: Sequence.h:328
llvm::detail::SafeIntIterator::operator+=
void operator+=(intmax_t Offset)
Definition: Sequence.h:232
llvm::detail::SafeIntIterator< value_type, false >::reference
value_type & reference
Definition: Sequence.h:194
llvm::SubOverflow
std::enable_if_t< std::is_signed< T >::value, T > SubOverflow(T X, T Y, T &Result)
Subtract two signed integers, computing the two's complement truncated result, returning true if an o...
Definition: MathExtras.h:910
llvm::force_iteration_on_noniterable_enum
constexpr force_iteration_on_noniterable_enum_t force_iteration_on_noniterable_enum
Definition: Sequence.h:109
llvm::iota_range::reverse_iterator
detail::SafeIntIterator< value_type, true > reverse_iterator
Definition: Sequence.h:269
llvm::detail::SafeIntIterator< value_type, false >::value_type
value_type value_type
Definition: Sequence.h:191
llvm::detail::SafeIntIterator::SafeIntIterator
SafeIntIterator(const SafeIntIterator< T, !IsReverse > &O)
Definition: Sequence.h:199
llvm::max
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:340
llvm::iota_range::reference
T & reference
Definition: Sequence.h:265
llvm::iota_range::iota_range
iota_range(T Begin, T End, bool Inclusive)
Definition: Sequence.h:274
llvm::detail::SafeIntIterator::operator<=
bool operator<=(const SafeIntIterator &O) const
Definition: Sequence.h:212
llvm::iota_range
Definition: Sequence.h:263
llvm::detail::CheckedInt::to
Integral to() const
Definition: Sequence.h:168
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::detail::canTypeFitValue
bool canTypeFitValue(const U Value)
Definition: Sequence.h:114
llvm::iota_range::rend
auto rend() const
Definition: Sequence.h:288
llvm::detail::CheckedInt::from
static CheckedInt from(Integral FromValue)
Definition: Sequence.h:131
llvm::detail::CheckedInt::operator!=
bool operator!=(const CheckedInt &O) const
Definition: Sequence.h:149
Other
Optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1198