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