15using namespace std::literals;
26 , node_(unsigned(node))
35 , num_ops_(ops.size())
37 std::ranges::copy(
ops, ops_ptr());
40 if (
auto var = isa<Var>()) {
64 :
Def(nullptr, n, type, ops, flags) {}
78 muts_.fv_consumers =
Muts();
79 std::fill_n(ops_ptr(),
num_ops,
nullptr);
84 :
Def(Node, world.type(),
Defs{}, 0) {}
86UMax::UMax(World& world,
Defs ops)
87 : Def(Node, world.univ(), ops, 0) {}
96Ref Infer ::rebuild_(World&, Ref,
Defs )
const { fe::unreachable(); }
97Ref Global ::rebuild_(World&, Ref,
Defs )
const { fe::unreachable(); }
98Ref Idx ::rebuild_(World& w, Ref ,
Defs )
const {
return w.type_idx(); }
99Ref Nat ::rebuild_(World& w, Ref ,
Defs )
const {
return w.type_nat(); }
100Ref Univ ::rebuild_(World& w, Ref ,
Defs )
const {
return w.univ(); }
101Ref Ac ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.ac(t, o); }
102Ref App ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.app(o[0], o[1]); }
103Ref Arr ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.arr(o[0], o[1]); }
104Ref Extract ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.extract(o[0], o[1]); }
105Ref Insert ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.insert(o[0], o[1], o[2]); }
106Ref Lam ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.lam(
t->as<Pi>(), o[0], o[1]); }
107Ref Lit ::rebuild_(World& w, Ref t,
Defs )
const {
return w.lit(t,
get()); }
108Ref Pack ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.pack(
t->arity(), o[0]); }
109Ref Pi ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.pi(o[0], o[1], is_implicit()); }
110Ref Pick ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.pick(t, o[0]); }
111Ref Proxy ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.proxy(t, o, pass(), tag()); }
112Ref Sigma ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.sigma(o); }
114Ref Type ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.type(o[0]); }
115Ref Test ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.test(o[0], o[1], o[2], o[3]); }
116Ref Tuple ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.tuple(t, o); }
117Ref UInc ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.uinc(o[0], offset()); }
118Ref UMax ::rebuild_(World& w, Ref ,
Defs o)
const {
return w.umax(o); }
119Ref Var ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.var(t, o[0]->as_mut()); }
120Ref Vel ::rebuild_(World& w, Ref t,
Defs o)
const {
return w.vel(t, o[0])->set(
dbg()); }
122Ref Axiom ::rebuild_(World& w, Ref t,
Defs )
const {
123 if (&w != &world())
return w.axiom(normalizer(), curry(), trip(), t, plugin(), tag(),
sub())->set(
dbg());
141Pi* Pi ::stub_(
World& w,
Ref t) {
return w.mut_pi (t, is_implicit()); }
184 if (
auto n =
Lit::isa(
shape()); n && *n < w.flags().scalerize_threshold)
185 return w.sigma(
DefVec(*n, [&](
size_t i) {
return reduce(w.lit_idx(*n, i)); }));
194 if (
auto n =
Lit::isa(
shape()); n && *n < w.flags().scalerize_threshold)
195 return w.tuple(
DefVec(*n, [&](
size_t i) {
return reduce(w.lit_idx(*n, i)); }));
205 if (
auto mut = isa_mut<Arr>())
return rewrite(1, mut, arg);
210 if (
auto mut = isa_mut<Pack>())
return rewrite(0, mut, arg);
215 if (
auto mut =
isa_mut())
return mut->reduce(arg);
220 auto& cache =
world().move_.cache;
221 if (
auto i = cache.find({this, arg}); i != cache.end())
return i->second;
223 return cache[{
this, arg}] =
rewrite(
this, arg);
236void Def::finalize() {
241 const auto& p =
op->uses_.emplace(
this, i);
242 assert_unused(p.second);
256 assert(def && !
op(i) && curr_op_ == i);
258 curr_op_ = (curr_op_ + 1) %
num_ops();
261 const auto& p = def->uses_.emplace(
this, i);
262 assert_unused(p.second);
277 for (
size_t i = 0, e =
num_ops(); i != e; ++i) {
281 assert(std::all_of(ops_ptr() + i + 1, ops_ptr() +
num_ops(), [](
auto op) {
return !
op; }));
290 assert(
op(i) &&
op(i)->uses_.contains(
Use(
this, i)));
291 op(i)->uses_.erase(
Use(
this, i));
292 ops_ptr()[i] =
nullptr;
316 if (
num_ops() == 0)
return true;
317 bool result =
ops().back();
318 assert((!result || std::ranges::all_of(
ops().rsubspan(1), [](
auto op) {
return op; }))
319 &&
"the last operand is set but others in front of it aren't");
333 if (
auto mut =
isa_mut())
return mut->free_vars();
347 for (
bool todo =
true; todo;) {
361 if (valid_ || mark_ == run)
return vars_.free;
364 auto fvs0 = vars_.free;
371 local_mut->muts_.fv_consumers =
world().
insert(local_mut->muts_.fv_consumers,
this);
372 fvs =
world().
merge(fvs, local_mut->free_vars(todo, run));
379 return vars_.free = fvs;
382void Def::validate() {
388 if (!local_mut->valid_) local_mut->validate();
392void Def::invalidate() {
397 muts_.fv_consumers.clear();
403#ifdef THORIN_ENABLE_CHECKS
422 if (isa<Univ>())
return *world_;
429 if (
auto t = isa<Type>())
return world().
type(
world().uinc(t->level()));
439#define CODE(op, abbr) \
440 case Node::op: return #abbr;
443 default: fe::unreachable();
448 if (isa<Type>() || isa<Univ>())
return Defs();
450 return Defs(ops_ptr() - 1, (
is_set() ? num_ops_ : 0) + 1);
468 if (var_)
return var_;
471 if (w.is_frozen())
return nullptr;
472 if (
auto lam = isa<Lam >())
return w.var(lam ->dom(), lam);
473 if (
auto pi = isa<Pi >())
return w.var(pi ->dom(), pi);
474 if (
auto sig = isa<Sigma>())
return w.var(sig, sig);
475 if (
auto arr = isa<Arr >())
return w.var(w.type_idx(arr ->shape()), arr );
476 if (
auto pack = isa<Pack >())
return w.var(w.type_idx(pack->shape()), pack);
477 if (isa<Bound >())
return w.var(
this,
this);
478 if (isa<Infer >())
return nullptr;
479 if (isa<Global>())
return nullptr;
484 if (
auto t =
type()) {
485 if (
auto u = t->type()) {
487 if (
auto level =
Lit::isa(
type->level()))
return *level == 0;
495 if (
auto sigma = isa<Sigma>())
return world().
lit_nat(sigma->num_ops());
496 if (
auto arr = isa<Arr >())
return arr->shape();
497 if (
auto t =
type())
return t->arity();
502 if (
auto sigma = isa<Sigma>())
return sigma->
num_ops();
503 if (
auto arr = isa<Arr >())
return Lit::isa(arr->shape());
504 if (
auto t =
type())
return t->isa_lit_arity();
510bool Def::equal(
const Def* other)
const {
511 if (isa<Univ>() || this->
isa_mut() || other->
isa_mut())
return this == other;
516 for (
size_t i = 0, e =
num_ops(); result && i != e; ++i) result &= this->
op(i) == other->
op(i);
532 static constexpr int Search_In_Uses_Threshold = 8;
535 if (!
type())
return this;
536 if (!isa_mut<Sigma>() && !
type()->isa_mut<Sigma>())
return this;
541 if (isa<Tuple>() || isa<Sigma>()) {
543 }
else if (
auto arr = isa<Arr>()) {
544 if (arr->arity()->isa<
Top>())
return arr->body();
545 return arr->reduce(w.lit_idx(a, i));
546 }
else if (
auto pack = isa<Pack>()) {
547 if (pack->arity()->isa<
Top>())
return pack->body();
548 assert(!w.is_frozen() &&
"TODO");
549 return pack->reduce(w.lit_idx(a, i));
552 if (w.is_frozen() ||
uses().size() < Search_In_Uses_Threshold) {
553 for (
auto u :
uses()) {
554 if (
auto ex = u->isa<
Extract>(); ex && ex->
tuple() ==
this) {
555 if (
auto index =
Lit::isa(ex->index()); index && *index == i)
return ex;
559 if (w.is_frozen())
return nullptr;
562 return w.extract(
this, a, i);
570 if (
auto app = def->isa<
App>()) {
571 if (app->callee()->isa<
Idx>())
return app->arg();
578 if (
size->isa<
Top>())
return 64;
A (possibly paramterized) Array.
const Def * reduce(const Def *arg) const
const Def * shape() const
const Def * immutabilize() override
Tries to make an immutable from a mutable.
static bool alpha(Ref d1, Ref d2)
Are d1 and d2 α-equivalent?
Def * reset(size_t i, const Def *def)
Successively reset from left to right.
const Def * refine(size_t i, const Def *new_op) const
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
std::string unique_name() const
name + "_" + Def::gid
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.
Def * set_type(const Def *)
const Def * op(size_t i) const
const Uses & uses() const
const Def * debug_prefix(std::string) 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.
DefVec reduce(const Def *arg) const
Rewrites Def::ops by substituting this mutable's Var with arg.
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.
bool is_term() const
Yields true if this:T and T:(.Type 0).
bool is_closed() const
Has no free_vars()?
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.
const Def * debug_suffix(std::string) const
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.
virtual Ref rebuild_(World &w, Ref type, Defs ops) const =0
const Def * alloced_type() const
Global * stub_(World &, Ref) override
A built-in constant of type .Nat -> *.
static Ref size(Ref def)
Checks if def is a .Idx s and returns s or nullptr otherwise.
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)
A (possibly paramterized) Tuple.
const Def * shape() const
const Def * immutabilize() override
Tries to make an immutable from a mutable.
const Def * reduce(const Def *arg) const
A dependent function type.
const Pi * immutabilize() override
Tries to make an immutable from a mutable.
constexpr bool contains(const T &elem) const
constexpr bool empty() const noexcept
Helper class to retrieve Infer::arg if present.
const Def * immutabilize() override
Tries to make an immutable from a mutable.
This is a thin wrapper for std::span<T, N> with the following additional features:
Specific Bound depending on Up.
Ref rebuild_(World &, Ref, Defs) const override
TBound * stub_(World &, Ref) override
Extremum. Either Top (Up) or Bottom.
TExt * stub_(World &, Ref) override
Ref rebuild_(World &, Ref, Defs) const override
static constexpr size_t Type
The World represents the whole program and manages creation of Thorin nodes (Defs).
Ref insert(Ref d, Ref i, Ref val)
Vars erase(Vars vars, const Var *var)
Flags & flags()
Retrive compile Flags.
void make_external(Def *def)
Sym sym(std::string_view)
Vars vars(const Var *var)
const Pi * pi(Ref dom, Ref codom, bool implicit=false)
void make_internal(Def *def)
const Lit * lit_nat(nat_t a)
Vars merge(Vars a, Vars b)
const Type * type(Ref level)
void * get(void *handle, const char *symbol_name)
DefVec rewrite(Def *mut, Ref arg)
hash_t murmur3_finalize(hash_t h, hash_t len)
uint64_t scalerize_threshold
hash_t murmur3(hash_t h, uint32_t key)
Vector< const Def * > DefVec
hash_t murmur3_rest(hash_t h, uint8_t key)
PooledSet< const Var * > Vars