9#include <absl/container/btree_map.h>
22concept Enum = std::is_enum_v<std::remove_reference_t<T>>;
54#ifdef MIM_ENABLE_CHECKS
60 assert((!s1.pod.loc || !s2.pod.loc) &&
"Why is get_loc() still set?");
62#ifdef MIM_ENABLE_CHECKS
63 swap(s1.breakpoints, s2.breakpoints);
64 swap(s1.watchpoints, s2.watchpoints);
76 :
World(&other.driver(), other.state()) {
85 s.pod.curr_gid += move_.defs.size();
86 return std::make_unique<World>(&
driver(), s);
97 Sym
name()
const {
return state_.pod.name; }
118 , old_loc_(old_loc) {}
126 Loc
get_loc()
const {
return state_.pod.loc; }
137 Sym
sym(std::string_view);
138 Sym
sym(
const char*);
139 Sym
sym(
const std::string&);
162 bool old = state_.pod.frozen;
163 state_.pod.frozen = on;
179#ifdef MIM_ENABLE_CHECKS
197 const auto&
sym2mut()
const {
return sym2mut_; }
198 auto syms()
const {
return sym2mut_ | std::views::keys; }
199 auto muts()
const {
return sym2mut_ | std::views::values; }
204 size_t size()
const {
return sym2mut_.size(); }
215 auto begin()
const {
return sym2mut_.cbegin(); }
216 auto end()
const {
return sym2mut_.cend(); }
221 swap(ex1.sym2mut_, ex2.sym2mut_);
225 fe::SymMap<Def*> sym2mut_;
243 auto entries()
const {
return flags2entry_ | std::views::values; }
245 return entries() | std::views::transform([](
Entry e) {
return e.def; });
248 size_t size()
const {
return flags2entry_.size(); }
261 auto begin()
const {
return flags2entry_.cbegin(); }
262 auto end()
const {
return flags2entry_.cend(); }
268 swap(a1.driver_, a2.driver_);
269 swap(a1.flags2entry_, a2.flags2entry_);
270 swap(a1.sym2flags_, a2.sym2flags_);
276 absl::btree_map<flags_t, Entry> flags2entry_;
277 fe::SymMap<flags_t> sym2flags_;
292 res.append_range(
annexes().defs());
318 template<annex_without_subs
id>
328 template<
int sort = UMax::Univ>
332 template<level_t level = 0>
334 if constexpr (level == 0)
336 else if constexpr (level == 1)
352 assert(
this == &res->world());
360 return unify<Axm>(n, curry, trip,
type, p, t, s);
377 const Pi*
pi(
const Def* dom,
const Def* codom,
bool implicit =
false) {
return unify<Pi>(
Pi::infer(dom, codom), dom, codom, implicit); }
378 const Pi*
pi(
Defs dom,
const Def* codom,
bool implicit =
false) {
return pi(
sigma(dom), codom, implicit); }
379 const Pi*
pi(
const Def* dom,
Defs codom,
bool implicit =
false) {
return pi(dom,
sigma(codom), implicit); }
392 const Pi*
fn(
const Def* dom,
const Def* codom,
bool implicit =
false) {
return cn({ dom ,
cn(codom)}, implicit); }
393 const Pi*
fn(
Defs dom,
const Def* codom,
bool implicit =
false) {
return fn(
sigma(dom), codom, implicit); }
394 const Pi*
fn(
const Def* dom,
Defs codom,
bool implicit =
false) {
return fn( dom ,
sigma(codom), implicit); }
403 return std::get<const Def*>(
filter);
436 return unify<Rule>(
type, lhs, rhs, guard);
442 template<
bool Normalize = true>
444 template<
bool Normalize = true>
457 template<level_t level = 0>
468 template<level_t level = 0>
474 const Def*
arr (
const Def* arity,
const Def* body) {
return seq(
false, arity, body); }
496 const Def*
seq(
bool is_pack,
const Def* arity,
const Def* body);
500 return seq(is_pack,
DefVec(shape.size(), [&](
size_t i) { return lit_nat(shape[i]); }), body);
557 static_assert(std::is_integral<I>());
578 const Lit*
lit_bool(
bool val) {
return data_.lit_bool[size_t(val)]; }
637 template<
bool Normalize = true>
639 template<
bool Normalize = true>
643 template<
bool Normalize = true>
647 template<
bool Normalize = true,
class E>
649 requires std::is_enum_v<E> && std::is_same_v<std::underlying_type_t<E>,
nat_t>
658 template<
bool Normalize =
true,
class T,
class... Args>
659 const Def*
call(
const Def* callee, T&& arg, Args&&... args) {
664 template<
bool Normalize = true,
class T>
670 template<
Enum Id,
bool Normalize =
true,
class... Args>
676 template<
class Id,
bool Normalize =
true,
class... Args>
677 requires std::is_enum_v<Id>
683 template<
bool Normalize =
true,
class... Args>
692 [[nodiscard]]
auto&
vars() {
return move_.vars; }
693 [[nodiscard]]
auto&
muts() {
return move_.muts; }
694 [[nodiscard]]
const auto&
vars()
const {
return move_.vars; }
695 [[nodiscard]]
const auto&
muts()
const {
return move_.muts; }
706 void for_each(
bool elide_empty, std::function<
void(
Def*)>,
bool schedule =
false);
709 void for_each(
bool elide_empty, std::function<
void(M*)> f,
bool schedule =
false) {
713 if (
auto mut = m->template isa<M>()) f(mut);
722 void dump(std::ostream& os);
725 void write(
const char* file);
737 void dot(std::ostream& os,
bool annexes =
false,
bool types =
false)
const;
739 void dot(
const char* file =
nullptr,
bool annexes =
false,
bool types =
false)
const;
745 template<
class T,
class... Args>
746 const T* unify(Args&&... args) {
747 auto num_ops = T::Num_Ops;
748 if constexpr (T::Num_Ops == std::dynamic_extent) {
749 auto&& last = std::get<
sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
750 num_ops = last.size();
753 auto state = move_.arena.defs.state();
754 auto def = allocate<T>(num_ops, std::forward<Args>(args)...);
755 assert(!def->isa_mut());
757 if (
auto loc =
get_loc()) def->set(loc);
759#ifdef MIM_ENABLE_CHECKS
760 if (
flags().trace_gids) std::println(
"{}: {} - {}", def->node_name(), def->gid(), def->flags());
761 if (
flags().reeval_breakpoints &&
breakpoints().contains(def->gid())) fe::breakpoint();
762 for (
auto op : def->ops())
763 assert(&op->world() ==
this &&
"op of new Def belongs to a different World");
764 assert((!def->type() || &def->type()->world() ==
this) &&
"type of new Def belongs to a different World");
768 auto i = move_.defs.find(def);
769 deallocate<T>(
state, def);
770 if (i != move_.defs.end())
return static_cast<const T*
>(*i);
774 if (
auto [i, ins] = move_.defs.emplace(def); !ins) {
775 deallocate<T>(
state, def);
776 return static_cast<const T*
>(*i);
779#ifdef MIM_ENABLE_CHECKS
786 void deallocate(fe::Arena::State
state,
const T* ptr) {
787 --state_.pod.curr_gid;
789 move_.arena.defs.deallocate(
state);
792 template<
class T,
class... Args>
793 T*
insert(Args&&... args) {
796 auto num_ops = T::Num_Ops;
797 if constexpr (T::Num_Ops == std::dynamic_extent)
798 num_ops = std::get<
sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
800 auto def = allocate<T>(num_ops, std::forward<Args>(args)...);
801 if (
auto loc =
get_loc()) def->set(loc);
803#ifdef MIM_ENABLE_CHECKS
804 if (
flags().trace_gids) std::println(
"{}: {} - {}", def->node_name(), def->gid(), def->flags());
811#if (!defined(_MSC_VER) && defined(NDEBUG))
813 Lock() { assert((guard_ = !guard_) &&
"you are not allowed to recursively invoke allocate"); }
814 ~Lock() { guard_ = !guard_; }
823 template<
class T,
class... Args>
824 T* allocate(
size_t num_ops, Args&&... args) {
825 static_assert(
sizeof(Def) ==
sizeof(T),
826 "you are not allowed to introduce any additional data in subclasses of Def");
828 auto num_bytes =
sizeof(Def) +
sizeof(uintptr_t) * num_ops;
829 auto ptr = move_.arena.defs.allocate(num_bytes,
alignof(T));
830 auto res =
new (ptr) T(std::forward<Args>(args)...);
831 assert(res->num_ops() == num_ops);
841 size_t operator()(
const Def* def)
const {
return def->hash(); }
845 bool operator()(
const Def* d1,
const Def* d2)
const {
return d1->equal(d2); }
850 constexpr Reduct(
size_t size) noexcept
853 template<
size_t N = std::dynamic_extent>
854 constexpr auto defs() const noexcept {
875 absl::flat_hash_set<const Def*, SeaHash, SeaEq> defs;
878 absl::flat_hash_map<std::pair<const Var*, const Def*>,
const Reduct*> substs;
880 friend void swap(Move& m1, Move& m2)
noexcept {
883 swap(m1.arena.defs, m2.arena.defs);
884 swap(m1.arena.substs, m2.arena.substs);
885 swap(m1.defs, m2.defs);
886 swap(m1.substs, m2.substs);
887 swap(m1.vars, m2.vars);
888 swap(m1.muts, m2.muts);
889 swap(m1.externals, m2.externals);
890 swap(m1.annexes, m2.annexes);
908 const Def* table_not;
922 swap(w1.driver_, w2.driver_ );
923 swap(w1.zonker_, w2.zonker_ );
924 swap(w1.state_, w2.state_);
925 swap(w1.data_, w2.data_ );
926 swap(w1.move_, w2.move_ );
929 swap(w1.data_.univ->world_, w2.data_.univ->world_);
930 assert(&w1.univ()->world() == &w1);
931 assert(&w2.univ()->world() == &w2);
A (possibly paramterized) Array.
Some "global" variables needed all over the place.
This node is a hole in the IR that is inferred by its context later on.
A built-in constant of type Nat -> *.
static constexpr nat_t bitwidth2size(nat_t n)
std::variant< bool, const Def * > Filter
static T as(const Def *def)
Facility to log what you are doing.
A (possibly paramterized) Tuple.
A dependent function type.
static const Def * infer(const Def *dom, const Def *codom)
Base class for Arr and Pack.
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
This is a thin wrapper for absl::InlinedVector<T, N, A> which is a drop-in replacement for std::vecto...
const Def * attach(flags_t, Sym, const Def *)
const auto & sym2flags() const
const Def * attach(plugin_t p, tag_t t, sub_t s, Sym sym, const Def *def)
const auto & flags2entry() const
An annex's flags map to its full name and its Def.
friend void swap(Annexes &a1, Annexes &a2) noexcept
Vector< Def * > mutate() const
Returns a copy of muts() in a Vector; this allows you to modify the Externals while iterating.
Def * operator[](Sym name) const
Lookup by name.
friend void swap(Externals &ex1, Externals &ex2) noexcept
const auto & sym2mut() const
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 Def * arr(Defs shape, const Def *body)
const Def * seq_unsafe(bool is_pack, const Def *body)
const Def * insert(const Def *d, const Def *i, const Def *val)
const Pi * fn(Defs dom, const Def *codom, bool implicit=false)
const Def * meet(Defs ops)
std::unique_ptr< World > inherit()
Inherits the State into the new World.
const Lam * con(Defs dom, Lam::Filter f, const Def *body)
const Def * uinc(const Def *op, level_t offset=1)
const Lit * lit(const Def *type, u64 val)
const Def * seq(bool is_pack, const Def *arity, const Def *body)
const Def * arr(u64 n, const Def *body)
const Def * call(flags_t id, Args &&... args)
Annex overload with flags_t as first argument.
friend void swap(World &w1, World &w2) noexcept
const Def * implicit_app(const Def *callee, nat_t arg)
const Def * extract(const Def *d, u64 a, u64 i)
Hole * mut_hole_infer_entity()
Either a value ?:?:Type ? or a type ?:Type ?:Type ?.
const Pi * cn(const Def *dom, bool implicit=false)
const Def * type_int(nat_t width)
Constructs a type Idx of size 2^width.
World & operator=(World)=delete
World(Driver *, Sym name)
const Lit * lit_i16(u16 val)
void watchpoint(u32 gid)
Trigger breakpoint in your debugger when Def::setting a Def with this gid.
const Lit * lit_i1(bool val)
const Def * arr(View< u64 > shape, const Def *body)
Lam * mut_fun(const Def *dom, Defs codom)
const Type * type(const Def *level)
const Driver & driver() const
const Lam * lam(const Def *dom, const Def *codom, Lam::Filter f, const Def *body)
Lam * mut_lam(const Def *dom, Defs codom)
const Def * filter(Lam::Filter filter)
const auto & watchpoints()
const Def * seq(bool is_pack, u64 n, const Def *body)
const Def * type_idx(nat_t size)
const Def * pack(const Def *arity, const Def *body)
void set(std::string_view name)
const Def * app(const Def *callee, const Def *arg)
u32 curr_gid() const
Manage global identifier - a unique number for each Def.
const Axm * axm(const Def *type)
See above.
const Pi * pi(const Def *dom, const Def *codom, bool implicit=false)
const Def * pack(u64 n, const Def *body)
const Def * insert(const Def *d, u64 a, u64 i, const Def *val)
const auto & muts() const
const Lam * lam(Defs dom, const Def *codom, Lam::Filter f, const Def *body)
const Def * unit(bool is_pack)
const Lam * fun(Defs dom, const Def *codom, Lam::Filter f, const Def *body)
Rule * mut_rule(const Reform *type)
World & verify()
Verifies that all externals() and annexes() are Def::is_closed(), if MIM_ENABLE_CHECKS.
const Def * bot(const Def *type)
Arr * mut_arr(const Def *type)
const Lam * lam(const Def *dom, Defs codom, Lam::Filter f, const Def *body)
const Lit * lit_idx_mod(nat_t mod, u64 val)
Constructs a Lit of type Idx of size mod.
Seq * mut_seq(bool is_pack, const Def *type)
Pi * mut_pi(const Def *type, bool implicit=false)
void for_each(bool elide_empty, std::function< void(M *)> f, bool schedule=false)
const Def * annex(Id id)
Lookup annex by Axm::id.
const Def * implicit_app(const Def *callee, E arg)
const Pi * cn(Defs dom, bool implicit=false)
void dump()
Dump to std::cout.
const Lam * fun(const Def *dom, Defs codom, Lam::Filter f, const Def *body)
const Reform * reform(const Def *dom)
void write()
Same above but file name defaults to World::name.
const Lam * lam(Defs dom, Defs codom, Lam::Filter f, const Def *body)
Lam * mut_fun(Defs dom, const Def *codom)
const Def * seq(bool is_pack, View< u64 > shape, const Def *body)
Lam * mut_fun(const Def *dom, const Def *codom)
const Def * annex(Sym sym)
Lookup annex by Sym.
const Axm * axm(NormalizeFn n, u8 curry, u8 trip, const Def *type)
Builds a fresh Axm with descending Axm::sub.
const Pi * fn(const Def *dom, Defs codom, bool implicit=false)
void for_each(bool elide_empty, std::function< void(Def *)>, bool schedule=false)
Hole * mut_hole(const Def *type)
const Axm * axm(const Def *type, plugin_t p, tag_t t, sub_t s)
const Lam * lam(const Pi *pi, Lam::Filter f, const Def *body)
const Lam * fun(Defs dom, Defs codom, Lam::Filter f, const Def *body)
Lam * mut_lam(const Def *dom, const Def *codom)
const Def * gid2def(u32 gid)
Lookup Def by gid.
Flags & flags()
Retrieve compile Flags.
const Def * implicit_app(const Def *callee, const Def *arg)
const Def * implicit_app(const Def *callee, Defs args)
void debug_dump()
Dump in Debug build if World::log::level is Log::Level::Debug.
const Def * extract(const Def *d, u64 i)
const Lam * fun(const Def *dom, const Def *codom, Lam::Filter f, const Def *body)
Freezer freeze()
Use like this to freeze and automatically unfreeze:
const Def * inj(const Def *type, const Def *value)
const Def * call(Args &&... args)
Annex overload with enum tempalte argument Id for annexes w/o subtag.
const auto & breakpoints()
const Axm * axm(NormalizeFn n, u8 curry, u8 trip, const Def *type, plugin_t p, tag_t t, sub_t s)
const Def * pack(Defs shape, const Def *body)
const Def * app(const Def *callee, Defs args)
const Def * pack(View< u64 > shape, const Def *body)
Lam * mut_fun(Defs dom, Defs codom)
const Lit * lit_i2(u8 val)
const Def * extract(const Def *d, const Def *i)
Pack * mut_pack(const Def *type)
const Lit * lit_idx_unsafe(u64 val)
bool do_freeze(bool on=true) const
Yields old frozen state.
const Def * arr(const Def *arity, const Def *body)
Sym sym(std::string_view)
Global * global(const Def *type, bool is_mutable=true)
Lam * mut_lam(Defs dom, const Def *codom)
const Lit * lit_nat_max()
const Def * raw_app(const Def *type, const Def *callee, Defs args)
const Pi * pi(Defs dom, const Def *codom, bool implicit=false)
const Def * bound(Defs ops)
const Def * join(Defs ops)
const Def * call(const Def *callee, T &&arg, Args &&... args)
const Def * ext(const Def *type)
Sym append_suffix(Sym name, std::string suffix)
Appends a suffix or an increasing number if the suffix already exists.
const Annexes & annexes() const
const Proxy * proxy(const Def *type, Defs ops, u32 index, u32 tag)
const Lit * lit_i32(u32 val)
const Lit * lit_i8(u8 val)
Lam * mut_lam(Defs dom, Defs codom)
const Lit * lit_idx_1_0()
Sigma * mut_sigma(size_t size)
A mutable Sigma of type level.
const Lit * lit_univ(u64 level)
const Pi * pi(Defs dom, Defs codom, bool implicit=false)
const Def * var(Def *mut)
const Tuple * tuple()
the unit value of type []
const Def * annex(flags_t flags)
Lookup annex by flags.
const Type * type_infer_univ()
const Def * call(Id id, Args &&... args)
Annex overload with enum instance as first argument.
const Def * uniq(const Def *inhabitant)
const Def * raw_app(const Axm *axm, u8 curry, u8 trip, const Def *type, const Def *callee, const Def *arg)
const Def * prod(bool term, Defs ops)
const Externals & externals() const
const Def * prod(bool term)
const Lam * con(const Def *dom, Lam::Filter f, const Def *body)
const Def * arr_unsafe(const Def *body)
const Def * merge(const Def *type, Defs ops)
const Lit * lit_i64(u64 val)
const Sigma * sigma()
The unit type within Type 0.
const Lit * lit_nat(nat_t a)
const State & state() const
const Def * pack_unsafe(const Def *body)
const auto & vars() const
const Def * top(const Def *type)
const Def * type_idx(const Def *size)
Lam * mut_con(const Def *dom)
Defs reduce(const Var *var, const Def *arg)
Yields the new body of [mut->var() -> arg]mut.
const Lit * lit_int(nat_t width, u64 val)
Constructs a Lit of type Idx of size 2^width.
const Lit * lit_bool(bool val)
void breakpoint(u32 gid)
Trigger breakpoint in your debugger when creating a Def with this gid.
const Def * select(const Def *cond, const Def *t, const Def *f)
Builds (f, t)#cond.
Sigma * mut_sigma(const Def *type, size_t size)
const Def * split(const Def *type, const Def *value)
const Pi * fn(const Def *dom, const Def *codom, bool implicit=false)
const Rule * rule(const Reform *type, const Def *lhs, const Def *rhs, const Def *guard)
u32 curr_run() const
Manage run - used to track fixed-point iterations to compute Def::free_vars.
World(World &&other) noexcept
auto roots() const
annexes() + externals().muts() in this order.
const Pi * pi(const Def *dom, Defs codom, bool implicit=false)
const Def * call(const Def *callee, T &&arg)
Base case.
const Lit * lit_i4(u8 val)
void dot(std::ostream &os, bool annexes=false, bool types=false) const
Dumps DOT to os.
const Def * insert(const Def *d, u64 i, const Def *val)
const Pi * fn(Defs dom, Defs codom, bool implicit=false)
Lam * mut_lam(const Pi *pi)
const Def * annex()
Get Axm from a plugin.
Vector< const Def * > DefVec
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...
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Compiler switches that must be saved and looked up in later phases of compilation.
static constexpr flags_t flags(plugin_t p, tag_t t, sub_t s=0)
Assembles the full flags from its plugin, tag, and sub fields.
static constexpr plugin_t Global_Plugin
static Sym demangle(Driver &, plugin_t plugin)
Reverts an Axm::mangled string to a Sym.
static consteval 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)
absl::flat_hash_set< uint32_t > watchpoints
friend void swap(State &s1, State &s2) noexcept
struct mim::World::State::POD pod
absl::flat_hash_set< uint32_t > breakpoints