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