MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
def.h
Go to the documentation of this file.
1#pragma once
2
3#include <optional>
4
5#include <fe/assert.h>
6#include <fe/cast.h>
7#include <fe/enum.h>
8
9#include "mim/config.h"
10
11#include "mim/util/dbg.h"
12#include "mim/util/sets.h"
13#include "mim/util/util.h"
14#include "mim/util/vector.h"
15
16// clang-format off
17#define MIM_NODE(m) \
18 m(Lit, lit, Judge::Intro) /* keep as first */ \
19 m(Axm, axm, Judge::Intro) \
20 m(Var, var, Judge::Intro) \
21 m(Global, global, Judge::Intro) \
22 m(Proxy, proxy, Judge::Intro) \
23 m(Hole, hole, Judge::Hole) \
24 m(Type, type, Judge::Meta) m(Univ, univ, Judge::Meta) m(UMax, umax, Judge::Meta) m(UInc, uinc, Judge::Meta) \
25 m(Pi, pi, Judge::Form) m(Lam, lam, Judge::Intro) m(App, app, Judge::Elim) \
26 m(Sigma, sigma, Judge::Form) m(Tuple, tuple, Judge::Intro) m(Extract, extract, Judge::Elim) m(Insert, insert, Judge::Intro | Judge::Elim) \
27 m(Arr, arr, Judge::Form) m(Pack, pack, Judge::Intro) \
28 m(Join, join, Judge::Form) m(Inj, inj, Judge::Intro) m(Match, match, Judge::Elim) m(Top, top, Judge::Intro) \
29 m(Meet, meet, Judge::Form) m(Merge, merge, Judge::Intro) m(Split, split, Judge::Elim) m(Bot, bot, Judge::Intro) \
30 m(Uniq, Uniq, Judge::Form) \
31 m(Nat, nat, Judge::Form) \
32 m(Idx, idx, Judge::Intro)
33// clang-format on
34
35namespace mim {
36
37class App;
38class Axm;
39class Var;
40class Def;
41class World;
42
43/// @name Def
44/// GIDSet / GIDMap keyed by Def::gid of `conset Def*`.
45///@{
46template<class To> using DefMap = GIDMap<const Def*, To>;
51///@}
52
53/// @name Def (Mutable)
54/// GIDSet / GIDMap keyed by Def::gid of `Def*`.
55///@{
56template<class To> using MutMap = GIDMap<Def*, To>;
60///@}
61
62/// @name Var
63/// GIDSet / GIDMap keyed by Var::gid of `const Var*`.
64///@{
65template<class To> using VarMap = GIDMap<const Var*, To>;
69///@}
70
71using NormalizeFn = const Def* (*)(const Def*, const Def*, const Def*);
72
73using fe::operator&;
74using fe::operator|;
75using fe::operator^;
76using fe::operator<=>;
77using fe::operator==;
78using fe::operator!=;
79
80/// @name Enums that classify certain aspects of Def%s.
81///@{
82
83enum class Node : node_t {
84#define CODE(node, name, _) node,
86#undef CODE
87};
88
89#define CODE(node, name, _) +size_t(1)
90static constexpr size_t Num_Nodes = size_t(0) MIM_NODE(CODE);
91#undef CODE
92
93/// TODO remove or fix this
94enum class Sort { Term, Type, Kind, Space, Univ, Level };
95
96/// Tracks a dependency to certain Def%s transitively through the Def::deps() up to but excliding *mutables*.
97enum class Dep : unsigned {
98 None = 0,
99 Mut = 1 << 0,
100 Var = 1 << 1,
101 Hole = 1 << 2,
102 Proxy = 1 << 3,
103};
104
105/// [Judgement](https://ncatlab.org/nlab/show/judgment).
106enum class Judge : u32 {
107 // clang-format off
108 Form = 1 << 0, ///< [Type Formation](https://ncatlab.org/nlab/show/type+formation) like `T -> T`.
109 Intro = 1 << 1, ///< [Term Introduction](https://ncatlab.org/nlab/show/natural+deduction) like `λ(x: Nat): Nat = x`.
110 Elim = 1 << 2, ///< [Term Elimination](https://ncatlab.org/nlab/show/term+elimination) like `f a`.
111 Meta = 1 << 3, ///< Meta rules for Univ%erse and Type levels.
112 Hole = 1 << 4, ///< Special rule for Hole.
113 // clang-format on
114};
115///@}
116
117} // namespace mim
118
119#ifndef DOXYGEN
120template<> struct fe::is_bit_enum<mim::Dep> : std::true_type {};
121template<> struct fe::is_bit_enum<mim::Judge> : std::true_type {};
122#endif
123
124namespace mim {
125
126/// Use as mixin to wrap all kind of Def::proj and Def::projs variants.
127#define MIM_PROJ(NAME, CONST) \
128 nat_t num_##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_projs(); } \
129 nat_t num_t##NAME##s() CONST noexcept { return ((const Def*)NAME())->num_tprojs(); } \
130 const Def* NAME(nat_t a, nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(a, i); } \
131 const Def* NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->proj(i); } \
132 const Def* t##NAME(nat_t i) CONST noexcept { return ((const Def*)NAME())->tproj(i); } \
133 template<nat_t A = std::dynamic_extent, class F> auto NAME##s(F f) CONST noexcept { \
134 return ((const Def*)NAME())->projs<A, F>(f); \
135 } \
136 template<class F> auto t##NAME##s(F f) CONST noexcept { return ((const Def*)NAME())->tprojs<F>(f); } \
137 template<nat_t A = std::dynamic_extent> auto NAME##s() CONST noexcept { return ((const Def*)NAME())->projs<A>(); } \
138 auto t##NAME##s() CONST noexcept { return ((const Def*)NAME())->tprojs(); } \
139 template<class F> auto NAME##s(nat_t a, F f) CONST noexcept { return ((const Def*)NAME())->projs<F>(a, f); } \
140 auto NAME##s(nat_t a) CONST noexcept { return ((const Def*)NAME())->projs(a); }
141
142/// CRTP-based Mixin to declare setters for Def::loc \& Def::name using a *covariant* return type.
143template<class P, class D = Def>
144class // D is only needed to make the resolution `D::template set` lazy
145#ifdef _MSC_VER
146 __declspec(empty_bases)
147#endif
148 Setters {
149private:
150 P* super() { return static_cast<P*>(this); }
151 const P* super() const { return static_cast<const P*>(this); }
152
153public:
154 // clang-format off
155 template<bool Ow = false> const P* set(Loc l ) const { super()->D::template set<Ow>(l); return super(); }
156 template<bool Ow = false> P* set(Loc l ) { super()->D::template set<Ow>(l); return super(); }
157 template<bool Ow = false> const P* set( Sym s ) const { super()->D::template set<Ow>(s); return super(); }
158 template<bool Ow = false> P* set( Sym s ) { super()->D::template set<Ow>(s); return super(); }
159 template<bool Ow = false> const P* set( std::string s) const { super()->D::template set<Ow>(std::move(s)); return super(); }
160 template<bool Ow = false> P* set( std::string s) { super()->D::template set<Ow>(std::move(s)); return super(); }
161 template<bool Ow = false> const P* set(Loc l, Sym s ) const { super()->D::template set<Ow>(l, s); return super(); }
162 template<bool Ow = false> P* set(Loc l, Sym s ) { super()->D::template set<Ow>(l, s); return super(); }
163 template<bool Ow = false> const P* set(Loc l, std::string s) const { super()->D::template set<Ow>(l, std::move(s)); return super(); }
164 template<bool Ow = false> P* set(Loc l, std::string s) { super()->D::template set<Ow>(l, std::move(s)); return super(); }
165 template<bool Ow = false> const P* set(Dbg d ) const { super()->D::template set<Ow>(d); return super(); }
166 template<bool Ow = false> P* set(Dbg d ) { super()->D::template set<Ow>(d); return super(); }
167 // clang-format on
168};
169
170/// Base class for all Def%s.
171///
172/// These are the most important subclasses:
173/// | Type Formation | Term Introduction | Term Elimination |
174/// | ----------------- | ----------------- | ----------------- |
175/// | Pi | Lam | App |
176/// | Sigma / Arr | Tuple / Pack | Extract |
177/// | | Insert | Insert |
178/// | Uniq | Wrap | Unwrap |
179/// | Join | Inj | Match |
180/// | Meet | Merge | Split |
181/// | Nat | Lit | |
182/// | Idx | Lit | |
183/// In addition there is:
184/// * Var: A variable. Currently the following Def%s may be binders:
185/// * Pi, Lam, Sigma, Arr, Pack
186/// * Axm: To introduce new entities.
187/// * Proxy: Used for intermediate values during optimizations.
188/// * Hole: A metavariable filled in by the type inference (always mutable as holes are filled in later).
189/// * Type, Univ, UMax, UInc: To keep track of type levels.
190///
191/// The data layout (see World::alloc and Def::deps) looks like this:
192/// ```
193/// Def| type | op(0) ... op(num_ops-1) |
194/// |-----------ops-----------|
195/// deps
196/// |--------------------------------| if type() != nullptr && is_set()
197/// |-------------------------| if type() == nullptr && is_set()
198/// |------| if type() != nullptr && !is_set()
199/// || if type() == nullptr && !is_set()
200/// ```
201/// @attention This means that any subclass of Def **must not** introduce additional members.
202/// @see @ref mut
203class Def : public fe::RuntimeCast<Def> {
204private:
205 Def& operator=(const Def&) = delete;
206 Def(const Def&) = delete;
207
208protected:
209 /// @name C'tors and D'tors
210 ///@{
211 Def(World*, Node, const Def* type, Defs ops, flags_t flags); ///< Constructor for an *immutable* Def.
212 Def(Node, const Def* type, Defs ops, flags_t flags); ///< As above but World retrieved from @p type.
213 Def(Node, const Def* type, size_t num_ops, flags_t flags); ///< Constructor for a *mutable* Def.
214 virtual ~Def() = default;
215 ///@}
216
217public:
218 /// @name Getters
219 ///@{
220 World& world() const noexcept;
221 constexpr flags_t flags() const noexcept { return flags_; }
222 constexpr u32 gid() const noexcept { return gid_; } ///< Global id - *unique* number for this Def.
223 constexpr u32 tid() const noexcept { return tid_; } ///< Trie id - only used in Trie.
224 constexpr u32 mark() const noexcept { return mark_; } ///< Used internally by free_vars().
225 constexpr size_t hash() const noexcept { return hash_; }
226 constexpr Node node() const noexcept { return node_; }
227 std::string_view node_name() const;
228 ///@}
229
230 /// @name Judgement
231 /// What kind of Judge%ment represents this Def?
232 ///@{
233 u32 judge() const noexcept;
234 // clang-format off
235 bool is_form() const noexcept { return judge() & Judge::Form; }
236 bool is_intro() const noexcept { return judge() & Judge::Intro; }
237 bool is_elim() const noexcept { return judge() & Judge::Elim; }
238 bool is_meta() const noexcept { return judge() & Judge::Meta; }
239 // clang-format on
240 ///@}
241
242 /// @name type
243 ///@{
244
245 /// Yields the "raw" type of this Def (maybe `nullptr`).
246 /// @see Def::unfold_type.
247 const Def* type() const noexcept { return type_; }
248 /// Yields the type of this Def and builds a new `Type (UInc n)` if necessary.
249 const Def* unfold_type() const;
250 bool is_term() const;
251 ///@}
252
253 /// @name arity
254 ///@{
255 const Def* arity() const;
256 std::optional<nat_t> isa_lit_arity() const;
258 auto a = isa_lit_arity();
259 assert(a.has_value());
260 return *a;
261 }
262 ///@}
263
264 /// @name ops
265 ///@{
266 template<size_t N = std::dynamic_extent> constexpr auto ops() const noexcept {
267 return View<const Def*, N>(ops_ptr(), num_ops_);
268 }
269 const Def* op(size_t i) const noexcept { return ops()[i]; }
270 constexpr size_t num_ops() const noexcept { return num_ops_; }
271 ///@}
272
273 /// @name Setting Ops (Mutables Only)
274 /// @anchor set_ops
275 /// You can set and change the Def::ops of a mutable after construction.
276 /// However, you have to obey the following rules:
277 /// If Def::is_set() is ...
278 /// * `false`, [set](@ref Def::set) the [operands](@ref Def::ops) from left to right.
279 /// * `true`, Def::unset() the operands first and then start over:
280 /// ```
281 /// mut->unset()->set({a, b, c});
282 /// ```
283 ///
284 /// MimIR assumes that a mutable is *final*, when its last operand is set.
285 /// Then, Def::check() will be invoked.
286 ///@{
287 Def* set(size_t i, const Def*); ///< Successively set from left to right.
288 Def* set(Defs ops); ///< Def::set @p ops all at once.
289 Def* unset(); ///< Unsets all Def::ops; works even, if not set at all or partially.
290 bool is_set() const; ///< Yields `true` if empty or the last op is set.
291
292 /// Update type.
293 /// @warning Only make type-preserving updates such as removing Hole%s.
294 /// Do this even before updating all other ops()!.
295 Def* set_type(const Def*);
296 ///@}
297
298 /// @name deps
299 /// All *dependencies* of a Def and includes:
300 /// * Def::type() (if not `nullptr`) and
301 /// * the other Def::ops() (only included, if Def::is_set()) in this order.
302 ///@{
303 Defs deps() const noexcept;
304 const Def* dep(size_t i) const noexcept { return deps()[i]; }
305 size_t num_deps() const noexcept { return deps().size(); }
306 ///@}
307
308 /// @name has_dep
309 /// Checks whether one Def::deps() contains specific elements defined in Dep.
310 /// This works up to the next *mutable*.
311 /// For example, consider the Tuple `tup`: `(?, lam (x: Nat) = y)`:
312 /// ```
313 /// bool has_hole = tup->has_dep(Dep::Hole); // true
314 /// bool has_mut = tup->has_dep(Dep::Mut); // true
315 /// bool has_var = tup->has_dep(Dep::Var); // false - y is contained in another mutable
316 /// ```
317 ///@{
318 bool has_dep() const { return dep_ != 0; }
319 bool has_dep(Dep d) const { return has_dep(unsigned(d)); }
320 bool has_dep(unsigned u) const { return dep_ & u; }
321 ///@}
322
323 /// @name proj
324 /// @anchor proj
325 /// Splits this Def via Extract%s or directly accessing the Def::ops in the case of Sigma%s or Arr%ays.
326 /// ```
327 /// std::array<const Def*, 2> ab = def->projs<2>();
328 /// std::array<u64, 2> xy = def->projs<2>([](auto def) { return Lit::as(def); });
329 /// auto [a, b] = def->projs<2>();
330 /// auto [x, y] = def->projs<2>([](auto def) { return Lit::as(def); });
331 /// Vector<const Def*> projs1 = def->projs(); // "projs1" has def->num_projs() many elements
332 /// Vector<const Def*> projs2 = def->projs(n);// "projs2" has n elements - asserts if incorrect
333 /// // same as above but applies Lit::as<nat_t>(def) to each element
334 /// Vector<const Lit*> lits1 = def->projs( [](auto def) { return Lit::as(def); });
335 /// Vector<const Lit*> lits2 = def->projs(n, [](auto def) { return Lit::as(def); });
336 /// ```
337 ///@{
338
339 /// Yields Def::as_lit_arity(), if it is in fact a Lit, or `1` otherwise.
340 nat_t num_projs() const { return isa_lit_arity().value_or(1); }
341 nat_t num_tprojs() const; ///< As above but yields 1, if Flags::scalarize_threshold is exceeded.
342
343 /// Similar to World::extract while assuming an arity of @p a, but also works on Sigma%s and Arr%ays.
344 const Def* proj(nat_t a, nat_t i) const;
345 const Def* proj(nat_t i) const { return proj(num_projs(), i); } ///< As above but takes Def::num_projs as arity.
346 const Def* tproj(nat_t i) const { return proj(num_tprojs(), i); } ///< As above but takes Def::num_tprojs.
347
348 /// Splits this Def via Def::proj%ections into an Array (if `A == std::dynamic_extent`) or `std::array` (otherwise).
349 /// Applies @p f to each element.
350 template<nat_t A = std::dynamic_extent, class F> auto projs(F f) const {
351 using R = std::decay_t<decltype(f(this))>;
352 if constexpr (A == std::dynamic_extent) {
353 return projs(num_projs(), f);
354 } else {
355 assert(A == as_lit_arity());
356 std::array<R, A> array;
357 for (nat_t i = 0; i != A; ++i) array[i] = f(proj(A, i));
358 return array;
359 }
360 }
361
362 template<class F> auto tprojs(F f) const { return projs(num_tprojs(), f); }
363
364 template<class F> auto projs(nat_t a, F f) const {
365 using R = std::decay_t<decltype(f(this))>;
366 return Vector<R>(a, [&](nat_t i) { return f(proj(a, i)); });
367 }
368 template<nat_t A = std::dynamic_extent> auto projs() const {
369 return projs<A>([](const Def* def) { return def; });
370 }
371 auto tprojs() const {
372 return tprojs([](const Def* def) { return def; });
373 }
374 auto projs(nat_t a) const {
375 return projs(a, [](const Def* def) { return def; });
376 }
377 ///@}
378
379 /// @name var
380 /// @anchor var
381 /// Retrieve Var for *mutables*.
382 /// @see @ref proj
383 ///@{
385 /// Not necessarily a Var: E.g., if the return type is `[]`, this will yield `()`.
386 const Def* var();
387 /// Only returns not `nullptr`, if Var of this mutable has ever been created.
388 const Var* has_var() { return var_; }
389 /// As above if `this` is a *mutable*.
390 const Var* has_var() const {
391 if (auto mut = isa_mut()) return mut->has_var();
392 return nullptr;
393 }
394 ///@}
395
396 /// @name Free Vars and Muts
397 /// * local_muts() / local_vars() are cached and hash-consed.
398 /// * free_vars() are computed on demand and cached in mutables.
399 /// They will be transitively invalidated by following users(), if a mutable is mutated.
400 ///@{
401
402 /// Mutables reachable by following *immutable* deps(); `mut->local_muts()` is by definition the set `{ mut }`.
403 Muts local_muts() const;
404
405 /// Var%s reachable by following *immutable* deps().
406 /// @note `var->local_vars()` is by definition the set `{ var }`.
407 Vars local_vars() const;
408
409 /// Compute a global solution by transitively following *mutables* as well.
410 Vars free_vars() const;
411 Vars free_vars();
412 Muts users() { return muts_; } ///< Set of mutables where this mutable is locally referenced.
413 bool is_open() const; ///< Has free_vars()?
414 bool is_closed() const; ///< Has no free_vars()?
415 ///@}
416
417 /// @name external
418 ///@{
419 bool is_external() const { return external_; }
420 void make_external();
421 void make_internal();
423 ///@}
424
425 /// @name Casts
426 /// @see @ref cast_builtin
427 ///@{
428 // clang-format off
429 template<class T = Def> const T* isa_imm() const { return isa_mut<T, true>(); }
430 template<class T = Def> const T* as_imm() const { return as_mut<T, true>(); }
431 // clang-format on
432
433 /// If `this` is *mutable*, it will cast `const`ness away and perform a `dynamic_cast` to @p T.
434 template<class T = Def, bool invert = false> T* isa_mut() const {
435 if constexpr (std::is_same<T, Def>::value)
436 return mut_ ^ invert ? const_cast<Def*>(this) : nullptr;
437 else
438 return mut_ ^ invert ? const_cast<Def*>(this)->template isa<T>() : nullptr;
439 }
440
441 /// Asserts that `this` is a *mutable*, casts `const`ness away and performs a `static_cast` to @p T.
442 template<class T = Def, bool invert = false> T* as_mut() const {
443 assert(mut_ ^ invert);
444 if constexpr (std::is_same<T, Def>::value)
445 return const_cast<Def*>(this);
446 else
447 return const_cast<Def*>(this)->template as<T>();
448 }
449 ///@}
450
451 /// @name Dbg Getters
452 ///@{
453 Dbg dbg() const { return dbg_; }
454 Loc loc() const { return dbg_.loc(); }
455 Sym sym() const { return dbg_.sym(); }
456 std::string unique_name() const; ///< name + "_" + Def::gid
457 ///@}
458
459 /// @name Dbg Setters
460 /// Every subclass `S` of Def has the same setters that return `S*`/`const S*` via the mixin Setters.
461 ///@{
462 // clang-format off
463 template<bool Ow = false> const Def* set(Loc l) const { if (Ow || !dbg_.loc()) dbg_.set(l); return this; }
464 template<bool Ow = false> Def* set(Loc l) { if (Ow || !dbg_.loc()) dbg_.set(l); return this; }
465 template<bool Ow = false> const Def* set(Sym s) const { if (Ow || !dbg_.sym()) dbg_.set(s); return this; }
466 template<bool Ow = false> Def* set(Sym s) { if (Ow || !dbg_.sym()) dbg_.set(s); return this; }
467 template<bool Ow = false> const Def* set( std::string s) const { set(sym(std::move(s))); return this; }
468 template<bool Ow = false> Def* set( std::string s) { set(sym(std::move(s))); return this; }
469 template<bool Ow = false> const Def* set(Loc l, Sym s ) const { set(l); set(s); return this; }
470 template<bool Ow = false> Def* set(Loc l, Sym s ) { set(l); set(s); return this; }
471 template<bool Ow = false> const Def* set(Loc l, std::string s) const { set(l); set(sym(std::move(s))); return this; }
472 template<bool Ow = false> Def* set(Loc l, std::string s) { set(l); set(sym(std::move(s))); return this; }
473 template<bool Ow = false> const Def* set(Dbg d) const { set(d.loc(), d.sym()); return this; }
474 template<bool Ow = false> Def* set(Dbg d) { set(d.loc(), d.sym()); return this; }
475 // clang-format on
476 ///@}
477
478 /// @name debug_prefix/suffix
479 /// Prepends/Appends a prefix/suffix to Def::name - but only in `Debug` build.
480 ///@{
481#ifndef NDEBUG
482 const Def* debug_prefix(std::string) const;
483 const Def* debug_suffix(std::string) const;
484#else
485 const Def* debug_prefix(std::string) const { return this; }
486 const Def* debug_suffix(std::string) const { return this; }
487#endif
488 ///@}
489
490 /// @name Rebuild
491 ///@{
492 Def* stub(World& w, const Def* type) { return stub_(w, type)->set(dbg()); }
493 Def* stub(const Def* type) { return stub(world(), type); }
494
495 /// Def::rebuild%s this Def while using @p new_op as substitute for its @p i'th Def::op
496 const Def* rebuild(World& w, const Def* type, Defs ops) const {
497 assert(isa_imm());
498 return rebuild_(w, type, ops)->set(dbg());
499 }
500 const Def* rebuild(const Def* type, Defs ops) const { return rebuild(world(), type, ops); }
501
502 /// Tries to make an immutable from a mutable.
503 /// This usually works if the mutable isn't recursive and its var isn't used.
504 virtual const Def* immutabilize() { return nullptr; }
505 bool is_immutabilizable();
506
507 const Def* refine(size_t i, const Def* new_op) const;
508
509 /// @see World::reduce
510 template<size_t N = std::dynamic_extent> constexpr auto reduce(const Def* arg) const {
511 return reduce_(arg).span<N>();
512 }
513
514 /// First Def::op that needs to be dealt with during reduction; e.g. for a Pi we don't reduce the Pi::dom.
515 /// @see World::reduce
516 virtual constexpr size_t reduction_offset() const noexcept { return size_t(-1); }
517 ///@}
518
519 /// @name Type Checking
520 ///@{
521
522 /// Checks whether the `i`th operand can be set to `def`.
523 /// The method returns a possibly updated version of `def` (e.g. where Hole%s have been resolved).
524 /// This is the actual `def` that will be set as the `i`th operand.
525 virtual const Def* check([[maybe_unused]] size_t i, const Def* def) { return def; }
526
527 /// After all Def::ops have ben Def::set, this method will be invoked to check the type of this mutable.
528 /// The method returns a possibly updated version of its type (e.g. where Hole%s have been resolved).
529 /// If different from Def::type, it will update its Def::type to a Def::zonk%ed version of that.
530 virtual const Def* check() { return type(); }
531
532 /// If Hole%s have been filled, reconstruct the program without them.
533 /// Only gues up to but excluding other mutables.
534 /// @see https://stackoverflow.com/questions/31889048/what-does-the-ghc-source-mean-by-zonk
535 const Def* zonk() const;
536
537 /// zonk%s all ops of this *mutable* and tries to immutabilize it; if it succeeds return it.
538 const Def* zonk_mut();
539 ///@}
540
541 static DefVec zonk(Defs);
542
543 /// @name dump
544 ///@{
545 void dump() const;
546 void dump(int max) const;
547 void write(int max) const;
548 void write(int max, const char* file) const;
549 std::ostream& stream(std::ostream&, int max) const;
550 ///@}
551
552 /// @name dot
553 /// Dumps DOT to @p os while obeying maximum recursion depth of @p max.
554 /// If @p types is `true`, Def::type() dependencies will be followed as well.
555 ///@{
556 void dot(std::ostream& os, uint32_t max = 0xFFFFFF, bool types = false) const;
557 /// Same as above but write to @p file or `std::cout` if @p file is `nullptr`.
558 void dot(const char* file = nullptr, uint32_t max = 0xFFFFFF, bool types = false) const;
559 void dot(const std::string& file, uint32_t max = 0xFFFFFF, bool types = false) const {
560 return dot(file.c_str(), max, types);
561 }
562 ///@}
563
564protected:
565 /// @name Wrappers for World::sym
566 /// These are here to have Def::set%ters inline without including `mim/world.h`.
567 ///@{
568 Sym sym(const char*) const;
569 Sym sym(std::string_view) const;
570 Sym sym(std::string) const;
571 ///@}
572
573private:
574 Defs reduce_(const Def* arg) const;
575 virtual Def* stub_(World&, const Def*) { fe::unreachable(); }
576 virtual const Def* rebuild_(World& w, const Def* type, Defs ops) const = 0;
577
578 Vars free_vars(bool&, bool&, uint32_t run);
579 void invalidate();
580 const Def** ops_ptr() const {
581 return reinterpret_cast<const Def**>(reinterpret_cast<char*>(const_cast<Def*>(this + 1)));
582 }
583 bool equal(const Def* other) const;
584
585protected:
586 mutable Dbg dbg_;
587 union {
588 NormalizeFn normalizer_; ///< Axm only: Axm%s use this member to store their normalizer.
589 const Axm* axm_; ///< App only: Curried App%s of Axm%s use this member to propagate the Axm.
590 const Var* var_; ///< Mutable only: Var of a mutable.
591 mutable World* world_;
592 };
596
597private:
598 Node node_;
599 bool mut_ : 1;
600 bool external_ : 1;
601 unsigned dep_ : 6;
602 u32 mark_ = 0;
603#ifndef NDEBUG
604 size_t curr_op_ = 0;
605#endif
606 u32 gid_;
607 u32 num_ops_;
608 size_t hash_;
609 Vars vars_; // Mutable: local vars; Immutable: free vars.
610 Muts muts_; // Immutable: local_muts; Mutable: users;
611 mutable u32 tid_ = 0;
612 const Def* type_;
613
614 template<class D, size_t N> friend class Sets;
615 friend class World;
616 friend void swap(World&, World&) noexcept;
617 friend std::ostream& operator<<(std::ostream&, const Def*);
618};
619
620class Var : public Def, public Setters<Var> {
621private:
622 Var(const Def* type, Def* mut)
623 : Def(Node, type, Defs{mut}, 0) {}
624
625public:
626 using Setters<Var>::set;
627
628 /// @name ops
629 ///@{
630 Def* mut() const { return op(0)->as_mut(); }
631 ///@}
632
633 static constexpr auto Node = mim::Node::Var;
634
635private:
636 const Def* rebuild_(World&, const Def*, Defs) const final;
637
638 friend class World;
639};
640
641class Univ : public Def, public Setters<Univ> {
642public:
643 using Setters<Univ>::set;
644 static constexpr auto Node = mim::Node::Univ;
645
646private:
648 : Def(&world, Node, nullptr, Defs{}, 0) {}
649
650 const Def* rebuild_(World&, const Def*, Defs) const final;
651
652 friend class World;
653};
654
655class UMax : public Def, public Setters<UMax> {
656public:
657 using Setters<UMax>::set;
658 static constexpr auto Node = mim::Node::UMax;
659
660private:
661 UMax(World&, Defs ops);
662
663 const Def* rebuild_(World&, const Def*, Defs) const final;
664
665 friend class World;
666};
667
668class UInc : public Def, public Setters<UInc> {
669private:
670 UInc(const Def* op, level_t offset)
671 : Def(Node, op->type()->as<Univ>(), {op}, offset) {}
672
673public:
674 using Setters<UInc>::set;
675
676 /// @name ops
677 ///@{
678 const Def* op() const { return Def::op(0); }
679 level_t offset() const { return flags(); }
680 ///@}
681
682 static constexpr auto Node = mim::Node::UInc;
683
684private:
685 const Def* rebuild_(World&, const Def*, Defs) const final;
686
687 friend class World;
688};
689
690class Type : public Def, public Setters<Type> {
691private:
692 Type(const Def* level)
693 : Def(Node, nullptr, {level}, 0) {}
694
695public:
696 using Setters<Type>::set;
697
698 /// @name ops
699 ///@{
700 const Def* level() const { return op(0); }
701 ///@}
702
703 static constexpr auto Node = mim::Node::Type;
704
705private:
706 const Def* rebuild_(World&, const Def*, Defs) const final;
707
708 friend class World;
709};
710
711class Lit : public Def, public Setters<Lit> {
712private:
713 Lit(const Def* type, flags_t val)
714 : Def(Node, type, Defs{}, val) {}
715
716public:
717 using Setters<Lit>::set;
718
719 /// @name Get actual Constant
720 ///@{
721 template<class T = flags_t> T get() const {
722 static_assert(sizeof(T) <= 8);
723 return bitcast<T>(flags_);
724 }
725 ///@}
726
727 using Def::as;
728 using Def::isa;
729
730 /// @name Casts
731 ///@{
732 /// @see @ref cast_lit
733 template<class T = nat_t> static std::optional<T> isa(const Def* def) {
734 if (!def) return {};
735 if (auto lit = def->isa<Lit>()) return lit->get<T>();
736 return {};
737 }
738 template<class T = nat_t> static T as(const Def* def) { return def->as<Lit>()->get<T>(); }
739 ///@}
740
741 static constexpr auto Node = mim::Node::Lit;
742
743private:
744 const Def* rebuild_(World&, const Def*, Defs) const final;
745
746 friend class World;
747};
748
749class Nat : public Def, public Setters<Nat> {
750public:
751 using Setters<Nat>::set;
752 static constexpr auto Node = mim::Node::Nat;
753
754private:
755 Nat(World& world);
756
757 const Def* rebuild_(World&, const Def*, Defs) const final;
758
759 friend class World;
760};
761
762/// A built-in constant of type `Nat -> *`.
763class Idx : public Def, public Setters<Idx> {
764private:
765 Idx(const Def* type)
766 : Def(Node, type, Defs{}, 0) {}
767
768public:
769 using Setters<Idx>::set;
770 using Def::as;
771 using Def::isa;
772
773 /// @name isa
774 ///@{
775
776 /// Checks if @p def is a `Idx s` and returns `s` or `nullptr` otherwise.
777 static const Def* isa(const Def* def);
778 static const Def* as(const Def* def) {
779 auto res = isa(def);
780 assert(res);
781 return res;
782 }
783 static std::optional<nat_t> isa_lit(const Def* def);
784 static nat_t as_lit(const Def* def) {
785 auto res = isa_lit(def);
786 assert(res.has_value());
787 return *res;
788 }
789 ///@}
790
791 /// @name Convert between Idx::isa and bitwidth and vice versa
792 ///@{
793 // clang-format off
794 static constexpr nat_t bitwidth2size(nat_t n) { assert(n != 0); return n == 64 ? 0 : (1_n << n); }
795 static constexpr nat_t size2bitwidth(nat_t n) { return n == 0 ? 64 : std::bit_width(n - 1_n); }
796 // clang-format on
797 static std::optional<nat_t> size2bitwidth(const Def* size);
798 ///@}
799
800 static constexpr auto Node = mim::Node::Idx;
801
802private:
803 const Def* rebuild_(World&, const Def*, Defs) const final;
804
805 friend class World;
806};
807
808class Proxy : public Def, public Setters<Proxy> {
809private:
810 Proxy(const Def* type, Defs ops, u32 pass, u32 tag)
811 : Def(Node, type, ops, (u64(pass) << 32_u64) | u64(tag)) {}
812
813public:
814 using Setters<Proxy>::set;
815
816 /// @name Getters
817 ///@{
818 u32 pass() const { return u32(flags() >> 32_u64); } ///< IPass::index within PassMan.
819 u32 tag() const { return u32(flags()); }
820 ///@}
821
822 static constexpr auto Node = mim::Node::Proxy;
823
824private:
825 const Def* rebuild_(World&, const Def*, Defs) const final;
826
827 friend class World;
828};
829
830/// @deprecated A global variable in the data segment.
831/// A Global may be mutable or immutable.
832/// @deprecated Will be removed.
833class Global : public Def, public Setters<Global> {
834private:
835 Global(const Def* type, bool is_mutable)
836 : Def(Node, type, 1, is_mutable) {}
837
838public:
839 using Setters<Global>::set;
840
841 /// @name ops
842 ///@{
843 const Def* init() const { return op(0); }
844 void set(const Def* init) { Def::set(0, init); }
845 ///@}
846
847 /// @name type
848 ///@{
849 const App* type() const;
850 const Def* alloced_type() const;
851 ///@}
852
853 /// @name Getters
854 ///@{
855 bool is_mutable() const { return flags(); }
856 ///@}
857
858 /// @name Rebuild
859 ///@{
860 Global* stub(const Def* type) { return stub_(world(), type)->set(dbg()); }
861 ///@}
862
863 static constexpr auto Node = mim::Node::Global;
864
865private:
866 const Def* rebuild_(World&, const Def*, Defs) const final;
867 Global* stub_(World&, const Def*) final;
868
869 friend class World;
870};
871
872} // namespace mim
Definition axm.h:9
Base class for all Defs.
Definition def.h:203
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:268
size_t num_deps() const noexcept
Definition def.h:305
const Def * set(Dbg d) const
Definition def.h:473
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:492
constexpr Node node() const noexcept
Definition def.h:226
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:241
void dot(std::ostream &os, uint32_t max=0xFFFFFF, bool types=false) const
Definition dot.cpp:127
void make_internal()
Definition def.cpp:483
virtual const Def * check(size_t i, const Def *def)
Checks whether the ith operand can be set to def.
Definition def.h:525
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Definition def.h:442
const Var * has_var() const
As above if this is a mutable.
Definition def.h:390
void dump() const
Definition dump.cpp:447
Defs deps() const noexcept
Definition def.cpp:405
auto projs() const
Definition def.h:368
u8 trip_
Definition def.h:595
bool has_dep(Dep d) const
Definition def.h:319
bool is_elim() const noexcept
Definition def.h:237
nat_t num_tprojs() const
As above but yields 1, if Flags::scalarize_threshold is exceeded.
Definition def.cpp:487
virtual ~Def()=default
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
Definition check.cpp:39
nat_t as_lit_arity() const
Definition def.h:257
bool has_dep(unsigned u) const
Definition def.h:320
World & world() const noexcept
Definition def.cpp:377
virtual const Def * check()
After all Def::ops have ben Def::set, this method will be invoked to check the type of this mutable.
Definition def.h:530
const Def * refine(size_t i, const Def *new_op) const
Definition def.cpp:225
Def * set_type(const Def *)
Update type.
Definition def.cpp:253
void dot(const std::string &file, uint32_t max=0xFFFFFF, bool types=false) const
Definition def.h:559
std::string_view node_name() const
Definition def.cpp:395
auto projs(nat_t a, F f) const
Definition def.h:364
bool is_intro() const noexcept
Definition def.h:236
constexpr auto ops() const noexcept
Definition def.h:266
Vars local_vars() const
Vars reachable by following immutable deps().
Definition def.cpp:295
void make_external()
Definition def.cpp:482
constexpr flags_t flags() const noexcept
Definition def.h:221
Dbg dbg_
Definition def.h:586
virtual Def * stub_(World &, const Def *)
Definition def.h:575
const Def * set(std::string s) const
Definition def.h:467
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:434
Vars free_vars()
Definition def.cpp:297
constexpr u32 mark() const noexcept
Used internally by free_vars().
Definition def.h:224
constexpr u32 tid() const noexcept
Trie id - only used in Trie.
Definition def.h:223
auto projs(nat_t a) const
Definition def.h:374
u8 curry_
Definition def.h:594
auto tprojs() const
Definition def.h:371
friend std::ostream & operator<<(std::ostream &, const Def *)
This will stream def as an operand.
Definition dump.cpp:419
bool is_term() const
Definition def.cpp:421
const Def * debug_prefix(std::string) const
Definition def.cpp:433
const Def * op(size_t i) const noexcept
Definition def.h:269
bool is_immutabilizable()
Definition def.cpp:174
virtual const Def * rebuild_(World &w, const Def *type, Defs ops) const =0
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:384
bool is_external() const
Definition def.h:419
void transfer_external(Def *to)
Definition def.h:422
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
Definition def.cpp:384
const Def * proj(nat_t i) const
As above but takes Def::num_projs as arity.
Definition def.h:345
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:350
bool is_open() const
Has free_vars()?
Definition def.cpp:364
constexpr size_t hash() const noexcept
Definition def.h:225
friend class World
Definition def.h:615
virtual const Def * immutabilize()
Tries to make an immutable from a mutable.
Definition def.h:504
const Def * zonk_mut()
zonks all ops of this mutable and tries to immutabilize it; if it succeeds return it.
Definition check.cpp:41
bool is_form() const noexcept
Definition def.h:235
Def * set(Dbg d)
Definition def.h:474
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
Definition def.cpp:280
Def * set(Sym s)
Definition def.h:466
const Def * debug_suffix(std::string) const
Definition def.cpp:434
const Def * set(Sym s) const
Definition def.h:465
Def * set(Loc l)
Definition def.h:464
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.h:247
const Def * dep(size_t i) const noexcept
Definition def.h:304
const Def * rebuild(World &w, const Def *type, Defs ops) const
Def::rebuilds this Def while using new_op as substitute for its i'th Def::op.
Definition def.h:496
const Def * set(Loc l, Sym s) const
Definition def.h:469
Def * set(std::string s)
Definition def.h:468
bool is_meta() const noexcept
Definition def.h:238
bool has_dep() const
Definition def.h:318
const Def * set(Loc l) const
Definition def.h:463
Loc loc() const
Definition def.h:454
void write(int max) const
Definition dump.cpp:455
auto tprojs(F f) const
Definition def.h:362
Def * set(Loc l, std::string s)
Definition def.h:472
friend class Sets
Definition def.h:614
const T * as_imm() const
Definition def.h:430
Def * stub(const Def *type)
Definition def.h:493
virtual constexpr size_t reduction_offset() const noexcept
First Def::op that needs to be dealt with during reduction; e.g.
Definition def.h:516
Sym sym() const
Definition def.h:455
nat_t num_projs() const
Yields Def::as_lit_arity(), if it is in fact a Lit, or 1 otherwise.
Definition def.h:340
std::optional< nat_t > isa_lit_arity() const
Definition def.cpp:462
std::ostream & stream(std::ostream &, int max) const
Definition dump.cpp:428
flags_t flags_
Definition def.h:593
friend void swap(World &, World &) noexcept
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
Definition def.h:222
const Def * arity() const
Definition def.cpp:455
Def * unset()
Unsets all Def::ops; works even, if not set at all or partially.
Definition def.cpp:259
std::string unique_name() const
name + "_" + Def::gid
Definition def.cpp:485
constexpr auto reduce(const Def *arg) const
Definition def.h:510
const Def * set(Loc l, std::string s) const
Definition def.h:471
const T * isa_imm() const
Definition def.h:429
Muts users()
Set of mutables where this mutable is locally referenced.
Definition def.h:412
bool is_closed() const
Has no free_vars()?
Definition def.cpp:356
const Def * rebuild(const Def *type, Defs ops) const
Definition def.h:500
Def * set(Loc l, Sym s)
Definition def.h:470
Dbg dbg() const
Definition def.h:453
Def * stub(World &w, const Def *type)
Definition def.h:492
u32 judge() const noexcept
Definition def.cpp:411
const Def * tproj(nat_t i) const
As above but takes Def::num_tprojs.
Definition def.h:346
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
Definition def.h:388
constexpr size_t num_ops() const noexcept
Definition def.h:270
const Def * init() const
Definition def.h:843
void set(const Def *init)
Definition def.h:844
Global * stub(const Def *type)
Definition def.h:860
const Def * alloced_type() const
Definition def.cpp:544
friend class World
Definition def.h:869
bool is_mutable() const
Definition def.h:855
const App * type() const
Definition def.cpp:543
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:111
Global * stub_(World &, const Def *) final
Definition def.cpp:150
static constexpr auto Node
Definition def.h:863
This node is a hole in the IR that is inferred by its context later on.
Definition check.h:10
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:112
static constexpr auto Node
Definition def.h:800
static nat_t as_lit(const Def *def)
Definition def.h:784
static constexpr nat_t size2bitwidth(nat_t n)
Definition def.h:795
static constexpr nat_t bitwidth2size(nat_t n)
Definition def.h:794
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
Definition def.cpp:519
friend class World
Definition def.h:805
static std::optional< nat_t > isa_lit(const Def *def)
Definition def.cpp:527
static const Def * as(const Def *def)
Definition def.h:778
static constexpr auto Node
Definition def.h:741
static std::optional< T > isa(const Def *def)
Definition def.h:733
friend class World
Definition def.h:746
T get() const
Definition def.h:721
static T as(const Def *def)
Definition def.h:738
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:121
friend class World
Definition def.h:759
static constexpr auto Node
Definition def.h:752
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:113
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:125
friend class World
Definition def.h:827
static constexpr auto Node
Definition def.h:822
u32 pass() const
IPass::index within PassMan.
Definition def.h:818
u32 tag() const
Definition def.h:819
CRTP-based Mixin to declare setters for Def::loc & Def::name using a covariant return type.
Definition def.h:148
P * set(Loc l, Sym s)
Definition def.h:162
P * set(std::string s)
Definition def.h:160
const P * set(Sym s) const
Definition def.h:157
const P * set(Loc l, Sym s) const
Definition def.h:161
const P * set(Loc l) const
Definition def.h:155
P * set(Loc l)
Definition def.h:156
const P * set(Dbg d) const
Definition def.h:165
const P * set(Loc l, std::string s) const
Definition def.h:163
P * set(Sym s)
Definition def.h:158
P * set(Dbg d)
Definition def.h:166
P * set(Loc l, std::string s)
Definition def.h:164
const P * set(std::string s) const
Definition def.h:159
friend class World
Definition def.h:708
static constexpr auto Node
Definition def.h:703
const Def * level() const
Definition def.h:700
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:130
const Def * op() const
Definition def.h:678
static constexpr auto Node
Definition def.h:682
friend class World
Definition def.h:687
level_t offset() const
Definition def.h:679
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:131
static constexpr auto Node
Definition def.h:658
friend class World
Definition def.h:665
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:132
static constexpr auto Node
Definition def.h:644
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:114
friend class World
Definition def.h:652
const Def * rebuild_(World &, const Def *, Defs) const final
Definition def.cpp:134
static constexpr auto Node
Definition def.h:633
friend class World
Definition def.h:638
Def * mut() const
Definition def.h:630
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
Definition vector.h:17
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:33
#define MIM_NODE(m)
Definition def.h:17
#define MIM_PROJ(NAME, CONST)
Use as mixin to wrap all kind of Def::proj and Def::projs variants.
Definition def.h:127
Definition ast.h:14
View< const Def * > Defs
Definition def.h:49
u64 nat_t
Definition types.h:43
DefMap< const Def * > Def2Def
Definition def.h:48
Vector< const Def * > DefVec
Definition def.h:50
D bitcast(const S &src)
A bitcast from src of type S to D.
Definition util.h:22
Dep
Tracks a dependency to certain Defs transitively through the Def::deps() up to but excliding mutables...
Definition def.h:97
@ None
Definition def.h:98
@ Mut
Definition def.h:99
u64 flags_t
Definition types.h:45
u8 node_t
Definition types.h:44
Span< const T, N > View
Definition span.h:93
absl::flat_hash_map< K, V, GIDHash< K > > GIDMap
Definition util.h:176
GIDSet< const Var * > VarSet
Definition def.h:66
GIDMap< const Var *, To > VarMap
Definition def.h:65
Sets< Def >::Set Muts
Definition def.h:59
u64 level_t
Definition types.h:42
GIDMap< const Def *, To > DefMap
Definition def.h:46
GIDSet< Def * > MutSet
Definition def.h:57
MutMap< Def * > Mut2Mut
Definition def.h:58
GIDSet< const Def * > DefSet
Definition def.h:47
static constexpr size_t Num_Nodes
Definition def.h:90
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Definition def.h:71
Sets< const Var >::Set Vars
Definition def.h:68
uint32_t u32
Definition types.h:34
uint64_t u64
Definition types.h:34
Judge
Judgement.
Definition def.h:106
@ Intro
Term Introduction like λ(x: Nat): Nat = x.
Definition def.h:109
@ Meta
Meta rules for Universe and Type levels.
Definition def.h:111
@ Form
Type Formation like T -> T.
Definition def.h:108
@ Elim
Term Elimination like f a.
Definition def.h:110
absl::flat_hash_set< K, GIDHash< K > > GIDSet
Definition util.h:177
uint8_t u8
Definition types.h:34
Sort
TODO remove or fix this.
Definition def.h:94
@ Level
Definition def.h:94
@ Term
Definition def.h:94
@ Space
Definition def.h:94
@ Kind
Definition def.h:94
Node
Definition def.h:83
@ Nat
Definition def.h:85
@ Univ
Definition def.h:85
@ Idx
Definition def.h:85
@ UInc
Definition def.h:85
@ Global
Definition def.h:85
@ Var
Definition def.h:85
@ Axm
Definition def.h:85
@ Type
Definition def.h:85
@ App
Definition def.h:85
@ Lit
Definition def.h:85
@ Proxy
Definition def.h:85
CODE(node, name, _)
Definition def.h:84
@ UMax
Definition def.h:85
Vector(I, I, A=A()) -> Vector< typename std::iterator_traits< I >::value_type, Default_Inlined_Size< typename std::iterator_traits< I >::value_type >, A >
GIDMap< Def *, To > MutMap
Definition def.h:56
VarMap< const Var * > Var2Var
Definition def.h:67