MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
lam.h
Go to the documentation of this file.
1#pragma once
2
3#include <variant>
4
5#include "mim/def.h"
6
7namespace mim {
8
9/// A [dependent function type](https://en.wikipedia.org/wiki/Dependent_type#%CE%A0_type).
10/// @see Lam
11class Pi : public Def, public Setters<Pi> {
12protected:
13 /// Constructor for an *immutable* Pi.
14 Pi(const Def* type, const Def* dom, const Def* codom, bool implicit)
15 : Def(Node, type, {dom, codom}, (flags_t)implicit) {}
16 /// Constructor for a *mut*able Pi.
17 Pi(const Def* type, bool implicit)
18 : Def(Node, type, 2, implicit ? 1 : 0) {}
19
20public:
21 /// @name Get/Set implicit
22 ///@{
23 bool is_implicit() const { return flags(); }
24 Pi* make_implicit() { return flags_ = (flags_t) true, this; }
25 Pi* make_explicit() { return flags_ = (flags_t) false, this; }
26 ///@}
27
28 /// @name dom & codom
29 /// @anchor pi_dom
30 /// @see @ref proj
31 ///@{
32 Ref dom() const { return op(0); }
33 Ref codom() const { return op(1); }
34 MIM_PROJ(dom, const)
35 MIM_PROJ(codom, const)
36 ///@}
37
38 /// @name Continuations
39 /// @anchor continuations
40 /// Checks certain properties of this Pi regarding continuations.
41 ///@{
42 // clang-format off
43 /// Is this a continuation - i.e. is the Pi::codom mim::Bot%tom?
44 static const Pi* isa_cn(Ref d) { return d->isa<Pi>() && d->as<Pi>()->codom()->node() == Node::Bot ? d->as<Pi>() : nullptr; }
45 /// Is this a continuation (Pi::isa_cn) which has a Pi::ret_pi?
46 static const Pi* isa_returning(Ref d) { return isa_cn(d) && d->as<Pi>()->ret_pi() ? d->as<Pi>() : nullptr; }
47 /// Is this a continuation (Pi::isa_cn) that is **not** Pi::isa_returning?
48 static const Pi* isa_basicblock(Ref d) { return isa_cn(d) && !d->as<Pi>()->ret_pi() ? d->as<Pi>() : nullptr; }
49 /// Is @p d an Pi::is_implicit (mutable) Pi?
50 static Pi* isa_implicit(Ref d) {
51 if (auto pi = d->isa_mut<Pi>(); pi && pi->is_implicit()) return pi;
52 return nullptr;
53 }
54 // clang-format on
55 ///@}
56
57 /// @name Return Continuation
58 /// @anchor return_continuation
59 ///@{
60 /// Yields the Pi::ret_pi() of @p d, if it is in fact a Pi.
61 static const Pi* ret_pi(Ref d) { return d->isa<Pi>() ? d->as<Pi>()->ret_pi() : nullptr; }
62 /// Yields the last Pi::dom, if it Pi::isa_basicblock.
63 const Pi* ret_pi() const;
64 /// Pi::dom%ain of Pi::ret_pi.
65 Ref ret_dom() const { return ret_pi()->dom(); }
66 ///@}
67
68 /// @name Setters
69 /// @see @ref set_ops "Setting Ops"
70 ///@{
71 using Setters<Pi>::set;
73 Pi* set_dom(Ref dom) { return Def::set(0, dom)->as<Pi>(); }
74 Pi* set_dom(Defs doms);
75 Pi* set_codom(Ref codom) { return Def::set(1, codom)->as<Pi>(); }
76 Pi* unset() { return Def::unset()->as<Pi>(); }
77 ///@}
78
79 /// @name Type Checking
80 ///@{
81 Ref check(size_t, Ref) override;
82 Ref check() override;
83 static Ref infer(Ref dom, Ref codom);
84 ///@}
85
86 /// @name Rebuild
87 ///@{
88 Ref reduce(Ref arg) const { return Def::reduce(1, arg); }
89 Pi* stub(Ref type) { return stub_(world(), type)->set(dbg()); }
90 const Pi* immutabilize() override;
91 ///@}
92
93 static constexpr auto Node = Node::Pi;
94
95private:
96 Ref rebuild_(World&, Ref, Defs) const override;
97 Pi* stub_(World&, Ref) override;
98
99 friend class World;
100};
101
102/// A function.
103/// @see Pi
104class Lam : public Def, public Setters<Lam> {
105private:
106 Lam(const Pi* pi, const Def* filter, const Def* body)
107 : Def(Node, pi, {filter, body}, 0) {}
108 Lam(const Pi* pi)
109 : Def(Node, pi, 2, 0) {}
110
111public:
112 /// @name ops & type
113 ///@{
114 Ref filter() const { return op(0); }
115 Ref body() const { return op(1); }
116 const Pi* type() const { return Def::type()->as<Pi>(); }
117 ///@}
118
119 /// @name dom & codom
120 /// @anchor lam_dom
121 /// @see @ref proj
122 ///@{
123 Ref dom() const { return type()->dom(); }
124 Ref codom() const { return type()->codom(); }
125 MIM_PROJ(dom, const)
126 MIM_PROJ(codom, const)
127 ///@}
128
129 /// @name Continuations
130 /// @see @ref continuations "Pi: Continuations"
131 ///@{
132 // clang-format off
133 static const Lam* isa_cn(Ref d) { return Pi::isa_cn(d->type()) ? d->isa<Lam>() : nullptr; }
134 static const Lam* isa_basicblock(Ref d) { return Pi::isa_basicblock(d->type()) ? d->isa<Lam>() : nullptr; }
135 static const Lam* isa_returning(Ref d) { return Pi::isa_returning (d->type()) ? d->isa<Lam>() : nullptr; }
136 static Lam* isa_mut_cn(Ref d) { return isa_cn(d) ? d->isa_mut<Lam>() : nullptr; } ///< Only for mutables.
137 static Lam* isa_mut_basicblock(Ref d) { return isa_basicblock(d) ? d->isa_mut<Lam>(): nullptr; } ///< Only for mutables.
138 static Lam* isa_mut_returning(Ref d) { return isa_returning (d) ? d->isa_mut<Lam>(): nullptr; } ///< Only for mutables.
139 // clang-format on
140 ///@}
141
142 /// @name Return Continuation
143 /// @see @ref return_continuation "Pi: Return Continuation"
144 ///@{
145 const Pi* ret_pi() const { return type()->ret_pi(); }
146 Ref ret_dom() const { return ret_pi()->dom(); }
147 /// Yields the Lam::var of the Lam::ret_pi.
148 Ref ret_var() { return type()->ret_pi() ? var(num_vars() - 1) : nullptr; }
149 ///@}
150
151 /// @name Setters
152 /// Lam::Filter is a `std::variant<bool, const Def*>` that lets you set the Lam::filter() like this:
153 /// ```cpp
154 /// lam1->app(true, f, arg);
155 /// lam2->app(my_filter_def, f, arg);
156 /// ```
157 /// @see @ref set_ops "Setting Ops"
158 ///@{
159 using Setters<Lam>::set;
160 using Filter = std::variant<bool, Ref>;
162 Lam* set_filter(Filter); ///< Set filter first.
163 Lam* set_body(Ref body) { return Def::set(1, body)->as<Lam>(); } ///< Set body second.
164 /// Set body to an App of @p callee and @p arg.
165 Lam* app(Filter filter, Ref callee, Ref arg);
166 /// Set body to an App of @p callee and @p args.
167 Lam* app(Filter filter, Ref callee, Defs args);
168 /// Set body to an App of `(f, t)#cond mem` or `(f, t)#cond ()` if @p mem is `nullptr`.
169 Lam* branch(Filter filter, Ref cond, Ref t, Ref f, Ref mem = nullptr);
170 Lam* test(Filter filter, Ref val, Ref idx, Ref match, Ref clash, Ref mem);
171 Lam* set(Defs ops) { return Def::set(ops)->as<Lam>(); }
172 Lam* unset() { return Def::unset()->as<Lam>(); }
173 ///@}
174
175 Lam* stub(Ref type) { return stub_(world(), type)->set(dbg()); }
176
177 /// @name Type Checking
178 ///@{
179 Ref check(size_t, Ref) override;
180 ///@}
181
182 static constexpr auto Node = Node::Lam;
183
184private:
185 Ref rebuild_(World&, Ref, Defs) const override;
186 Lam* stub_(World&, Ref) override;
187
188 friend class World;
189};
190
191/// @name Lam
192/// GIDSet / GIDMap keyed by Lam::gid of `Lam*`.
193///@{
194template<class To> using LamMap = GIDMap<Lam*, To>;
197///@}
198
199class App : public Def, public Setters<App> {
200private:
201 App(const Axiom* axiom, u8 curry, u8 trip, const Def* type, const Def* callee, const Def* arg)
202 : Def(Node, type, {callee, arg}, 0) {
203 axiom_ = axiom;
204 curry_ = curry;
205 trip_ = trip;
206 }
207
208public:
209 using Setters<App>::set;
210
211 /// @name callee
212 ///@{
213 Ref callee() const { return op(0); }
214 const App* decurry() const { return callee()->as<App>(); } ///< Returns App::callee again as App.
215 const Pi* callee_type() const { return callee()->type()->as<Pi>(); }
216 ///@}
217
218 /// @name arg
219 /// @anchor app_arg
220 /// @see @ref proj
221 ///@{
222 Ref arg() const { return op(1); }
223 MIM_PROJ(arg, const)
224 ///@}
225
226 /// @name Get axiom, current curry counter and trip count
227 ///@{
228 const Axiom* axiom() const { return axiom_; }
229 u8 curry() const { return curry_; }
230 u8 trip() const { return trip_; }
231 ///@}
232
233 static constexpr auto Node = Node::App;
234
235private:
236 Ref rebuild_(World&, Ref, Defs) const override;
237
238 friend class World;
239};
240
241/// @name Helpers to work with Functions
242///@{
243inline const App* isa_callee(Ref def, size_t i) { return i == 0 ? def->isa<App>() : nullptr; }
244
245/// These are Lam%s that are neither `nullptr`, nor Lam::is_external, nor Lam::is_unset.
246inline Lam* isa_workable(Lam* lam) {
247 if (!lam || lam->is_external() || !lam->is_set()) return nullptr;
248 return lam;
249}
250
251inline std::pair<const App*, Lam*> isa_apped_mut_lam(Ref def) {
252 if (auto app = def->isa<App>()) return {app, app->callee()->isa_mut<Lam>()};
253 return {nullptr, nullptr};
254}
255
256/// Yields curried App%s in a flat `std::deque<const App*>`.
257std::deque<const App*> decurry(Ref);
258
259/// The high level view is:
260/// ```
261/// f: B -> C
262/// g: A -> B
263/// f o g := λ x. f(g(x)) : A -> C
264/// ```
265/// In CPS the types look like:
266/// ```
267/// f: Cn[B, Cn C]
268/// g: Cn[A, Cn B]
269/// h = f o g
270/// h: Cn[A, cn C]
271/// h = λ (a ret_h) = g (a, h')
272/// h': Cn B
273/// h'= λ b = f (b, ret_h)
274/// ```
275Ref compose_cn(Ref f, Ref g);
276
277/// Helper function to cope with the fact that normalizers take all arguments and not only its axiom arguments.
278std::pair<Ref, DefVec> collect_args(Ref def);
279///@}
280
281} // namespace mim
Ref arg() const
Definition lam.h:222
const Pi * callee_type() const
Definition lam.h:215
u8 curry() const
Definition lam.h:229
const Axiom * axiom() const
Definition lam.h:228
Ref rebuild_(World &, Ref, Defs) const override
Definition def.cpp:97
const App * decurry() const
Returns App::callee again as App.
Definition lam.h:214
static constexpr auto Node
Definition lam.h:233
Ref callee() const
Definition lam.h:213
u8 trip() const
Definition lam.h:230
Base class for all Defs.
Definition def.h:226
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:305
Ref type() const
Definition def.h:251
Ref var()
Not necessarily a Var: E.g., if the return type is [], this will yield ().
Definition def.cpp:450
u8 trip_
Definition def.h:595
nat_t num_vars()
Definition def.h:395
virtual Ref check()
Definition def.h:530
Def * set(size_t i, Ref)
Successively set from left to right.
Definition def.cpp:256
World & world() const
Definition def.cpp:411
Ref op(size_t i) const
Definition def.h:272
DefVec reduce(Ref arg) const
Rewrites Def::ops by substituting this mutable's Var with arg.
Definition def.cpp:204
u8 curry_
Definition def.h:594
bool is_external() const
Definition def.h:429
auto ops() const
Definition def.h:271
node_t node() const
Definition def.h:244
flags_t flags() const
Definition def.h:241
flags_t flags_
Definition def.h:593
Def * unset()
Unsets all Def::ops; works even, if not set at all or partially.
Definition def.cpp:281
Dbg dbg() const
Definition def.h:464
A function.
Definition lam.h:104
Lam * unset()
Definition lam.h:172
Ref filter() const
Definition lam.h:114
Lam * app(Filter filter, Ref callee, Ref arg)
Set body to an App of callee and arg.
Definition lam.cpp:29
Lam * stub(Ref type)
Definition lam.h:175
Lam * set(Filter filter, Ref body)
Definition lam.h:161
Lam * set_filter(Filter)
Set filter first.
Definition lam.cpp:28
Ref codom() const
Definition lam.h:124
static Lam * isa_mut_basicblock(Ref d)
Only for mutables.
Definition lam.h:137
Lam * stub_(World &, Ref) override
Definition def.cpp:133
const Pi * ret_pi() const
Definition lam.h:145
const Pi * type() const
Definition lam.h:116
Lam * set(Defs ops)
Definition lam.h:171
static Lam * isa_mut_returning(Ref d)
Only for mutables.
Definition lam.h:138
static constexpr auto Node
Definition lam.h:182
Ref body() const
Definition lam.h:115
Ref dom() const
Definition lam.h:123
static Lam * isa_mut_cn(Ref d)
Only for mutables.
Definition lam.h:136
Lam * set_body(Ref body)
Set body second.
Definition lam.h:163
static const Lam * isa_cn(Ref d)
Definition lam.h:133
static const Lam * isa_basicblock(Ref d)
Definition lam.h:134
std::variant< bool, Ref > Filter
Definition lam.h:160
Ref ret_dom() const
Definition lam.h:146
Ref rebuild_(World &, Ref, Defs) const override
Definition def.cpp:101
Lam * test(Filter filter, Ref val, Ref idx, Ref match, Ref clash, Ref mem)
Definition lam.cpp:36
Lam * branch(Filter filter, Ref cond, Ref t, Ref f, Ref mem=nullptr)
Set body to an App of (f, t)#cond mem or (f, t)#cond () if mem is nullptr.
Definition lam.cpp:32
Ref ret_var()
Yields the Lam::var of the Lam::ret_pi.
Definition lam.h:148
static const Lam * isa_returning(Ref d)
Definition lam.h:135
A dependent function type.
Definition lam.h:11
static const Pi * isa_returning(Ref d)
Is this a continuation (Pi::isa_cn) which has a Pi::ret_pi?
Definition lam.h:46
Ref codom() const
Definition lam.h:33
static Ref infer(Ref dom, Ref codom)
Definition check.cpp:288
static Pi * isa_implicit(Ref d)
Is d an Pi::is_implicit (mutable) Pi?
Definition lam.h:50
Pi(const Def *type, bool implicit)
Constructor for a *mut*able Pi.
Definition lam.h:17
Pi * stub(Ref type)
Definition lam.h:89
Pi * unset()
Definition lam.h:76
Pi * set_codom(Ref codom)
Definition lam.h:75
Pi * make_implicit()
Definition lam.h:24
Pi(const Def *type, const Def *dom, const Def *codom, bool implicit)
Constructor for an immutable Pi.
Definition lam.h:14
Ref reduce(Ref arg) const
Definition lam.h:88
bool is_implicit() const
Definition lam.h:23
Pi * make_explicit()
Definition lam.h:25
Pi * set(Ref dom, Ref codom)
Definition lam.h:72
Ref rebuild_(World &, Ref, Defs) const override
Definition def.cpp:104
Pi * stub_(World &, Ref) override
Definition def.cpp:135
static constexpr auto Node
Definition lam.h:93
const Pi * immutabilize() override
Tries to make an immutable from a mutable.
Definition def.cpp:170
static const Pi * isa_cn(Ref d)
Is this a continuation - i.e. is the Pi::codom mim::Bottom?
Definition lam.h:44
static const Pi * isa_basicblock(Ref d)
Is this a continuation (Pi::isa_cn) that is not Pi::isa_returning?
Definition lam.h:48
static const Pi * ret_pi(Ref d)
Definition lam.h:61
const Pi * ret_pi() const
Yields the last Pi::dom, if it Pi::isa_basicblock.
Definition lam.cpp:13
Ref dom() const
Definition lam.h:32
Ref check() override
Definition check.cpp:295
Pi * set_dom(Ref dom)
Definition lam.h:73
Ref ret_dom() const
Pi::domain of Pi::ret_pi.
Definition lam.h:65
Helper class to retrieve Infer::arg if present.
Definition def.h:86
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:189
This is a thin wrapper for std::span<T, N> with the following additional features:
Definition span.h:28
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
#define MIM_PROJ(NAME, CONST)
Use as mixin to wrap all kind of Def::proj and Def::projs variants.
Definition def.h:173
@ App
Definition def.h:40
@ Bot
Definition def.h:40
@ Pi
Definition def.h:40
@ Lam
Definition def.h:40
The mem Plugin
Definition mem.h:11
Definition cfg.h:11
const App * isa_callee(Ref def, size_t i)
Definition lam.h:243
GIDSet< Lam * > LamSet
Definition lam.h:195
u64 flags_t
Definition types.h:45
auto match(Ref def)
Definition axiom.h:112
std::deque< const App * > decurry(Ref)
Yields curried Apps in a flat std::deque<const App*>.
Definition lam.cpp:44
std::pair< Ref, DefVec > collect_args(Ref def)
Helper function to cope with the fact that normalizers take all arguments and not only its axiom argu...
Definition lam.cpp:86
absl::flat_hash_set< K, GIDHash< K >, GIDEq< K > > GIDSet
Definition util.h:180
LamMap< Lam * > Lam2Lam
Definition lam.h:196
GIDMap< Lam *, To > LamMap
Definition lam.h:194
Lam * isa_workable(Lam *lam)
These are Lams that are neither nullptr, nor Lam::is_external, nor Lam::is_unset.
Definition lam.h:246
absl::flat_hash_map< K, V, GIDHash< K >, GIDEq< K > > GIDMap
Definition util.h:179
std::pair< const App *, Lam * > isa_apped_mut_lam(Ref def)
Definition lam.h:251
Ref compose_cn(Ref f, Ref g)
The high level view is:
Definition lam.cpp:53
uint8_t u8
Definition types.h:34