MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
tuple.h
Go to the documentation of this file.
1#pragma once
2
3#include <concepts>
4
5#include <algorithm>
6#include <span>
7
8#include "mim/def.h"
9
10namespace mim {
11
12/// Base class for Sigma and Tuple.
13class Prod : public Def, public Setters<Prod> {
14protected:
15 using Def::Def;
16
17public:
18 /// Prod groups Sigma and Tuple; see fe::NodeSetable.
19 static constexpr bool isa_node(mim::Node n) noexcept { return n == mim::Node::Sigma || n == mim::Node::Tuple; }
20
21 /// @name Concatenation
22 /// Splices @p a as @p n and @p b as @p m components into one flat Prod.
23 /// @note @p n / @p m are *not* necessarily Def::arity: `n == 1` leaves @p a a single component,
24 /// which is exactly what `tuple.append` / `tuple.prepend` instantiate `tuple.cat` with.
25 ///@{
26 static const Def* cat(bool term, nat_t n, nat_t m, const Def* a, const Def* b);
27 /// Splices @p a and @p b *completely*, with @p n / @p m from Def::arity.
28 /// @returns `nullptr`, if they are not statically known.
29 static const Def* cat(bool term, const Def* a, const Def* b);
30 /// The spliced components themselves - for when you want to build something other than a Prod from them.
31 static DefVec cat_projs(nat_t n, nat_t m, const Def* a, const Def* b);
32 ///@}
33
34 static constexpr size_t Num_Ops = std::dynamic_extent;
35};
36
37/// A [dependent tuple type](https://en.wikipedia.org/wiki/Dependent_type#%CE%A3_type).
38/// @see Tuple, Arr, Pack, Prod
39class Sigma : public Prod, public Setters<Sigma> {
40private:
41 Sigma(const Def* type, Defs ops)
42 : Prod(Node, type, ops, 0) {} ///< Constructor for an *immutable* Sigma.
43 Sigma(const Def* type, size_t size)
44 : Prod(Node, type, size, 0) {} ///< Constructor for a *mutable* Sigma.
45
46public:
47 /// @name Setters
48 /// @see @ref set_ops "Setting Ops"
49 ///@{
50 using Setters<Sigma>::set;
51 Sigma* set(size_t i, const Def* def) { return Def::set(i, def)->as<Sigma>(); }
52 Sigma* set(Defs ops) { return Def::set(ops)->as<Sigma>(); }
53 Sigma* unset() { return Def::unset()->as<Sigma>(); }
54 ///@}
55
56 /// @name Rebuild
57 ///@{
58 /// @note Technically, it would make sense to have an offset of 1 as the first element can't be reduced.
59 /// For example, in `[n: Nat, F n]` `n` only occurs free in the second element.
60 /// However, this would cause a lot of confusion and special code to cope with the first element,
61 /// So we just keep it.
62 ///@}
63
64 /// @name Type Checking
65 ///@{
66 static const Def* infer(World&, Defs);
67 ///@}
68
69 /// @name Concatenation
70 /// @see Prod::cat
71 ///@{
72 static const Def* cat(nat_t n, nat_t m, const Def* a, const Def* b) { return Prod::cat(false, n, m, a, b); }
73 static const Def* cat(const Def* a, const Def* b) { return Prod::cat(false, a, b); }
74 ///@}
75
76 static constexpr auto Node = mim::Node::Sigma;
77
78private:
79 friend class World;
80};
81
82/// Data constructor for a Sigma.
83/// @see Sigma, Arr, Pack, Prod
84class Tuple : public Prod, public Setters<Tuple> {
85public:
86 using Setters<Tuple>::set;
87 static const Def* infer(World&, Defs);
88
89 /// @name Concatenation
90 /// @see Prod::cat
91 ///@{
92 static const Def* cat(nat_t n, nat_t m, const Def* a, const Def* b) { return Prod::cat(true, n, m, a, b); }
93 static const Def* cat(const Def* a, const Def* b) { return Prod::cat(true, a, b); }
94 ///@}
95
96 static constexpr auto Node = mim::Node::Tuple;
97
98private:
99 Tuple(const Def* type, Defs args)
100 : Prod(Node, type, args, 0) {}
101
102 friend class World;
103};
104
105/// Filters the components of an aggregate and keeps track of where the survivors end up.
106/// This is what a Phase needs that *drops* components of a Sigma - or the parameters of a Lam:
107/// * Sieve::gather rebuilds an immutable aggregate,
108/// * Sieve::new2old rebuilds a mutable one via Rewriter::rewrite_stub, and
109/// * Sieve::operator[] adjusts the index of every Extract / Insert into it.
110///
111/// @note Only a Sigma ever needs that last adjustment: an Arr's components all share one type - so it is dropped as a
112/// whole - and World::extract_fused splits a fused index at the Arr boundary, which leaves a Sigma's index scalar.
113///
114/// A rewrite that also *adds* components - `mem::SEO` threads fresh φs through a Lam - Sieve::cat%s them as further
115/// candidates: they extend the very same index space, so one Sieve still answers the whole new layout.
116class Sieve {
117public:
118 static constexpr size_t Gone = size_t(-1); ///< @see Sieve::operator[]
119
120 /// @name Construction
121 ///@{
122 /// Keeps all @p num components.
123 explicit Sieve(size_t num)
124 : num_(num)
125 , new2old_(num, [](size_t i) { return i; }) {}
126
127 /// Keeps those of @p num candidates that satisfy @p pred.
128 Sieve(size_t num, std::predicate<size_t> auto pred)
129 : num_(num) {
130 new2old_.reserve(num);
131 for (size_t i = 0; i != num; ++i)
132 if (pred(i)) new2old_.emplace_back(i);
133 }
134
135 /// Keeps those @p ops that satisfy @p pred.
136 Sieve(Defs ops, std::predicate<const Def*> auto pred)
137 : Sieve(ops.size(), [ops, pred](size_t i) { return pred(ops[i]); }) {}
138 ///@}
139
140 /// @name Concat
141 /// Candidates the rewrite *adds*; they have no old counterpart and simply continue the candidate indices.
142 ///@{
143 /// Concats @p num candidates behind the old ones and keeps those that satisfy @p pred.
144 /// @note A concat'ed component has no old op to rewrite from, so this rules out Sieve::new2old.
145 void cat(size_t num, std::predicate<size_t> auto pred) {
146 new2old_.reserve(new2old_.size() + num);
147 for (size_t i = 0; i != num; ++i)
148 if (pred(i)) {
149 new2old_.emplace_back(num_ + i);
150 ++num_cat_new_;
151 }
152 num_ += num;
153 num_cat_ += num;
154 }
155
156 size_t num_cat() const { return num_cat_; } ///< Number of concat'ed candidates.
157 size_t cat(size_t i) const { return (*this)[num_old() + i]; } ///< As Sieve::operator[] but for concat'ed @p i.
158 ///@}
159
160 /// @name Getters
161 ///@{
162 size_t num_old() const { return num_ - num_cat_; } ///< Number of old components.
163 size_t num_new() const { return new2old_.size(); } ///< Number of survivors.
164 /// Is the new aggregate the old one - nothing dropped and nothing concat'ed?
165 bool all() const { return num_new() == num_old() && num_cat_new_ == 0; }
166 /// The old index of the @p i th survivor; this is what Rewriter::rewrite_stub expects.
167 fe::View<size_t> new2old() const {
168 assert(num_cat_ == 0 && "rewrite_stub cannot rewrite a concat'ed component from an old op");
169 return new2old_;
170 }
171 /// The new index of the candidate @p i - or Sieve::Gone, if it didn't survive.
172 size_t operator[](size_t i) const {
173 auto j = std::ranges::lower_bound(new2old_, i);
174 return j != new2old_.end() && *j == i ? size_t(j - new2old_.begin()) : Gone;
175 }
176 /// The surviving components of @p ops - one per candidate, concat'ed ones included.
177 DefVec gather(Defs ops) const {
178 assert(ops.size() == num_);
179 return DefVec(num_new(), [this, ops](size_t i) { return ops[new2old_[i]]; });
180 }
181 ///@}
182
183private:
184 size_t num_; ///< Candidates - old ones followed by concat'ed ones.
185 size_t num_cat_ = 0;
186 size_t num_cat_new_ = 0; ///< Survivors among the concat'ed candidates.
187 fe::Vector<size_t> new2old_;
188};
189
190/// The extents of a Seq's axes: a plain `Nat` for a single axis, an aggregate of them for several.
191/// A multi-dimensional *index* into a Seq has the very same structure - one component per axis, `Idx` instead of
192/// `Nat` - so it uses this view as well.
193/// @note A Shape is a non-owning view over a Def and may be null; Shape::operator* hands the Def back.
194class Shape {
195public:
196 constexpr Shape() noexcept = default;
197 constexpr Shape(const Def* def) noexcept
198 : def_(def) {}
199 Shape(World&, Defs shape);
200
201 /// @name Getters
202 ///@{
203 constexpr const Def* operator*() const noexcept { return def_; }
204 constexpr const Def* operator->() const noexcept { return def_; }
205 constexpr explicit operator bool() const noexcept { return def_ != nullptr; }
206 ///@}
207
208 /// @name Axes
209 ///@{
210 bool is_dim() const; ///< Is this a *single* axis - a `Nat`/`Idx` rather than an aggregate of them?
211 bool is_fused() const { return !is_dim(); } ///< Does this span several axes? Also `true` for a dynamic rank.
212 std::optional<nat_t> rank() const; ///< Number of axes; `std::nullopt` if not statically known.
213 /// The @p i th axis.
214 /// @note Needs Shape::rank: Def::num_projs would silently read a dynamic rank as `1` and hand back the Shape.
215 const Def* operator[](nat_t i) const {
216 auto r = rank();
217 assert(r && "a dynamic rank has no statically indexable axes");
218 return def_->proj(*r, i);
219 }
220 /// The outermost axis - the Def::arity of the Seq this shape describes; null for a null Shape.
221 const Def* front() const;
222 /// The extent of @p axis: the axis itself for a shape, its `Idx` size for an index.
223 static std::optional<nat_t> extent(const Def* axis);
224 ///@}
225
226 /// @name Type Checking
227 ///@{
228 static bool isa_extents(const Def*); ///< Is @p type `Nat` - or an aggregate of `Nat`s, i.e. a shape?
229 static bool isa_indices(const Def*); ///< Is @p type `Idx` - or an aggregate of `Idx`%s, i.e. a fused index?
230 ///@}
231
232 /// @name Transform
233 /// Each of these needs Shape::rank and yields a null Shape without it.
234 ///@{
235 Shape slice(nat_t begin, nat_t end) const; ///< The axes `[begin, end)`.
236 Shape take(nat_t n) const { return slice(0, n); } ///< The leading @p n axes.
237 Shape drop(nat_t n) const; ///< All but the leading @p n axes.
238 Shape operator+(Shape) const; ///< Concatenation - what fuses `«a; «b; T»»` into `«a, b; T»`.
239 Shape zonk() const { return {def_->zonk()}; } ///< Wraps Def::zonk();
240
241 /// This Shape with only the axes @p keep accepts; `*this`, if it accepts all of them or the rank is dynamic.
242 Shape filter(auto keep) const {
243 if (auto r = rank()) {
244 auto kept = DefVec();
245 kept.reserve(*r);
246 for (nat_t i = 0; i != *r; ++i)
247 if (auto a = def_->proj(*r, i); keep(i, a)) kept.emplace_back(a);
248
249 return kept.size() == *r ? *this : Shape(def_->world(), kept);
250 }
251 return *this;
252 }
253
254 /// Drops every literal size-1 axis, mirroring `«1; T»` ≡ `T`; all of them folded away leaves rank `0`.
255 Shape fold() const;
256
257 /// As above but driven by @p shape: drops the axes *it* has as literal `1`, whatever this one's own extents
258 /// are - a broadcast reads a size-1 input axis at the *output*'s loop index.
259 Shape fold(Shape shape) const;
260 ///@}
261
262private:
263 const Def* def_ = nullptr;
264};
265
266/// Base class for Arr and Pack.
267class Seq : public Def, public Setters<Seq> {
268protected:
269 using Def::Def;
270
271public:
272 /// Seq groups Arr and Pack; see fe::NodeSetable.
273 static constexpr bool isa_node(mim::Node n) noexcept { return n == mim::Node::Arr || n == mim::Node::Pack; }
274
275 /// @name ops
276 ///@{
277 /// The extents of all axes this Seq fuses.
278 /// Def::arity is the *first* of them; `«2, 3; T»` still projects into two `«3; T»`.
279 Shape shape() const { return op(0); }
280 const Def* body() const { return op(1); }
281
282 /// The element one axis down: Seq::body for a one-dimensional Seq, the Seq of the remaining axes otherwise.
283 const Def* elem() const;
284 ///@}
285
286 /// @name Setters
287 /// @see @ref set_ops "Setting Ops"
288 ///@{
289 using Setters<Seq>::set;
290
291 /// Common setter for Pack%s and Arr%ays.
292 Seq* set(const Def* shape, const Def* body) { return Def::set({shape, body})->as<Seq>(); }
293 Seq* unset() { return Def::unset()->as<Seq>(); }
294 ///@}
295
296 /// @name Rebuild
297 ///@{
298 const Def* reduce(const Def* arg) const { return Def::reduce(arg).front(); }
299 ///@}
300};
301
302/// A (possibly paramterized) Arr%ay.
303/// Arr%ays are usually homogenous but they can be *inhomogenous* as well: `«i: N; T#i»`
304/// @see Sigma, Tuple, Pack
305class Arr : public Seq, public Setters<Arr> {
306private:
307 Arr(const Def* type, const Def* arity, const Def* body)
308 : Seq(Node, type, {arity, body}, 0) {} ///< Constructor for an *immutable* Arr.
309 Arr(const Def* type)
310 : Seq(Node, type, 2, 0) {} ///< Constructor for a *mutable* Arr.
311
312public:
313 /// @name Setters
314 /// @see @ref set_ops "Setting Ops"
315 ///@{
316 using Setters<Arr>::set;
317 Arr* set_shape(const Def* shape) { return Def::set(0, shape)->as<Arr>(); }
318 Arr* set_body(const Def* body) { return Def::set(1, body)->as<Arr>(); }
319 Arr* set(const Def* shape, const Def* body) { return set_shape(shape)->set_body(body); }
320 Arr* unset() { return Def::unset()->as<Arr>(); }
321 ///@}
322
323 static constexpr auto Node = mim::Node::Arr;
324 static constexpr size_t Num_Ops = 2;
325
326private:
327 friend class World;
328};
329
330/// A (possibly paramterized) Tuple.
331/// @see Sigma, Tuple, Arr
332class Pack : public Seq, public Setters<Pack> {
333private:
334 Pack(const Def* type, const Def* shape, const Def* body)
335 : Seq(Node, type, {shape, body}, 0) {} ///< Constructor for an *immutable* Pack.
336 Pack(const Def* type)
337 : Seq(Node, type, 2, 0) {} ///< Constructor for a *mutable* Pack.
338
339public:
340 /// @name Setters
341 /// @see @ref set_ops "Setting Ops"
342 ///@{
343 using Setters<Pack>::set;
344 /// @note A Pack carries its own Seq::shape: its type fuses *every* axis down to a non-array element,
345 /// which is more than the Pack itself supplies whenever its body is an aggregate - `‹2; v›` for `v: «3; T»`.
346 Pack* set_shape(const Def* shape) { return Def::set(0, shape)->as<Pack>(); }
347 Pack* set_body(const Def* body) { return Def::set(1, body)->as<Pack>(); }
348 Pack* set(const Def* shape, const Def* body) { return set_shape(shape)->set_body(body); }
349 Pack* unset() { return Def::unset()->as<Pack>(); }
350 ///@}
351
352 static constexpr auto Node = mim::Node::Pack;
353 static constexpr size_t Num_Ops = 2;
354
355private:
356 friend class World;
357};
358
359/// Extracts from a Sigma or Arr%ay-typed Extract::tuple the element at position Extract::index.
360class Extract : public Def, public Setters<Extract> {
361private:
362 Extract(const Def* type, const Def* tuple, const Def* index)
363 : Def(Node, type, {tuple, index}, 0) {}
364
365public:
366 using Setters<Extract>::set;
367
368 /// @name ops
369 ///@{
370 const Def* tuple() const { return op(0); }
371 const Def* index() const { return op(1); }
372 ///@}
373
374 static constexpr auto Node = mim::Node::Extract;
375 static constexpr size_t Num_Ops = 2;
376
377private:
378 friend class World;
379};
380
381/// Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple.
382/// @attention This is a *functional* Insert.
383/// The Insert::tuple itself remains untouched.
384/// The Insert itself is a *new* Tuple / Pack which contains the inserted Insert::value.
385class Insert : public Def, public Setters<Insert> {
386private:
387 Insert(const Def* tuple, const Def* index, const Def* value)
388 : Def(Node, tuple->type(), {tuple, index, value}, 0) {}
389
390public:
391 using Setters<Insert>::set;
392
393 /// @name ops
394 ///@{
395 const Def* tuple() const { return op(0); }
396 const Def* index() const { return op(1); }
397 const Def* value() const { return op(2); }
398 ///@}
399
400 static constexpr auto Node = mim::Node::Insert;
401 static constexpr size_t Num_Ops = 3;
402
403private:
404 friend class World;
405};
406
407/// Matches a jump table `(target_0, target_1, ...)#index` where `index` is a non-Lit%eral `Idx n` and `n` the arity.
408class Switch {
409public:
410 Switch(const Def*);
411
412 explicit operator bool() const noexcept { return extract_; }
413
414 const Extract* extract() const { return extract_; }
415 const Def* tuple() const { return extract()->tuple(); }
416 const Def* index() const { return extract()->index(); }
417
418 size_t num_targets() const { return Lit::as(tuple()->arity()); }
419 const Def* target(size_t i) const { return tuple()->proj(num_targets(), i); }
420
421protected:
422 const Extract* extract_ = nullptr;
423};
424
425/// Matches `(ff, tt)#cond` - where `cond` is a Bool but **not** a Lit%eral.
426/// @note If `cond` is a Lit%eral, either
427/// * `(x, y)#lit` would have been folded to `x`/`y` anyway, or
428/// * we have something like this: `pair#0_2`
429class Select : public Switch {
430public:
431 Select(const Def*);
432
433 const Def* pair() const { return tuple(); }
434 const Def* cond() const { return index(); }
435 const Def* tt() const { return target(1); }
436 const Def* ff() const { return target(0); }
437};
438
439/// Matches `(ff, tt)#cond arg` where `cond` is **not** a Lit%eral.
440/// `(ff, tt)#cond` is matched as a Select.
441class Branch : public Select {
442public:
443 Branch(const Def*);
444
445 explicit operator bool() const noexcept { return app_; }
446
447 const App* app() const { return app_; }
448 const Def* callee() const;
449 const Def* arg() const;
450
451private:
452 const App* app_ = nullptr;
453};
454
455/// Matches `(target_0, target_1, ...)#index arg`.
456/// `(target_0, target_1, ...)#index` is matched as a Switch.
457/// @note Subsumes Branch.
458/// If you want to deal with Branch separately, match Branch first:
459/// ```
460/// if (auto branch = Branch(def)) {
461/// // special case first
462/// } else if (auto dispatch = Dispatch(def)) {
463/// // now, the generic case
464/// }
465/// ```
466class Dispatch : public Switch {
467public:
468 Dispatch(const Def*);
469
470 explicit operator bool() const noexcept { return app_; }
471
472 const App* app() const { return app_; }
473 const Def* callee() const;
474 const Def* arg() const;
475
476private:
477 const App* app_ = nullptr;
478};
479
480/// @name Helpers to work with Tuples/Sigmas/Arrays/Packs
481///@{
482bool is_unit(const Def*);
483std::string tuple2str(const Def*);
484
485const Def* tuple_of_types(const Def* t);
486///@}
487
488} // namespace mim
static constexpr auto Node
Definition tuple.h:323
Arr * unset()
Definition tuple.h:320
static constexpr size_t Num_Ops
Definition tuple.h:324
Arr * set_body(const Def *body)
Definition tuple.h:318
Arr * set(const Def *shape, const Def *body)
Definition tuple.h:319
Arr * set_shape(const Def *shape)
Definition tuple.h:317
friend class World
Definition tuple.h:327
const App * app() const
Definition tuple.h:447
const Def * callee() const
Definition tuple.cpp:102
Branch(const Def *)
Definition tuple.cpp:97
const Def * arg() const
Definition tuple.cpp:103
Base class for all Defs.
Definition def.h:289
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
Definition def.cpp:647
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:188
constexpr auto ops() const noexcept
Definition def.h:374
const Def * op(size_t i) const noexcept
Definition def.h:377
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1119
const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
Definition def.cpp:612
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
Definition def.cpp:205
constexpr auto reduce(const Def *arg) const
Definition def.h:681
const Def * callee() const
Definition tuple.cpp:110
const Def * arg() const
Definition tuple.cpp:111
Dispatch(const Def *)
Definition tuple.cpp:105
const App * app() const
Definition tuple.h:472
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:360
const Def * tuple() const
Definition tuple.h:370
friend class World
Definition tuple.h:378
static constexpr size_t Num_Ops
Definition tuple.h:375
static constexpr auto Node
Definition tuple.h:374
const Def * index() const
Definition tuple.h:371
static constexpr auto Node
Definition tuple.h:400
const Def * tuple() const
Definition tuple.h:395
friend class World
Definition tuple.h:404
const Def * index() const
Definition tuple.h:396
static constexpr size_t Num_Ops
Definition tuple.h:401
const Def * value() const
Definition tuple.h:397
static T as(const Def *def)
Definition def.h:982
Pack * set_body(const Def *body)
Definition tuple.h:347
Pack * set_shape(const Def *shape)
Definition tuple.h:346
static constexpr size_t Num_Ops
Definition tuple.h:353
Pack * set(const Def *shape, const Def *body)
Definition tuple.h:348
Pack * unset()
Definition tuple.h:349
friend class World
Definition tuple.h:356
static constexpr auto Node
Definition tuple.h:352
Base class for Sigma and Tuple.
Definition tuple.h:13
static constexpr bool isa_node(mim::Node n) noexcept
Prod groups Sigma and Tuple; see fe::NodeSetable.
Definition tuple.h:19
static DefVec cat_projs(nat_t n, nat_t m, const Def *a, const Def *b)
The spliced components themselves - for when you want to build something other than a Prod from them.
Definition tuple.cpp:146
static const Def * cat(bool term, nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.cpp:150
static constexpr size_t Num_Ops
Definition tuple.h:34
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Definition def.cpp:29
const Def * cond() const
Definition tuple.h:434
const Def * pair() const
Definition tuple.h:433
const Def * tt() const
Definition tuple.h:435
const Def * ff() const
Definition tuple.h:436
Select(const Def *)
Definition tuple.cpp:92
Base class for Arr and Pack.
Definition tuple.h:267
static constexpr bool isa_node(mim::Node n) noexcept
Seq groups Arr and Pack; see fe::NodeSetable.
Definition tuple.h:273
const Def * body() const
Definition tuple.h:280
Seq * set(const Def *shape, const Def *body)
Common setter for Packs and Arrays.
Definition tuple.h:292
Shape shape() const
Definition tuple.h:279
Seq * unset()
Definition tuple.h:293
const Def * elem() const
The element one axis down: Seq::body for a one-dimensional Seq, the Seq of the remaining axes otherwi...
Definition tuple.cpp:82
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Definition def.cpp:29
const Def * reduce(const Def *arg) const
Definition tuple.h:298
CRTP-based mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:220
const Tuple * set(Args &&... args) const
Definition def.h:232
The extents of a Seq's axes: a plain Nat for a single axis, an aggregate of them for several.
Definition tuple.h:194
Shape zonk() const
Wraps Def::zonk();.
Definition tuple.h:239
std::optional< nat_t > rank() const
Number of axes; std::nullopt if not statically known.
Definition tuple.cpp:23
bool is_fused() const
Does this span several axes? Also true for a dynamic rank.
Definition tuple.h:211
static std::optional< nat_t > extent(const Def *axis)
The extent of axis: the axis itself for a shape, its Idx size for an index.
Definition tuple.cpp:33
const Def * front() const
The outermost axis - the Def::arity of the Seq this shape describes; null for a null Shape.
Definition tuple.cpp:25
Shape operator+(Shape) const
Concatenation - what fuses «a; «b; T»» into «a, b; T».
Definition tuple.cpp:66
bool is_dim() const
Is this a single axis - a Nat/Idx rather than an aggregate of them?
Definition tuple.cpp:16
constexpr const Def * operator->() const noexcept
Definition tuple.h:204
Shape slice(nat_t begin, nat_t end) const
The axes [begin, end).
Definition tuple.cpp:54
Shape fold() const
Drops every literal size-1 axis, mirroring «1; T» ≡ T; all of them folded away leaves rank 0.
Definition tuple.cpp:71
const Def * operator[](nat_t i) const
The i th axis.
Definition tuple.h:215
static bool isa_extents(const Def *)
Is type Nat - or an aggregate of Nats, i.e. a shape?
Definition tuple.cpp:46
Shape drop(nat_t n) const
All but the leading n axes.
Definition tuple.cpp:61
constexpr const Def * operator*() const noexcept
Definition tuple.h:203
Shape filter(auto keep) const
This Shape with only the axes keep accepts; *this, if it accepts all of them or the rank is dynamic.
Definition tuple.h:242
Shape take(nat_t n) const
The leading n axes.
Definition tuple.h:236
constexpr Shape() noexcept=default
static bool isa_indices(const Def *)
Is type Idx - or an aggregate of Idxs, i.e. a fused index?
Definition tuple.cpp:50
size_t num_cat() const
Number of concat'ed candidates.
Definition tuple.h:156
Sieve(size_t num)
Definition tuple.h:123
size_t cat(size_t i) const
As Sieve::operator[] but for concat'ed i.
Definition tuple.h:157
void cat(size_t num, std::predicate< size_t > auto pred)
Definition tuple.h:145
DefVec gather(Defs ops) const
The surviving components of ops - one per candidate, concat'ed ones included.
Definition tuple.h:177
Sieve(Defs ops, std::predicate< const Def * > auto pred)
Keeps those ops that satisfy pred.
Definition tuple.h:136
fe::View< size_t > new2old() const
The old index of the i th survivor; this is what Rewriter::rewrite_stub expects.
Definition tuple.h:167
size_t num_new() const
Number of survivors.
Definition tuple.h:163
size_t num_old() const
Number of old components.
Definition tuple.h:162
size_t operator[](size_t i) const
The new index of the candidate i - or Sieve::Gone, if it didn't survive.
Definition tuple.h:172
static constexpr size_t Gone
Definition tuple.h:118
bool all() const
Is the new aggregate the old one - nothing dropped and nothing concat'ed?
Definition tuple.h:165
Sieve(size_t num, std::predicate< size_t > auto pred)
Keeps those of num candidates that satisfy pred.
Definition tuple.h:128
Sigma * unset()
Definition tuple.h:53
Sigma * set(Defs ops)
Definition tuple.h:52
static const Def * cat(nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.h:72
friend class World
Definition tuple.h:79
static const Def * infer(World &, Defs)
Definition check.cpp:492
static constexpr auto Node
Definition tuple.h:76
Sigma * set(size_t i, const Def *def)
Definition tuple.h:51
static const Def * cat(const Def *a, const Def *b)
Definition tuple.h:73
size_t num_targets() const
Definition tuple.h:418
const Extract * extract_
Definition tuple.h:422
Switch(const Def *)
Definition tuple.cpp:84
const Extract * extract() const
Definition tuple.h:414
const Def * index() const
Definition tuple.h:416
const Def * target(size_t i) const
Definition tuple.h:419
const Def * tuple() const
Definition tuple.h:415
static const Def * cat(nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.h:92
static const Def * cat(const Def *a, const Def *b)
Definition tuple.h:93
friend class World
Definition tuple.h:102
static const Def * infer(World &, Defs)
Definition check.cpp:488
static constexpr auto Node
Definition tuple.h:96
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:43
Definition ast.h:16
u64 nat_t
Definition types.h:37
bool is_unit(const Def *)
Definition tuple.cpp:113
fe::View< const Def * > Defs
Definition def.h:96
std::string tuple2str(const Def *)
Definition tuple.cpp:115
const Def * tuple_of_types(const Def *t)
Definition tuple.cpp:167
fe::Vector< const Def * > DefVec
Definition def.h:98
Node
Definition def.h:123
@ Arr
Definition def.h:125
@ Pack
Definition def.h:125
@ Sigma
Definition def.h:125
@ Extract
Definition def.h:125
@ Insert
Definition def.h:125
@ Tuple
Definition def.h:125