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