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