MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
tuple.cpp
Go to the documentation of this file.
1#include "mim/tuple.h"
2
3#include <cassert>
4
5#include "mim/world.h"
6
7namespace mim {
8
9/*
10 * Shape
11 */
12
14 : Shape(w.tuple(shape)) {}
15
16bool Shape::is_dim() const {
17 auto t = def_ ? def_->unfold_type() : nullptr;
18 if (!t) return false;
19 if (t->isa<Nat>() || Idx::isa(t)) return true;
20 return t->zonk_mut()->isa<Nat>(); // only a Hole needs the zonk
21}
22
23std::optional<nat_t> Shape::rank() const { return def_ ? Lit::isa(def_->arity()) : std::nullopt; }
24
25const Def* Shape::front() const {
26 if (!def_ || is_dim()) return def_; // an unset mutable Seq has no shape yet
27 if (auto r = rank()) return def_->proj(*r, 0);
28
29 auto& w = def_->world(); // a dynamic rank cannot be projected
30 return w.extract(def_, w.lit(w.type_idx(def_->arity()), 0));
31}
32
33std::optional<nat_t> Shape::extent(const Def* axis) {
34 if (auto size = Idx::isa(axis->unfold_type())) return Lit::isa(size);
35 return Lit::isa(axis);
36}
37
38/// Is @p type a @p leaf - or an aggregate of them? This is what makes a shape a shape and an index an index.
39static bool isa_axes(const Def* type, auto leaf) {
40 if (leaf(type)) return true;
41 if (auto sigma = type->isa<Sigma>()) return std::ranges::all_of(sigma->ops(), leaf);
42 if (auto arr = type->isa<Arr>()) return leaf(arr->body()->zonk());
43 return false;
44}
45
46bool Shape::isa_extents(const Def* type) {
47 return isa_axes(type, [](const Def* l) { return l->isa<Nat>() != nullptr; });
48}
49
50bool Shape::isa_indices(const Def* type) {
51 return isa_axes(type, [](const Def* l) { return Idx::isa(l) != nullptr; });
52}
53
54Shape Shape::slice(nat_t begin, nat_t end) const {
55 auto r = rank();
56 if (!r) return {};
57 if (begin == 0 && end == *r) return *this;
58 return def_->world().tuple(DefVec(end - begin, [&](size_t i) { return def_->proj(*r, begin + i); }));
59}
60
62 auto r = rank();
63 return r ? slice(n, *r) : Shape();
64}
65
67 if (!def_ || !other) return {};
68 return Tuple::cat(def_, *other);
69}
70
72 if (is_dim()) return extent(def_) == 1 ? Shape(def_->world().tuple()) : *this;
73 return filter([](nat_t, const Def* a) { return extent(a) != 1; });
74}
75
76Shape Shape::fold(Shape shape) const {
77 if (!shape.rank()) return *this;
78 assert(rank() == shape.rank() && "an index folds against the shape of the very Seq it indexes");
79 return filter([&](nat_t i, const Def*) { return extent(shape[i]) != 1; });
80}
81
82const Def* Seq::elem() const { return shape().is_fused() ? world().drop(this, 1) : body(); }
83
84Select::Select(const Def* def) {
85 if (!def) return;
86 auto extract = def->isa<Extract>();
87 if (!extract || Lit::isa(extract->index())) return;
88 if (auto a = Lit::isa(extract->tuple()->arity()); a && *a == 2) extract_ = extract;
89}
90
92 : Select(App::callee_of(def)) {
93 if (extract()) app_ = def->as<App>();
94}
95
96const Def* Branch::callee() const { return app()->callee(); }
97const Def* Branch::arg() const { return app()->arg(); }
98
100 auto app = def->isa<App>();
101 if (!app) return;
102 auto extract = app->callee()->isa<Extract>();
103 if (!extract || Lit::isa(extract->index())) return;
104 if (Lit::isa(extract->tuple()->arity())) {
105 app_ = app;
106 extract_ = extract;
107 }
108}
109
110const Def* Dispatch::callee() const { return app()->callee(); }
111const Def* Dispatch::arg() const { return app()->arg(); }
112
113bool is_unit(const Def* def) { return def->type() == def->world().sigma(); }
114
115std::string tuple2str(const Def* def) {
116 auto& w = def->world();
117 auto res = std::string();
118 if (auto n = Lit::isa(def->arity())) {
119 res.reserve(*n);
120 for (size_t i = 0; i != *n; ++i) {
121 auto elem = def->proj(*n, i);
122 if (elem->type() == w.type_i8()) {
123 if (auto l = Lit::isa<char>(elem)) {
124 res.push_back(*l);
125 continue;
126 }
127 }
128 return {};
129 }
130 }
131 return res;
132}
133
134/*
135 * cat
136 */
137
139 auto res = DefVec();
140 res.reserve(a.size() + b.size());
141 res.append_range(a);
142 res.append_range(b);
143 return res;
144}
145
146DefVec Prod::cat_projs(nat_t n, nat_t m, const Def* a, const Def* b) {
147 return DefVec(n + m, [=](size_t i) { return i < n ? a->proj(n, i) : b->proj(m, i - n); });
148}
149
150const Def* Prod::cat(bool term, nat_t n, nat_t m, const Def* a, const Def* b) {
151 auto& w = a->world();
152 // Two *fully* spliced Seq%s of the same element concatenate without materializing their n + m projections.
153 if (auto sa = a->isa_imm<Seq>(), sb = b->isa_imm<Seq>(); sa && sb && Lit::isa(a->arity()) == n
154 && Lit::isa(b->arity()) == m && sa->is_intro() == term
155 && sb->is_intro() == term && sa->elem() == sb->elem())
156 return w.seq(term, n + m, sa->elem());
157
158 return w.prod(term, cat_projs(n, m, a, b));
159}
160
161const Def* Prod::cat(bool term, const Def* a, const Def* b) {
162 auto n = Lit::isa(a->arity());
163 auto m = Lit::isa(b->arity());
164 return n && m ? cat(term, *n, *m, a, b) : nullptr;
165}
166
167const Def* tuple_of_types(const Def* t) {
168 auto& world = t->world();
169 if (auto sigma = t->isa<Sigma>()) return world.tuple(sigma->ops());
170 if (auto arr = t->isa<Arr>()) {
171 // One entry per *top-level* element, so a fused Arr contributes its sub-arrays, not its elements.
172 if (auto elem = arr->elem()) return world.pack(arr->arity(), elem);
173 }
174 return t;
175}
176
177} // namespace mim
const Def * callee() const
Definition lam.h:235
const Def * arg() const
Definition lam.h:249
A (possibly paramterized) Array.
Definition tuple.h:305
const App * app() const
Definition tuple.h:435
const Def * callee() const
Definition tuple.cpp:96
Branch(const Def *)
Definition tuple.cpp:91
const Def * arg() const
Definition tuple.cpp:97
Base class for all Defs.
Definition def.h:313
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:635
World & world() const noexcept
Definition def.h:1172
static DefVec cat(Defs a, Defs b)
Definition tuple.cpp:138
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
Definition def.cpp:463
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:1186
const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
Definition def.cpp:606
const T * isa_imm() const
Definition def.h:620
const Def * callee() const
Definition tuple.cpp:110
const Def * arg() const
Definition tuple.cpp:111
Dispatch(const Def *)
Definition tuple.cpp:99
const Extract * extract() const
Definition tuple.h:464
const App * app() const
Definition tuple.h:460
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
const Def * index() const
Definition tuple.h:371
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Definition def.cpp:659
static std::optional< T > isa(const Def *def)
Definition def.h:1013
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
Def(World *, Node, const Def *type, Defs ops, flags_t flags)
Constructor for an immutable Def.
Definition def.cpp:43
const Extract * extract() const
Definition tuple.h:417
Select(const Def *)
Definition tuple.cpp:84
Base class for Arr and Pack.
Definition tuple.h:267
const Def * body() const
Definition tuple.h:280
Shape shape() const
Definition tuple.h:279
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:43
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
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
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
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
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
A dependent tuple type.
Definition tuple.h:39
static const Def * cat(nat_t n, nat_t m, const Def *a, const Def *b)
Definition tuple.h:92
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:43
const Def * sigma(Defs ops)
Definition world.cpp:374
const Def * drop(const Seq *s, nat_t k)
s without its leading k axes - its body once k covers all of them; nullptr if that isn't a type.
Definition world.cpp:464
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
static bool isa_axes(const Def *type, auto leaf)
Is type a leaf - or an aggregate of them? This is what makes a shape a shape and an index an index.
Definition tuple.cpp:39
const Def * tuple_of_types(const Def *t)
Definition tuple.cpp:167
fe::Vector< const Def * > DefVec
Definition def.h:98