7#include <absl/container/btree_map.h>
8#include <absl/container/btree_set.h>
49#ifdef MIM_ENABLE_CHECKS
54 assert((!s1.pod.loc || !s2.pod.loc) &&
"Why is get_loc() still set?");
56#ifdef MIM_ENABLE_CHECKS
57 swap(s1.breakpoints, s2.breakpoints);
70 :
World(&other.driver(), other.state()) {
101 , old_loc_(old_loc) {}
120 Sym
sym(std::string_view);
121 Sym
sym(
const char*);
122 Sym
sym(
const std::string&);
153#ifdef MIM_ENABLE_CHECKS
167 const auto&
annexes()
const {
return move_.annexes; }
168 const auto&
externals()
const {
return move_.externals; }
172 def->external_ =
true;
177 def->external_ =
false;
178 auto num = move_.externals.erase(def->
sym());
179 assert_unused(num == 1);
187 if (
auto i = move_.annexes.find(
flags); i != move_.annexes.end())
return i->second;
210 if constexpr (level == 0)
212 else if constexpr (level == 1)
219 return unify<Proxy>(ops.size(),
type, ops, index, tag);
230 assert(
this == &res->world());
238 return unify<Axiom>(0, n, curry, trip,
type, p, t, s);
255 const Pi*
pi(
Ref dom,
Ref codom,
bool implicit =
false) {
return unify<Pi>(2,
Pi::infer(dom, codom), dom, codom, implicit); }
270 const Pi*
fn(
Ref dom,
Ref codom,
bool implicit =
false) {
return cn({ dom ,
cn(codom)}, implicit); }
272 const Pi*
fn(
Ref dom,
Defs codom,
bool implicit =
false) {
return fn( dom ,
sigma(codom), implicit); }
337 return arr(
DefVec(shape.size(), [&](
size_t i) { return lit_nat(shape[i]); }), body);
358 return pack(
DefVec(shape.size(), [&](
auto i) { return lit_nat(shape[i]); }), body);
404 static_assert(std::is_integral<I>());
425 const Lit*
lit_bool(
bool val) {
return data_.lit_bool[size_t(val)]; }
497 Ref iapp(
Ref callee, E arg)
requires std::is_enum_v<E> && std::is_same_v<std::underlying_type_t<E>,
nat_t>
506 [[nodiscard]]
Muts muts(
Def* mut) {
return move_.muts.singleton(mut); }
518 template<
class Id,
class... Args>
const Def*
call(Id
id, Args&&... args) {
return call_(
annex(
id), std::forward<Args>(args)...); }
519 template<
class Id,
class... Args>
const Def*
call( Args&&... args) {
return call_(
annex<Id>(), std::forward<Args>(args)...); }
520 template<
class T,
class... Args>
const Def*
call_(
Ref callee, T arg, Args&&... args) {
return call_(
iapp(callee, arg), std::forward<Args>(args)...); }
535 void dump(std::ostream& os);
538 void write(
const char* file);
548 void dot(std::ostream& os,
bool annexes =
false,
bool types =
false)
const;
550 void dot(
const char* file =
nullptr,
bool annexes =
false,
bool types =
false)
const;
556 template<
class T,
class... Args>
const T* unify(
size_t num_ops, Args&&... args) {
557 auto state = move_.arena.state();
558 auto def = allocate<T>(num_ops, std::forward<Args&&>(args)...);
559 if (
auto loc =
get_loc()) def->set(loc);
560 assert(!def->isa_mut());
561#ifdef MIM_ENABLE_CHECKS
562 if (
flags().trace_gids)
outln(
"{}: {} - {}", def->node_name(), def->gid(), def->flags());
563 if (
flags().reeval_breakpoints &&
breakpoints().contains(def->gid())) fe::breakpoint();
567 auto i = move_.defs.find(def);
568 deallocate<T>(
state, def);
569 if (i != move_.defs.end())
return static_cast<const T*
>(*i);
573 if (
auto [i, ins] = move_.defs.emplace(def); !ins) {
574 deallocate<T>(
state, def);
575 return static_cast<const T*
>(*i);
577#ifdef MIM_ENABLE_CHECKS
578 if (!
flags().reeval_breakpoints &&
breakpoints().contains(def->gid())) fe::breakpoint();
584 template<
class T>
void deallocate(fe::Arena::State
state,
const T* ptr) {
586 move_.arena.deallocate(
state);
589 template<
class T,
class... Args> T*
insert(
size_t num_ops, Args&&... args) {
590 auto def = allocate<T>(num_ops, std::forward<Args&&>(args)...);
591 if (
auto loc =
get_loc()) def->set(loc);
592#ifdef MIM_ENABLE_CHECKS
593 if (
flags().trace_gids)
outln(
"{}: {} - {}", def->node_name(), def->gid(), def->flags());
594 if (
breakpoints().contains(def->gid())) fe::breakpoint();
600#if (!defined(_MSC_VER) && defined(NDEBUG))
602 Lock() { assert((guard_ = !guard_) &&
"you are not allowed to recursively invoke allocate"); }
603 ~Lock() { guard_ = !guard_; }
612 template<
class T,
class... Args> T* allocate(
size_t num_ops, Args&&... args) {
613 static_assert(
sizeof(Def) ==
sizeof(T),
614 "you are not allowed to introduce any additional data in subclasses of Def");
616 move_.arena.align(
alignof(T));
617 size_t num_bytes =
sizeof(Def) +
sizeof(uintptr_t) * num_ops;
618 auto ptr = move_.arena.allocate(num_bytes);
619 auto res =
new (ptr) T(std::forward<Args&&>(args)...);
620 assert(res->num_ops() == num_ops);
629 size_t operator()(
const Def* def)
const {
return def->hash(); }
633 bool operator()(
const Def* d1,
const Def* d2)
const {
return d1->equal(d2); }
637 absl::btree_map<flags_t, const Def*> annexes;
638 absl::btree_map<Sym, Def*> externals;
640 absl::flat_hash_set<const Def*, SeaHash, SeaEq> defs;
641 Pool<const Var*> vars;
645 friend void swap(Move& m1, Move& m2)
noexcept {
648 swap(m1.annexes, m2.annexes);
649 swap(m1.externals, m2.externals);
650 swap(m1.arena, m2.arena);
651 swap(m1.defs, m2.defs);
652 swap(m1.vars, m2.vars);
653 swap(m1.muts, m2.muts);
654 swap(m1.cache, m2.cache);
672 const Def* table_not;
686 swap(w1.state_, w2.state_);
687 swap(w1.data_, w2.data_ );
688 swap(w1.move_, w2.move_ );
691 swap(w1.data_.univ->world_, w2.data_.univ->world_);
692 assert(&w1.univ()->world() == &w1);
693 assert(&w2.univ()->world() == &w2);
A (possibly paramterized) Array.
DefVec reduce(const Def *arg) const
Rewrites Def::ops by substituting this mutable's Var with arg.
bool is_closed() const
Has no free_vars()?
Some "global" variables needed all over the place.
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 bitwidth2size(nat_t n)
This node is a hole in the IR that is inferred by its context later on.
std::variant< bool, const Def * > Filter
Facility to log what you are doing.
A (possibly paramterized) Tuple.
A dependent function type.
static Ref infer(Ref dom, Ref codom)
Helper class to retrieve Infer::arg if present.
This is a thin wrapper for std::span<T, N> with the following additional features:
Specific Bound depending on Up.
Data constructor for a Sigma.
The World represents the whole program and manages creation of MimIR nodes (Defs).
const Lit * lit_idx(nat_t size, u64 val)
Constructs a Lit of type Idx of size size.
const Lit * lit_idx(I val)
const Lam * fun(Ref dom, Ref codom, Lam::Filter f, Ref body)
Meet * mut_meet(Ref type, size_t size)
bool has_intersection(Vars v1, Vars v2)
Lam * mut_lam(Defs dom, Ref codom)
Ref pack(View< u64 > shape, Ref body)
Lam * mut_lam(Ref dom, Ref codom)
friend void swap(World &w1, World &w2) noexcept
const Lam * lam(Ref dom, Defs codom, Lam::Filter f, Ref body)
Infer * mut_infer(Ref type)
Ref gid2def(u32 gid)
Lookup Def by gid.
Ref pack(u64 n, Ref body)
World & operator=(World)=delete
const Lit * lit_i16(u16 val)
Muts insert(Muts muts, Def *mut)
Ref app(Ref callee, Defs args)
Vars vars(const Var *var)
const Lit * lit_i1(bool val)
Global * global(Ref type, bool is_mutable=true)
const Proxy * proxy(Ref type, Defs ops, u32 index, u32 tag)
const Lam * con(Defs dom, Lam::Filter f, Ref body)
Lam * mut_fun(Ref dom, Ref codom)
const Def * call_(Ref callee, T arg, Args &&... args)
const Driver & driver() const
const Lam * lam(Defs dom, Ref codom, Lam::Filter f, Ref body)
const Axiom * axiom(Ref type)
See above.
World(Driver *)
Inherits the state into the new World.
const Lam * fun(Defs dom, Ref codom, Lam::Filter f, Ref body)
void set(std::string_view name)
Ref iapp(Ref callee, nat_t arg)
Ref extract(Ref d, u64 i)
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
Lam * exit()
Used as a dummy exit node within Scope.
const auto & annexes() const
Ref iapp(Ref callee, Ref arg)
const Lam * lam(Defs dom, Defs codom, Lam::Filter f, Ref body)
Muts merge(Muts a, Muts b)
const Pi * fn(Ref dom, Ref codom, bool implicit=false)
Ref test(Ref value, Ref probe, Ref match, Ref clash)
const Def * call_(Ref callee, T arg)
const Pi * pi(Defs dom, Ref codom, bool implicit=false)
const Pi * pi(Ref dom, Defs codom, bool implicit=false)
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
const Lam * fun(Defs dom, Defs codom, Lam::Filter f, Ref body)
const Lit * lit_idx_mod(nat_t mod, u64 val)
Constructs a Lit of type Idx of size mod.
Pi * mut_pi(Ref type, bool implicit=false)
const Def * annex(Id id)
Lookup annex by Axiom::id.
const Pi * cn(Ref dom, bool implicit=false)
Join * mut_join(Ref type, size_t size)
Ref insert(Ref d, u64 i, Ref val)
Ref iapp(Ref callee, E arg)
const Pi * cn(Defs dom, bool implicit=false)
void dump()
Dump to std::cout.
void make_internal(Def *def)
void write()
Same above but file name defaults to World::name.
const Def * register_annex(plugin_t p, tag_t t, sub_t s, const Def *def)
const auto & externals() const
Ref insert(Ref d, Ref i, Ref val)
Sigma * mut_sigma(Ref type, size_t size)
Ref var(Ref type, Def *mut)
Ref arr(Ref shape, Ref body)
const Pi * fn(Ref dom, Defs codom, bool implicit=false)
Lam * mut_lam(Ref dom, Defs codom)
Flags & flags()
Retrive compile Flags.
void debug_dump()
Dump in Debug build if World::log::level is Log::Level::Debug.
Lam * mut_fun(Ref dom, Defs codom)
Muts erase(Muts muts, Def *mut)
const auto & breakpoints()
Ref type_int(nat_t width)
Constructs a type Idx of size $2^width$.
Lam * mut_fun(Defs dom, Defs codom)
const Lit * lit_i2(u8 val)
Ref app(Ref callee, Ref arg)
Vars merge(Vars a, Vars b)
Ref ac(Ref type, Defs ops)
Sym sym(std::string_view)
const Pi * pi(Ref dom, Ref codom, bool implicit=false)
Infer * mut_infer_entity()
Either a value ?:?:Type ? or a type ?:Type ?:Type ?.
const Lit * lit_nat_max()
Ref raw_app(Ref type, Ref callee, Defs args)
Def * external(Sym name)
Lookup by name.
const Def * call(Id id, Args &&... args)
Ref select(Ref cond, Ref t, Ref f)
Builds (f, t)#cond.
Vars insert(Vars vars, const Var *var)
TBound< Up > * mut_bound(Ref type, size_t size)
Sym append_suffix(Sym name, std::string suffix)
Appends a suffix or an increasing number if the suffix already exists.
Join * mut_join(size_t size)
const Lam * fun(Ref dom, Defs codom, Lam::Filter f, Ref body)
const Lit * lit_i32(u32 val)
const Lit * lit_i8(u8 val)
Ref pack(Ref arity, Ref body)
Ref arr(View< u64 > shape, Ref body)
Ref insert(Ref d, u64 a, u64 i, Ref val)
Lam * mut_lam(Defs dom, Defs codom)
Sigma * mut_sigma(size_t size)
A *mut*able Sigma of type level.
const Lit * lit_univ(u64 level)
Ref pick(Ref type, Ref value)
const Pi * pi(Defs dom, Defs codom, bool implicit=false)
const Tuple * tuple()
the unit value of type []
const Type * type_infer_univ()
Ref iapp(Ref callee, Defs args)
void make_external(Def *def)
Ref extract(Ref d, Ref i)
Lam * mut_fun(Defs dom, Ref codom)
const Lit * lit_i64(u64 val)
Ref filter(Lam::Filter filter)
const Lit * lit(Ref type, u64 val)
Ref vel(Ref type, Ref value)
const Sigma * sigma()
The unit type within Type 0.
const Lit * lit_nat(nat_t a)
const State & state() const
Ref extract(Ref d, u64 a, u64 i)
TBound< Up > * mut_bound(size_t size)
A *mut*able Bound of Type level.
const Axiom * axiom(NormalizeFn n, u8 curry, u8 trip, Ref type, plugin_t p, tag_t t, sub_t s)
const Def * register_annex(flags_t f, const Def *)
const Pi * fn(Defs dom, Ref codom, bool implicit=false)
const Axiom * axiom(NormalizeFn n, u8 curry, u8 trip, Ref type)
Builds a fresh Axiom with descending Axiom::sub.
const Lit * lit_int(nat_t width, u64 val)
Constructs a Lit of type Idx of size $2^width$.
Ref raw_app(Ref type, Ref callee, Ref arg)
const Lit * lit_bool(bool val)
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating Def with Def::gid gid.
const Lam * lam(Ref dom, Ref codom, Lam::Filter f, Ref body)
Ref uinc(Ref op, level_t offset=1)
Meet * mut_meet(size_t size)
Vars erase(Vars vars, const Var *var)
const Def * call(Args &&... args)
const Axiom * axiom(Ref type, plugin_t p, tag_t t, sub_t s)
Ref singleton(Ref inner_type)
World(World &&other) noexcept
bool freeze(bool on=true) const
Yields old frozen state.
Pack * mut_pack(Ref type)
const Lit * lit_i4(u8 val)
void dot(std::ostream &os, bool annexes=false, bool types=false) const
const Lam * lam(const Pi *pi, Lam::Filter f, Ref body)
const Lam * con(Ref dom, Lam::Filter f, Ref body)
const Pi * fn(Defs dom, Defs codom, bool implicit=false)
bool has_intersection(Muts m1, Muts m2)
Lam * mut_lam(const Pi *pi)
const Def * annex()
Get Axiom from a plugin.
Vector< const Def * > DefVec
absl::flat_hash_map< DefDef, To, DefDefHash, DefDefEq > DefDefMap
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
auto lookup(const C &container, const K &key)
Yields pointer to element (or the element itself if it is already a pointer), if found and nullptr ot...
void error(Loc loc, const char *f, Args &&... args)
std::ostream & outln(const char *fmt, Args &&... args)
Ref(*)(Ref, Ref, Ref) NormalizeFn
Compiler switches that must be saved and looked up in later phases of compilation.
constexpr decltype(auto) get(mim::Span< T, N > span)
static constexpr plugin_t Global_Plugin
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axiom::mangled string to a Sym.
static constexpr flags_t Base
Use to World::freeze and automatically unfreeze at the end of scope.
Freezer(const World &world)
ScopedLoc(World &world, Loc old_loc)
friend void swap(State &s1, State &s2) noexcept
struct mim::World::State::POD pod
absl::flat_hash_set< uint32_t > breakpoints