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