MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
mem.h
Go to the documentation of this file.
1#pragma once
2
3#include <mim/axm.h>
4#include <mim/lam.h>
5#include <mim/world.h>
6
8
10
11namespace mim::plug::mem {
12
13/// @name %%mem.M
14///@{
15
16inline Lam* mut_con(World& w, nat_t a = 0) { return w.mut_con(w.call<M>(a)); } ///< Yields `con[%mem.M 0]`.
17
18/// Yields `con[%mem.M 0, dom]`.
19inline Lam* mut_con(const Def* dom) {
20 World& w = dom->world();
21 return w.mut_con({w.call<M>(0), dom});
22}
23
24/// If @p def is a `%mem.M`-typed value, yields its memory type `%mem.M a`; otherwise `nullptr`.
25/// Null-safe: type-level Def%s (e.g. mim::Univ) have no type and hence are not memory.
26inline const App* isa_mem(const Def* def) {
27 if (auto type = def->type()) return Axm::isa<mem::M>(type);
28 return nullptr;
29}
30
31/// Does @p pi already thread memory - a leading `%mem.M`, either directly or grouped as the first
32/// component of the first parameter (e.g. the `Fn [%mem.M 0, To, ins] → …` shape of a mem-threaded combiner)?
33inline bool has_leading_mem(const Pi* pi) {
34 if (pi->num_doms() == 0) return false;
35 auto dom0 = pi->dom(0uz);
36 if (Axm::isa<mem::M>(dom0)) return true;
37 if (auto sig = dom0->isa<Sigma>(); sig && sig->num_ops() != 0 && Axm::isa<mem::M>(sig->op(0))) return true;
38 return false;
39}
40
41/// Returns the (first) element of type `%mem.M a` from the given tuple.
42inline const Def* mem_def(const Def* def) {
43 if (isa_mem(def)) return def;
44 if (def->type()->isa<Arr>()) return {}; // don't look into possibly gigantic arrays
45
46 if (def->num_projs() > 1) {
47 for (auto proj : def->projs())
48 if (auto mem = mem_def(proj)) return mem;
49 }
50
51 return {};
52}
53
54/// Returns the memory argument of a function if it has one.
55inline const Def* mem_var(Lam* lam) { return mem_def(lam->var()); }
56
57/// Removes recusively all occurences of mem from a type (sigma).
58inline const Def* strip_mem_ty(const Def* def) {
59 auto& world = def->world();
60
61 if (auto sigma = def->isa<Sigma>()) {
62 DefVec new_ops;
63 for (auto op : sigma->ops())
64 if (auto new_op = strip_mem_ty(op); new_op != world.sigma()) new_ops.push_back(new_op);
65
66 return world.sigma(new_ops);
67 } else if (Axm::isa<mem::M>(def)) {
68 return world.sigma();
69 }
70
71 return def;
72}
73
74/// Recursively removes all occurrences of mem from a tuple.
75/// Returns an empty tuple if applied with mem alone.
76inline const Def* strip_mem(const Def* def) {
77 auto& world = def->world();
78
79 if (auto tuple = def->isa<Tuple>()) {
80 DefVec new_ops;
81 for (auto op : tuple->ops())
82 if (auto new_op = strip_mem(op); new_op != world.tuple()) new_ops.push_back(new_op);
83
84 return world.tuple(new_ops);
85 } else if (Axm::isa<mem::M>(def->type())) {
86 return world.tuple();
87 } else if (auto extract = def->isa<Extract>()) {
88 // The case that this one element is a mem and should return () is handled above.
89 if (extract->num_projs() == 1) return extract;
90
91 DefVec new_ops;
92 for (auto op : extract->projs())
93 if (auto new_op = strip_mem(op); new_op != world.tuple()) new_ops.push_back(new_op);
94
95 return world.tuple(new_ops);
96 }
97
98 return def;
99}
100///@}
101
102/// @name %%mem.lea
103///@{
104inline const Def* pointee(const Def* ptr) {
105 auto [pointee, _] = Axm::as<Ptr>(ptr->type())->args<2>();
106 return pointee;
107}
108///@}
109
110/// @name %%mem.lea
111///@{
112inline const Def* op_lea(const Def* ptr, const Def* index) {
113 World& w = ptr->world();
114 auto [pointee, addr_space] = Axm::as<Ptr>(ptr->type())->args<2>();
115 auto Ts = tuple_of_types(pointee);
116 return w.app(w.app(w.annex<lea>(), {pointee->arity(), Ts, addr_space}), {ptr, index});
117}
118
119inline const Def* op_lea_unsafe(const Def* ptr, const Def* i) {
120 World& w = ptr->world();
121 return op_lea(ptr, w.call(core::conv::u, Axm::as<Ptr>(ptr->type())->arg(0)->arity(), i));
122}
123
124inline const Def* op_lea_unsafe(const Def* ptr, u64 i) { return op_lea_unsafe(ptr, ptr->world().lit_i64(i)); }
125///@}
126
127/// @name %%mem.alloc
128///@{
129inline const Def* op_alloc(const Def* type, const Def* as, const Def* mem) {
130 World& w = type->world();
131 return w.app(w.app(w.annex<alloc>(), {type, as}), mem);
132}
133inline const Def* op_alloc(const Def* type, const Def* mem) { return op_alloc(type, type->world().lit_nat_0(), mem); }
134///@}
135
136/// @name %%mem.slot
137///@{
138/// Builds the continuation-based `%%mem.slot (type, as)` applied to @p mem and the continuation @p ret.
139/// @p ret is a `Cn [%mem.M as, %mem.Ptr (type, as)]` receiving the fresh slot; its scope delimits the slot's lifetime.
140inline const Def* op_slot(const Def* type, const Def* as, const Def* mem, const Def* ret) {
141 World& w = type->world();
142 return w.app(w.app(w.annex<slot>(), {type, as}), {mem, ret});
143}
144inline const Def* op_slot(const Def* type, const Def* mem, const Def* ret) {
145 return op_slot(type, type->world().lit_nat_0(), mem, ret);
146}
147/// Decomposes the continuation-based @p slot into `(mem, ret_lam, ret_mem, ptr)`,
148/// where `ret_mem` is the continuation's mem and `ptr` is the continuation's slot var;
149/// the slot's lifetime is `ret_lam`'s scope.
150inline std::tuple<const Def*, Lam*, const Def*, const Def*> split_slot(const App* slot) {
151 auto [mem, ret] = slot->args<2>();
152 auto ret_lam = ret->isa_mut<Lam>();
153 return {mem, ret_lam, ret_lam->var(2, 0), ret_lam->var(2, 1)};
154}
155
156///@}
157
158/// @name %%mem.malloc
159///@{
160inline const Def* op_malloc(const Def* type, const Def* as, const Def* mem) {
161 World& w = type->world();
162 auto size = w.call(core::trait::size, type);
163 return w.app(w.app(w.annex<malloc>(), {type, as}), {mem, size});
164}
165inline const Def* op_malloc(const Def* type, const Def* mem) { return op_malloc(type, type->world().lit_nat_0(), mem); }
166///@}
167
168/// @name %%mem.mslot
169///@{
170/// Builds the continuation-based `%%mem.mslot (type, as)` applied to `(mem, size)` and the continuation @p ret.
171/// @p ret is a `Cn [%mem.M as, %mem.Ptr (type, as)]` receiving the fresh slot; its scope delimits the slot's lifetime.
172inline const Def* op_mslot(const Def* type, const Def* as, const Def* mem, const Def* ret) {
173 World& w = type->world();
174 auto size = w.call(core::trait::size, type);
175 return w.app(w.app(w.annex<mslot>(), {type, as}), {w.tuple({mem, size}), ret});
176}
177inline const Def* op_mslot(const Def* type, const Def* mem, const Def* ret) {
178 return op_mslot(type, type->world().lit_nat_0(), mem, ret);
179}
180///@}
181
182} // namespace mim::plug::mem
A (possibly paramterized) Array.
Definition tuple.h:121
static auto isa(const Def *def)
Definition axm.h:107
static auto as(const Def *def)
Definition axm.h:130
Base class for all Defs.
Definition def.h:261
World & world() const noexcept
Definition def.cpp:483
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:441
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
Definition def.h:402
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
nat_t num_projs() const
Yields Def::arity(), if it is a Lit, or 1 otherwise.
Definition def.cpp:628
constexpr size_t num_ops() const noexcept
Definition def.h:321
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:210
A function.
Definition lam.h:110
A dependent function type.
Definition lam.h:14
const Def * dom() const
Definition lam.h:35
A dependent tuple type.
Definition tuple.h:22
Data constructor for a Sigma.
Definition tuple.h:70
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:36
const Lit * lit_i64()
Definition world.h:532
The mem Plugin
Definition mem.h:11
bool has_leading_mem(const Pi *pi)
Does pi already thread memory - a leading mem.M, either directly or grouped as the first component of...
Definition mem.h:33
const Def * mem_var(Lam *lam)
Returns the memory argument of a function if it has one.
Definition mem.h:55
const Def * mem_def(const Def *def)
Returns the (first) element of type mem.M a from the given tuple.
Definition mem.h:42
const Def * strip_mem_ty(const Def *def)
Removes recusively all occurences of mem from a type (sigma).
Definition mem.h:58
const Def * op_lea(const Def *ptr, const Def *index)
Definition mem.h:112
const Def * op_mslot(const Def *type, const Def *as, const Def *mem, const Def *ret)
Definition mem.h:172
const Def * op_lea_unsafe(const Def *ptr, const Def *i)
Definition mem.h:119
Lam * mut_con(World &w, nat_t a=0)
Yields con[mem.M 0].
Definition mem.h:16
const Def * strip_mem(const Def *def)
Recursively removes all occurrences of mem from a tuple.
Definition mem.h:76
const Def * op_alloc(const Def *type, const Def *as, const Def *mem)
Definition mem.h:129
const App * isa_mem(const Def *def)
If def is a mem.M-typed value, yields its memory type mem.M a; otherwise nullptr.
Definition mem.h:26
std::tuple< const Def *, Lam *, const Def *, const Def * > split_slot(const App *slot)
Decomposes the continuation-based slot into (mem, ret_lam, ret_mem, ptr), where ret_mem is the contin...
Definition mem.h:150
const Def * pointee(const Def *ptr)
Definition mem.h:104
const Def * op_slot(const Def *type, const Def *as, const Def *mem, const Def *ret)
Definition mem.h:140
const Def * op_malloc(const Def *type, const Def *as, const Def *mem)
Definition mem.h:160
The tuple Plugin
u64 nat_t
Definition types.h:37
Vector< const Def * > DefVec
Definition def.h:79
const Def * tuple_of_types(const Def *t)
Definition tuple.cpp:106
uint64_t u64
Definition types.h:27