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