10#include <absl/container/btree_map.h>
13#include <fe/restore.h>
26concept Enum = std::is_enum_v<std::remove_reference_t<T>>;
64#ifdef MIM_ENABLE_CHECKS
70 assert((!s1.pod.curr_loc.loc || !s2.pod.curr_loc.loc) &&
"Why is get_loc() still set?");
72#ifdef MIM_ENABLE_CHECKS
73 swap(s1.breakpoints, s2.breakpoints);
74 swap(s1.watchpoints, s2.watchpoints);
86 :
World(&other.driver(), other.state()) {
95 s.pod.curr_gid += move_.sea.size();
96 return std::make_unique<World>(&
driver(), s);
106 const fe::Error&
error()
const;
109 Sym
name()
const {
return state_.pod.name; }
128 Loc
get_loc()
const {
return state_.pod.curr_loc.loc; }
129 DbgKey
dbg_key()
const {
return state_.pod.curr_loc.key; }
135 Sym
sym(std::string_view);
136 Sym
sym(
const char*);
137 Sym
sym(
const std::string&);
154 [[nodiscard]]
auto freeze()
const {
return fe::Restore(state_.pod.frozen,
true); }
159#ifdef MIM_ENABLE_CHECKS
177 const auto&
sym2mut()
const {
return sym2mut_; }
178 auto syms()
const {
return sym2mut_ | std::views::keys; }
179 auto muts()
const {
return sym2mut_ | std::views::values; }
184 size_t size()
const {
return sym2mut_.size(); }
195 auto begin()
const {
return sym2mut_.cbegin(); }
196 auto end()
const {
return sym2mut_.cend(); }
201 swap(ex1.sym2mut_, ex2.sym2mut_);
205 absl::btree_map<Sym, Def*> sym2mut_;
224 auto entries()
const {
return flags2entry_ | std::views::values; }
226 return entries() | std::views::transform([](
const Entry& e) {
return e.def; });
230 size_t size()
const {
return flags2entry_.size(); }
247 auto i = flags2entry_.find(
flags);
248 assert(i != flags2entry_.end() &&
"cannot reattach an annex that was never attached");
257 auto begin()
const {
return flags2entry_.cbegin(); }
258 auto end()
const {
return flags2entry_.cend(); }
264 swap(a1.driver_, a2.driver_);
265 swap(a1.flags2entry_, a2.flags2entry_);
266 swap(a1.sym2flags_, a2.sym2flags_);
272 absl::btree_map<flags_t, Entry> flags2entry_;
273 absl::btree_map<Sym, flags_t> sym2flags_;
288 res.append_range(
annexes().defs());
301 if (
auto e = fe::lookup(
annexes().flags2entry(),
flags))
return e->def;
314 template<annex_without_subs
id>
324 template<
int sort = UMax::Univ>
328 template<level_t level = 0>
330 if constexpr (level == 0)
332 else if constexpr (level == 1)
348 assert(
this == &res->world());
356 return unify<Axm>(n, curry, trip,
type, p, t, s);
373 const Pi*
pi(
const Def* dom,
const Def* codom,
bool implicit =
false) {
return unify<Pi>(
Pi::infer(dom, codom), dom, codom, implicit); }
374 const Pi*
pi(
Defs dom,
const Def* codom,
bool implicit =
false) {
return pi(
sigma(dom), codom, implicit); }
375 const Pi*
pi(
const Def* dom,
Defs codom,
bool implicit =
false) {
return pi(dom,
sigma(codom), implicit); }
388 const Pi*
fn(
const Def* dom,
const Def* codom,
bool implicit =
false) {
return cn({ dom ,
cn(codom)}, implicit); }
389 const Pi*
fn(
Defs dom,
const Def* codom,
bool implicit =
false) {
return fn(
sigma(dom), codom, implicit); }
390 const Pi*
fn(
const Def* dom,
Defs codom,
bool implicit =
false) {
return fn( dom ,
sigma(codom), implicit); }
399 return std::get<const Def*>(
filter);
432 return unify<Rule>(
type, lhs, rhs, guard);
438 template<
bool Normalize = true>
440 template<
bool Normalize = true>
453 template<level_t level = 0>
464 template<level_t level = 0>
470 const Def*
arr (
const Def* arity,
const Def* body) {
return seq(
false, arity, body); }
476 const Def*
arr (fe::View<u64> shape,
const Def* body) {
return seq(
false, shape, body); }
477 const Def*
pack(fe::View<u64> shape,
const Def* body) {
return seq(
true , shape, body); }
492 const Def*
seq(
bool is_pack,
const Def* arity,
const Def* body);
495 const Def*
seq(
bool is_pack, fe::View<u64> shape,
const Def* body) {
542 if (
auto cached = data_.lit_nats[a])
return cached;
561 static_assert(std::is_integral<I>());
582 const Lit*
lit_bool(
bool val) {
return data_.lit_bool[size_t(val)]; }
641 template<
bool Normalize = true>
643 template<
bool Normalize = true>
647 template<
bool Normalize = true>
651 template<
bool Normalize = true,
class E>
653 requires std::is_enum_v<E> && std::is_same_v<std::underlying_type_t<E>,
nat_t> {
661 template<
bool Normalize =
true,
class T,
class... Args>
662 const Def*
call(
const Def* callee, T&& arg, Args&&... args) {
667 template<
bool Normalize = true,
class T>
673 template<
Enum Id,
bool Normalize =
true,
class... Args>
679 template<
class Id,
bool Normalize =
true,
class... Args>
680 requires std::is_enum_v<Id>
const Def*
call(Args&&... args) {
685 template<
bool Normalize =
true,
class... Args>
694 [[nodiscard]]
auto&
vars() {
return move_.vars; }
695 [[nodiscard]]
auto&
muts() {
return move_.muts; }
696 [[nodiscard]]
const auto&
vars()
const {
return move_.vars; }
697 [[nodiscard]]
const auto&
muts()
const {
return move_.muts; }
708 void for_each(
bool elide_empty, std::function<
void(
Def*)>,
bool schedule =
false);
711 void for_each(
bool elide_empty, std::function<
void(M*)> f,
bool schedule =
false) {
715 if (
auto mut = m->template isa<M>()) f(mut);
723 const fe::Log&
log()
const;
724 void dump(std::ostream& os);
727 void write(
const char* file);
738 void dot(
const char* file =
nullptr, DotConfig cfg = {})
const;
748#ifdef MIM_ENABLE_CHECKS
749 if (
flags().trace_gids) std::println(
"{}: {} - {}", def->node_name(), def->gid(), def->flags());
753 template<
class T,
class... Args>
754 const T* unify(Args&&... args) {
755 auto num_ops = T::Num_Ops;
756 if constexpr (T::Num_Ops == std::dynamic_extent) {
757 auto&&
last = std::get<
sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
758 num_ops =
last.size();
761 auto state = move_.arena.defs.state();
762 auto def = allocate<T>(num_ops, std::forward<Args>(args)...);
763 assert(!def->isa_mut());
766#ifdef MIM_ENABLE_CHECKS
768 for (
auto op : def->ops())
769 assert(&
op->world() ==
this &&
"op of new Def belongs to a different World");
770 assert((!def->type() || &def->type()->world() ==
this) &&
"type of new Def belongs to a different World");
774 auto i = move_.sea.find(def);
775 deallocate<T>(
state, def);
776 if (i != move_.sea.end())
return static_cast<const T*
>(*i);
780 if (
auto [i, ins] = move_.sea.emplace(def); !ins) {
781 deallocate<T>(
state, def);
782 return static_cast<const T*
>(*i);
785#ifdef MIM_ENABLE_CHECKS
792 void deallocate(fe::Arena::State
state,
const T* ptr) {
793 --state_.pod.curr_gid;
795 move_.arena.defs.deallocate(
state);
798 template<
class T,
class... Args>
799 T*
insert(Args&&... args) {
802 auto num_ops = T::Num_Ops;
803 if constexpr (T::Num_Ops == std::dynamic_extent)
804 num_ops = std::get<
sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
806 auto def = allocate<T>(num_ops, std::forward<Args>(args)...);
809#ifdef MIM_ENABLE_CHECKS
812 fe::assert_emplace(move_.sea, def);
816#if (!defined(_MSC_VER) && defined(NDEBUG))
818 Lock() { assert((guard_ = !guard_) &&
"you are not allowed to recursively invoke allocate"); }
819 ~Lock() { guard_ = !guard_; }
828 template<
class T,
class... Args>
829 T* allocate(
size_t num_ops, Args&&... args) {
830 static_assert(
sizeof(Def) ==
sizeof(T),
831 "you are not allowed to introduce any additional data in subclasses of Def");
833 auto num_bytes =
sizeof(Def) +
sizeof(uintptr_t) * num_ops;
834 auto ptr = move_.arena.defs.allocate(num_bytes,
alignof(T));
835 auto res =
new (ptr) T(std::forward<Args>(args)...);
836 assert(res->num_ops() == num_ops);
846 size_t operator()(
const Def* def)
const {
return def->hash(); }
850 bool operator()(
const Def* d1,
const Def* d2)
const {
return d1->equal(d2); }
853 class Reduct :
public fe::VLA<Reduct> {
855 using VLA_Types = std::tuple<const Def*>;
857 template<
size_t N = std::dynamic_extent>
858 auto defs() const noexcept {
859 return vla<0>().template span<N>();
865 const Reduct* cache_reduct(
const Var*
var,
const Def* arg,
size_t n, F f) {
866 return cache_reduct(
var, arg,
DefVec(n, f));
870 const Reduct* cache_reduct(
const Var*
var,
const Def* arg,
Defs defs) {
871 auto reduct = move_.arena.substs.ref<Reduct>(defs).
get();
872 fe::assert_emplace(move_.substs, std::pair{var, arg}, reduct);
886 absl::flat_hash_set<const Def*, SeaHash, SeaEq> sea;
887 fe::Patricia<Def, DefKey> muts;
888 fe::Patricia<const Var, DefKey> vars;
889 absl::flat_hash_map<std::pair<const Var*, const Def*>,
const Reduct*> substs;
891 friend void swap(Move& m1, Move& m2)
noexcept {
894 swap(m1.arena.defs, m2.arena.defs);
895 swap(m1.arena.substs, m2.arena.substs);
896 swap(m1.sea, m2.sea);
897 swap(m1.substs, m2.substs);
898 swap(m1.vars, m2.vars);
899 swap(m1.muts, m2.muts);
900 swap(m1.externals, m2.externals);
901 swap(m1.annexes, m2.annexes);
925 std::array<const Lit*, Num_Lit_Nats> lit_nats = {};
932 swap(w1.driver_, w2.driver_ );
933 swap(w1.zonker_, w2.zonker_ );
934 swap(w1.state_, w2.state_);
935 swap(w1.data_, w2.data_ );
936 swap(w1.move_, w2.move_ );
939 swap(w1.data_.univ->world_, w2.data_.univ->world_);
940 assert(&w1.univ()->world() == &w1);
941 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)
A (possibly paramterized) Tuple.
A dependent function type.
static const Def * infer(const Def *dom, const Def *codom)
Used as intermediate value during optimizatinos such as Analysis.
Base class for Arr and Pack.
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
const Def * reattach(flags_t flags, const Def *def)
Overwrites the Def of an already attach()ed annex, keeping its Sym.
void attach_alias(flags_t, Sym)
Registers a further Sym for an already attach()ed annex, sharing its flags_t;.
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
friend void swap(Annexes &a1, Annexes &a2) noexcept
void attach_alias(plugin_t p, tag_t t, sub_t s, Sym sym)
auto & flags2entry()
An annex's flags map to its full name and its Def.
Def * operator[](Sym name) const
Lookup by name.
friend void swap(Externals &ex1, Externals &ex2) noexcept
fe::Vector< Def * > mutate() const
Returns a copy of muts() in a fe::Vector; this allows you to modify the Externals while iterating.
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)
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)
const Proxy * proxy(const Def *type, Defs ops, flags_t tag)
Lam * mut_lam(const Def *dom, Defs codom)
const Def * filter(Lam::Filter filter)
const auto & watchpoints()
const Def * sigma(Defs ops)
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 fe::Log & log() const
Log via log().e("...", args) etc.; owned by the Driver.
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 dot(std::ostream &os, DotConfig cfg={}) const
Dumps DOT to os, configured via cfg (see DotConfig).
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)
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)
const Def * call(Args &&... args)
Annex overload with enum tempalte argument Id for annexes w/o subtag.
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 Def * tuple(Defs ops)
const Lam * fun(Defs dom, Defs codom, Lam::Filter f, const Def *body)
const Def * pack(fe::View< u64 > shape, 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 fe::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)
const Def * inj(const Def *type, const Def *value)
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)
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)
const Def * arr(fe::View< u64 > shape, const Def *body)
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)
fe::Restore< CurrLoc > ScopedLoc
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
static constexpr nat_t Num_Lit_Nats
Def::arity of a Sigma is lit_nat(num_ops()) and Def::num_projs reads it straight back out,...
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)
DbgKey dbg_key() const
World::get_loc, already interned.
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.
auto freeze() const
Freezes the World until the end of the scope and restores the previous frozen state afterwards:
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 * seq(bool is_pack, fe::View< u64 > shape, const Def *body)
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)
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.
World::get_loc together with its interned DbgKey, so pushing/popping a Loc never re-interns it.
fe::View< const Def * > Defs
fe::Vector< const Def * > DefVec
const Def *(*)(const Def *, const Def *, const Def *) NormalizeFn
Options for Def::dot and World::dot.
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 std::string demangle(plugin_t plugin)
Reverts an Axm::mangled plugin back to its name; never longer than Annex::Max_Plugin_Size.
static consteval flags_t base()
Compiler switches that must be saved and looked up in later phases of compilation.
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