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) \
29 m(Nat, nat) m(Idx, idx) \
33 m(Singleton, singleton)
40#define CODE(node, name) node,
44#define CODE(node, name) +size_t(1)
95 operator const Def*()
const {
return refer(def_); }
96 explicit operator bool()
const {
return def_; }
100 const Def* def_ =
nullptr;
111 static constexpr size_t Type = -1_s;
118 size_t index()
const {
return index_; }
120 operator const Def*()
const {
return def_; }
122 bool operator==(
Use other)
const {
return this->def_ == other.def_ && this->index_ == other.index_; }
137using Uses = absl::flat_hash_set<Use, UseHash, UseEq>;
146enum class Dep :
unsigned {
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); \
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); }
176#define THORIN_SETTERS_(T) \
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; }
193# define THORIN_SETTERS(T) public:
195# define THORIN_SETTERS(T) THORIN_SETTERS_(T)
198#define THORIN_DEF_MIXIN(T) \
201 static constexpr auto Node = Node::T; \
204 Ref rebuild_(World&, Ref, Defs) const override; \
222class Def :
public fe::RuntimeCast<Def> {
224 Def& operator=(
const Def&) =
delete;
261 assert(a.has_value());
335 unsigned dep()
const {
return dep_; }
370 using R = std::decay_t<
decltype(f(
this))>;
371 if constexpr (A == -1_n) {
375 std::array<R, A> array;
376 for (
nat_t i = 0; i != A; ++i) array[i] = f(
proj(A, i));
384 using R = std::decay_t<
decltype(f(
this))>;
388 return projs<A>([](
const Def* def) {
return def; });
391 return tprojs([](
const Def* def) {
return def; });
394 return projs(a, [](
const Def* def) {
return def; });
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); }
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;
453 return mut_ ^ invert ?
const_cast<Def*
>(
this)->
template isa<T>() :
nullptr;
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);
462 return const_cast<Def*
>(
this)->
template as<T>();
469 Loc
loc()
const {
return dbg_.loc; }
470 Sym
sym()
const {
return dbg_.sym; }
471 std::string unique_name()
const;
484 const Def* debug_prefix(std::string)
const;
485 const Def* debug_suffix(std::string)
const;
487 const Def* debug_prefix(std::string)
const {
return this; }
488 const Def* debug_suffix(std::string)
const {
return this; }
500 return rebuild_(w, type, ops)->set(dbg());
508 const Def* refine(
size_t i,
const Def* new_op)
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;
533 void dot(std::ostream& os, uint32_t max = 0xFFFFFF,
bool types =
false)
const;
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);
545 Sym sym(
const char*)
const;
546 Sym sym(std::string_view)
const;
547 Sym sym(std::string)
const;
554 Vars free_vars(
bool&, uint32_t run);
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)));
575 mutable World* world_;
592 union LocalOrFreeVars {
599 union LocalOrConsumerMuts {
600 LocalOrConsumerMuts() {}
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)...);
629using DefDef = std::tuple<const Def*, const Def*>;
644template<
class To>
using DefDefMap = absl::flat_hash_map<DefDef, To, DefDefHash, DefDefEq>;
645using DefDefSet = absl::flat_hash_set<DefDef, DefDefHash, DefDefEq>;
651 :
Def(Node, type,
Defs{mut}, 0) {}
665 :
Def(&world, Node,
nullptr,
Defs{}, 0) {}
680 :
Def(Node, op->
type()->as<
Univ>(), {op}, offset) {}
685 const Def*
op()
const {
return Def::op(0); }
695 :
Def(Node,
nullptr, {level}, 0) {}
709 :
Def(Node, type,
Defs{}, val) {}
714 template<
class T = flags_t> T
get()
const {
715 static_assert(
sizeof(T) <= 8);
716 return bitcast<T>(flags_);
726 template<
class T = nat_t>
static std::optional<T>
isa(
Ref def) {
728 if (
auto lit = def->isa<
Lit>())
return lit->get<T>();
731 template<
class T = nat_t>
static T
as(
Ref def) {
return def->as<
Lit>()->get<T>(); }
748 :
Def(Node, type,
Defs{}, 0) {}
760 static std::optional<nat_t> size2bitwidth(
const Def* size);
769 :
Def(Node, type, ops, (
u64(pass) << 32_u64) |
u64(tag)) {}
787 :
Def(Node, type, 1, is_mutable) {}
794 void set(
const Def* init) { Def::set(0, init); }
799 const App* type()
const;
800 const Def* alloced_type()
const;
Def * reset(size_t i, const Def *def)
Successively reset from left to right.
nat_t as_lit_arity() const
virtual Def * stub_(World &, Ref)
Ref var()
Not necessarily a Var: E.g., if the return type is [], this will yield ().
void update()
Resolves Infers of this Def's type.
std::optional< nat_t > isa_lit_arity() const
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == -1_n) or std::array (otherwise).
const T * isa_imm(R(T::*f)() const) const
size_t num_extended_ops() const
Ref rebuild(Ref type, Defs ops) const
Defs extended_ops() const
bool is_open() const
Has free_vars()?
bool is_set() const
Yields true if empty or the last op is set.
auto projs(nat_t a, F f) const
auto projs(nat_t a) const
size_t num_partial_ops() const
bool has_dep(Dep d) const
virtual const Def * immutabilize()
Tries to make an immutable from a mutable.
Def * set_type(const Def *)
const T * isa_imm() const
void transfer_external(Def *to)
const Def * op(size_t i) const
Def * stub(World &w, Ref type)
const Uses & uses() const
bool has_dep(unsigned u) const
Def * unset()
Unsets all Def::ops; works even, if not set at all or partially.
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.
const Def * type() const
Yields the raw type of this Def, i.e. maybe nullptr.
std::string_view node_name() const
T * isa_mut() const
If this is *mut*able, it will cast constness away and perform a dynamic_cast to T.
void dot(const std::string &file, uint32_t max=0xFFFFFF, bool types=false) const
bool is_term() const
Yields true if this:T and T:(.Type 0).
bool is_closed() const
Has no free_vars()?
const Def * partial_op(size_t i) const
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
const Def * unfold_type() const
Yields the type of this Def and builds a new .Type (UInc n) if necessary.
nat_t num_projs() const
Yields Def::as_lit_arity(), if it is in fact a Lit, or 1 otherwise.
friend void swap(World &, World &) noexcept
const Def * extended_op(size_t i) const
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
nat_t num_tprojs() const
As above but yields 1, if Flags::scalerize_threshold is exceeded.
Def * set(size_t i, const Def *def)
Successively set from left to right.
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.
const Var * has_var() const
As above if this is a mutable.
const Def * proj(nat_t i) const
As above but takes Def::num_projs as arity.
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.
void set(const Def *init)
A built-in constant of type .Nat -> *.
static constexpr nat_t bitwidth2size(nat_t n)
static constexpr nat_t size2bitwidth(nat_t n)
This node is a hole in the IR that is inferred by its context later on.
static std::optional< T > isa(Ref def)
u32 pass() const
IPass::index within PassMan.
Helper class to retrieve Infer::arg if present.
const Def * operator->() const
const Def * operator*() const
static const Def * refer(const Def *def)
Retrieves Infer::arg from def.
This is a thin wrapper for std::span<T, N> with the following additional features:
const Def * level() const
bool operator==(Use other) const
const Def * operator->() const
Use(const Def *def, size_t index)
The World represents the whole program and manages creation of Thorin nodes (Defs).
#define THORIN_SETTERS_(T)
Use as mixin to declare setters for Def::loc & Def::name using a covariant return type.
#define THORIN_PROJ(NAME, CONST)
Use as mixin to wrap all kind of Def::proj and Def::projs variants.
#define THORIN_DEF_MIXIN(T)
Ref(*)(Ref, Ref, Ref) NormalizeFn
hash_t murmur3_finalize(hash_t h, hash_t len)
std::tuple< const Def *, const Def * > DefDef
GIDMap< Def *, To > MutMap
GIDSet< const Var * > VarSet
absl::flat_hash_set< Use, UseHash, UseEq > Uses
hash_t hash_combine(hash_t seed, T v)
Returns a new hash by combining the hash seed with val.
VarMap< const Var * > Var2Var
bool equal(R range1, S range2)
}@
DefMap< const Def * > Def2Def
absl::flat_hash_map< K, V, GIDHash< K >, GIDEq< K > > GIDMap
GIDSet< const Def * > DefSet
hash_t hash(const char *)
hash_t murmur3(hash_t h, uint32_t key)
std::ostream & operator<<(std::ostream &, const CFNode *)
absl::flat_hash_set< DefDef, DefDefHash, DefDefEq > DefDefSet
std::string fmt(const char *s, Args &&... args)
Wraps thorin::print to output a formatted std:string.
absl::flat_hash_set< K, GIDHash< K >, GIDEq< K > > GIDSet
GIDMap< const Def *, To > DefMap
absl::flat_hash_map< DefDef, To, DefDefHash, DefDefEq > DefDefMap
GIDMap< const Var *, To > VarMap
PooledSet< const Var * > Vars
bool operator()(DefDef p1, DefDef p2) const
hash_t operator()(DefDef pair) const
bool operator()(Use u1, Use u2) const
hash_t operator()(Use) const
#define THORIN_ENUM_OPERATORS(E)
Use this to declare all kind of bit and comparison operators for an enum E.