7#include <fe/worklist.h>
13using namespace std::literals;
16template void fe::Patricia<const mim::Var, mim::DefKey>::Set::dump()
const;
17template void fe::Patricia<mim::Def, mim::DefKey>::Set::dump()
const;
22std::ostream&
DefKey::stream(std::ostream& os,
const Def* d) {
return os << d->sym() <<
": " << d->gid(); }
39 return fe::to_underlying(dep);
51 , num_ops_(
ops.size())
57 hash_ = fe::hash_begin(
u8(
node));
58 hash_ = fe::hash_combine(hash_,
flags_);
63 vars_ =
type->local_vars();
64 muts_ =
type->local_muts();
65 hash_ = fe::hash_combine(hash_,
type->gid());
76 for (
size_t i = 0, e =
ops.size(); i != e; ++i) {
79 hash_ = fe::hash_combine(hash_,
op->
gid());
82 for (
size_t i = 0, e =
ops.size(); i != e; ++i) {
88 hash_ = fe::hash_combine(hash_,
op->
gid());
108 hash_ = fe::hash(
gid());
110 std::fill_n(ops_ptr(),
num_ops,
nullptr);
124 gid_ = binder->
world().next_gid();
125 vars_ =
Vars(as<Var>());
127 hash_ = fe::hash_combine(hash_, binder->
gid());
130Nat::Nat(
World& world)
133UMax::UMax(World& world,
Defs ops)
134 : Def(Node, world.univ(), ops, 0) {}
141 if (!
is_set())
return false;
147 if (mut ==
this)
return false;
156Defs Def::reduce_(
const Def* arg)
const {
159 return {
ops().begin() + off,
num_ops() - off};
166void Def::watch()
const {
167#ifdef MIM_ENABLE_CHECKS
172Def* Def::finalize() {
181 size_t n =
ops.size();
182 assert(n ==
num_ops() &&
"num ops don't match");
184 for (
size_t i = 0; i != n; ++i) {
200 assert(def && !
op(i) && curr_op_++ == i);
203 if (i + 1 ==
num_ops())
return finalize();
218 std::fill_n(ops_ptr(),
num_ops(),
nullptr);
227 if (var_)
return var_;
234 case Node::Lam:
return as<Lam >()->dom();
235 case Node::Pi:
return as<Pi >()->dom();
244 default: fe::unreachable();
250 if (
auto mut =
isa_mut())
return mut->free_vars();
255 fvs =
vars.merge(fvs, mut->free_vars());
264 if (
auto mut = def->
isa_mut())
return f(mut->free_vars());
268 if (f(mut->free_vars()))
return true;
294 for (
bool todo = cyclic; todo;) {
314 if (mark_ != 0 && mark_ != run - 1) {
315 if constexpr (init) todo |= mark_ == run;
323 auto& muts = w.muts();
324 auto&
vars = w.vars();
330 if constexpr (init) mut->muts_ = muts.insert(mut->muts_,
this);
331 fvs =
vars.merge(fvs, mut->free_vars<init>(w, todo, run));
337 if constexpr (!
init) todo |= fvs0 != fvs;
342void Def::invalidate() {
346 for (
auto mut :
users())
355 assert((!
is_external() || closed) &&
"an external must not have free Vars");
361 if (fvs.empty())
return isa_mut();
363 return fvs.min()->binder()->outermost_binder();
369 if (fvs.contains(
var))
return true;
370 if (
auto [_, ins] = checked.emplace(mut); !ins)
return false;
373 if (this->
nests(fv->binder(), checked))
return true;
379 if (!this->
has_var())
return false;
381 return this->
nests(mut, checked);
386 if (!this->
has_var())
return false;
390 if (this->
nests(fv->binder(), checked))
return true;
404 if (
auto loc = w.get_loc())
return loc;
408 auto queue = fe::BFSWorklist<DefSet>{
this};
412 constexpr size_t Budget = 512;
413 auto budget = Budget;
415 while (!queue.empty()) {
416 for (
auto dep : queue.pop()->
deps()) {
417 if (budget-- == 0)
return {};
418 if (!queue.push(
dep))
continue;
438 auto mine =
dbg(), merged = mine;
439 if (!merged.loc()) merged.set(d.loc());
440 if (!merged.sym()) merged.set(d.sym());
441 if (!(merged == mine))
set_dbg(merged);
447 if (ow || !dbg_ || dbg_ == key)
return void(dbg_ = key);
452 if (
auto t =
type())
return t;
454 if (
auto t = isa<Type>())
return w.type(w.uinc(t->level()));
460 static constexpr std::string_view Names[Num_Nodes] = {
461#define CODE(node, _) #node,
472 assert((
const void*)(ops_ptr() - 1) == (
const void*)&type_
473 &&
"Def::type_ must stay Def's last member: Def::deps() and Def::ops_ptr() depend on it");
477 assert(isa<Univ>() || isa<Type>() || isa<Var>());
482 bool set = num_ops_ == 0 || ops_ptr()[num_ops_ - 1];
483 return Defs(ops_ptr() - 1, (
set ? num_ops_ : 0) + 1);
488 if (
auto u = t->type())
503 if (a == b)
return Cmp::E;
513 if (a->is_mutable())
return Cmp::U;
515 if (
auto va = a->isa<
Var>()) {
516 auto vb = b->as<
Var>();
518 auto mb = vb->binder();
520 if (mb->is_set() && mb->free_vars().contains(va))
return Cmp::G;
525 for (
size_t i = a->num_ops(); i-- != 0;)
526 if (
auto res =
cmp(a->op(i), b->
op(i)); res ==
Cmp::L || res ==
Cmp::G)
return res;
528 return cmp(a->type(), b->
type());
532bool Def::cmp_(
const Def* a,
const Def* b) {
533 auto res =
cmp(a, b);
535 a->world().log().w(
"commute check resorts to an unstable gid-based compare");
536 return c ==
Cmp::L ? a->gid() < b->
gid() : a->gid() > b->
gid();
542bool Def::less (
const Def* a,
const Def* b) {
return cmp_<Cmp::L>(a, b); }
543bool Def::greater(
const Def* a,
const Def* b) {
return cmp_<Cmp::G>(a, b); }
563 auto seq = as<Seq>();
566 return arr ? w.arr(seq->arity(), seq->body()) : w.pack(seq->arity(), seq->body());
568 if (
auto n =
Lit::isa(seq->arity()); n && *n < w.flags().scalarize_threshold) {
569 auto elems =
DefVec(*n, [&](
size_t i) {
return seq->reduce(w.lit_idx(*n, i)); });
570 return arr ? w.sigma(elems) : w.tuple(elems);
574 default:
return nullptr;
588 default:
return size_t(-1);
597 if (
auto arr =
type()->isa<Arr>())
return arr->
arity();
600 if (
auto t =
type(); t && !t->isa<
Type>())
return t->arity();
611 assert(this->
sym() == to->
sym());
625 assert(i == 0 &&
"only inhabitant of Idx 2 is 0_1");
631 if (
auto seq = isa<Seq>()) {
632 if (seq->has_var())
return seq->reduce(
world().lit_idx(a, i));
636 if (isa<Prod>())
return op(i);
646 if (
auto app = def ? def->isa<
App>() :
nullptr) {
647 if (app->callee()->isa<Idx>())
return app->arg();
655 if (
auto l =
Lit::isa(size))
return l;
660 if (size->isa<
Top>())
return 64;
Loc err_loc() const
Returns a blame Loc from World::get_loc, this Def, or its nearest located dependency,...
void set_dbg(Dbg) const
Interns dbg via Driver::dbg and stores the key in Def::dbg_.
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.
constexpr Node node() const noexcept
Def * set(size_t i, const Def *)
Successively set from left to right.
Defs deps() const noexcept
nat_t num_tprojs() const
As above but yields 1, if Flags::scalarize_threshold is exceeded.
const Def * zonk() const
If Holes have been filled, reconstruct the program without them.
World & world() const noexcept
Def * set_type(const Def *)
Update type.
std::string_view node_name() const
fe::Error & error() const noexcept
constexpr auto ops() const noexcept
Vars local_vars() const
Vars reachable by following immutable deps().
size_t reduction_offset() const noexcept
First Def::op that needs to be dealt with during reduction; e.g.
constexpr flags_t flags() const noexcept
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
bool is_term() const
Is this Def a term, i.e. is its type() a Type?
const Def * debug_prefix(std::string) const
const Def * op(size_t i) const noexcept
bool is_immutabilizable()
const Def * var(nat_t a, nat_t i) noexcept
void transfer_external(Def *to)
const Def * unfold_type() const
Yields the type of this Def and builds a new Type (UInc n) if necessary.
bool has_free_vars() const
Same as !free_vars().empty().
bool has_free_var(const Var *) const
Same as free_vars().contains(var).
void set_dbg_(Dbg, bool ow) const
Backs Def::set(Dbg).
Muts local_muts() const
Mutables reachable by following immutable deps(); mut->local_muts() is by definition the set { mut }...
const Def * debug_suffix(std::string) const
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Def * outermost_binder() const
Transitively walks up free_vars() till the outermoust binder has been found.
bool nests(Def *mut)
Does this nest mut?
const Def * dep(size_t i) const noexcept
bool is_mutable() const noexcept
bool is_external() const noexcept
static bool less(const Def *a, const Def *b)
static bool greater(const Def *a, const Def *b)
const Def * var()
Not necessarily a Var: E.g., if the return type is [], this will yield ().
static Cmp cmp(const Def *a, const Def *b)
Driver & driver() const noexcept
const Def * immutabilize()
const Def * var_type()
If this is a binder, compute the type of its Variable.
constexpr u32 gid() const noexcept
Global id - unique number for this Def.
const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
Def * unset()
Unsets all Def::ops; works even, if not set at all or only partially set.
std::string unique_name() const
name + "_" + Def::gid
void set_dbg_key_(DbgKey, bool ow) const
Backs Def::set(DbgKey).
Muts users()
Set of mutables where this mutable is locally referenced.
bool is_closed() const
Same as !has_free_vars().
Vars free_vars() const
Global set of free Vars: extends local_vars() by transitively following mutables as well.
Dbg dbg() const
Looks up Def::dbg_ in Driver::dbg.
const Def * check(size_t i, const Def *def)
Checks whether the ith operand can be set to def.
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
bool has_free_vars_in(Vars) const
Same as vars.has_intersection(free_vars()).
constexpr size_t num_ops() const noexcept
Some "global" variables needed all over the place.
const Def * alloced_type() const
static constexpr nat_t size2bitwidth(nat_t n)
static const Def * isa(const Def *def)
Checks if def is a Idx s and returns s or nullptr otherwise.
static std::optional< nat_t > isa_lit(const Def *def)
static std::optional< T > isa(const Def *def)
A variable introduced by a binder (mutable).
Def * binder() const
The binder of this Var.
The World represents the whole program and manages creation of MimIR nodes (Defs).
const Def * sigma(Defs ops)
Flags & flags()
Retrieve compile Flags.
const Def * extract(const Def *d, const Def *i)
Sym sym(std::string_view)
const Def * var(Def *mut)
const Externals & externals() const
const Lit * lit_nat(nat_t a)
Defs reduce(const Var *var, const Def *arg)
Yields the new body of [mut->var() -> arg]mut.
@ None
Depends on nothing of interest.
@ Mut
Depends on a mutable.
@ Proxy
Depends on a Proxy.
static bool any_free_vars(const Def *def, F f)
fe::View< const Def * > Defs
fe::Vector< const Def * > DefVec
fe::Patricia< const Var, DefKey >::Set Vars
static constexpr unsigned node2dep(Node node, bool mut)
fe::Patricia< Def, DefKey >::Set Muts
static std::ostream & stream(std::ostream &, const Def *)
uint64_t scalarize_threshold