diff --git a/cli/main.cpp b/cli/main.cpp index 8dd171e4e3..34d7d0b0e3 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -8,6 +8,7 @@ #include "thorin/config.h" #include "thorin/dialects.h" +#include "thorin/driver.h" #include "thorin/be/dot/dot.h" #include "thorin/fe/parser.h" @@ -26,7 +27,7 @@ int main(int argc, char** argv) { try { static const auto version = "thorin command-line utility version " THORIN_VER "\n"; - World::State state; + Driver driver; bool show_help = false; bool show_version = false; std::string input, prefix; @@ -37,7 +38,7 @@ int main(int argc, char** argv) { int verbose = 0; int opt = 2; auto inc_verbose = [&](bool) { ++verbose; }; - auto& flags = state.pod.flags; + auto& flags = driver.flags; // clang-format off auto cli = lyra::cli() @@ -78,9 +79,9 @@ int main(int argc, char** argv) { } #if THORIN_ENABLE_CHECKS - for (auto b : breakpoints) state.breakpoints.emplace(b); + for (auto b : breakpoints) driver.breakpoints.emplace(b); #endif - World world(state); + World& world = driver.world; world.log().ostream = &std::cerr; world.log().level = (Log::Level)verbose; // prepare output files and streams @@ -124,9 +125,11 @@ int main(int argc, char** argv) { } for (const auto& dialect : dialects) - fe::Parser::import_module(world, dialect.name(), dialect_paths, &normalizers); + fe::Parser::import_module(world, world.sym(dialect.name()), dialect_paths, &normalizers); - fe::Parser parser(world, input, ifs, dialect_paths, &normalizers, os[Md]); + auto sym = world.sym(std::move(input)); + world.set(sym); + fe::Parser parser(world, sym, ifs, dialect_paths, &normalizers, os[Md]); parser.parse_module(); if (os[H]) { diff --git a/cmake/Thorin.cmake b/cmake/Thorin.cmake index 7663399e9a..a40b288954 100644 --- a/cmake/Thorin.cmake +++ b/cmake/Thorin.cmake @@ -1,6 +1,6 @@ # clear globals -SET(THORIN_DIALECT_LIST "" CACHE INTERNAL "THORIN_DIALECT_LIST") -SET(THORIN_DIALECT_LAYOUT "" CACHE INTERNAL "THORIN_DIALECT_LAYOUT") +SET(THORIN_DIALECT_LIST "" CACHE INTERNAL "THORIN_DIALECT_LIST") +SET(THORIN_DIALECT_LAYOUT "" CACHE INTERNAL "THORIN_DIALECT_LAYOUT") if(NOT THORIN_TARGET_NAMESPACE) set(THORIN_TARGET_NAMESPACE "") diff --git a/dialects/affine/passes/lower_for.cpp b/dialects/affine/passes/lower_for.cpp index c6a6983317..be9a368836 100644 --- a/dialects/affine/passes/lower_for.cpp +++ b/dialects/affine/passes/lower_for.cpp @@ -16,18 +16,22 @@ const Def* LowerFor::rewrite(const Def* def) { auto for_pi = for_ax->callee_type(); DefArray for_dom{for_pi->num_doms() - 2, [&](size_t i) { return for_pi->dom(i); }}; - auto for_lam = w.nom_lam(w.cn(for_dom), w.dbg("for")); + auto for_lam = w.nom_lam(w.cn(for_dom))->set("for"); - auto body = for_ax->arg(for_ax->num_args() - 2, w.dbg("body")); - auto brk = for_ax->arg(for_ax->num_args() - 1, w.dbg("break")); + auto body = for_ax->arg(for_ax->num_args() - 2)->set("body"); + auto brk = for_ax->arg(for_ax->num_args() - 1)->set("break"); auto body_type = body->type()->as(); auto yield_pi = body_type->doms().back()->as(); - auto yield_lam = w.nom_lam(yield_pi, w.dbg("yield")); + auto yield_lam = w.nom_lam(yield_pi)->set("yield"); { // construct yield - auto [iter, end, step, acc] = for_lam->vars<4>({w.dbg("begin"), w.dbg("end"), w.dbg("step"), w.dbg("acc")}); - auto yield_acc = yield_lam->var(); + auto [iter, end, step, acc] = for_lam->vars<4>(); + iter->set("iter"); + end->set("end"); + step->set("step"); + acc->set("acc"); + auto yield_acc = yield_lam->var(); auto add = w.call(core::wrap::add, 0_n, Defs{iter, step}); yield_lam->app(false, for_lam, {add, end, step, yield_acc}); @@ -37,12 +41,12 @@ const Def* LowerFor::rewrite(const Def* def) { // reduce the body to remove the cn parameter auto nom_body = body->as_nom(); - auto new_body = nom_body->stub(w, w.cn(w.sigma()), body->dbg()); + auto new_body = nom_body->stub(w, w.cn(w.sigma()))->set(body->dbg()); new_body->set(nom_body->reduce(w.tuple({iter, acc, yield_lam}))); // break auto if_else_cn = w.cn(w.sigma()); - auto if_else = w.nom_lam(if_else_cn, nullptr); + auto if_else = w.nom_lam(if_else_cn); if_else->app(false, brk, acc); auto cmp = w.call(core::icmp::ul, Defs{iter, end}); @@ -50,7 +54,7 @@ const Def* LowerFor::rewrite(const Def* def) { } DefArray for_args{for_ax->num_args() - 2, [&](size_t i) { return for_ax->arg(i); }}; - return rewritten_[def] = w.app(for_lam, for_args, for_ax->dbg()); + return rewritten_[def] = w.app(for_lam, for_args); } return def; diff --git a/dialects/autodiff/auxiliary/autodiff_aux.cpp b/dialects/autodiff/auxiliary/autodiff_aux.cpp index 7c6780cee2..6d01a9e739 100644 --- a/dialects/autodiff/auxiliary/autodiff_aux.cpp +++ b/dialects/autodiff/auxiliary/autodiff_aux.cpp @@ -6,13 +6,15 @@ #include "dialects/autodiff/autodiff.h" #include "dialects/mem/mem.h" +using namespace std::literals; + namespace thorin::autodiff { const Def* id_pullback(const Def* A) { auto& world = A->world(); auto arg_pb_ty = pullback_type(A, A); - auto id_pb = world.nom_lam(arg_pb_ty, world.dbg("id_pb")); - auto id_pb_scalar = id_pb->var((nat_t)0, world.dbg("s")); + auto id_pb = world.nom_lam(arg_pb_ty)->set("id_pb"); + auto id_pb_scalar = id_pb->var(0_s)->set("s"); id_pb->app(true, id_pb->var(1), // can not use ret_var as the result might be higher order id_pb_scalar); @@ -24,7 +26,7 @@ const Def* zero_pullback(const Def* E, const Def* A) { auto& world = A->world(); auto A_tangent = tangent_type_fun(A); auto pb_ty = pullback_type(E, A); - auto pb = world.nom_lam(pb_ty, world.dbg("zero_pb")); + auto pb = world.nom_lam(pb_ty)->set("zero_pb"); world.DLOG("zero_pullback for {} resp. {} (-> {})", E, A, A_tangent); pb->app(true, pb->var(1), op_zero(A_tangent)); return pb; @@ -129,7 +131,7 @@ const Def* zero_def(const Def* T) { return zero_arr; } else if (Idx::size(T)) { // TODO: real - auto zero = world.lit(T, 0, world.dbg("zero")); + auto zero = world.lit(T, 0)->set("zero"); world.DLOG("zero_def for int is {}", zero); return zero; } else if (auto sig = T->isa()) { @@ -234,8 +236,8 @@ const Def* compose_continuation(const Def* f, const Def* g) { auto H = world.cn({A, world.cn(C)}); auto Hcont = world.cn(B); - auto h = world.nom_lam(H, world.dbg("comp_" + f->name() + "_" + g->name())); - auto hcont = world.nom_lam(Hcont, world.dbg("comp_" + f->name() + "_" + g->name() + "_cont")); + auto h = world.nom_lam(H)->set("comp_"s + *f->sym() + "_"s + *g->sym()); + auto hcont = world.nom_lam(Hcont)->set("comp_"s + *f->sym() + "_"s + *g->sym() + "_cont"s); h->app(true, g, {h->var((nat_t)0), hcont}); diff --git a/dialects/autodiff/auxiliary/autodiff_rewrite_inner.cpp b/dialects/autodiff/auxiliary/autodiff_rewrite_inner.cpp index 90b3e9487c..cc29cf3bfb 100644 --- a/dialects/autodiff/auxiliary/autodiff_rewrite_inner.cpp +++ b/dialects/autodiff/auxiliary/autodiff_rewrite_inner.cpp @@ -11,6 +11,8 @@ #include "dialects/core/core.h" #include "dialects/direct/direct.h" +using namespace std::literals; + namespace thorin::autodiff { // TODO remove macro @@ -44,8 +46,8 @@ const Def* AutoDiffEval::augment_lam(Lam* lam, Lam* f, Lam* f_diff) { } // TODO: better fix (another pass as analysis?) // TODO: handle open functions - if (is_open_continuation(lam) || lam->name().find("ret") != std::string::npos || - lam->name().find("_cont") != std::string::npos) { + if (is_open_continuation(lam) || lam->sym()->find("ret") != std::string::npos || + lam->sym()->find("_cont") != std::string::npos) { // A open continuation behaves the same as return: // ``` // cont: Cn[X] @@ -62,7 +64,7 @@ const Def* AutoDiffEval::augment_lam(Lam* lam, Lam* f, Lam* f_diff) { world.DLOG("pb type is {}", pb_ty); auto aug_ty = world.cn({aug_dom, pb_ty}); world.DLOG("augmented type is {}", aug_ty); - auto aug_lam = world.nom_lam(aug_ty, world.dbg("aug_" + lam->name())); + auto aug_lam = world.nom_lam(aug_ty)->set("aug_"s + *lam->sym()); auto aug_var = aug_lam->var((nat_t)0); augmented[lam->var()] = aug_var; augmented[lam] = aug_lam; // TODO: only one of these two @@ -115,10 +117,10 @@ const Def* AutoDiffEval::augment_extract(const Extract* ext, Lam* f, Lam* f_diff assert(partial_pullback.count(aug_tuple)); auto tuple_pb = partial_pullback[aug_tuple]; auto pb_ty = pullback_type(ext->type(), f_arg_ty); - auto pb_fun = world.nom_lam(pb_ty, world.dbg("extract_pb")); + auto pb_fun = world.nom_lam(pb_ty)->set("extract_pb"); world.DLOG("Pullback: {} : {}", pb_fun, pb_fun->type()); - auto pb_tangent = pb_fun->var((nat_t)0, world.dbg("s")); - auto tuple_tan = world.insert(op_zero(aug_tuple->type()), aug_index, pb_tangent, world.dbg("tup_s")); + auto pb_tangent = pb_fun->var(0_s)->set("s"); + auto tuple_tan = world.insert(op_zero(aug_tuple->type()), aug_index, pb_tangent)->set("tup_s"); pb_fun->app(true, tuple_pb, { tuple_tan, @@ -152,12 +154,12 @@ const Def* AutoDiffEval::augment_tuple(const Tuple* tup, Lam* f, Lam* f_diff) { // ((cps2ds e0*) (s#0), ..., (cps2ds em*) (s#m)) // ``` auto pb_ty = pullback_type(tup->type(), f_arg_ty); - auto pb = world.nom_lam(pb_ty, world.dbg("tup_pb")); + auto pb = world.nom_lam(pb_ty)->set("tup_pb"); world.DLOG("Augmented tuple: {} : {}", aug_tup, aug_tup->type()); world.DLOG("Tuple Pullback: {} : {}", pb, pb->type()); world.DLOG("shadow pb: {} : {}", shadow_pb, shadow_pb->type()); - auto pb_tangent = pb->var((nat_t)0, world.dbg("tup_s")); + auto pb_tangent = pb->var(0_s)->set("tup_s"); DefArray tangents(pbs.size(), [&](nat_t i) { return world.app(direct::op_cps2ds_dep(pbs[i]), world.extract(pb_tangent, i)); }); @@ -188,7 +190,7 @@ const Def* AutoDiffEval::augment_pack(const Pack* pack, Lam* f, Lam* f_diff) { world.DLOG("shadow pb of pack: {} : {}", pb_pack, pb_pack->type()); auto pb_type = pullback_type(pack->type(), f_arg_ty); - auto pb = world.nom_lam(pb_type, world.dbg("pack_pb")); + auto pb = world.nom_lam(pb_type)->set("pack_pb"); world.DLOG("pb of pack: {} : {}", pb, pb_type); @@ -305,7 +307,7 @@ const Def* AutoDiffEval::augment_app(const App* app, Lam* f, Lam* f_diff) { world.DLOG("ret_g_deriv_ty: {} ", ret_g_deriv_ty); auto c1_ty = ret_g_deriv_ty->as(); world.DLOG("c1_ty: (cn[X, cn[X+, cn E+]]) {}", c1_ty); - auto c1 = world.nom_lam(c1_ty, world.dbg("c1")); + auto c1 = world.nom_lam(c1_ty)->set("c1"); auto res = c1->var((nat_t)0); auto r_pb = c1->var(1); c1->app(true, aug_cont, {res, compose_continuation(e_pb, r_pb)}); @@ -364,14 +366,14 @@ const Def* AutoDiffEval::augment_(const Def* def, Lam* f, Lam* f_diff) { world.DLOG("Augment axiom: {} : {}", ax, ax->type()); world.DLOG("axiom curry: {}", ax->curry()); world.DLOG("axiom flags: {}", ax->flags()); - std::string diff_name = ax->name(); + std::string diff_name = ax->sym(); findAndReplaceAll(diff_name, ".", "_"); findAndReplaceAll(diff_name, "%", ""); diff_name = "internal_diff_" + diff_name; - world.DLOG("axiom name: {}", ax->name()); + world.DLOG("axiom name: {}", ax->sym()); world.DLOG("axiom function name: {}", diff_name); - auto diff_fun = world.lookup(diff_name); + auto diff_fun = world.lookup(world.sym(diff_name)); if (!diff_fun) { world.ELOG("derivation not found: {}", diff_name); auto expected_type = autodiff_type_fun(ax->type()); diff --git a/dialects/autodiff/auxiliary/autodiff_rewrite_toplevel.cpp b/dialects/autodiff/auxiliary/autodiff_rewrite_toplevel.cpp index efd7ae9a4e..b4e2afecca 100644 --- a/dialects/autodiff/auxiliary/autodiff_rewrite_toplevel.cpp +++ b/dialects/autodiff/auxiliary/autodiff_rewrite_toplevel.cpp @@ -10,7 +10,7 @@ const Def* AutoDiffEval::derive_(const Def* def) { auto lam = def->as_nom(); // TODO check if nominal world.DLOG("Derive lambda: {}", def); auto deriv_ty = autodiff_type_fun_pi(lam->type()); - auto deriv = world.nom_lam(deriv_ty, world.dbg(lam->name() + "_deriv")); + auto deriv = world.nom_lam(deriv_ty)->set(*lam->sym() + "_deriv"); // We first pre-register the derivatives. // This knowledge is needed for recursion. @@ -20,7 +20,7 @@ const Def* AutoDiffEval::derive_(const Def* def) { auto [arg_ty, ret_pi] = lam->type()->doms<2>(); auto deriv_all_args = deriv->var(); - const Def* deriv_arg = deriv->var((nat_t)0, world.dbg("arg")); + const Def* deriv_arg = deriv->var(0_s)->set("arg"); // We generate the shadow pullbacks dynamically to save work and avoid code duplication. // Only the toplevel pullback for arguments and return continuation is special cased. diff --git a/dialects/autodiff/normalizers.cpp b/dialects/autodiff/normalizers.cpp index db1d6646c3..8763a2bc18 100644 --- a/dialects/autodiff/normalizers.cpp +++ b/dialects/autodiff/normalizers.cpp @@ -11,31 +11,31 @@ namespace thorin::autodiff { /// Currently this normalizer does nothin. /// TODO: Maybe we want to handle trivial lookup replacements here. -const Def* normalize_ad(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_ad(Ref type, Ref callee, Ref arg) { auto& world = type->world(); - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } -const Def* normalize_AD(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_AD(Ref type, Ref callee, Ref arg) { auto& world = type->world(); auto ad_ty = autodiff_type_fun(arg); if (ad_ty) return ad_ty; - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } -const Def* normalize_Tangent(const Def*, const Def*, const Def* arg, const Def*) { return tangent_type_fun(arg); } +Ref normalize_Tangent(Ref, Ref, Ref arg) { return tangent_type_fun(arg); } /// Currently this normalizer does nothing. /// We usually want to keep zeros as long as possible to avoid unnecessary allocations. /// A high-level addition with zero can be shortened directly. -const Def* normalize_zero(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_zero(Ref type, Ref callee, Ref arg) { auto& world = type->world(); - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } /// Currently resolved the full addition. /// There is no benefit in keeping additions around longer than necessary. -const Def* normalize_add(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_add(Ref type, Ref callee, Ref arg) { auto& world = type->world(); // TODO: add tuple -> tuple of adds @@ -85,10 +85,10 @@ const Def* normalize_add(const Def* type, const Def* callee, const Def* arg, con } // TODO: mem stays here (only resolved after direct simplification) - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } -const Def* normalize_sum(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_sum(Ref type, Ref callee, Ref arg) { auto& world = type->world(); auto [count, T] = callee->as()->args<2>(); @@ -105,7 +105,7 @@ const Def* normalize_sum(const Def* type, const Def* callee, const Def* arg, con } assert(0); - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } THORIN_autodiff_NORMALIZER_IMPL diff --git a/dialects/autodiff/passes/autodiff_ext_cleanup.cpp b/dialects/autodiff/passes/autodiff_ext_cleanup.cpp index 24d5f5825b..799735d6ec 100644 --- a/dialects/autodiff/passes/autodiff_ext_cleanup.cpp +++ b/dialects/autodiff/passes/autodiff_ext_cleanup.cpp @@ -14,7 +14,7 @@ namespace thorin::autodiff { void AutoDiffExternalCleanup::enter() { Lam* lam = curr_nom(); - if (lam->name().starts_with("internal_diff_")) { + if (lam->sym()->starts_with("internal_diff_")) { lam->make_internal(); world().DLOG("internalized {}", lam); } diff --git a/dialects/clos/clos.cpp b/dialects/clos/clos.cpp index c83741275d..4e99860f95 100644 --- a/dialects/clos/clos.cpp +++ b/dialects/clos/clos.cpp @@ -24,12 +24,12 @@ namespace thorin::clos { * ClosLit */ -const Def* ClosLit::env() { +Ref ClosLit::env() { assert(def_); return std::get<2_u64>(clos_unpack(def_)); } -const Def* ClosLit::fnc() { +Ref ClosLit::fnc() { assert(def_); return std::get<1_u64>(clos_unpack(def_)); } @@ -40,9 +40,9 @@ Lam* ClosLit::fnc_as_lam() { return f->isa_nom(); } -const Def* ClosLit::env_var() { return fnc_as_lam()->var(Clos_Env_Param); } +Ref ClosLit::env_var() { return fnc_as_lam()->var(Clos_Env_Param); } -ClosLit isa_clos_lit(const Def* def, bool lambda_or_branch) { +ClosLit isa_clos_lit(Ref def, bool lambda_or_branch) { auto tpl = def->isa(); if (tpl && isa_clos_type(def->type())) { auto a = attr::bot; @@ -56,17 +56,17 @@ ClosLit isa_clos_lit(const Def* def, bool lambda_or_branch) { return ClosLit(nullptr, attr::bot); } -const Def* clos_pack_dbg(const Def* env, const Def* lam, const Def* dbg, const Def* ct) { +Ref clos_pack(Ref env, Ref lam, Ref ct) { assert(env && lam); assert(!ct || isa_clos_type(ct)); auto& w = env->world(); auto pi = lam->type()->as(); assert(env->type() == pi->dom(Clos_Env_Param)); ct = (ct) ? ct : clos_type(w.cn(clos_remove_env(pi->dom()))); - return w.tuple(ct, {env->type(), lam, env}, dbg)->isa(); + return w.tuple(ct, {env->type(), lam, env})->isa(); } -std::tuple clos_unpack(const Def* c) { +std::tuple clos_unpack(Ref c) { assert(c && isa_clos_type(c->type())); // auto& w = c->world(); // auto env_type = c->proj(0_u64); @@ -78,7 +78,7 @@ std::tuple clos_unpack(const Def* c) { return {ty, pi, env}; } -const Def* clos_apply(const Def* closure, const Def* args) { +Ref clos_apply(Ref closure, Ref args) { auto& w = closure->world(); auto [_, fn, env] = clos_unpack(closure); auto pi = fn->type()->as(); @@ -89,7 +89,7 @@ const Def* clos_apply(const Def* closure, const Def* args) { * closure types */ -const Sigma* isa_clos_type(const Def* def) { +const Sigma* isa_clos_type(Ref def) { auto& w = def->world(); auto sig = def->isa_nom(); if (!sig || sig->num_ops() < 3 || sig->op(0_u64) != w.type()) return nullptr; @@ -101,7 +101,7 @@ const Sigma* isa_clos_type(const Def* def) { Sigma* clos_type(const Pi* pi) { return ctype(pi->world(), pi->doms(), nullptr)->as_nom(); } -const Pi* clos_type_to_pi(const Def* ct, const Def* new_env_type) { +const Pi* clos_type_to_pi(Ref ct, Ref new_env_type) { assert(isa_clos_type(ct)); auto& w = ct->world(); auto pi = ct->op(1_u64)->as(); @@ -113,15 +113,15 @@ const Pi* clos_type_to_pi(const Def* ct, const Def* new_env_type) { * closure environments */ -const Def* clos_insert_env(size_t i, const Def* env, std::function f) { +Ref clos_insert_env(size_t i, Ref env, std::function f) { return (i == Clos_Env_Param) ? env : f(shift_env(i)); } -const Def* clos_remove_env(size_t i, std::function f) { return f(skip_env(i)); } +Ref clos_remove_env(size_t i, std::function f) { return f(skip_env(i)); } -const Def* ctype(World& w, Defs doms, const Def* env_type) { +Ref ctype(World& w, Defs doms, Ref env_type) { if (!env_type) { - auto sigma = w.nom_sigma(w.type(), 3_u64, w.dbg("Clos")); + auto sigma = w.nom_sigma(w.type(), 3_u64)->set("Clos"); sigma->set(0_u64, w.type()); sigma->set(1_u64, ctype(w, doms, sigma->var(0_u64))); sigma->set(2_u64, sigma->var(0_u64)); @@ -165,8 +165,7 @@ extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { register_pass(passes); register_pass(passes); // TODO:; remove after ho_codegen merge - passes[flags_t(Axiom::Base)] = [&](World&, PipelineBuilder& builder, - const Def* app) { + passes[flags_t(Axiom::Base)] = [&](World&, PipelineBuilder& builder, Ref app) { auto bb = app->as()->arg(); auto bb_only = bb->as()->get(); builder.add_pass(app, bb_only); diff --git a/dialects/clos/clos.h b/dialects/clos/clos.h index 7cb6047f55..cf776668d0 100644 --- a/dialects/clos/clos.h +++ b/dialects/clos/clos.h @@ -6,21 +6,21 @@ namespace thorin::clos { -inline const Def* op_alloc_jumpbuf(const Def* mem, const Def* dbg = {}) { +inline Ref op_alloc_jumpbuf(Ref mem) { World& w = mem->world(); - return w.app(w.ax(), {w.tuple(), mem}, dbg); + return w.app(w.ax(), {w.tuple(), mem}); } -inline const Def* op_setjmp(const Def* mem, const Def* buf, const Def* dbg = {}) { +inline Ref op_setjmp(Ref mem, Ref buf) { World& w = mem->world(); - return w.app(w.ax(), {mem, buf}, dbg); + return w.app(w.ax(), {mem, buf}); } -inline const Def* op_longjmp(const Def* mem, const Def* buf, const Def* id, const Def* dbg = {}) { +inline Ref op_longjmp(Ref mem, Ref buf, Ref id) { World& w = mem->world(); - return w.app(w.ax(), {mem, buf, id}, dbg); + return w.app(w.ax(), {mem, buf, id}); } -inline const Def* op(attr o, const Def* def, const Def* dbg = {}) { +inline Ref op(attr o, Ref def) { World& w = def->world(); - return w.app(w.app(w.ax(o), def->type()), def, dbg); + return w.app(w.app(w.ax(o), def->type()), def); } /// @name closures @@ -36,15 +36,15 @@ class ClosLit { return def_->type()->isa(); } - const Def* env(); - const Def* env_type() { return env()->type(); } + Ref env(); + Ref env_type() { return env()->type(); } - const Def* fnc(); + Ref fnc(); const Pi* fnc_type() { return fnc()->type()->isa(); } Lam* fnc_as_lam(); - const Def* env_var(); - const Def* ret_var() { return fnc_as_lam()->ret_var(); } + Ref env_var(); + Ref ret_var() { return fnc_as_lam()->ret_var(); } ///@} operator bool() const { return def_ != nullptr; } @@ -71,27 +71,23 @@ class ClosLit { const Tuple* def_; const attr attr_; - friend ClosLit isa_clos_lit(const Def*, bool); + friend ClosLit isa_clos_lit(Ref, bool); }; /// Tries to match a closure literal. -ClosLit isa_clos_lit(const Def* def, bool fn_isa_lam = true); +ClosLit isa_clos_lit(Ref def, bool fn_isa_lam = true); /// Pack a typed closure. This assumes that @p fn expects the environment as its Clos_Env_Param%th argument. -const Def* clos_pack_dbg(const Def* env, const Def* fn, const Def* dbg, const Def* ct = nullptr); - -inline const Def* clos_pack(const Def* env, const Def* fn, const Def* ct = nullptr) { - return clos_pack_dbg(env, fn, nullptr, ct); -} +Ref clos_pack(Ref env, Ref fn, Ref ct = nullptr); /// Deconstruct a closure into `(env_type, function, env)`. /// **Important**: use this or ClosLit to destruct closures, since typechecking dependent pairs is currently /// broken. -std::tuple clos_unpack(const Def* c); +std::tuple clos_unpack(Ref c); /// Apply a closure to arguments. -const Def* clos_apply(const Def* closure, const Def* args); -inline const Def* apply_closure(const Def* closure, Defs args) { +Ref clos_apply(Ref closure, Ref args); +inline Ref apply_closure(Ref closure, Defs args) { auto& w = closure->world(); return clos_apply(closure, w.tuple(args)); } @@ -99,7 +95,7 @@ inline const Def* apply_closure(const Def* closure, Defs args) { // TODO: rename this /// Checks is def is the variable of a nom of type N. template -std::tuple ca_isa_var(const Def* def) { +std::tuple ca_isa_var(Ref def) { if (auto proj = def->isa()) { if (auto var = proj->tuple()->isa(); var && var->nom()->isa()) return std::tuple(proj, var->nom()->as()); @@ -112,14 +108,14 @@ std::tuple ca_isa_var(const Def* def) { ///@{ /// Returns @p def if @p def is a closure and @c nullptr otherwise -const Sigma* isa_clos_type(const Def* def); +const Sigma* isa_clos_type(Ref def); /// Creates a typed closure type from @p pi. Sigma* clos_type(const Pi* pi); /// Convert a closure type to a Pi, where the environment type has been removed or replaced by @p new_env_type /// (if @p new_env_type != @c nullptr) -const Pi* clos_type_to_pi(const Def* ct, const Def* new_env_type = nullptr); +const Pi* clos_type_to_pi(Ref ct, Ref new_env_type = nullptr); ///@} @@ -137,32 +133,30 @@ inline size_t shift_env(size_t i) { return (i < Clos_Env_Param) ? i : i - 1_u64; inline size_t skip_env(size_t i) { return (i < Clos_Env_Param) ? i : i + 1_u64; } // TODO what does this do exactly? -const Def* ctype(World& w, Defs doms, const Def* env_type = nullptr); +Ref ctype(World& w, Defs doms, Ref env_type = nullptr); -const Def* clos_insert_env(size_t i, const Def* env, std::function f); -inline const Def* clos_insert_env(size_t i, const Def* env, const Def* a) { +Ref clos_insert_env(size_t i, Ref env, std::function f); +inline Ref clos_insert_env(size_t i, Ref env, Ref a) { return clos_insert_env(i, env, [&](auto i) { return a->proj(i); }); } -inline const Def* clos_insert_env(const Def* env, const Def* tup_or_sig) { +inline Ref clos_insert_env(Ref env, Ref tup_or_sig) { auto& w = tup_or_sig->world(); auto new_ops = DefArray(tup_or_sig->num_projs() + 1, [&](auto i) { return clos_insert_env(i, env, tup_or_sig); }); return (tup_or_sig->isa()) ? w.sigma(new_ops) : w.tuple(new_ops); } -const Def* clos_remove_env(size_t i, std::function f); -inline const Def* clos_remove_env(size_t i, const Def* def) { +Ref clos_remove_env(size_t i, std::function f); +inline Ref clos_remove_env(size_t i, Ref def) { return clos_remove_env(i, [&](auto i) { return def->proj(i); }); } -inline const Def* clos_remove_env(const Def* tup_or_sig) { +inline Ref clos_remove_env(Ref tup_or_sig) { auto& w = tup_or_sig->world(); auto new_ops = DefArray(tup_or_sig->num_projs() - 1, [&](auto i) { return clos_remove_env(i, tup_or_sig); }); return (tup_or_sig->isa()) ? w.sigma(new_ops) : w.tuple(new_ops); } -inline const Def* clos_sub_env(const Def* tup_or_sig, const Def* new_env) { - return tup_or_sig->refine(Clos_Env_Param, new_env); -} +inline Ref clos_sub_env(Ref tup_or_sig, Ref new_env) { return tup_or_sig->refine(Clos_Env_Param, new_env); } ///@} } // namespace thorin::clos diff --git a/dialects/clos/normalizers.cpp b/dialects/clos/normalizers.cpp index d1b08512b6..98b0dddbf1 100644 --- a/dialects/clos/normalizers.cpp +++ b/dialects/clos/normalizers.cpp @@ -3,9 +3,9 @@ namespace thorin::clos { template -const Def* normalize_clos(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_clos(Ref type, Ref callee, Ref arg) { auto& w = type->world(); - return o == attr::bot ? arg : w.raw_app(type, callee, arg, dbg); + return o == attr::bot ? arg : w.raw_app(type, callee, arg); } THORIN_clos_NORMALIZER_IMPL diff --git a/dialects/clos/pass/rw/branch_clos_elim.cpp b/dialects/clos/pass/rw/branch_clos_elim.cpp index 020d8a5179..754f00c0a6 100644 --- a/dialects/clos/pass/rw/branch_clos_elim.cpp +++ b/dialects/clos/pass/rw/branch_clos_elim.cpp @@ -34,7 +34,7 @@ const Def* BranchClosElim::rewrite(const Def* def) { auto& dropped_lam = entry->second; if (inserted || !dropped_lam) { auto clam = c.fnc_as_lam(); - dropped_lam = clam->stub(w, clos_type_to_pi(c.type()), clam->dbg()); + dropped_lam = clam->stub(w, clos_type_to_pi(c.type())); auto new_vars = clos_insert_env(c.env(), dropped_lam->var()); dropped_lam->set(clam->reduce(new_vars)); } diff --git a/dialects/clos/pass/rw/clos2sjlj.cpp b/dialects/clos/pass/rw/clos2sjlj.cpp index 12ac4b0fe0..631e1a4468 100644 --- a/dialects/clos/pass/rw/clos2sjlj.cpp +++ b/dialects/clos/pass/rw/clos2sjlj.cpp @@ -83,7 +83,7 @@ Lam* Clos2SJLJ::get_throw(const Def* dom) { auto& tlam = p->second; if (inserted || !tlam) { auto pi = w.cn(clos_sub_env(dom, w.sigma({jb_type(), rb_type(), tag_type()}))); - tlam = w.nom_lam(pi, w.dbg("throw")); + tlam = w.nom_lam(pi)->set("throw"); auto [m0, env, var] = split(tlam->var()); auto [jbuf, rbuf, tag] = env->projs<3>(); auto [m1, r] = mem::op_alloc(var->type(), m0)->projs<2>(); @@ -103,7 +103,7 @@ Lam* Clos2SJLJ::get_lpad(Lam* lam, const Def* rb) { if (inserted || !lpad) { auto [_, env_type, dom] = split(lam->dom()); auto pi = w.cn(w.sigma({mem::type_mem(w), env_type})); - lpad = w.nom_lam(pi, w.dbg("lpad")); + lpad = w.nom_lam(pi)->set("lpad"); auto [m, env, __] = split(lpad->var()); auto [m1, arg_ptr] = w.call(Defs{m, rb})->projs<2>(); arg_ptr = core::op_bitcast(mem::type_ptr(dom), arg_ptr); @@ -142,10 +142,10 @@ void Clos2SJLJ::enter() { auto branches = DefVec(lam2tag_.size() + 1); { auto env = w.tuple(body->args().skip_front()); - auto new_callee = w.nom_lam(w.cn({mem::type_mem(w), env->type()}), w.dbg("sjlj_wrap")); + auto new_callee = w.nom_lam(w.cn({mem::type_mem(w), env->type()}))->set("sjlj_wrap"); auto [m, env_var, _] = split(new_callee->var()); auto new_args = DefArray(env->num_projs() + 1, [&](auto i) { return (i == 0) ? m : env_var->proj(i - 1); }); - new_callee->app(false, body->callee(), new_args, body->dbg()); + new_callee->app(false, body->callee(), new_args); branches[0] = clos_pack(env, new_callee, branch_type); } diff --git a/dialects/clos/pass/rw/clos_conv_prep.cpp b/dialects/clos/pass/rw/clos_conv_prep.cpp index 2d780a7221..11e99ea870 100644 --- a/dialects/clos/pass/rw/clos_conv_prep.cpp +++ b/dialects/clos/pass/rw/clos_conv_prep.cpp @@ -73,7 +73,7 @@ const App* ClosConvPrep::rewrite_arg(const App* app) { if (auto lam = isa_retvar(op); lam && from_outer_scope(lam)) { w.DLOG("found return var from enclosing scope: {}", op); - return refine(eta_wrap(op, attr::freeBB, "free_ret")); + return refine(eta_wrap(op, attr::freeBB)->set("free_ret")); } if (auto bb_lam = op->isa_nom(); bb_lam && bb_lam->is_basicblock() && from_outer_scope(bb_lam)) { w.DLOG("found BB from enclosing scope {}", op); @@ -85,7 +85,7 @@ const App* ClosConvPrep::rewrite_arg(const App* app) { } else if (auto contlam = op->isa_nom()) { return refine(thorin::clos::op(attr::ret, contlam)); } else { - auto wrapper = eta_wrap(op, attr::ret, "eta_cont"); + auto wrapper = eta_wrap(op, attr::ret)->set("eta_cont"); w.DLOG("eta expanded return cont: {} -> {}", op, wrapper); return refine(wrapper); } @@ -99,7 +99,7 @@ const App* ClosConvPrep::rewrite_arg(const App* app) { // TODO: If EtaRed eta-reduces branches, we have to wrap them again! if (isa_retvar(op)) { w.DLOG("found firstclass use of return var: {}", op); - return refine(eta_wrap(op, attr::fstclassBB, "fstclass_ret")); + return refine(eta_wrap(op, attr::fstclassBB)->set("fstclass_ret")); } } } @@ -116,7 +116,7 @@ const App* ClosConvPrep::rewrite_callee(const App* app) { if (branches->isa() && branches->type()->isa()) { for (auto i = 0u; i < branches->num_ops(); i++) { if (!branches->op(i)->isa_nom()) { - auto wrapper = eta_wrap(branches->op(i), attr::bot, "eta_br"); + auto wrapper = eta_wrap(branches->op(i), attr::bot)->set("eta_br"); w.DLOG("eta wrap branch: {} -> {}", branches->op(i), wrapper); branches = branches->refine(i, wrapper); } diff --git a/dialects/clos/pass/rw/clos_conv_prep.h b/dialects/clos/pass/rw/clos_conv_prep.h index 9a16e7df2c..8774a2b5bd 100644 --- a/dialects/clos/pass/rw/clos_conv_prep.h +++ b/dialects/clos/pass/rw/clos_conv_prep.h @@ -32,12 +32,12 @@ class ClosConvPrep : public RWPass { bool from_outer_scope(const Def* lam) { return scope_->free_defs().contains(lam); } - const Def* eta_wrap(const Def* def, attr a, const std::string& dbg) { + const Def* eta_wrap(const Def* def, attr a) { auto& w = world(); auto [entry, inserted] = old2wrapper_.emplace(def, nullptr); auto& wrapper = entry->second; if (inserted) { - wrapper = w.nom_lam(def->type()->as(), w.dbg(dbg)); + wrapper = w.nom_lam(def->type()->as()); wrapper->app(false, def, wrapper->var()); lam2fscope_[wrapper] = scope(curr_nom()); wrapper_.emplace(wrapper); diff --git a/dialects/clos/phase/clos_conv.cpp b/dialects/clos/phase/clos_conv.cpp index f13c839bac..d31ed7d467 100644 --- a/dialects/clos/phase/clos_conv.cpp +++ b/dialects/clos/phase/clos_conv.cpp @@ -7,6 +7,8 @@ #include "dialects/mem/autogen.h" #include "dialects/mem/mem.h" +using namespace std::literals; + namespace thorin::clos { /* @@ -68,23 +70,19 @@ std::pair FreeDefAna::build_node(Def* nom, NodeQueue& w } void FreeDefAna::run(NodeQueue& worklist) { - int iter = 0; while (!worklist.empty()) { auto node = worklist.front(); worklist.pop(); - // w.DLOG("FA: iter {}: {}", iter, node->nom); if (is_done(node)) continue; auto changed = is_bot(node); mark(node); for (auto p : node->preds) { auto& pfvs = p->fvs; - for (auto&& pfv : pfvs) { changed |= node->add_fvs(pfv).second; } - // w.DLOG("\tFV({}) ∪= FV({}) = {{{, }}}\b", node->nom, p->nom, pfvs); + for (auto&& pfv : pfvs) changed |= node->add_fvs(pfv).second; } if (changed) { - for (auto s : node->succs) { worklist.push(s); } + for (auto s : node->succs) worklist.push(s); } - iter++; } } @@ -129,19 +127,18 @@ void ClosConv::rewrite_body(Lam* new_lam, Def2Def& subst) { if (!old_fn->is_set()) return; w.DLOG("rw body: {} [old={}, env={}]\nt", new_fn, old_fn, env); - auto env_param = new_fn->var(Clos_Env_Param, w.dbg("closure_env")); + auto env_param = new_fn->var(Clos_Env_Param)->set("closure_env"); if (num_fvs == 1) { subst.emplace(env, env_param); } else { for (size_t i = 0; i < num_fvs; i++) { - auto fv = env->op(i); - auto dbg = (fv->name().empty()) ? w.dbg("fv_" + std::to_string(i)) : w.dbg("fv_" + env->op(i)->name()); - subst.emplace(fv, env_param->proj(i, dbg)); + auto fv = env->op(i); + auto sym = w.sym("fv_"s + (fv->sym() ? *fv->sym() : std::to_string(i))); + subst.emplace(fv, env_param->proj(i)->set(sym)); } } - auto params = - w.tuple(DefArray(old_fn->num_doms(), [&](auto i) { return new_lam->var(skip_env(i), old_fn->var(i)->dbg()); })); + auto params = w.tuple(DefArray(old_fn->num_doms(), [&](auto i) { return new_lam->var(skip_env(i)); })); subst.emplace(old_fn->var(), params); auto filter = rewrite(new_fn->filter(), subst); @@ -186,7 +183,7 @@ const Def* ClosConv::rewrite(const Def* def, Def2Def& subst) { // put into the local subst only auto new_doms = DefArray(ret_lam->num_doms(), [&](auto i) { return rewrite(ret_lam->dom(i), subst); }); - auto new_lam = ret_lam->stub(w, w.cn(new_doms), ret_lam->dbg()); + auto new_lam = ret_lam->stub(w, w.cn(new_doms)); subst[ret_lam] = new_lam; if (ret_lam->is_set()) { new_lam->set_filter(rewrite(ret_lam->filter(), subst)); @@ -216,19 +213,18 @@ const Def* ClosConv::rewrite(const Def* def, Def2Def& subst) { } auto new_type = rewrite(def->type(), subst); - auto new_dbg = (def->dbg()) ? rewrite(def->dbg(), subst) : nullptr; if (auto nom = def->isa_nom()) { if (auto global = def->isa_nom()) { if (auto i = glob_noms_.find(global); i != glob_noms_.end()) return i->second; auto subst = Def2Def(); - return glob_noms_[nom] = rewrite_nom(global, new_type, new_dbg, subst); + return glob_noms_[nom] = rewrite_nom(global, new_type, subst); } assert(!isa_clos_type(nom)); w.DLOG("RW: nom {}", nom); - auto new_nom = rewrite_nom(nom, new_type, new_dbg, subst); + auto new_nom = rewrite_nom(nom, new_type, subst); // Try to reduce the amount of noms that are created - if (!nom->isa_nom() && Checker(w).equiv(nom, new_nom, nullptr)) return map(nom); + if (!nom->isa_nom() && Checker(w).equiv(nom, new_nom)) return map(nom); if (auto restruct = new_nom->restructure()) return map(restruct); return map(new_nom); } else { @@ -238,16 +234,16 @@ const Def* ClosConv::rewrite(const Def* def, Def2Def& subst) { } else if (def->isa()) { return def; } else { - return map(def->rebuild(w, new_type, new_ops, new_dbg)); + return map(def->rebuild(w, new_type, new_ops)); } } thorin::unreachable(); } -Def* ClosConv::rewrite_nom(Def* nom, const Def* new_type, const Def* new_dbg, Def2Def& subst) { +Def* ClosConv::rewrite_nom(Def* nom, const Def* new_type, Def2Def& subst) { auto& w = world(); - auto new_nom = nom->stub(w, new_type, new_dbg); + auto new_nom = nom->stub(w, new_type); subst.emplace(nom, new_nom); for (size_t i = 0; i < nom->num_ops(); i++) { if (nom->op(i)) new_nom->set(i, rewrite(nom->op(i), subst)); @@ -284,11 +280,13 @@ ClosConv::Stub ClosConv::make_stub(const DefSet& fvs, Lam* old_lam, Def2Def& sub auto num_fvs = fvs.size(); auto env_type = rewrite(env->type(), subst); auto new_fn_type = type_clos(old_lam->type(), subst, env_type)->as(); - auto new_lam = old_lam->stub(w, new_fn_type, w.dbg(old_lam->name())); - new_lam->set_debug_name((old_lam->is_external() || !old_lam->is_set()) ? "cc_" + old_lam->name() : old_lam->name()); + auto new_lam = old_lam->stub(w, new_fn_type); + // TODO + // new_lam->set_debug_name((old_lam->is_external() || !old_lam->is_set()) ? "cc_" + old_lam->name() : + // old_lam->name()); if (!isa_workable(old_lam)) { auto new_ext_type = w.cn(clos_remove_env(new_fn_type->dom())); - auto new_ext_lam = old_lam->stub(w, new_ext_type, w.dbg(old_lam->name())); + auto new_ext_lam = old_lam->stub(w, new_ext_type); w.DLOG("wrap ext lam: {} -> stub: {}, ext: {}", old_lam, new_lam, new_ext_lam); if (old_lam->is_set()) { old_lam->make_internal(); @@ -296,7 +294,7 @@ ClosConv::Stub ClosConv::make_stub(const DefSet& fvs, Lam* old_lam, Def2Def& sub new_ext_lam->app(false, new_lam, clos_insert_env(env, new_ext_lam->var())); new_lam->set(old_lam->filter(), old_lam->body()); } else { - new_ext_lam->set(nullptr, nullptr); + new_ext_lam->set((const Def*)nullptr, (const Def*)nullptr); new_lam->app(false, new_ext_lam, clos_remove_env(new_lam->var())); } } else { diff --git a/dialects/clos/phase/clos_conv.h b/dialects/clos/phase/clos_conv.h index c536883ab7..64a7149129 100644 --- a/dialects/clos/phase/clos_conv.h +++ b/dialects/clos/phase/clos_conv.h @@ -19,7 +19,7 @@ class FreeDefAna { FreeDefAna(World& world) : world_(world) , cur_pass_id(1) - , lam2nodes_(){}; + , lam2nodes_() {} /// FreeDefAna::run will compute free defs (FD) that appear in @p lam%s body. /// Nominal Def%s are only considered free if they are annotated with Clos::freeBB or @@ -114,7 +114,7 @@ class ClosConv : public Phase { /// @{ void rewrite_body(Lam* lam, Def2Def& subst); const Def* rewrite(const Def* old_def, Def2Def& subst); - Def* rewrite_nom(Def* nom, const Def* new_type, const Def* new_dbg, Def2Def& subst); + Def* rewrite_nom(Def* nom, const Def* new_type, Def2Def& subst); const Pi* rewrite_type_cn(const Pi*, Def2Def& subst); const Def* type_clos(const Pi* pi, Def2Def& subst, const Def* ent_type = nullptr); /// @} diff --git a/dialects/clos/phase/lower_typed_clos.cpp b/dialects/clos/phase/lower_typed_clos.cpp index 5f320bb9e2..f703cdd8ec 100644 --- a/dialects/clos/phase/lower_typed_clos.cpp +++ b/dialects/clos/phase/lower_typed_clos.cpp @@ -44,9 +44,8 @@ Lam* LowerTypedClos::make_stub(Lam* lam, enum Mode mode, bool adjust_bb_type) { })); if (lam->is_basicblock() && adjust_bb_type) new_dom = insert_ret(new_dom, dummy_ret_->type()); auto new_type = w.cn(new_dom); - auto new_lam = lam->stub(w, new_type, w.dbg(lam->name())); + auto new_lam = lam->stub(w, new_type)->set(lam->sym()); w.DLOG("stub {} ~> {}", lam, new_lam); - new_lam->set_debug_name(lam->name()); new_lam->set(lam->filter(), lam->body()); if (lam->is_external()) { lam->make_internal(); @@ -54,22 +53,22 @@ Lam* LowerTypedClos::make_stub(Lam* lam, enum Mode mode, bool adjust_bb_type) { } const Def* lcm = mem::mem_var(new_lam); const Def* env = - new_lam->var(Clos_Env_Param, (mode != No_Env) ? w.dbg("closure_env") : lam->var(Clos_Env_Param)->dbg()); + new_lam->var(Clos_Env_Param); //, (mode != No_Env) ? w.dbg("closure_env") : lam->var(Clos_Env_Param)->dbg()); if (mode == Box) { auto env_mem = w.call(Defs{lcm, env}); - lcm = w.extract(env_mem, 0_u64, w.dbg("mem")); - env = w.extract(env_mem, 1_u64, w.dbg("closure_env")); + lcm = w.extract(env_mem, 0_u64)->set("mem"); + env = w.extract(env_mem, 1_u64)->set("closure_env"); } else if (mode == Unbox) { - env = core::op_bitcast(lam->dom(Clos_Env_Param), env, w.dbg("unboxed_env")); + env = core::op_bitcast(lam->dom(Clos_Env_Param), env)->set("unboxed_env"); } auto new_args = w.tuple(Array(lam->num_doms(), [&](auto i) { - return (i == Clos_Env_Param) ? env : (lam->var(i) == mem::mem_var(lam)) ? lcm : new_lam->var(i); + return (i == Clos_Env_Param) ? env : (lam->var(i) == mem::mem_var(lam)) ? lcm : *new_lam->var(i); })); assert(new_args->num_projs() == lam->num_doms()); assert(lam->num_doms() <= new_lam->num_doms()); map(lam->var(), new_args); worklist_.emplace(mem::mem_var(lam), lcm, new_lam); - return map(lam, new_lam); + return map(lam, new_lam)->as(); } const Def* LowerTypedClos::rewrite(const Def* def) { @@ -89,7 +88,6 @@ const Def* LowerTypedClos::rewrite(const Def* def) { assert(false && "Lam vars should appear in a map!"); auto new_type = rewrite(def->type()); - auto new_dbg = def->dbg() ? rewrite(def->dbg()) : nullptr; if (auto ct = isa_clos_type(def)) { auto pi = rewrite(ct->op(1))->as(); @@ -120,7 +118,7 @@ const Def* LowerTypedClos::rewrite(const Def* def) { } else if (!mode) { auto mem_ptr = (c.get() == attr::esc) ? mem::op_alloc(env->type(), lcm_) : mem::op_slot(env->type(), lcm_); auto mem = w.extract(mem_ptr, 0_u64); - auto env_ptr = mem_ptr->proj(1_u64, w.dbg(fn->name() + "_env")); + auto env_ptr = mem_ptr->proj(1_u64); //, w.dbg(fn->sym() + "_env")); lcm_ = w.call(Defs{mem, env_ptr, env}); map(lvm_, lcm_); env = env_ptr; @@ -132,11 +130,11 @@ const Def* LowerTypedClos::rewrite(const Def* def) { return make_stub(lam, No_Env, false); } else if (auto nom = def->isa_nom()) { assert(!isa_clos_type(nom)); - auto new_nom = nom->stub(w, new_type, new_dbg); + auto new_nom = nom->stub(w, new_type); map(nom, new_nom); for (size_t i = 0; i < nom->num_ops(); i++) if (nom->op(i)) new_nom->set(i, rewrite(nom->op(i))); - if (!def->isa_nom() && Checker(w).equiv(nom, new_nom, nullptr)) return map(nom, nom); + if (!def->isa_nom() && Checker(w).equiv(nom, new_nom)) return map(nom, nom); if (auto restruct = new_nom->restructure()) return map(nom, restruct); return new_nom; } else if (def->isa()) { @@ -151,7 +149,7 @@ const Def* LowerTypedClos::rewrite(const Def* def) { new_ops[1] = insert_ret(new_ops[1], dummy_ret_); } - auto new_def = def->rebuild(w, new_type, new_ops, new_dbg); + auto new_def = def->rebuild(w, new_type, new_ops); // We may need to update the mem token after all ops have been rewritten: // F (m, a1, ..., (env, f):pct) diff --git a/dialects/clos/phase/lower_typed_clos.h b/dialects/clos/phase/lower_typed_clos.h index 99ecbb2f52..2cac5e318e 100644 --- a/dialects/clos/phase/lower_typed_clos.h +++ b/dialects/clos/phase/lower_typed_clos.h @@ -54,9 +54,9 @@ class LowerTypedClos : public Phase { ///@{ /// wrapper arround old2new_ - template - D* map(const Def* old_def, D* new_def) { - old2new_[old_def] = static_cast(new_def); + const Def* map(const Def* old_def, const Def* new_def) { return old2new_[old_def] = new_def; } + Def* map(const Def* old_def, Def* new_def) { + old2new_[old_def] = new_def; return new_def; } diff --git a/dialects/compile/compile.h b/dialects/compile/compile.h index 7c5c31cec2..0b224d3b58 100644 --- a/dialects/compile/compile.h +++ b/dialects/compile/compile.h @@ -23,7 +23,7 @@ inline void handle_optimization_part(const Def* part, World& world, Passes& pass auto phase_fun = passes[flag]; phase_fun(world, builder, part); } else { - world.WLOG("pass/phase '{}' not found", phase_ax->name()); + world.WLOG("pass/phase '{}' not found", phase_ax->sym()); assert(passes.contains(flag) && "pass/phase not found"); } } else if (phase_def->isa()) { diff --git a/dialects/compile/normalizers.cpp b/dialects/compile/normalizers.cpp index e90a53bff3..45cc9bf5b6 100644 --- a/dialects/compile/normalizers.cpp +++ b/dialects/compile/normalizers.cpp @@ -4,16 +4,16 @@ namespace thorin::compile { // `pass_phase (pass_list pass1 ... passn)` -> `passes_to_phase n (pass1, ..., passn)` -const Def* normalize_pass_phase(const Def* type, const Def*, const Def* arg, const Def* dbg) { +Ref normalize_pass_phase(Ref type, Ref, Ref arg) { auto& world = type->world(); auto [ax, _] = collect_args(arg); if (ax->flags() != flags_t(Axiom::Base)) { - // return world.raw_app(type, callee, arg, dbg); + // return world.raw_app(type, callee, arg); // TODO: remove when normalizers are fixed if (ax->flags() == flags_t(Axiom::Base)) { auto arg_cpl = arg->as(); - arg = normalize_combine_pass_list(arg_cpl->type(), arg_cpl->callee(), arg_cpl->arg(), arg_cpl->dbg()); + arg = normalize_combine_pass_list(arg_cpl->type(), arg_cpl->callee(), arg_cpl->arg()); } else { world.ELOG("pass_phase expects a pass_list as argument but got {}", arg); } @@ -23,29 +23,29 @@ const Def* normalize_pass_phase(const Def* type, const Def*, const Def* arg, con assert(f_ax->flags() == flags_t(Axiom::Base)); auto n = pass_list_defs.size(); - return world.app(world.app(world.ax(), world.lit_nat(n), dbg), pass_list_defs, dbg); + return world.app(world.app(world.ax(), world.lit_nat(n)), pass_list_defs); } /// `combined_phase (phase_list phase1 ... phasen)` -> `phases_to_phase n (phase1, ..., phasen)` -const Def* normalize_combined_phase(const Def* type, const Def*, const Def* arg, const Def* dbg) { +Ref normalize_combined_phase(Ref type, Ref, Ref arg) { auto& world = type->world(); auto [ax, phase_list_defs] = collect_args(arg); assert(ax->flags() == flags_t(Axiom::Base)); auto n = phase_list_defs.size(); - return world.app(world.app(world.ax(), world.lit_nat(n), dbg), phase_list_defs, dbg); + return world.app(world.app(world.ax(), world.lit_nat(n)), phase_list_defs); } /// `single_pass_phase pass` -> `passes_to_phase 1 pass` -const Def* normalize_single_pass_phase(const Def* type, const Def*, const Def* arg, const Def* dbg) { +Ref normalize_single_pass_phase(Ref type, Ref, Ref arg) { auto& world = type->world(); - return world.app(world.app(world.ax(), world.lit_nat_1(), dbg), arg, dbg); + return world.app(world.app(world.ax(), world.lit_nat_1()), arg); } /// `combine_pass_list K (pass_list pass11 ... pass1N) ... (pass_list passK1 ... passKM) = pass_list pass11 ... p1N ... /// passK1 ... passKM` -const Def* normalize_combine_pass_list(const Def* type, const Def*, const Def* arg, const Def* dbg) { +Ref normalize_combine_pass_list(Ref type, Ref, Ref arg) { auto& world = type->world(); auto pass_lists = arg->projs(); DefVec passes; @@ -55,8 +55,8 @@ const Def* normalize_combine_pass_list(const Def* type, const Def*, const Def* a assert(ax->flags() == flags_t(Axiom::Base)); passes.insert(passes.end(), pass_list_defs.begin(), pass_list_defs.end()); } - const Def* app_list = world.ax(); - for (auto pass : passes) app_list = world.app(app_list, pass, dbg); + Ref app_list = world.ax(); + for (auto pass : passes) app_list = world.app(app_list, pass); return app_list; } diff --git a/dialects/compile/passes/internal_cleanup.cpp b/dialects/compile/passes/internal_cleanup.cpp index d32c2ed02f..9c5c5956bf 100644 --- a/dialects/compile/passes/internal_cleanup.cpp +++ b/dialects/compile/passes/internal_cleanup.cpp @@ -8,7 +8,7 @@ namespace thorin::compile { void InternalCleanup::enter() { Lam* lam = curr_nom(); - if (lam->name().starts_with("internal_")) { + if (lam->sym()->starts_with("internal_")) { lam->make_internal(); world().DLOG("internalized {}", lam); } diff --git a/dialects/core/be/ll/ll.cpp b/dialects/core/be/ll/ll.cpp index 7ff63195b1..fc90c6018f 100644 --- a/dialects/core/be/ll/ll.cpp +++ b/dialects/core/be/ll/ll.cpp @@ -70,7 +70,7 @@ struct BB { swap(a.parts, b.parts); } - DefMap>> phis; + DefMap>> phis; std::array, 3> parts; }; @@ -119,12 +119,12 @@ std::string Emitter::id(const Def* def, bool force_bb /*= false*/) const { if (auto lam = def->isa_nom(); lam && !force_bb) { if (lam->type()->ret_pi()) { if (lam->is_external() || !lam->is_set()) - return "@" + lam->name(); // TODO or use is_internal or sth like that? - return "@" + lam->unique_name(); + return "@"s + *lam->sym(); // TODO or use is_internal or sth like that? + return "@"s + lam->unique_name(); } } - return "%" + def->unique_name(); + return "%"s + def->unique_name(); } std::string Emitter::convert(const Def* type) { @@ -158,9 +158,8 @@ std::string Emitter::convert(const Def* type) { assert(pi->is_returning() && "should never have to convert type of BB"); print(s, "{} (", convert_ret_pi(pi->ret_pi())); - std::string_view sep = ""; - auto doms = pi->doms(); - for (auto dom : doms.skip_back()) { + auto doms = pi->doms(); + for (auto sep = ""; auto dom : doms.skip_back()) { if (match(dom)) continue; s << sep << convert(dom); sep = ", "; @@ -174,8 +173,7 @@ std::string Emitter::convert(const Def* type) { print(s, "{} = type", name); } print(s, "{{"); - std::string_view sep = ""; - for (auto t : sigma->ops()) { + for (auto sep = ""; auto t : sigma->ops()) { if (match(t)) continue; s << sep << convert(t); sep = ", "; @@ -224,9 +222,8 @@ void Emitter::emit_imported(Lam* lam) { // TODO merge with declare method print(func_decls_, "declare {} {}(", convert_ret_pi(lam->type()->ret_pi()), id(lam)); - auto sep = ""; auto doms = lam->doms(); - for (auto dom : doms.skip_back()) { + for (auto sep = ""; auto dom : doms.skip_back()) { if (match(dom)) continue; print(func_decls_, "{}{}", sep, convert(dom)); sep = ", "; @@ -240,9 +237,8 @@ std::string Emitter::prepare(const Scope& scope) { print(func_impls_, "define {} {}(", convert_ret_pi(lam->type()->ret_pi()), id(lam)); - auto sep = ""; auto vars = lam->vars(); - for (auto var : vars.skip_back()) { + for (auto sep = ""; auto var : vars.skip_back()) { if (match(var->type())) continue; auto name = id(var); locals_[var] = name; @@ -258,8 +254,7 @@ void Emitter::finalize(const Scope& scope) { for (auto& [lam, bb] : lam2bb_) { for (const auto& [phi, args] : bb.phis) { print(bb.head().emplace_back(), "{} = phi {} ", id(phi), convert(phi->type())); - auto sep = ""; - for (const auto& [arg, pred] : args) { + for (auto sep = ""; const auto& [arg, pred] : args) { print(bb.head().back(), "{}[ {}, {} ]", sep, arg, pred); sep = ", "; } @@ -892,9 +887,9 @@ std::string Emitter::emit_bb(BB& bb, const Def* def) { declare("{} @{}({})", t, f, t); return bb.assign(name, "tail call {} @{}({} {})", t, f, t, a); } else if (auto er = match(def)) { - auto a = emit(er->arg()); - auto t = convert(er->type()); - std::string f = er.id() == math::er::f ? "erf" : "erfc"; + auto a = emit(er->arg()); + auto t = convert(er->type()); + auto f = er.id() == math::er::f ? "erf"s : "erfc"s; f += math_suffix(er->type()); declare("{} @{}({})", t, f, t); return bb.assign(name, "tail call {} @{}({} {})", t, f, t, a); @@ -950,7 +945,8 @@ std::string Emitter::emit_bb(BB& bb, const Def* def) { return bb.assign(name, "{} {} {} to {}", op, t_src, v_src, t_dst); } - unreachable(); // not yet implemented + def->dump(1); + err("unhandled def in LLVM backend: {}", def); } void emit(World& world, std::ostream& ostream) { diff --git a/dialects/core/core.h b/dialects/core/core.h index ac9e9d628a..fa512d0e77 100644 --- a/dialects/core/core.h +++ b/dialects/core/core.h @@ -13,68 +13,68 @@ enum Mode : nat_t { nuw = 1 << 1, }; -using VMode = std::variant; +using VMode = std::variant; -inline const Def* mode(World& w, VMode m) { - if (auto def = std::get_if(&m)) return *def; +inline Ref mode(World& w, VMode m) { + if (auto def = std::get_if(&m)) return *def; if (auto nat = std::get_if(&m)) return w.lit_nat(*nat); return w.lit_nat(std::get(m)); } /// @name fn - these guys yield the final function to be invoked for the various operations ///@{ -inline const Def* fn_bitcast(const Def* dst_t, const Def* src_t, const Def* dbg = {}) { +inline Ref fn_bitcast(Ref dst_t, Ref src_t) { World& w = dst_t->world(); - return w.app(w.ax(), {dst_t, src_t}, dbg); + return w.app(w.ax(), {dst_t, src_t}); } ///@} /// @name op - these guys build the final function application for the various operations ///@{ -inline const Def* op(trait o, const Def* type, const Def* dbg = {}) { +inline Ref op(trait o, Ref type) { World& w = type->world(); - return w.app(w.ax(o), type, dbg); + return w.app(w.ax(o), type); } -inline const Def* op_bitcast(const Def* dst_t, const Def* src, const Def* dbg = {}) { +inline Ref op_bitcast(Ref dst_t, Ref src) { World& w = dst_t->world(); - return w.app(fn_bitcast(dst_t, src->type()), src, dbg); + return w.app(fn_bitcast(dst_t, src->type()), src); } -inline const Def* op(pe o, const Def* def, const Def* dbg = {}) { +inline Ref op(pe o, Ref def) { World& w = def->world(); - return w.app(w.app(w.ax(o), def->type()), def, dbg); + return w.app(w.app(w.ax(o), def->type()), def); } ///@} /// @name extract helper ///@{ -inline const Def* extract_unsafe(const Def* d, const Def* i, const Def* dbg = {}) { +inline Ref extract_unsafe(Ref d, Ref i) { World& w = d->world(); - return w.extract(d, w.call(conv::u, d->unfold_type()->arity(), i), dbg); + return w.extract(d, w.call(conv::u, d->unfold_type()->arity(), i)); } -inline const Def* extract_unsafe(const Def* d, u64 i, const Def* dbg = {}) { +inline Ref extract_unsafe(Ref d, u64 i) { World& w = d->world(); - return extract_unsafe(d, w.lit_idx(0_u64, i), dbg); + return extract_unsafe(d, w.lit_idx(0_u64, i)); } ///@} /// @name insert helper ///@{ -inline const Def* insert_unsafe(const Def* d, const Def* i, const Def* val, const Def* dbg = {}) { +inline Ref insert_unsafe(Ref d, Ref i, Ref val) { World& w = d->world(); - return w.insert(d, w.call(conv::u, d->unfold_type()->arity(), i), val, dbg); + return w.insert(d, w.call(conv::u, d->unfold_type()->arity(), i), val); } -inline const Def* insert_unsafe(const Def* d, u64 i, const Def* val, const Def* dbg = {}) { +inline Ref insert_unsafe(Ref d, u64 i, Ref val) { World& w = d->world(); - return insert_unsafe(d, w.lit_idx(0_u64, i), val, dbg); + return insert_unsafe(d, w.lit_idx(0_u64, i), val); } ///@} /// @name wrappers for unary operations ///@{ -inline const Def* op_wminus(VMode m, const Def* a, const Def* dbg = {}) { +inline Ref op_wminus(VMode m, Ref a) { World& w = a->world(); auto s = as_lit(w.iinfer(a)); - return w.dcall(dbg, wrap::sub, mode(w, m), Defs{w.lit_idx(s, 0), a}); + return w.call(wrap::sub, mode(w, m), Defs{w.lit_idx(s, 0), a}); } ///@} diff --git a/dialects/core/normalizers.cpp b/dialects/core/normalizers.cpp index e8b4e9ef85..dff0a56573 100644 --- a/dialects/core/normalizers.cpp +++ b/dialects/core/normalizers.cpp @@ -102,18 +102,17 @@ Res fold(u64 a, u64 b, [[maybe_unused]] bool nsw, [[maybe_unused]] bool nuw) { /// @attention Note that @p a and @p b are passed by reference as fold also commutes if possible. @sa commute(). template -static const Def* -fold(World& world, const Def* type, const Def*& a, const Def*& b, const Def* dbg, const Def* mode = {}) { +static Ref fold(World& world, Ref type, const Def*& a, const Def*& b, Ref mode = {}) { auto la = a->isa(), lb = b->isa(); - if (a->isa() || b->isa()) return world.bot(type, dbg); + if (a->isa() || b->isa()) return world.bot(type); if (la && lb) { auto size = as_lit(Idx::size(a->type())); auto width = Idx::size2bitwidth(size); bool nsw = false, nuw = false; if constexpr (std::is_same_v) { - auto m = as_lit(mode); + auto m = mode ? as_lit(mode) : 0_n; nsw = m & Mode::nsw; nuw = m & Mode::nuw; } @@ -127,7 +126,7 @@ fold(World& world, const Def* type, const Def*& a, const Def*& b, const Def* dbg default: unreachable(); } - return res ? world.lit(type, *res, dbg) : world.bot(type, dbg); + return res ? world.lit(type, *res) : world.bot(type); } commute(id, a, b); @@ -146,8 +145,7 @@ fold(World& world, const Def* type, const Def*& a, const Def*& b, const Def* dbg /// (4) (lx op y) op b -> lx op (y op b) /// ``` template -static const Def* -reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, const Def* b, const Def* dbg) { +static Ref reassociate(Id id, World& world, [[maybe_unused]] const App* ab, Ref a, Ref b) { if (!is_associative(id)) return nullptr; auto la = a->isa(); @@ -158,13 +156,13 @@ reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, c auto y = xy ? xy->arg(1) : nullptr; auto w = zw ? zw->arg(1) : nullptr; - std::function make_op; + std::function make_op; if constexpr (std::is_same_v) { // if we reassociate Wraps, we have to forget about nsw/nuw - make_op = [&](const Def* a, const Def* b) { return world.dcall(dbg, id, Mode::none, Defs{a, b}); }; + make_op = [&](Ref a, Ref b) { return world.call(id, Mode::none, Defs{a, b}); }; } else { - make_op = [&](const Def* a, const Def* b) { return world.dcall(dbg, id, Defs{a, b}); }; + make_op = [&](Ref a, Ref b) { return world.call(id, Defs{a, b}); }; } if (la && lz) return make_op(make_op(la, lz), w); // (1) @@ -176,7 +174,7 @@ reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, c } template -const Def* normalize_nop(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_nop(Ref type, Ref callee, Ref arg) { auto& world = type->world(); auto [a, b] = arg->projs<2>(); commute(id, a, b); @@ -190,11 +188,11 @@ const Def* normalize_nop(const Def* type, const Def* callee, const Def* arg, con } } - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } template -const Def* normalize_ncmp(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_ncmp(Ref type, Ref callee, Ref arg) { auto& world = type->world(); if (id == ncmp::t) return world.lit_tt(); @@ -219,16 +217,16 @@ const Def* normalize_ncmp(const Def* type, const Def* callee, const Def* arg, co } } - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } template -const Def* normalize_icmp(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_icmp(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); - if (auto result = fold(world, type, a, b, dbg)) return result; + if (auto result = fold(world, type, a, b)) return result; if (id == icmp::f) return world.lit_ff(); if (id == icmp::t) return world.lit_tt(); if (a == b) { @@ -236,11 +234,11 @@ const Def* normalize_icmp(const Def* type, const Def* c, const Def* arg, const D if (id == icmp::ne) return world.lit_ff(); } - return world.raw_app(type, callee, {a, b}, dbg); + return world.raw_app(type, callee, {a, b}); } template -const Def* normalize_bit1(const Def* type, const Def* c, const Def* a, const Def* dbg) { +Ref normalize_bit1(Ref type, Ref c, Ref a) { auto& world = type->world(); auto callee = c->as(); auto l = isa_lit(a); @@ -256,11 +254,11 @@ const Def* normalize_bit1(const Def* type, const Def* c, const Def* a, const Def if (l) return world.lit_idx_mod(*ls, ~*l); } - return world.raw_app(type, callee, a, dbg); + return world.raw_app(type, callee, a); } template -static const Def* merge_cmps(std::array, 2> tab, const Def* a, const Def* b, const Def* dbg) { +static Ref merge_cmps(std::array, 2> tab, Ref a, Ref b) { static_assert(sizeof(sub_t) == 1, "if this ever changes, please adjust the logic below"); static constexpr size_t num_bits = std::bit_width(Axiom::Num - 1_u64); @@ -278,17 +276,16 @@ static const Def* merge_cmps(std::array, 2> tab, const Def* a res >>= (7_u8 - u8(num_bits)); if constexpr (std::is_same_v) - return world.dcall(dbg, math::cmp(res), /*rmode*/ a_cmp->decurry()->arg(0), - Defs{a_cmp->arg(0), a_cmp->arg(1)}); + return world.call(math::cmp(res), /*rmode*/ a_cmp->decurry()->arg(0), Defs{a_cmp->arg(0), a_cmp->arg(1)}); else - return world.dcall(dbg, icmp(Axiom::Base | res), Defs{a_cmp->arg(0), a_cmp->arg(1)}); + return world.call(icmp(Axiom::Base | res), Defs{a_cmp->arg(0), a_cmp->arg(1)}); } return nullptr; } template -const Def* normalize_bit2(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_bit2(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); @@ -297,8 +294,8 @@ const Def* normalize_bit2(const Def* type, const Def* c, const Def* arg, const D commute(id, a, b); auto tab = make_truth_table(id); - if (auto res = merge_cmps(tab, a, b, dbg)) return res; - if (auto res = merge_cmps(tab, a, b, dbg)) return res; + if (auto res = merge_cmps(tab, a, b)) return res; + if (auto res = merge_cmps(tab, a, b)) return res; auto la = isa_lit(a); auto lb = isa_lit(b); @@ -309,10 +306,10 @@ const Def* normalize_bit2(const Def* type, const Def* c, const Def* arg, const D case bit2:: t: if (ls) return world.lit(type, *ls-1_u64); break; case bit2:: fst: return a; case bit2:: snd: return b; - case bit2:: nfst: return world.dcall(dbg, bit1::neg, a); - case bit2:: nsnd: return world.dcall(dbg, bit1::neg, b); - case bit2:: ciff: return world.dcall(dbg, bit2:: iff, Defs{b, a}); - case bit2::nciff: return world.dcall(dbg, bit2::niff, Defs{b, a}); + case bit2:: nfst: return world.call(bit1::neg, a); + case bit2:: nsnd: return world.call(bit1::neg, b); + case bit2:: ciff: return world.call(bit2:: iff, Defs{b, a}); + case bit2::nciff: return world.call(bit2::niff, Defs{b, a}); default: break; } @@ -331,11 +328,11 @@ const Def* normalize_bit2(const Def* type, const Def* c, const Def* arg, const D } // TODO rewrite using bit2 - auto unary = [&](bool x, bool y, const Def* a) -> const Def* { + auto unary = [&](bool x, bool y, Ref a) -> Ref { if (!x && !y) return world.lit(type, 0); if ( x && y) return ls ? world.lit(type, *ls-1_u64) : nullptr; if (!x && y) return a; - if ( x && !y && id != bit2::xor_) return world.dcall(dbg, bit1::neg, a); + if ( x && !y && id != bit2::xor_) return world.call(bit1::neg, a); return nullptr; }; // clang-format on @@ -360,20 +357,20 @@ const Def* normalize_bit2(const Def* type, const Def* c, const Def* arg, const D } } - if (auto res = reassociate(id, world, callee, a, b, dbg)) return res; + if (auto res = reassociate(id, world, callee, a, b)) return res; - return world.raw_app(type, callee, {a, b}, dbg); + return world.raw_app(type, callee, {a, b}); } template -const Def* normalize_shr(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_shr(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); auto s = Idx::size(arg->type()); auto ls = isa_lit(s); - if (auto result = fold(world, type, a, b, dbg)) return result; + if (auto result = fold(world, type, a, b)) return result; if (auto la = a->isa()) { if (la == world.lit(type, 0)) { @@ -392,14 +389,14 @@ const Def* normalize_shr(const Def* type, const Def* c, const Def* arg, const De } } - if (ls && lb->get() > *ls) return world.bot(type, dbg); + if (ls && lb->get() > *ls) return world.bot(type); } - return world.raw_app(type, callee, {a, b}, dbg); + return world.raw_app(type, callee, {a, b}); } template -const Def* normalize_wrap(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_wrap(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); @@ -407,7 +404,7 @@ const Def* normalize_wrap(const Def* type, const Def* c, const Def* arg, const D auto s = Idx::size(a->type()); auto ls = isa_lit(s); - if (auto result = fold(world, type, a, b, dbg, mode)) return result; + if (auto result = fold(world, type, a, b)) return result; // clang-format off if (auto la = a->isa()) { @@ -441,35 +438,35 @@ const Def* normalize_wrap(const Def* type, const Def* c, const Def* arg, const D } if (id == wrap::sub) - return world.dcall(dbg, wrap::add, mode, Defs{a, world.lit_idx_mod(*ls, ~lb->get() + 1_u64)}); // a - lb -> a + (~lb + 1) + return world.call(wrap::add, mode, Defs{a, world.lit_idx_mod(*ls, ~lb->get() + 1_u64)}); // a - lb -> a + (~lb + 1) else if (id == wrap::shl && ls && lb->get() > *ls) - return world.bot(type, dbg); + return world.bot(type); } if (a == b) { switch (id) { - case wrap::add: return world.dcall(dbg, wrap::mul, mode, Defs{world.lit(type, 2), a}); // a + a -> 2 * a - case wrap::sub: return world.lit(type, 0); // a - a -> 0 + case wrap::add: return world.call(wrap::mul, mode, Defs{world.lit(type, 2), a}); // a + a -> 2 * a + case wrap::sub: return world.lit(type, 0); // a - a -> 0 case wrap::mul: break; case wrap::shl: break; } } // clang-format on - if (auto res = reassociate(id, world, callee, a, b, dbg)) return res; + if (auto res = reassociate(id, world, callee, a, b)) return res; - return world.raw_app(type, callee, {a, b}, dbg); + return world.raw_app(type, callee, {a, b}); } template
-const Def* normalize_div(const Def* full_type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_div(Ref full_type, Ref c, Ref arg) { auto& world = full_type->world(); auto callee = c->as(); auto [mem, a, b] = arg->projs<3>(); auto [_, type] = full_type->projs<2>(); // peel off actual type - auto make_res = [&, mem = mem](const Def* res) { return world.tuple({mem, res}, dbg); }; + auto make_res = [&, mem = mem](Ref res) { return world.tuple({mem, res}); }; - if (auto result = fold(world, type, a, b, dbg)) return make_res(result); + if (auto result = fold(world, type, a, b)) return make_res(result); if (auto la = a->isa()) { if (la == world.lit(type, 0)) return make_res(la); // 0 / b -> 0 and 0 % b -> 0 @@ -497,11 +494,11 @@ const Def* normalize_div(const Def* full_type, const Def* c, const Def* arg, con } } - return world.raw_app(full_type, callee, {mem, a, b}, dbg); + return world.raw_app(full_type, callee, {mem, a, b}); } template -const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const Def* dbg) { +Ref normalize_conv(Ref dst_t, Ref c, Ref x) { auto& world = dst_t->world(); auto callee = c->as(); auto s_t = x->type()->as(); @@ -512,9 +509,9 @@ const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const De auto ld = isa_lit(d); if (s_t == d_t) return x; - if (x->isa()) return world.bot(d_t, dbg); + if (x->isa()) return world.bot(d_t); if constexpr (id == conv::s) { - if (ls && ld && *ld < *ls) return world.dcall(dbg, conv::u, d, x); // just truncate - we don't care for signedness + if (ls && ld && *ld < *ls) return world.call(conv::u, d, x); // just truncate - we don't care for signedness } if (auto l = isa_lit(x); l && ls && ld) { @@ -529,7 +526,7 @@ const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const De // clang-format off if (false) {} #define M(S, D) \ - else if (S == sw && D == dw) return world.lit(d_t, w2s(thorin::bitcast>(*l)), dbg); + else if (S == sw && D == dw) return world.lit(d_t, w2s(thorin::bitcast>(*l))); M( 1, 8) M( 1, 16) M( 1, 32) M( 1, 64) M( 8, 16) M( 8, 32) M( 8, 64) M(16, 32) M(16, 64) @@ -538,24 +535,24 @@ const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const De // clang-format on } - return world.raw_app(dst_t, callee, x, dbg); + return world.raw_app(dst_t, callee, x); } -const Def* normalize_bitcast(const Def* dst_t, const Def* callee, const Def* src, const Def* dbg) { +Ref normalize_bitcast(Ref dst_t, Ref callee, Ref src) { auto& world = dst_t->world(); if (src->isa()) return world.bot(dst_t); if (src->type() == dst_t) return src; if (auto other = match(src)) - return other->arg()->type() == dst_t ? other->arg() : op_bitcast(dst_t, other->arg(), dbg); + return other->arg()->type() == dst_t ? other->arg() : *op_bitcast(dst_t, other->arg()); if (auto lit = src->isa()) { - if (dst_t->isa()) return world.lit(dst_t, lit->get(), dbg); - if (Idx::size(dst_t)) return world.lit(dst_t, lit->get(), dbg); + if (dst_t->isa()) return world.lit(dst_t, lit->get()); + if (Idx::size(dst_t)) return world.lit(dst_t, lit->get()); } - return world.raw_app(dst_t, callee, src, dbg); + return world.raw_app(dst_t, callee, src); } // TODO I guess we can do that with C++20 @@ -570,7 +567,7 @@ inline u64 pad(u64 offset, u64 align) { // and every occurance of these types in a later phase // TODO Pi and others template -const Def* normalize_trait(const Def* nat, const Def* callee, const Def* type, const Def* dbg) { +Ref normalize_trait(Ref nat, Ref callee, Ref type) { auto& world = type->world(); if (auto ptr = match(type)) { return world.lit_nat(8); @@ -607,17 +604,16 @@ const Def* normalize_trait(const Def* nat, const Def* callee, const Def* type, c } else if (auto arr = type->isa_structural()) { auto align = op(trait::align, arr->body()); if constexpr (id == trait::align) return align; - if (auto b = op(trait::size, arr->body())->isa()) - return world.dcall(dbg, core::nop::mul, Defs{arr->shape(), b}); + if (auto b = op(trait::size, arr->body())->isa()) return world.call(core::nop::mul, Defs{arr->shape(), b}); } else if (auto join = type->isa()) { - if (auto sigma = convert(join)) return core::op(id, sigma, dbg); + if (auto sigma = convert(join)) return core::op(id, sigma); } out: - return world.raw_app(nat, callee, type, dbg); + return world.raw_app(nat, callee, type); } -const Def* normalize_zip(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_zip(Ref type, Ref c, Ref arg) { auto& w = type->world(); auto callee = c->as(); auto is_os = callee->arg(); @@ -631,12 +627,12 @@ const Def* normalize_zip(const Def* type, const Def* c, const Def* arg, const De // TODO more than one Os // TODO select which Is/Os to zip - if (lr && ls && *lr == 1 && *ls == 1) return w.app(f, arg, dbg); + if (lr && ls && *lr == 1 && *ls == 1) return w.app(f, arg); if (auto l_in = isa_lit(n_i)) { auto args = arg->projs(*l_in); - if (lr && std::ranges::all_of(args, [](const Def* arg) { return arg->isa(); })) { + if (lr && std::ranges::all_of(args, [](Ref arg) { return arg->isa(); })) { auto shapes = s->projs(*lr); auto s_n = isa_lit(shapes.front()); @@ -655,11 +651,11 @@ const Def* normalize_zip(const Def* type, const Def* c, const Def* arg, const De } } - return w.raw_app(type, callee, arg, dbg); + return w.raw_app(type, callee, arg); } template -const Def* normalize_pe(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_pe(Ref type, Ref callee, Ref arg) { auto& world = type->world(); if constexpr (id == pe::known) { @@ -667,7 +663,7 @@ const Def* normalize_pe(const Def* type, const Def* callee, const Def* arg, cons if (arg->dep_const()) return world.lit_tt(); } - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } THORIN_core_NORMALIZER_IMPL diff --git a/dialects/demo/demo.h b/dialects/demo/demo.h index 532a5221c8..7b3d1127a9 100644 --- a/dialects/demo/demo.h +++ b/dialects/demo/demo.h @@ -1,7 +1,3 @@ #pragma once -#include - #include "dialects/demo/autogen.h" - -namespace thorin::demo {} // namespace thorin::demo diff --git a/dialects/demo/normalizers.cpp b/dialects/demo/normalizers.cpp index 7407dc6e84..5ff9594d1c 100644 --- a/dialects/demo/normalizers.cpp +++ b/dialects/demo/normalizers.cpp @@ -4,8 +4,8 @@ namespace thorin::demo { -const Def* normalize_const(const Def*, const Def*, const Def* arg, const Def*) { - auto& world = arg->world(); +Ref normalize_const(Ref type, Ref, Ref arg) { + auto& world = type->world(); return world.lit(world.type_idx(arg), 42); } diff --git a/dialects/direct/direct.h b/dialects/direct/direct.h index 3b45cdd46b..4a4397e4e5 100644 --- a/dialects/direct/direct.h +++ b/dialects/direct/direct.h @@ -6,7 +6,7 @@ namespace thorin::direct { -inline const Def* op_cps2ds_dep(const Def* f, const Def* dbg = {}) { +inline const Def* op_cps2ds_dep(const Def* f) { auto& world = f->world(); // TODO: assert continuation world.DLOG("f: {} : {}", f, f->type()); @@ -16,7 +16,7 @@ inline const Def* op_cps2ds_dep(const Def* f, const Def* dbg = {}) { world.DLOG("T: {}", T); world.DLOG("U: {}", U); - auto Uf = world.nom_lam(world.pi(T, world.type()), world.dbg("Uf")); + auto Uf = world.nom_lam(world.pi(T, world.type()))->set("Uf"); world.DLOG("Uf: {} : {}", Uf, Uf->type()); const Def* rewritten_codom; @@ -37,7 +37,7 @@ inline const Def* op_cps2ds_dep(const Def* f, const Def* dbg = {}) { world.DLOG("axiom app: {} : {}", ax_app, ax_app->type()); - return world.app(ax_app, f, dbg); + return world.app(ax_app, f); } } // namespace thorin::direct diff --git a/dialects/direct/normalizers.cpp b/dialects/direct/normalizers.cpp index 4473aca6c5..0fb65beca6 100644 --- a/dialects/direct/normalizers.cpp +++ b/dialects/direct/normalizers.cpp @@ -5,7 +5,7 @@ namespace thorin::direct { /// `cps2ds` is directly converted to `op_cps2ds_dep f` in its normalizer. -const Def* normalize_cps2ds(const Def*, const Def*, const Def* fun, const Def* dbg) { return op_cps2ds_dep(fun, dbg); } +Ref normalize_cps2ds(Ref, Ref, Ref fun) { return op_cps2ds_dep(fun); } THORIN_direct_NORMALIZER_IMPL diff --git a/dialects/direct/passes/cps2ds.cpp b/dialects/direct/passes/cps2ds.cpp index cc54a82dc0..9fb0d39557 100644 --- a/dialects/direct/passes/cps2ds.cpp +++ b/dialects/direct/passes/cps2ds.cpp @@ -14,7 +14,7 @@ void CPS2DS::enter() { lam->world().DLOG("skipped non-nom {}", lam); return; } - world().DLOG("CPS2DS: {}", lam->name()); + world().DLOG("CPS2DS: {}", lam->sym()); rewrite_lam(lam); } @@ -89,10 +89,10 @@ const Def* CPS2DS::rewrite_body_(const Def* def) { } // The continuation that receives the result of the cps function call. - auto fun_cont = world.nom_lam(world.cn(inst_ret_ty), world.dbg(curr_lam_->name() + "_cont")); + auto fun_cont = world.nom_lam(world.cn(inst_ret_ty))->set(*curr_lam_->sym() + "_cont"); // Generate the cps function call `f a` -> `f_cps(a,cont)` - auto cps_call = world.app(cps_fun, {new_arg, fun_cont}, world.dbg("cps_call")); - world.DLOG(" curr_lam {}", curr_lam_->name()); + auto cps_call = world.app(cps_fun, {new_arg, fun_cont})->set(cps_call_); + world.DLOG(" curr_lam {}", curr_lam_->sym()); curr_lam_->set_body(cps_call); // Fixme: would be great to PE the newly added overhead away.. @@ -128,9 +128,9 @@ const Def* CPS2DS::rewrite_body_(const Def* def) { if (auto old_nom = def->isa_nom()) { return old_nom; } DefArray new_ops{def->ops(), [&](const Def* op) { return rewrite_body(op); }}; - if (def->isa()) return world.tuple(new_ops, def->dbg()); + if (def->isa()) return world.tuple(new_ops); // TODO just remove this line? there is rebuild below - return def->rebuild(world, def->type(), new_ops, def->dbg()); + return def->rebuild(world, def->type(), new_ops); } } // namespace thorin::direct diff --git a/dialects/direct/passes/cps2ds.h b/dialects/direct/passes/cps2ds.h index ffd7644753..d82131cd27 100644 --- a/dialects/direct/passes/cps2ds.h +++ b/dialects/direct/passes/cps2ds.h @@ -11,11 +11,13 @@ namespace thorin::direct { class CPS2DS : public RWPass { public: CPS2DS(PassMan& man) - : RWPass(man, "cps2ds") {} + : RWPass(man, "cps2ds") + , cps_call_{world().sym("csp_call")} {} void enter() override; private: + Sym cps_call_; Def2Def rewritten_lams; Def2Def rewritten_; Lam* curr_lam_ = nullptr; diff --git a/dialects/direct/passes/ds2cps.cpp b/dialects/direct/passes/ds2cps.cpp index 9a2a35262f..f0bcc9615a 100644 --- a/dialects/direct/passes/ds2cps.cpp +++ b/dialects/direct/passes/ds2cps.cpp @@ -16,8 +16,7 @@ const Def* DS2CPS::rewrite(const Def* def) { world.DLOG("encountered lam app"); auto new_lam = rewrite_lam(lam); world.DLOG("new lam: {} : {}", new_lam, new_lam->type()); - auto arg = app->arg(); - world.DLOG("arg: {} : {}", arg, arg->type()); + world.DLOG("arg: {} : {}", app->arg(), app->arg()->type()); auto new_app = world.app(new_lam, app->arg()); world.DLOG("new app: {} : {}", new_app, new_app->type()); return new_app; @@ -63,7 +62,7 @@ const Def* DS2CPS::rewrite_lam(Lam* lam) { auto cps_ty = world().cn(sig); world().DLOG("cps type: {}", cps_ty); - auto cps_lam = world().nom_lam(cps_ty, world().dbg(lam->name() + "_cps")); + auto cps_lam = world().nom_lam(cps_ty)->set(*lam->sym() + "_cps"); // rewrite vars of new function // calls handled separately diff --git a/dialects/math/math.h b/dialects/math/math.h index 93d5b86a4e..8f85af4eac 100644 --- a/dialects/math/math.h +++ b/dialects/math/math.h @@ -36,26 +36,26 @@ enum Mode : nat_t { }; // clang-format on -using VMode = std::variant; +using VMode = std::variant; -inline const Def* mode(World& w, VMode m) { - if (auto def = std::get_if(&m)) return *def; +inline Ref mode(World& w, VMode m) { + if (auto def = std::get_if(&m)) return *def; if (auto nat = std::get_if(&m)) return w.lit_nat(*nat); return w.lit_nat(std::get(m)); } ///@{ template -inline auto match_f(const Def* def) { +inline auto match_f(Ref def) { if (auto f_ty = match(def)) { if (auto [p, e] = f_ty->arg()->projs<2>(isa_lit); p && e && *p == P && *e == E) return f_ty; } return Match(); } -inline auto match_f16(const Def* def) { return match_f<10, 5>(def); } -inline auto match_f32(const Def* def) { return match_f<23, 8>(def); } -inline auto match_f64(const Def* def) { return match_f<52, 11>(def); } -inline std::optional isa_f(const Def* def) { +inline auto match_f16(Ref def) { return match_f<10, 5>(def); } +inline auto match_f32(Ref def) { return match_f<23, 8>(def); } +inline auto match_f64(Ref def) { return match_f<52, 11>(def); } +inline std::optional isa_f(Ref def) { if (auto f_ty = match(def)) { if (auto [p, e] = f_ty->arg()->projs<2>(isa_lit); p && e) { if (*p == 10 && e == 5) return 16; @@ -70,38 +70,38 @@ inline std::optional isa_f(const Def* def) { /// @name type_f ///@{ inline const Axiom* type_f(World& w) { return w.ax(); } -inline const Def* type_f(const Def* pe) { +inline Ref type_f(Ref pe) { World& w = pe->world(); return w.app(type_f(w), pe); } -inline const Def* type_f(World& w, nat_t p, nat_t e) { +inline Ref type_f(World& w, nat_t p, nat_t e) { auto lp = w.lit_nat(p); auto le = w.lit_nat(e); return type_f(w.tuple({lp, le})); } -inline const Def* type_f16(World& w) { return type_f(w, 10, 5); } -inline const Def* type_f32(World& w) { return type_f(w, 23, 8); } -inline const Def* type_f64(World& w) { return type_f(w, 52, 11); } +inline Ref type_f16(World& w) { return type_f(w, 10, 5); } +inline Ref type_f32(World& w) { return type_f(w, 23, 8); } +inline Ref type_f64(World& w) { return type_f(w, 52, 11); } ///@} /// @name lit_f ///@{ // clang-format off template -const Lit* lit_f(World& w, R val, const Def* dbg = {}) { +const Lit* lit_f(World& w, R val) { static_assert(std::is_floating_point() || std::is_same()); if constexpr (false) {} - else if constexpr (sizeof(R) == 2) return w.lit(type_f16(w), thorin::bitcast(val), dbg); - else if constexpr (sizeof(R) == 4) return w.lit(type_f32(w), thorin::bitcast(val), dbg); - else if constexpr (sizeof(R) == 8) return w.lit(type_f64(w), thorin::bitcast(val), dbg); + else if constexpr (sizeof(R) == 2) return w.lit(type_f16(w), thorin::bitcast(val)); + else if constexpr (sizeof(R) == 4) return w.lit(type_f32(w), thorin::bitcast(val)); + else if constexpr (sizeof(R) == 8) return w.lit(type_f64(w), thorin::bitcast(val)); else unreachable(); } -inline const Lit* lit_f(World& w, nat_t width, f64 val, const Def* dbg = {}) { +inline const Lit* lit_f(World& w, nat_t width, f64 val) { switch (width) { - case 16: assert(f64(f16(f32(val))) == val && "loosing precision"); return lit_f(w, f16(f32(val)), dbg); - case 32: assert(f64(f32( (val))) == val && "loosing precision"); return lit_f(w, f32( (val)), dbg); - case 64: assert(f64(f64( (val))) == val && "loosing precision"); return lit_f(w, f64( (val)), dbg); + case 16: assert(f64(f16(f32(val))) == val && "loosing precision"); return lit_f(w, f16(f32(val))); + case 32: assert(f64(f32( (val))) == val && "loosing precision"); return lit_f(w, f32( (val))); + case 64: assert(f64(f64( (val))) == val && "loosing precision"); return lit_f(w, f64( (val))); default: unreachable(); } } @@ -110,10 +110,10 @@ inline const Lit* lit_f(World& w, nat_t width, f64 val, const Def* dbg = {}) { /// @name wrappers for unary operations ///@{ -inline const Def* op_rminus(VMode m, const Def* a, const Def* dbg = {}) { +inline Ref op_rminus(VMode m, Ref a) { World& w = a->world(); auto s = isa_f(a->type()); - return w.dcall(dbg, arith::sub, mode(w, m), Defs{lit_f(w, *s, -0.0), a}); + return w.call(arith::sub, mode(w, m), Defs{lit_f(w, *s, -0.0), a}); } ///@} diff --git a/dialects/math/normalizers.cpp b/dialects/math/normalizers.cpp index 751d9c9e6e..80902b4b43 100644 --- a/dialects/math/normalizers.cpp +++ b/dialects/math/normalizers.cpp @@ -119,8 +119,8 @@ Res fold(u64 a, u64 b) { // clang-format on template -static const Def* fold(World& world, const Def* type, const Def* a, const Def* dbg) { - if (a->isa()) return world.bot(type, dbg); +static Ref fold(World& world, Ref type, const Def* a) { + if (a->isa()) return world.bot(type); auto la = a->isa(); if (la) { @@ -134,7 +134,7 @@ static const Def* fold(World& world, const Def* type, const Def* a, const Def* d default: unreachable(); } - return world.lit(type, *res, dbg); + return world.lit(type, *res); } return nullptr; @@ -142,10 +142,10 @@ static const Def* fold(World& world, const Def* type, const Def* a, const Def* d /// @attention Note that @p a and @p b are passed by reference as fold also commutes if possible. @sa commute(). template -static const Def* fold(World& world, const Def* type, const Def*& a, const Def*& b, const Def* dbg) { +static Ref fold(World& world, Ref type, const Def*& a, const Def*& b) { auto la = a->isa(), lb = b->isa(); - if (a->isa() || b->isa()) return world.bot(type, dbg); + if (a->isa() || b->isa()) return world.bot(type); if (la && lb) { nat_t width = *isa_f(a->type()); @@ -158,7 +158,7 @@ static const Def* fold(World& world, const Def* type, const Def*& a, const Def*& default: unreachable(); } - return world.lit(type, *res, dbg); + return world.lit(type, *res); } commute(id, a, b); @@ -177,8 +177,7 @@ static const Def* fold(World& world, const Def* type, const Def*& a, const Def*& /// (4) (lx op y) op b -> lx op (y op b) /// ``` template -static const Def* -reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, const Def* b, const Def* dbg) { +static Ref reassociate(Id id, World& world, [[maybe_unused]] const App* ab, Ref a, Ref b) { if (!is_associative(id)) return nullptr; auto la = a->isa(); @@ -189,7 +188,7 @@ reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, c auto y = xy ? xy->arg(1) : nullptr; auto w = zw ? zw->arg(1) : nullptr; - std::function make_op; + std::function make_op; // build mode for all new ops by using the least upper bound of all involved apps nat_t mode = Mode::bot; @@ -204,7 +203,7 @@ reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, c if (lx && !check_mode(xy->decurry())) return nullptr; if (lz && !check_mode(zw->decurry())) return nullptr; - make_op = [&](const Def* a, const Def* b) { return world.dcall(dbg, id, mode, Defs{a, b}); }; + make_op = [&](Ref a, Ref b) { return world.call(id, mode, Defs{a, b}); }; if (la && lz) return make_op(make_op(la, lz), w); // (1) if (lx && lz) return make_op(make_op(lx, lz), make_op(y, w)); // (2) @@ -215,7 +214,7 @@ reassociate(Id id, World& world, [[maybe_unused]] const App* ab, const Def* a, c } template -const Def* normalize_arith(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_arith(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); @@ -223,7 +222,7 @@ const Def* normalize_arith(const Def* type, const Def* c, const Def* arg, const auto lm = isa_lit(mode); auto w = isa_f(a->type()); - if (auto result = fold(world, type, a, b, dbg)) return result; + if (auto result = fold(world, type, a, b)) return result; // clang-format off // TODO check mode properly @@ -231,11 +230,11 @@ const Def* normalize_arith(const Def* type, const Def* c, const Def* arg, const if (auto la = a->isa()) { if (la == lit_f(world, *w, 0.0)) { switch (id) { - case arith::add: return b; // 0 + b -> b + case arith::add: return b; // 0 + b -> b case arith::sub: break; - case arith::mul: return la; // 0 * b -> 0 - case arith::div: return la; // 0 / b -> 0 - case arith::rem: return la; // 0 % b -> 0 + case arith::mul: return la; // 0 * b -> 0 + case arith::div: return la; // 0 / b -> 0 + case arith::rem: return la; // 0 % b -> 0 } } @@ -243,7 +242,7 @@ const Def* normalize_arith(const Def* type, const Def* c, const Def* arg, const switch (id) { case arith::add: break; case arith::sub: break; - case arith::mul: return b; // 1 * b -> b + case arith::mul: return b; // 1 * b -> b case arith::div: break; case arith::rem: break; } @@ -253,7 +252,7 @@ const Def* normalize_arith(const Def* type, const Def* c, const Def* arg, const if (auto lb = b->isa()) { if (lb == lit_f(world, *w, 0.0)) { switch (id) { - case arith::sub: return a; // a - 0 -> a + case arith::sub: return a; // a - 0 -> a case arith::div: break; case arith::rem: break; default: unreachable(); @@ -264,95 +263,95 @@ const Def* normalize_arith(const Def* type, const Def* c, const Def* arg, const if (a == b) { switch (id) { - case arith::add: return world.dcall(dbg, arith::mul, mode, Defs{lit_f(world, *w, 2.0), a}); // a + a -> 2 * a - case arith::sub: return lit_f(world, *w, 0.0); // a - a -> 0 + case arith::add: return world.call(arith::mul, mode, Defs{lit_f(world, *w, 2.0), a}); // a + a -> 2 * a + case arith::sub: return lit_f(world, *w, 0.0); // a - a -> 0 case arith::mul: break; - case arith::div: return lit_f(world, *w, 1.0); // a / a -> 1 + case arith::div: return lit_f(world, *w, 1.0); // a / a -> 1 case arith::rem: break; } } } // clang-format on - if (auto res = reassociate(id, world, callee, a, b, dbg)) return res; + if (auto res = reassociate(id, world, callee, a, b)) return res; - return world.raw_app(type, callee, {a, b}, dbg); + return world.raw_app(type, callee, {a, b}); } template -const Def* normalize_extrema(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_extrema(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); auto m = callee->arg(); auto lm = isa_lit(m); - if (auto lit = fold(world, type, a, b, dbg)) return lit; + if (auto lit = fold(world, type, a, b)) return lit; if (lm && *lm & (Mode::nnan | Mode::nsz)) { // if ignore NaNs and signed zero, then *imum -> *num switch (id) { - case extrema::ieee754min: return world.dcall(dbg, extrema::fmin, m, Defs{a, b}); - case extrema::ieee754max: return world.dcall(dbg, extrema::fmax, m, Defs{a, b}); + case extrema::ieee754min: return world.call(extrema::fmin, m, Defs{a, b}); + case extrema::ieee754max: return world.call(extrema::fmax, m, Defs{a, b}); default: break; } } - return world.raw_app(type, c, arg, dbg); + return world.raw_app(type, c, arg); } template -const Def* normalize_tri(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_tri(Ref type, Ref c, Ref arg) { auto& world = type->world(); - if (auto lit = fold(world, type, arg, dbg)) return lit; - return world.raw_app(type, c, arg, dbg); + if (auto lit = fold(world, type, arg)) return lit; + return world.raw_app(type, c, arg); } -const Def* normalize_pow(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_pow(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto [a, b] = arg->projs<2>(); - if (auto lit = fold(world, type, a, b, dbg)) return lit; - return world.raw_app(type, c, arg, dbg); + if (auto lit = fold(world, type, a, b)) return lit; + return world.raw_app(type, c, arg); } template -const Def* normalize_rt(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_rt(Ref type, Ref c, Ref arg) { auto& world = type->world(); - if (auto lit = fold(world, type, arg, dbg)) return lit; - return world.raw_app(type, c, arg, dbg); + if (auto lit = fold(world, type, arg)) return lit; + return world.raw_app(type, c, arg); } template -const Def* normalize_exp(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_exp(Ref type, Ref c, Ref arg) { auto& world = type->world(); - if (auto lit = fold(world, type, arg, dbg)) return lit; - return world.raw_app(type, c, arg, dbg); + if (auto lit = fold(world, type, arg)) return lit; + return world.raw_app(type, c, arg); } template -const Def* normalize_er(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_er(Ref type, Ref c, Ref arg) { auto& world = type->world(); - if (auto lit = fold(world, type, arg, dbg)) return lit; - return world.raw_app(type, c, arg, dbg); + if (auto lit = fold(world, type, arg)) return lit; + return world.raw_app(type, c, arg); } template -const Def* normalize_gamma(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_gamma(Ref type, Ref c, Ref arg) { auto& world = type->world(); - if (auto lit = fold(world, type, arg, dbg)) return lit; - return world.raw_app(type, c, arg, dbg); + if (auto lit = fold(world, type, arg)) return lit; + return world.raw_app(type, c, arg); } template -const Def* normalize_cmp(const Def* type, const Def* c, const Def* arg, const Def* dbg) { +Ref normalize_cmp(Ref type, Ref c, Ref arg) { auto& world = type->world(); auto callee = c->as(); auto [a, b] = arg->projs<2>(); - if (auto result = fold(world, type, a, b, dbg)) return result; + if (auto result = fold(world, type, a, b)) return result; if (id == cmp::f) return world.lit_ff(); if (id == cmp::t) return world.lit_tt(); - return world.raw_app(type, callee, {a, b}, dbg); + return world.raw_app(type, callee, {a, b}); } template @@ -363,7 +362,7 @@ Res fold(u64 a) { } template -const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const Def* dbg) { +Ref normalize_conv(Ref dst_t, Ref c, Ref x) { auto& world = dst_t->world(); auto callee = c->as(); auto s_t = x->type()->as(); @@ -374,7 +373,7 @@ const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const De auto ld = isa_lit(d); if (s_t == d_t) return x; - if (x->isa()) return world.bot(d_t, dbg); + if (x->isa()) return world.bot(d_t); if (auto l = isa_lit(x); l && ls && ld) { constexpr bool sf = id == conv::f2f || id == conv::f2s || id == conv::f2u; @@ -403,11 +402,11 @@ const Def* normalize_conv(const Def* dst_t, const Def* c, const Def* x, const De else unreachable(); // clang-format on - return world.lit(d_t, *res, dbg); + return world.lit(d_t, *res); } } out: - return world.raw_app(dst_t, callee, x, dbg); + return world.raw_app(dst_t, callee, x); } // TODO I guess we can do that with C++20 diff --git a/dialects/mem/mem.h b/dialects/mem/mem.h index 191343dc58..68494fcafd 100644 --- a/dialects/mem/mem.h +++ b/dialects/mem/mem.h @@ -23,89 +23,87 @@ enum : nat_t { inline const Axiom* type_mem(World& w) { return w.ax(); } inline const Axiom* type_ptr(World& w) { return w.ax(); } -inline const App* type_ptr(const Def* pointee, const Def* addr_space, const Def* dbg = {}) { +inline const App* type_ptr(Ref pointee, Ref addr_space) { World& w = pointee->world(); - return w.app(type_ptr(w), {pointee, addr_space}, dbg)->as(); + return w.app(type_ptr(w), {pointee, addr_space})->as(); } -inline const App* type_ptr(const Def* pointee, nat_t addr_space = AddrSpace::Generic, const Def* dbg = {}) { +inline const App* type_ptr(Ref pointee, nat_t addr_space = AddrSpace::Generic) { World& w = pointee->world(); - return type_ptr(pointee, w.lit_nat(addr_space), dbg); + return type_ptr(pointee, w.lit_nat(addr_space)); } /// Same as World::cn / World::pi but adds a World::type_mem-typed Var to each Pi. -inline const Pi* cn_mem(const Def* dom, const Def* dbg = {}) { +inline const Pi* cn_mem(Ref dom) { World& w = dom->world(); - return w.cn({type_mem(w), dom}, dbg); + return w.cn({type_mem(w), dom}); } -inline const Pi* cn_mem_ret(const Def* dom, const Def* ret_dom, const Def* dbg = {}) { +inline const Pi* cn_mem_ret(Ref dom, Ref ret_dom) { World& w = dom->world(); - return w.cn({type_mem(w), dom, cn_mem(ret_dom)}, dbg); + return w.cn({type_mem(w), dom, cn_mem(ret_dom)}); } -inline const Pi* pi_mem(const Def* domain, const Def* codomain, const Def* dbg = {}) { +inline const Pi* pi_mem(Ref domain, Ref codomain) { World& w = domain->world(); auto d = w.sigma({type_mem(w), domain}); - return w.pi(d, w.sigma({type_mem(w), codomain}), dbg); + return w.pi(d, w.sigma({type_mem(w), codomain})); } -inline const Pi* fn_mem(const Def* domain, const Def* codomain, const Def* dbg = {}) { +inline const Pi* fn_mem(Ref domain, Ref codomain) { World& w = domain->world(); - return w.cn({type_mem(w), domain, cn_mem(codomain)}, dbg); + return w.cn({type_mem(w), domain, cn_mem(codomain)}); } -static inline const Def* tuple_of_types(const Def* t) { +static inline Ref tuple_of_types(Ref t) { auto& world = t->world(); if (auto sigma = t->isa()) return world.tuple(sigma->ops()); if (auto arr = t->isa()) return world.pack(arr->shape(), arr->body()); return t; } -inline const Def* op_lea(const Def* ptr, const Def* index, const Def* dbg = {}) { +inline Ref op_lea(Ref ptr, Ref index) { World& w = ptr->world(); auto [pointee, addr_space] = force(ptr->type())->args<2>(); auto Ts = tuple_of_types(pointee); - return w.app(w.app(w.ax(), {pointee->arity(), Ts, addr_space}), {ptr, index}, dbg); + return w.app(w.app(w.ax(), {pointee->arity(), Ts, addr_space}), {ptr, index}); } -inline const Def* op_lea_unsafe(const Def* ptr, const Def* i, const Def* dbg = {}) { - World& w = ptr->world(); - return op_lea(ptr, w.call(core::conv::u, force(ptr->type())->arg(0)->arity(), i), dbg); +inline Ref op_lea_unsafe(Ref ptr, Ref i) { + World& w = ptr->world(); + return op_lea(ptr, w.call(core::conv::u, force(ptr->type())->arg(0)->arity(), i)); } -inline const Def* op_lea_unsafe(const Def* ptr, u64 i, const Def* dbg = {}) { +inline Ref op_lea_unsafe(Ref ptr, u64 i) { World& w = ptr->world(); - return op_lea_unsafe(ptr, w.lit_idx(i), dbg); + return op_lea_unsafe(ptr, w.lit_idx(i)); } -inline const Def* op_remem(const Def* mem, const Def* dbg = {}) { +inline Ref op_remem(Ref mem) { World& w = mem->world(); - return w.app(w.ax(), mem, dbg); + return w.app(w.ax(), mem); } -inline const Def* op_alloc(const Def* type, const Def* mem, const Def* dbg = {}) { +inline Ref op_alloc(Ref type, Ref mem) { World& w = type->world(); - return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), mem, dbg); + return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), mem); } -inline const Def* op_slot(const Def* type, const Def* mem, const Def* dbg = {}) { +inline Ref op_slot(Ref type, Ref mem) { World& w = type->world(); - return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), {mem, w.lit_nat(w.curr_gid())}, dbg); + return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), {mem, w.lit_nat(w.curr_gid())}); } -inline const Def* op_malloc(const Def* type, const Def* mem, const Def* dbg) { +inline Ref op_malloc(Ref type, Ref mem) { World& w = type->world(); - auto size = w.dcall(dbg, core::trait::size, type); - return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), {mem, size}, dbg); + auto size = w.call(core::trait::size, type); + return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), {mem, size}); } -inline const Def* op_mslot(const Def* type, const Def* mem, const Def* id, const Def* dbg) { +inline Ref op_mslot(Ref type, Ref mem, Ref id) { World& w = type->world(); - auto size = w.dcall(dbg, core::trait::size, type); - return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), {mem, size, id}, dbg); + auto size = w.call(core::trait::size, type); + return w.app(w.app(w.ax(), {type, w.lit_nat_0()}), {mem, size, id}); } -const Def* op_malloc(const Def* type, const Def* mem, const Def* dbg = {}); -const Def* op_mslot(const Def* type, const Def* mem, const Def* id, const Def* dbg = {}); +Ref op_malloc(Ref type, Ref mem); +Ref op_mslot(Ref type, Ref mem, Ref id); -inline const Def* mem_var(Lam* lam, const Def* dbg = nullptr) { - return match(lam->var(0_s)->type()) ? lam->var(0, dbg) : nullptr; -} +inline Ref mem_var(Lam* lam) { return match(lam->var(0_s)->type()) ? lam->var(0) : nullptr; } } // namespace thorin::mem diff --git a/dialects/mem/normalizers.cpp b/dialects/mem/normalizers.cpp index d7d8001a9c..8dc800f98a 100644 --- a/dialects/mem/normalizers.cpp +++ b/dialects/mem/normalizers.cpp @@ -4,7 +4,7 @@ namespace thorin::mem { -const Def* normalize_lea(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_lea(Ref type, Ref callee, Ref arg) { auto& world = type->world(); auto [ptr, index] = arg->projs<2>(); auto [pointee, addr_space] = force(ptr->type())->args<2>(); @@ -12,41 +12,41 @@ const Def* normalize_lea(const Def* type, const Def* callee, const Def* arg, con if (auto a = isa_lit(pointee->arity()); a && *a == 1) return ptr; // TODO - return world.raw_app(type, callee, {ptr, index}, dbg); + return world.raw_app(type, callee, {ptr, index}); } -const Def* normalize_load(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_load(Ref type, Ref callee, Ref arg) { auto& world = type->world(); auto [mem, ptr] = arg->projs<2>(); auto [pointee, addr_space] = force(ptr->type())->args<2>(); - if (ptr->isa()) return world.tuple({mem, world.bot(type->as()->op(1))}, dbg); + if (ptr->isa()) return world.tuple({mem, world.bot(type->as()->op(1))}); // loading an empty tuple can only result in an empty tuple if (auto sigma = pointee->isa(); sigma && sigma->num_ops() == 0) - return world.tuple({mem, world.tuple(sigma->type(), {}, dbg)}); + return world.tuple({mem, world.tuple(sigma->type(), {})}); - return world.raw_app(type, callee, {mem, ptr}, dbg); + return world.raw_app(type, callee, {mem, ptr}); } -const Def* normalize_remem(const Def* type, const Def* callee, const Def* mem, const Def* dbg) { +Ref normalize_remem(Ref type, Ref callee, Ref mem) { auto& world = type->world(); // if (auto m = match(mem)) mem = m; - return world.raw_app(type, callee, mem, dbg); + return world.raw_app(type, callee, mem); } -const Def* normalize_store(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_store(Ref type, Ref callee, Ref arg) { auto& world = type->world(); auto [mem, ptr, val] = arg->projs<3>(); if (ptr->isa() || val->isa()) return mem; if (auto pack = val->isa(); pack && pack->body()->isa()) return mem; if (auto tuple = val->isa()) { - if (std::ranges::all_of(tuple->ops(), [](const Def* op) { return op->isa(); })) return mem; + if (std::ranges::all_of(tuple->ops(), [](Ref op) { return op->isa(); })) return mem; } - return world.raw_app(type, callee, {mem, ptr, val}, dbg); + return world.raw_app(type, callee, {mem, ptr, val}); } THORIN_mem_NORMALIZER_IMPL diff --git a/dialects/mem/passes/fp/copy_prop.cpp b/dialects/mem/passes/fp/copy_prop.cpp index ef95b7ee53..5a4de9a277 100644 --- a/dialects/mem/passes/fp/copy_prop.cpp +++ b/dialects/mem/passes/fp/copy_prop.cpp @@ -62,7 +62,7 @@ const Def* CopyProp::rewrite(const Def* def) { old_args = args; auto prop_dom = world().sigma(new_doms); auto new_pi = world().pi(prop_dom, var_lam->codom()); - prop_lam = var_lam->stub(world(), new_pi, var_lam->dbg()); + prop_lam = var_lam->stub(world(), new_pi); world().DLOG("new prop_lam: {}", prop_lam); if (beta_red_) beta_red_->keep(prop_lam); @@ -82,7 +82,7 @@ const Def* CopyProp::rewrite(const Def* def) { } world().DLOG("var_lam => prop_lam: {}: {} => {}: {}", var_lam, var_lam->dom(), prop_lam, prop_lam->dom()); - auto res = app->world().app(prop_lam, new_args, app->dbg()); + auto res = app->world().app(prop_lam, new_args); // Don't optimize again. Also, keep this line here at the very bottom as this invalidates all references. Lam* key = prop_lam; // prop_lam is a Lam*& which might get invalidated by the very insertion happening next. @@ -104,8 +104,7 @@ undo_t CopyProp::analyze(const Proxy* proxy) { } } else { assert(proxy->tag() == Appxy); - auto ops = proxy->ops(); - for (auto op : ops.skip_front()) { + for (auto ops = proxy->ops(); auto op : ops.skip_front()) { auto i = as_lit(op); if (auto& l = lattice[i]; l != Lattice::Keep) { l = Lattice::Keep; diff --git a/dialects/mem/passes/fp/ssa_constr.cpp b/dialects/mem/passes/fp/ssa_constr.cpp index 447b0e551b..099cd2574c 100644 --- a/dialects/mem/passes/fp/ssa_constr.cpp +++ b/dialects/mem/passes/fp/ssa_constr.cpp @@ -29,7 +29,7 @@ const Def* SSAConstr::rewrite(const Def* def) { if (auto slot = match(def)) { auto [mem, id] = slot->args<2>(); auto [_, ptr] = slot->projs<2>(); - auto sloxy = proxy(ptr->type(), {curr_nom(), id}, Sloxy, slot->dbg()); + auto sloxy = proxy(ptr->type(), {curr_nom(), id}, Sloxy)->set(slot->dbg()); world().DLOG("sloxy: '{}'", sloxy); if (!keep_.contains(sloxy)) { set_val(curr_nom(), sloxy, world().bot(get_sloxy_type(sloxy))); @@ -44,7 +44,7 @@ const Def* SSAConstr::rewrite(const Def* def) { if (auto sloxy = isa_proxy(ptr, Sloxy)) { if (data(curr_nom()).writable.contains(sloxy)) { set_val(curr_nom(), sloxy, val); - return op_remem(mem, store->dbg()); + return op_remem(mem)->set(store->dbg()); } } } else if (auto [app, mem_lam] = isa_apped_nom_lam(def); isa_workable(mem_lam)) { @@ -73,8 +73,8 @@ const Def* SSAConstr::get_val(Lam* lam, const Proxy* sloxy) { world().DLOG("get_val recurse: '{}': '{}' -> '{}'", sloxy, pred, lam); return get_val(pred, sloxy); } else { - auto phixy = proxy(get_sloxy_type(sloxy), {sloxy, lam}, Phixy, sloxy->dbg()); - phixy->set_debug_name(std::string("phi_") + phixy->debug().name); + auto phixy = proxy(get_sloxy_type(sloxy), {sloxy, lam}, Phixy)->set(sloxy->dbg()); + phixy->debug_prefix("_phi_"); world().DLOG("get_val phixy: '{}' '{}'", sloxy, lam); return set_val(lam, sloxy, phixy); } @@ -108,15 +108,14 @@ const Def* SSAConstr::mem2phi(const App* app, Lam* mem_lam) { if (phi_lam == nullptr || old_phis != phis) { old_phis = phis; auto new_type = world().pi(merge_sigma(mem_lam->dom(), types), mem_lam->codom()); - phi_lam = world().nom_lam(new_type, mem_lam->dbg()); + phi_lam = world().nom_lam(new_type)->set(mem_lam->dbg()); eta_exp_->new2old(phi_lam, mem_lam); world().DLOG("new phi_lam '{}'", phi_lam); auto num_mem_vars = mem_lam->num_vars(); - size_t i = 0; DefArray traxy_ops(2 * num_phis + 1); traxy_ops[0] = phi_lam->var(); - for (auto sloxy : sloxys) { + for (size_t i = 0; auto sloxy : sloxys) { traxy_ops[2 * i + 1] = sloxy; traxy_ops[2 * i + 2] = phi_lam->var(num_mem_vars + i); ++i; @@ -163,8 +162,7 @@ undo_t SSAConstr::analyze(const Def* def) { // TODO this is a bit scruffy - maybe we can do better if (succ_lam->is_basicblock() && succ_lam != curr_nom()) { - auto writable = data(curr_nom()).writable; - for (auto&& w : writable) succ_info.writable.insert(w); + for (auto writable = data(curr_nom()).writable; auto&& w : writable) succ_info.writable.insert(w); } if (!isa_callee(def, i)) { diff --git a/dialects/mem/passes/rw/alloc2malloc.cpp b/dialects/mem/passes/rw/alloc2malloc.cpp index 7e2583bda6..b702489b99 100644 --- a/dialects/mem/passes/rw/alloc2malloc.cpp +++ b/dialects/mem/passes/rw/alloc2malloc.cpp @@ -7,11 +7,11 @@ namespace thorin::mem { const Def* Alloc2Malloc::rewrite(const Def* def) { if (auto alloc = match(def)) { auto [pointee, addr_space] = alloc->decurry()->args<2>(); - return op_malloc(pointee, alloc->arg(), alloc->dbg()); + return op_malloc(pointee, alloc->arg()); } else if (auto slot = match(def)) { auto [pointee, addr_space] = slot->decurry()->args<2>(); auto [mem, id] = slot->args<2>(); - return op_mslot(pointee, mem, id, slot->dbg()); + return op_mslot(pointee, mem, id); } return def; diff --git a/dialects/mem/phases/rw/add_mem.cpp b/dialects/mem/phases/rw/add_mem.cpp index 517bc630e0..492d55ba71 100644 --- a/dialects/mem/phases/rw/add_mem.cpp +++ b/dialects/mem/phases/rw/add_mem.cpp @@ -44,7 +44,7 @@ static const Def* rewrite_nom_lam_in_tuple(const Def* def, F&& rewrite, H&& rewr DefArray new_ops{tuple->ops(), [&](const Def* op) { return rewrite_nom_lam_in_tuple(op, std::forward(rewrite), std::forward(rewrite_idx)); }}; - return w.extract(w.tuple(new_ops, tuple->dbg()), rewrite_idx(extract->index()), extract->dbg()); + return w.extract(w.tuple(new_ops), rewrite_idx(extract->index())); } // @pre isa_apped_nom_lam_in_tuple(def) valid @@ -58,7 +58,7 @@ static const Def* rewrite_apped_nom_lam_in_tuple(const Def* def, auto callee = rewrite_nom_lam_in_tuple(app->callee(), std::forward(rewrite_callee), std::forward(rewrite_idx)); auto arg = std::forward(rewrite_arg)(app->arg()); - return app->rebuild(w, app->type(), {callee, arg}, app->dbg()); + return app->rebuild(w, app->type(), {callee, arg}); } void AddMem::visit(const Scope& scope) { @@ -83,7 +83,7 @@ const Def* AddMem::rewrite_type(const Def* type) { if (auto it = mem_rewritten_.find(type); it != mem_rewritten_.end()) return it->second; DefArray new_ops{type->num_ops(), [&](size_t i) { return rewrite_type(type->op(i)); }}; - return mem_rewritten_[type] = type->rebuild(world(), type->type(), new_ops, type->dbg()); + return mem_rewritten_[type] = type->rebuild(world(), type->type(), new_ops); } const Def* AddMem::rewrite_pi(const Pi* pi) { @@ -96,7 +96,7 @@ const Def* AddMem::rewrite_pi(const Pi* pi) { DefArray{dom->num_projs() + 1, [&](size_t i) { return i == 0 ? mem::type_mem(world()) : new_dom[i - 1]; }}; } - return mem_rewritten_[pi] = world().pi(new_dom, pi->codom(), pi->dbg()); + return mem_rewritten_[pi] = world().pi(new_dom, pi->codom()); } const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { @@ -135,7 +135,7 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { bool is_bound = sched_.scope().bound(nom) || nom == curr_lam; if (new_nom == nom) // if not stubbed yet - if (auto new_pi = rewrite_pi(pi); new_pi != pi) { new_nom = nom->stub(world(), new_pi, nom->dbg()); } + if (auto new_pi = rewrite_pi(pi); new_pi != pi) { new_nom = nom->stub(world(), new_pi); } if (!is_bound) { world().DLOG("free lam {}", nom); @@ -144,9 +144,9 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { } auto var_offset = new_nom->num_doms() - nom->num_doms(); // have we added a mem var? - if (nom->num_vars() != 0) mem_rewritten_[nom->var()] = new_nom->var(nom->var()->dbg()); + if (nom->num_vars() != 0) mem_rewritten_[nom->var()] = new_nom->var(); for (size_t i = 0; i < nom->num_vars() && new_nom->num_vars() > 1; ++i) - mem_rewritten_[nom->var(i)] = new_nom->var(i + var_offset, nom->var(i)->dbg()); + mem_rewritten_[nom->var(i)] = new_nom->var(i + var_offset); mem_rewritten_[new_nom] = new_nom; mem_rewritten_[nom] = new_nom; @@ -182,7 +182,7 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { new_args[i] = i == 0 ? add_mem_to_lams(place, mem_for_lam(place)) : add_mem_to_lams(place, arg->proj(i - offset)); } - return arg->world().tuple(new_args, arg->dbg()); + return arg->world().tuple(new_args); }; // call-site of a nominal lambda @@ -194,8 +194,8 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { // call-site of a continuation if (auto app = def->isa(); app && (app->callee()->dep() & Dep::Var)) { - return mem_rewritten_[def] = app->rebuild( - world(), app->type(), {add_mem_to_lams(place, app->callee()), rewrite_arg(app->arg())}, app->dbg()); + return mem_rewritten_[def] = + app->rebuild(world(), app->type(), {add_mem_to_lams(place, app->callee()), rewrite_arg(app->arg())}); } // call-site of an axiom (assuming mems are only in the final app..) @@ -214,8 +214,7 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { } } auto rewritten = mem_rewritten_[def] = - app->rebuild(world(), app->type(), - {add_mem_to_lams(place, app->callee()), world().tuple(new_args, arg->dbg())}, app->dbg()); + app->rebuild(world(), app->type(), {add_mem_to_lams(place, app->callee()), world().tuple(new_args)}); if (match(rewritten->type())) val2mem_[place] = rewritten; if (rewritten->num_projs() > 0 && match(rewritten->proj(0)->type())) { mem_rewritten_[rewritten->proj(0)] = rewritten->proj(0); @@ -230,7 +229,7 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { auto new_arg = add_mem_to_lams(place, app->arg()); if (app->callee()->type()->as()->num_doms() + 1 == new_callee->type()->as()->num_doms()) new_arg = rewrite_arg(app->arg()); - auto rewritten = mem_rewritten_[def] = app->rebuild(world(), app->type(), {new_callee, new_arg}, app->dbg()); + auto rewritten = mem_rewritten_[def] = app->rebuild(world(), app->type(), {new_callee, new_arg}); if (match(rewritten->type())) val2mem_[place] = rewritten; if (rewritten->num_projs() > 0 && match(rewritten->proj(0)->type())) { mem_rewritten_[rewritten->proj(0)] = rewritten->proj(0); @@ -248,7 +247,7 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { return add_mem_to_lams(place, op); }}; - auto tmp = mem_rewritten_[def] = def->rebuild(world(), rewrite_type(def->type()), new_ops, def->dbg()); + auto tmp = mem_rewritten_[def] = def->rebuild(world(), rewrite_type(def->type()), new_ops); if (match(tmp->type())) val2mem_[place] = tmp; if (tmp->num_projs() > 0 && match(tmp->proj(0)->type())) { mem_rewritten_[tmp->proj(0)] = tmp->proj(0); diff --git a/dialects/opt/normalizers.cpp b/dialects/opt/normalizers.cpp index 0a2e40cf53..a3a5b6b1a1 100644 --- a/dialects/opt/normalizers.cpp +++ b/dialects/opt/normalizers.cpp @@ -4,10 +4,10 @@ namespace thorin::opt { -const Def* normalize_is_loaded(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_is_loaded(Ref type, Ref callee, Ref arg) { auto& world = arg->world(); world.DLOG("normalize is_loaded: {}", arg); - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } THORIN_opt_NORMALIZER_IMPL diff --git a/dialects/opt/opt.cpp b/dialects/opt/opt.cpp index 124059cbf2..69713820b7 100644 --- a/dialects/opt/opt.cpp +++ b/dialects/opt/opt.cpp @@ -20,24 +20,20 @@ extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { auto dialect_axiom = args[1]->as(); auto then_phase = args[2]; auto else_phase = args[3]; - world.DLOG("dialect_phase for: {}", dialect_axiom->name()); + world.DLOG("dialect_phase for: {}", dialect_axiom->sym()); // name has the form %opt.tag where tag = [dialect]_dialect // we want to extract the dialect part - auto name = dialect_axiom->name(); - std::string_view tag = Axiom::split(name).value()[1]; - assert(tag.find('_') != std::string_view::npos && "dialect_phase: invalid dialect name"); - auto dialect = tag.substr(0, tag.find('_')); + auto name = dialect_axiom->sym(); + auto [_, tag, __] = Axiom::split(world, name); + assert(tag->find('_') != std::string_view::npos && "dialect_phase: invalid dialect name"); + auto dialect = tag->substr(0, tag->find('_')); auto dialect_str = std::string(dialect); world.DLOG("dialect: {}", dialect_str); auto is_loaded = builder.is_registered_dialect(dialect_str); world.DLOG("contained: {}", is_loaded); - if (is_loaded) { - compile::handle_optimization_part(then_phase, world, passes, builder); - } else { - compile::handle_optimization_part(else_phase, world, passes, builder); - } + compile::handle_optimization_part(is_loaded ? then_phase : else_phase, world, passes, builder); }; }, nullptr, [](Normalizers& normalizers) { opt::register_normalizers(normalizers); }}; diff --git a/dialects/refly/normalizers.cpp b/dialects/refly/normalizers.cpp index 1c3e1ee6ef..86831d9916 100644 --- a/dialects/refly/normalizers.cpp +++ b/dialects/refly/normalizers.cpp @@ -4,41 +4,37 @@ namespace thorin::refly { -static_assert(sizeof(const Def*) <= sizeof(u64), "pointer doesn't fit into Lit"); +static_assert(sizeof(void*) <= sizeof(u64), "pointer doesn't fit into Lit"); /// The trick is that we simply "box" the pointer of @p def inside a Lit of type `%refly.Code`. -static const Def* do_reify(const Def* def, const Def* dbg = {}) { - return def->world().lit(type_code(def->world()), reinterpret_cast(def), dbg); -} +static Ref do_reify(const Def* def) { return def->world().lit(type_code(def->world()), reinterpret_cast(def)); } /// And here we are doing the reverse to retrieve the original pointer again. static const Def* do_reflect(const Def* def) { return reinterpret_cast(def->as()->get()); } template -const Def* normalize_dbg(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_dbg(Ref type, Ref callee, Ref arg) { auto& world = arg->world(); debug_print(arg); - return id == dbg::perm ? world.raw_app(type, callee, arg, dbg) : arg; + return id == dbg::perm ? world.raw_app(type, callee, arg) : arg; } -const Def* normalize_reify(const Def*, const Def*, const Def* arg, const Def* dbg) { return do_reify(arg, dbg); } +Ref normalize_reify(Ref, Ref, Ref arg) { return do_reify(arg); } -const Def* normalize_reflect(const Def*, const Def*, const Def* arg, const Def*) { return do_reflect(arg); } +Ref normalize_reflect(Ref, Ref, Ref arg) { return do_reflect(arg); } -const Def* normalize_refine(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_refine(Ref type, Ref callee, Ref arg) { auto& world = arg->world(); auto [code, i, x] = arg->projs<3>(); if (auto l = isa_lit(i)) { auto def = do_reflect(code); - return do_reify(def->refine(*l, do_reflect(x)), dbg); + return do_reify(def->refine(*l, do_reflect(x))); } - return world.raw_app(type, callee, arg, dbg); + return world.raw_app(type, callee, arg); } -const Def* normalize_gid(const Def*, const Def*, const Def* arg, const Def*) { - return arg->world().lit_nat(arg->gid()); -} +Ref normalize_gid(Ref, Ref, Ref arg) { return arg->world().lit_nat(arg->gid()); } THORIN_refly_NORMALIZER_IMPL diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index fab0acfa12..f4f49b39b6 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,15 +1,15 @@ -set(CLI_HELP ${CMAKE_CURRENT_BINARY_DIR}/cli-help.md) +set(CLI_HELP ${CMAKE_CURRENT_BINARY_DIR}/cli-help.inc) add_custom_command( OUTPUT ${CLI_HELP} COMMAND thorin --help > ${CLI_HELP} - DEPENDS thorin + DEPENDS thorin COMMENT "Generating help text of Thorin's CLI" ) set(DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) set(DOXY_LAYOUT ${CMAKE_CURRENT_BINARY_DIR}/DoxygenLayout.xml) set(DOXY_INDEX_HTML ${CMAKE_CURRENT_BINARY_DIR}/html/index.html) -set(DOXY_EXTRA_FILES +set(DOXY_EXTRA_FILES ${CMAKE_CURRENT_SOURCE_DIR}/cli.md ${CMAKE_CURRENT_SOURCE_DIR}/coding.md ${CMAKE_CURRENT_SOURCE_DIR}/dev.md @@ -27,6 +27,7 @@ add_custom_command( MAIN_DEPENDENCY ${DOXYFILE} DEPENDS thorin ${CLI_HELP} ${DOXY_EXTRA_FILES} ${DOXY_LAYOUT} COMMENT "Generating Doxygen HTML documentation" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) add_custom_target(docs ALL DEPENDS ${DOXY_INDEX_HTML} ${THORIN_DIALECT_LIST}) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 60defca8e2..22c9d488af 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -184,7 +184,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@/.. +STRIP_FROM_PATH = . # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -193,7 +193,7 @@ STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@/.. # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = @CMAKE_CURRENT_SOURCE_DIR@/.. +STRIP_FROM_INC_PATH = . # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -908,8 +908,11 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../thorin \ - @CMAKE_CURRENT_SOURCE_DIR@/../dialects \ +INPUT = cli \ + cmake \ + dialects \ + docs \ + thorin \ @DOXY_EXTRA_FILES_CONFIG@ \ @CMAKE_CURRENT_BINARY_DIR@/../include \ @CMAKE_CURRENT_BINARY_DIR@/../docs/dialects @@ -1012,7 +1015,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -1045,8 +1048,8 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/../thorin \ - @CMAKE_CURRENT_SOURCE_DIR@/../dialects \ +EXAMPLE_PATH = thorin \ + dialects \ @CMAKE_CURRENT_BINARY_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the @@ -1321,11 +1324,11 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome.css \ - @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome-sidebar-only.css \ - @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css \ - @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome-interactive-toc.js \ - @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-custom/custom.css +HTML_EXTRA_STYLESHEET = modules/doxygen-awesome-css/doxygen-awesome.css \ + modules/doxygen-awesome-css/doxygen-awesome-sidebar-only.css \ + modules/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css \ + modules/doxygen-awesome-css/doxygen-awesome-interactive-toc.js \ + modules/doxygen-awesome-css/doxygen-custom/custom.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1335,9 +1338,9 @@ HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-c # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js \ - @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js \ - @CMAKE_CURRENT_SOURCE_DIR@/../modules/doxygen-awesome-css/doxygen-awesome-paragraph-link.js +HTML_EXTRA_FILES = modules/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js \ + modules/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js \ + modules/doxygen-awesome-css/doxygen-awesome-paragraph-link.js # The HTML_COLORSTYLE tag can be used to specify if the generated HTML output # should be rendered with a dark or light theme. Default setting AUTO_LIGHT @@ -2313,10 +2316,10 @@ SEARCH_INCLUDES = YES # RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/../cli \ - @CMAKE_CURRENT_SOURCE_DIR@/../thorin \ - @CMAKE_CURRENT_SOURCE_DIR@/../dialects \ - @CMAKE_CURRENT_BINARY_DIR@/../include +INCLUDE_PATH = . \ + @DOXY_EXTRA_FILES_CONFIG@ \ + @CMAKE_CURRENT_BINARY_DIR@/../include \ + @CMAKE_CURRENT_BINARY_DIR@/../docs/dialects # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -2364,7 +2367,9 @@ EXPAND_AS_DEFINED = CODE \ THORIN_CONV \ THORIN_TRAIT \ THORIN_ACC \ - THORIN_PE + THORIN_PE \ + THORIN_SETTERS \ + THORIN_DEF_MIXIN # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have diff --git a/docs/cli.md b/docs/cli.md index c0a7e76d7d..cbd94e271d 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -4,7 +4,7 @@ ## Usage -\include "cli-help.md" +\include "cli-help.inc" ## Debugging Features {#clidebug} diff --git a/gtest/lexer.cpp b/gtest/lexer.cpp index 79e8ca078c..8c362f4558 100644 --- a/gtest/lexer.cpp +++ b/gtest/lexer.cpp @@ -5,16 +5,16 @@ #include -#include "thorin/world.h" +#include "thorin/driver.h" using namespace std::literals; using namespace thorin; using namespace thorin::fe; TEST(Lexer, Toks) { - World world; + Driver driver; std::istringstream is("{ } ( ) [ ] ‹ › « » : , . .lam .Pi λ Π"); - Lexer lexer(world, "", is); + Lexer lexer(driver.world, driver.sym(""), is); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::D_brace_l)); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::D_brace_r)); @@ -37,9 +37,10 @@ TEST(Lexer, Toks) { } TEST(Lexer, Loc) { - World world; + Driver driver; + auto sym = driver.sym(""); std::istringstream is(" test abc def if \nwhile λ foo "); - Lexer lexer(world, "", is); + Lexer lexer(driver.world, sym, is); auto t1 = lexer.lex(); auto t2 = lexer.lex(); auto t3 = lexer.lex(); @@ -51,50 +52,51 @@ TEST(Lexer, Loc) { EXPECT_EQ(fmt("{} {} {} {} {} {} {} {}", t1, t2, t3, t4, t5, t6, t7, t8), "test abc def if while λ foo "); // clang-format off - EXPECT_EQ(t1.loc(), Loc("", {1, 2}, {1, 5})); - EXPECT_EQ(t2.loc(), Loc("", {1, 8}, {1, 10})); - EXPECT_EQ(t3.loc(), Loc("", {1, 15}, {1, 17})); - EXPECT_EQ(t4.loc(), Loc("", {1, 19}, {1, 20})); - EXPECT_EQ(t5.loc(), Loc("", {2, 1}, {2, 5})); - EXPECT_EQ(t6.loc(), Loc("", {2, 7}, {2, 7})); - EXPECT_EQ(t7.loc(), Loc("", {2, 9}, {2, 11})); - EXPECT_EQ(t8.loc(), Loc("", {2, 14}, {2, 14})); + EXPECT_EQ(t1.loc(), Loc(sym, {1, 2}, {1, 5})); + EXPECT_EQ(t2.loc(), Loc(sym, {1, 8}, {1, 10})); + EXPECT_EQ(t3.loc(), Loc(sym, {1, 15}, {1, 17})); + EXPECT_EQ(t4.loc(), Loc(sym, {1, 19}, {1, 20})); + EXPECT_EQ(t5.loc(), Loc(sym, {2, 1}, {2, 5})); + EXPECT_EQ(t6.loc(), Loc(sym, {2, 7}, {2, 7})); + EXPECT_EQ(t7.loc(), Loc(sym, {2, 9}, {2, 11})); + EXPECT_EQ(t8.loc(), Loc(sym, {2, 14}, {2, 14})); // clang-format on } TEST(Lexer, Errors) { - World world; + Driver driver; std::istringstream is1("asdf \xc0\xc0"); - Lexer l1(world, "", is1); + Lexer l1(driver.world, driver.sym(""), is1); l1.lex(); EXPECT_ANY_THROW(l1.lex()); std::istringstream is2("foo \xaa"); - Lexer l2(world, "", is2); + Lexer l2(driver.world, driver.sym(""), is2); l2.lex(); EXPECT_ANY_THROW(l2.lex()); std::istringstream is3("+"); - Lexer l3(world, "", is3); + Lexer l3(driver.world, driver.sym(""), is3); EXPECT_ANY_THROW(l3.lex()); std::istringstream is4("-"); - Lexer l4(world, "", is4); + Lexer l4(driver.world, driver.sym(""), is4); EXPECT_ANY_THROW(l4.lex()); } TEST(Lexer, Eof) { - World world; + Driver driver; std::istringstream is(""); - Lexer lexer(world, "", is); + Lexer lexer(driver.world, driver.sym(""), is); for (int i = 0; i < 10; i++) EXPECT_TRUE(lexer.lex().isa(Tok::Tag::M_eof)); } class Real : public testing::TestWithParam {}; TEST_P(Real, sign) { - World w; + Driver driver; + World& w = driver.world; // clang-format off auto check = [&w](std::string s, f64 r) { @@ -107,7 +109,7 @@ TEST_P(Real, sign) { } std::istringstream is(s); - Lexer lexer(w, "", is); + Lexer lexer(w, w.sym(""), is); auto tag = lexer.lex(); EXPECT_TRUE(tag.isa(Tok::Tag::L_r)); @@ -126,11 +128,11 @@ TEST_P(Real, sign) { // clang-format on std::istringstream is1("0x2.34"); - Lexer l1(w, "", is1); + Lexer l1(w, w.sym(""), is1); EXPECT_ANY_THROW(l1.lex()); std::istringstream is2("2.34e"); - Lexer l2(w, "", is2); + Lexer l2(w, w.sym(""), is2); EXPECT_ANY_THROW(l2.lex()); } diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index 09c2ef68bf..ac39d83aca 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -8,7 +8,7 @@ #include "thorin/def.h" #include "thorin/dialects.h" -#include "thorin/world.h" +#include "thorin/driver.h" #include "thorin/fe/parser.h" #include "thorin/pass/fp/beta_red.h" @@ -30,37 +30,38 @@ using namespace thorin; TEST(RestrictedDependentTypes, join_singleton) { auto test_on_world = [](auto test) { - World w; + Driver driver; + World& w = driver.world; Normalizers normalizers; auto compile_d = Dialect::load("compile", {}); compile_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "compile", {}, &normalizers); + fe::Parser::import_module(w, w.sym("compile"), {}, &normalizers); auto mem_d = Dialect::load("mem", {}); mem_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "mem", {}, &normalizers); + fe::Parser::import_module(w, w.sym("mem"), {}, &normalizers); auto core_d = Dialect::load("core", {}); core_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "core", {}, &normalizers); + fe::Parser::import_module(w, w.sym("core"), {}, &normalizers); auto math_d = Dialect::load("math", {}); math_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "math", {}, &normalizers); + fe::Parser::import_module(w, w.sym("math"), {}, &normalizers); auto i32_t = w.type_int(32); auto i64_t = w.type_int(64); - auto R = w.axiom(w.type(), w.dbg("R")); - auto W = w.axiom(w.type(), w.dbg("W")); + auto R = w.axiom(w.type())->set("R"); + auto W = w.axiom(w.type())->set("W"); - auto RW = w.join({w.singleton(R), w.singleton(W)}, w.dbg("RW")); - auto DT = w.join({w.singleton(i32_t), w.singleton(i64_t)}, w.dbg("DT")); + auto RW = w.join({w.singleton(R), w.singleton(W)})->set("RW"); + auto DT = w.join({w.singleton(i32_t), w.singleton(i64_t)})->set("DT"); auto exp_pi = w.nom_pi(w.type<1>())->set_dom({DT, RW}); exp_pi->set_codom(w.type()); - auto Exp = w.axiom(exp_pi, w.dbg("exp")); + auto Exp = w.axiom(exp_pi)->set("exp"); test(w, R, W, Exp); }; @@ -72,27 +73,27 @@ TEST(RestrictedDependentTypes, join_singleton) { EXPECT_NO_THROW( // no type error w.app(exp_lam, {i32_t, R, core::op_bitcast(w.app(Exp, {w.vel(DT, i32_t), w.vel(RW, R)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i32_t), nullptr)})); + w.nom_lam(w.cn(i32_t))})); }); cases.emplace_back([](World& w, auto, auto W, auto Exp, auto exp_lam, auto DT, auto RW, auto i32_t, auto) { EXPECT_NO_THROW( // no type error w.app(exp_lam, {i32_t, W, core::op_bitcast(w.app(Exp, {w.vel(DT, i32_t), w.vel(RW, W)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i32_t), nullptr)})); + w.nom_lam(w.cn(i32_t))})); }); cases.emplace_back( [](World& w, auto R, auto, auto Exp, auto exp_lam, auto DT, auto RW, auto i32_t, auto i64_t) { EXPECT_NO_THROW( // no type error w.app(exp_lam, {i64_t, R, core::op_bitcast(w.app(Exp, {w.vel(DT, i64_t), w.vel(RW, R)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i64_t), nullptr)})); + w.nom_lam(w.cn(i64_t))})); }); cases.emplace_back( [](World& w, auto, auto W, auto Exp, auto exp_lam, auto DT, auto RW, auto i32_t, auto i64_t) { EXPECT_NO_THROW( // no type error w.app(exp_lam, {i64_t, W, core::op_bitcast(w.app(Exp, {w.vel(DT, i64_t), w.vel(RW, W)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i64_t), nullptr)})); + w.nom_lam(w.cn(i64_t))})); }); cases.emplace_back([](World& w, auto R, auto, auto Exp, auto exp_lam, auto DT, auto RW, auto i32_t, auto) { EXPECT_NONFATAL_FAILURE( // disable until we have vel type checking.. @@ -101,7 +102,7 @@ TEST(RestrictedDependentTypes, join_singleton) { w.app(exp_lam, {math::type_f32(w), R, core::op_bitcast(w.app(Exp, {w.vel(DT, math::type_f32(w)), w.vel(RW, R)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(math::type_f32(w)), nullptr)}), + w.nom_lam(w.cn(math::type_f32(w)))}), std::logic_error); }, "std::logic_error"); @@ -113,7 +114,7 @@ TEST(RestrictedDependentTypes, join_singleton) { w.app(exp_lam, {math::type_f32(w), W, core::op_bitcast(w.app(Exp, {w.vel(DT, math::type_f32(w)), w.vel(RW, W)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(math::type_f32(w)), nullptr)}), + w.nom_lam(w.cn(math::type_f32(w)))}), std::logic_error); }, "std::logic_error"); @@ -125,7 +126,7 @@ TEST(RestrictedDependentTypes, join_singleton) { w.app(exp_lam, {i32_t, i32_t, core::op_bitcast(w.app(Exp, {w.vel(DT, i32_t), w.vel(RW, i32_t)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i32_t), nullptr)}), + w.nom_lam(w.cn(i32_t))}), std::logic_error); }, "std::logic_error"); @@ -137,7 +138,7 @@ TEST(RestrictedDependentTypes, join_singleton) { w.app(exp_lam, {i64_t, i64_t, core::op_bitcast(w.app(Exp, {w.vel(DT, i64_t), w.vel(RW, i64_t)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i64_t), nullptr)}), + w.nom_lam(w.cn(i64_t))}), std::logic_error); }, "std::logic_error"); @@ -147,8 +148,8 @@ TEST(RestrictedDependentTypes, join_singleton) { test_on_world([&test](World& w, auto R, auto W, auto Exp) { auto i32_t = w.type_int(32); auto i64_t = w.type_int(64); - auto RW = w.join({w.singleton(R), w.singleton(W)}, w.dbg("RW")); - auto DT = w.join({w.singleton(i32_t), w.singleton(i64_t)}, w.dbg("DT")); + auto RW = w.join({w.singleton(R), w.singleton(W)})->set("RW"); + auto DT = w.join({w.singleton(i32_t), w.singleton(i64_t)})->set("DT"); auto exp_sig = w.nom_sigma(4); exp_sig->set(0, w.type()); @@ -157,7 +158,7 @@ TEST(RestrictedDependentTypes, join_singleton) { exp_sig->set(3, w.cn(exp_sig->var(0_s))); auto exp_lam_pi = w.cn(exp_sig); - auto exp_lam = w.nom_lam(exp_lam_pi, nullptr); + auto exp_lam = w.nom_lam(exp_lam_pi); exp_lam->app(false, exp_lam->var(3), core::op_bitcast(exp_lam->var(0_s), exp_lam->var(2_s))); test(w, R, W, Exp, exp_lam, DT, RW, i32_t, i64_t); }); @@ -171,13 +172,13 @@ TEST(RestrictedDependentTypes, join_singleton) { EXPECT_NO_THROW( // no type error w.app(exp_lam, {i32_t, core::op_bitcast(w.app(Exp, {w.vel(DT, i32_t), w.vel(RW, R)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i32_t), nullptr)})); + w.nom_lam(w.cn(i32_t))})); }); cases.emplace_back([](World& w, auto R, auto, auto Exp, auto exp_lam, auto DT, auto RW, auto, auto i64_t) { EXPECT_NO_THROW( // no type error w.app(exp_lam, {i64_t, core::op_bitcast(w.app(Exp, {w.vel(DT, i64_t), w.vel(RW, R)}), w.lit(i64_t, 1000)), - w.nom_lam(w.cn(i64_t), nullptr)})); + w.nom_lam(w.cn(i64_t))})); }); cases.emplace_back([](World& w, auto R, auto, auto Exp, auto exp_lam, auto DT, auto RW, auto i32_t, auto) { EXPECT_NONFATAL_FAILURE( // disable until we have vel type checking.. @@ -186,7 +187,7 @@ TEST(RestrictedDependentTypes, join_singleton) { w.app(exp_lam, {math::type_f32(w), core::op_bitcast(w.app(Exp, {w.vel(DT, math::type_f32(w)), w.vel(RW, R)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(math::type_f32(w)), nullptr)}), + w.nom_lam(w.cn(math::type_f32(w)))}), std::logic_error); }, "std::logic_error"); @@ -195,29 +196,29 @@ TEST(RestrictedDependentTypes, join_singleton) { EXPECT_ANY_THROW( // W type error w.app(exp_lam, {i32_t, core::op_bitcast(w.app(Exp, {w.vel(DT, i32_t), w.vel(RW, W)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i32_t), nullptr)})); + w.nom_lam(w.cn(i32_t))})); }); cases.emplace_back( [](World& w, auto, auto W, auto Exp, auto exp_lam, auto DT, auto RW, auto i32_t, auto i64_t) { EXPECT_ANY_THROW( // W type error w.app(exp_lam, {i64_t, core::op_bitcast(w.app(Exp, {w.vel(DT, i64_t), w.vel(RW, W)}), w.lit(i32_t, 1000)), - w.nom_lam(w.cn(i64_t), nullptr)})); + w.nom_lam(w.cn(i64_t))})); }); cases.emplace_back([](World& w, auto, auto W, auto Exp, auto exp_lam, auto DT, auto RW, auto, auto) { EXPECT_ANY_THROW( // float + W type error (note, the float is not yet what triggers the issue..) w.app(exp_lam, {math::type_f32(w), core::op_bitcast(w.app(Exp, {w.vel(DT, math::type_f32(w)), w.vel(RW, W)}), w.lit(math::type_f32(w), 1000)), - w.nom_lam(w.cn(math::type_f32(w)), nullptr)})); + w.nom_lam(w.cn(math::type_f32(w)))})); }); for (auto&& test : cases) { test_on_world([&test](World& w, auto R, auto W, auto Exp) { auto i32_t = w.type_int(32); auto i64_t = w.type_int(64); - auto RW = w.join({w.singleton(R), w.singleton(W)}, w.dbg("RW")); - auto DT = w.join({w.singleton(i32_t), w.singleton(i64_t)}, w.dbg("DT")); + auto RW = w.join({w.singleton(R), w.singleton(W)})->set("RW"); + auto DT = w.join({w.singleton(i32_t), w.singleton(i64_t)})->set("DT"); auto exp_sig = w.nom_sigma(3); exp_sig->set(0, w.type()); @@ -225,7 +226,7 @@ TEST(RestrictedDependentTypes, join_singleton) { exp_sig->set(2, w.cn(exp_sig->var(0_s))); auto exp_lam_pi = w.cn(exp_sig); - auto exp_lam = w.nom_lam(exp_lam_pi, nullptr); + auto exp_lam = w.nom_lam(exp_lam_pi); exp_lam->app(false, exp_lam->var(2_s), core::op_bitcast(exp_lam->var(0_s), exp_lam->var(1_s))); test(w, R, W, Exp, exp_lam, DT, RW, i32_t, i64_t); }); @@ -234,7 +235,8 @@ TEST(RestrictedDependentTypes, join_singleton) { } TEST(RestrictedDependentTypes, ll) { - World w; + Driver driver; + World& w = driver.world; std::vector dialect_plugins = { "compile", @@ -256,7 +258,8 @@ TEST(RestrictedDependentTypes, ll) { dialects.back().register_passes(passes); } - for (const auto& dialect : dialects) fe::Parser::import_module(w, dialect.name(), dialect_paths, &normalizers); + for (const auto& dialect : dialects) + fe::Parser::import_module(w, w.sym(dialect.name()), dialect_paths, &normalizers); auto mem_t = mem::type_mem(w); auto i32_t = w.type_int(32); @@ -264,19 +267,19 @@ TEST(RestrictedDependentTypes, ll) { // Cn [mem, i32, ptr(ptr(i32, 0), 0) Cn [mem, i32]] auto main_t = w.cn({mem_t, i32_t, argv_t, w.cn({mem_t, i32_t})}); - auto main = w.nom_lam(main_t, w.dbg("main")); + auto main = w.nom_lam(main_t)->set("main"); main->make_external(); - auto R = w.axiom(w.type(), w.dbg("R")); - auto W = w.axiom(w.type(), w.dbg("W")); + auto R = w.axiom(w.type())->set("R"); + auto W = w.axiom(w.type())->set("W"); - auto RW = w.join({w.singleton(R), w.singleton(W)}, w.dbg("RW")); + auto RW = w.join({w.singleton(R), w.singleton(W)})->set("RW"); - auto DT = w.join({w.singleton(i32_t), w.singleton(math::type_f32(w))}, w.dbg("DT")); + auto DT = w.join({w.singleton(i32_t), w.singleton(math::type_f32(w))})->set("DT"); auto exp_pi = w.nom_pi(w.type<1>())->set_dom({DT, RW}); exp_pi->set_codom(w.type()); - auto Exp = w.axiom(exp_pi, w.dbg("exp")); + auto Exp = w.axiom(exp_pi)->set("exp"); auto app_exp = w.app(Exp, {w.vel(DT, i32_t), w.vel(RW, R)}); @@ -289,7 +292,7 @@ TEST(RestrictedDependentTypes, ll) { exp_sig->set(4, w.cn({mem_t, i32_t})); auto exp_lam_pi = w.cn(exp_sig); - auto exp_lam = w.nom_lam(exp_lam_pi, nullptr); + auto exp_lam = w.nom_lam(exp_lam_pi); auto bc = core::op_bitcast(i32_t, exp_lam->var(3_s)); exp_lam->app(false, exp_lam->var(4), {exp_lam->var(0_s), bc}); diff --git a/gtest/test.cpp b/gtest/test.cpp index d07db4e40c..c79e8ba271 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -3,7 +3,7 @@ #include #include -#include "thorin/world.h" +#include "thorin/driver.h" #include "thorin/fe/parser.h" #include "thorin/util/sys.h" @@ -14,12 +14,13 @@ using namespace thorin; TEST(Zip, fold) { - World w; + Driver driver; + World& w = driver.world; Normalizers normalizers; auto core_d = Dialect::load("core", {}); core_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "core", {}, &normalizers); + fe::Parser::import_module(w, w.sym("core"), {}, &normalizers); // clang-format off auto a = w.tuple({w.tuple({w.lit_idx( 0), w.lit_idx( 1), w.lit_idx( 2)}), @@ -43,12 +44,13 @@ TEST(Zip, fold) { } TEST(World, simplify_one_tuple) { - World w; + Driver driver; + World& w = driver.world; ASSERT_EQ(w.lit_ff(), w.tuple({w.lit_ff()})) << "constant fold (false) -> false"; auto type = w.nom_sigma(w.type(), 2); - type->set({w.type_nat(), w.type_nat()}); + type->set(Defs{w.type_nat(), w.type_nat()}); ASSERT_EQ(type, w.sigma({type})) << "constant fold [nom] -> nom"; auto v = w.tuple(type, {w.lit_idx(42), w.lit_idx(1337)}); @@ -56,7 +58,9 @@ TEST(World, simplify_one_tuple) { } TEST(World, dependent_extract) { - World w; + Driver driver; + World& w = driver.world; + auto sig = w.nom_sigma(w.type<1>(), 2); // sig = [T: *, T] sig->set(0, w.type<0>()); sig->set(1, sig->var(0_u64)); @@ -65,29 +69,37 @@ TEST(World, dependent_extract) { } TEST(Axiom, mangle) { - EXPECT_EQ(Axiom::demangle(*Axiom::mangle("test")), "test"); - EXPECT_EQ(Axiom::demangle(*Axiom::mangle("azAZ09_")), "azAZ09_"); - EXPECT_EQ(Axiom::demangle(*Axiom::mangle("01234567")), "01234567"); - EXPECT_FALSE(Axiom::mangle("012345678")); - EXPECT_FALSE(Axiom::mangle("!")); + Driver driver; + World& w = driver.world; + + EXPECT_EQ(Axiom::demangle(w, *Axiom::mangle(w.sym("test"))), w.sym("test")); + EXPECT_EQ(Axiom::demangle(w, *Axiom::mangle(w.sym("azAZ09_"))), w.sym("azAZ09_")); + EXPECT_EQ(Axiom::demangle(w, *Axiom::mangle(w.sym("01234567"))), w.sym("01234567")); + EXPECT_FALSE(Axiom::mangle(w.sym("012345678"))); + EXPECT_FALSE(Axiom::mangle(w.sym("!"))); // Check whether lower 16 bits are properly ignored - EXPECT_EQ(Axiom::demangle(*Axiom::mangle("test") | 0xFF_u64), "test"); - EXPECT_EQ(Axiom::demangle(*Axiom::mangle("01234567") | 0xFF_u64), "01234567"); + EXPECT_EQ(Axiom::demangle(w, *Axiom::mangle(w.sym("test")) | 0xFF_u64), w.sym("test")); + EXPECT_EQ(Axiom::demangle(w, *Axiom::mangle(w.sym("01234567")) | 0xFF_u64), w.sym("01234567")); } TEST(Axiom, split) { - auto [dialect, group, tag] = *Axiom::split("%foo.bar.baz"); - EXPECT_EQ(dialect, "foo"); - EXPECT_EQ(group, "bar"); - EXPECT_EQ(tag, "baz"); + Driver driver; + World& w = driver.world; + + auto [dialect, group, tag] = Axiom::split(w, w.sym("%foo.bar.baz")); + EXPECT_EQ(dialect, w.sym("foo")); + EXPECT_EQ(group, w.sym("bar")); + EXPECT_EQ(tag, w.sym("baz")); } TEST(trait, idx) { - World w; + Driver driver; + World& w = driver.world; + Normalizers normalizers; auto core_d = Dialect::load("core", {}); core_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "core", {}, &normalizers); + fe::Parser::import_module(w, w.sym("core"), {}, &normalizers); EXPECT_EQ(as_lit(op(core::trait::size, w.type_idx(0x0000'0000'0000'00FF_n))), 1); EXPECT_EQ(as_lit(op(core::trait::size, w.type_idx(0x0000'0000'0000'0100_n))), 1); @@ -105,13 +117,14 @@ TEST(trait, idx) { EXPECT_EQ(as_lit(op(core::trait::size, w.type_idx(0x0000'0000'0000'0000_n))), 8); } -const Def* normalize_test_curry(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { +Ref normalize_test_curry(Ref type, Ref callee, Ref arg) { auto& w = arg->world(); - return w.raw_app(type, callee, w.lit_nat(42), dbg); + return w.raw_app(type, callee, w.lit_nat(42)); } TEST(Axiom, curry) { - World w; + Driver driver; + World& w = driver.world; DefArray n(11, [&w](size_t i) { return w.lit_nat(i); }); auto nat = w.type_nat(); @@ -129,7 +142,7 @@ TEST(Axiom, curry) { EXPECT_EQ(curry, 5); EXPECT_EQ(trip, 3); - auto ax = w.axiom(normalize_test_curry, curry, trip, pi, w.dbg("test_5_3")); + auto ax = w.axiom(normalize_test_curry, curry, trip, pi)->set("test_5_3"); auto a1 = w.app(w.app(w.app(w.app(w.app(ax, n[0]), n[1]), n[2]), n[3]), n[4]); auto a2 = w.app(w.app(w.app(a1, n[5]), n[6]), n[7]); auto a3 = w.app(w.app(w.app(a2, n[8]), n[9]), n[10]); @@ -150,7 +163,7 @@ TEST(Axiom, curry) { EXPECT_EQ(curry, 1); EXPECT_EQ(trip, 1); - auto ax = w.axiom(normalize_test_curry, curry, trip, rec, w.dbg("test_1_1")); + auto ax = w.axiom(normalize_test_curry, curry, trip, rec)->set("test_1_1"); auto a1 = w.app(ax, n[0]); auto a2 = w.app(a1, n[1]); auto a3 = w.app(a2, n[2]); @@ -169,7 +182,7 @@ TEST(Axiom, curry) { EXPECT_EQ(curry, 4); EXPECT_EQ(trip, 0); - auto ax = w.axiom(normalize_test_curry, 3, 0, pi, w.dbg("test_3_0")); + auto ax = w.axiom(normalize_test_curry, 3, 0, pi)->set("test_3_0"); auto a1 = w.app(w.app(w.app(ax, n[0]), n[1]), n[2]); auto a2 = w.app(a1, n[3]); diff --git a/lit/affine/lower_for.thorin b/lit/affine/lower_for.thorin index 22bc52e7d8..dd2d53dfa0 100644 --- a/lit/affine/lower_for.thorin +++ b/lit/affine/lower_for.thorin @@ -23,12 +23,12 @@ // CHECK-DAG: .con return_[[returnId:[0-9_]+]] _[[returnVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] -// CHECK-DAG: .con for_[[forId:[0-9_]+]] _[[forVarId:[0-9_]+]]::[_[[forIdxId:[0-9_]+]]: .Idx 4294967296, _[[forAccId:[0-9_]+]]: .Idx 4294967296] +// CHECK-DAG: .con for_[[forId:[0-9_]+]] _[[forVarId:[0-9_]+]]::[iter_[[forIdxId:[0-9_]+]]: .Idx 4294967296, acc_[[forAccId:[0-9_]+]]: .Idx 4294967296] // CHECK-DAG: _[[cmpId:[0-9_]+]]: .Idx 2 = %core.icmp.XygLe // CHECK-DAG: (_[[falseId:[0-9_]+]], for_body_[[bodyId:[0-9_]+]])#_[[cmpId]] // CHECK-DAG: .con _{{[0-9]+}} [] -// CHECK-DAG: return_[[returnId]] (mem_[[memVar]], _{{[0-9]+}}) +// CHECK-DAG: return_[[returnId]] (mem_[[memVar]], acc_{{[0-9]+}}) // CHECK-DAG: .con for_body_[[bodyId]] [] // CHECK-DAG: = %core.wrap.add diff --git a/lit/core/pow.thorin b/lit/core/pow.thorin index f1ee4d72a9..dee2db2753 100644 --- a/lit/core/pow.thorin +++ b/lit/core/pow.thorin @@ -44,8 +44,8 @@ }; -// CHECK-DAG: .con f_{{[0-9_]+}} _{{[0-9_]+}}::[_{{[0-9_]+}}: .Idx 4294967296, _{{[0-9_]+}}: .Cn .Idx 4294967296] = { -// CHECK-DAG: .con _{{[0-9_]+}} _{{[0-9_]+}}: .Idx 4294967296 = { +// CHECK-DAG: .con f_{{[0-9_]+}} _{{[0-9_]+}}::[b_{{[0-9_]+}}: .Idx 4294967296, ret_{{[0-9_]+}}: .Cn .Idx 4294967296] = { +// CHECK-DAG: .con ret_{{[0-9_]+}} _{{[0-9_]+}}: .Idx 4294967296 = { // CHECK-DAG: _{{[0-9_]+}} _{{[0-9_]+}} // CHECK-DAG: .con pow_then_{{[0-9_]+}} [] = { @@ -56,9 +56,9 @@ // CHECK-DAG: _{{[0-9_]+}} _{{[0-9_]+}} // CHECK-DAG: .con pow_else_{{[0-9_]+}} [] = { -// CHECK-DAG: .let _{{[0-9_]+}}: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _{{[0-9_]+}}); +// CHECK-DAG: .let _{{[0-9_]+}}: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), b_{{[0-9_]+}}); // CHECK-DAG: f_{{[0-9_]+}} (_{{[0-9_]+}}, pow_cont_{{[0-9_]+}}) -// CHECK-DAG: .let _{{[0-9_]+}}: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _{{[0-9_]+}}); +// CHECK-DAG: .let _{{[0-9_]+}}: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), b_{{[0-9_]+}}); // CHECK-DAG: (pow_else_{{[0-9_]+}}, pow_then_{{[0-9_]+}})#_{{[0-9_]+}} () diff --git a/thorin/CMakeLists.txt b/thorin/CMakeLists.txt index 11b26c4998..76ee044197 100644 --- a/thorin/CMakeLists.txt +++ b/thorin/CMakeLists.txt @@ -3,14 +3,12 @@ add_library(libthorin axiom.h check.cpp check.h - debug.cpp - debug.h def.cpp def.h dialects.cpp dialects.h dump.cpp - flags.h + driver.h lam.cpp lam.h lattice.cpp @@ -84,10 +82,13 @@ add_library(libthorin util/hash.h util/indexmap.h util/indexset.h + util/loc.cpp + util/loc.h util/log.cpp util/log.h util/print.cpp util/print.h + util/sym.h util/sys.cpp util/sys.h util/types.h @@ -100,11 +101,11 @@ set_target_properties(libthorin PROPERTIES PREFIX "") get_target_property(libthorin_HEADERS libthorin SOURCES) list(FILTER libthorin_HEADERS INCLUDE REGEX ".*\.h") -configure_file(config.h.in config.h) +configure_file(config.h.in ${CMAKE_BINARY_DIR}/include/thorin/config.h) target_include_directories(libthorin PUBLIC - $ # for config.h - $ # for thorin/* + $ # for config.h + $ # for thorin/* $ $ ) diff --git a/thorin/analyses/deptree.cpp b/thorin/analyses/deptree.cpp index fb0538a9c3..7710db4953 100644 --- a/thorin/analyses/deptree.cpp +++ b/thorin/analyses/deptree.cpp @@ -36,7 +36,7 @@ VarSet DepTree::run(Def* nom) { parent = n->depth() > parent->depth() ? n : parent; } if (nom->is_external() && parent != root_.get()) { - world().WLOG("external {} would be hidden inside parent {}..", nom, parent->nom()); + world().WLOG("external {} would be hidden inside parent {}.", nom, parent->nom()); node->set_parent(root_.get()); } else node->set_parent(parent); diff --git a/thorin/analyses/deptree.h b/thorin/analyses/deptree.h index ac7adf335f..b745f333be 100644 --- a/thorin/analyses/deptree.h +++ b/thorin/analyses/deptree.h @@ -35,13 +35,13 @@ class DepNode { class DepTree { public: - DepTree(const World& world) + DepTree(World& world) : world_(world) , root_(std::make_unique(nullptr, 0)) { run(); } - const World& world() const { return world_; }; + World& world() const { return world_; }; const DepNode* root() const { return root_.get(); } const DepNode* nom2node(Def* nom) const { return nom2node_.find(nom)->second.get(); } bool depends(Def* a, Def* b) const; ///< Does @p a depend on @p b? @@ -52,7 +52,7 @@ class DepTree { VarSet run(Def*, const Def*); static void adjust_depth(DepNode* node, size_t depth); - const World& world_; + World& world_; std::unique_ptr root_; NomMap> nom2node_; DefMap def2vars_; diff --git a/thorin/analyses/scope.cpp b/thorin/analyses/scope.cpp index cdb58ea6e9..e3f3e68e71 100644 --- a/thorin/analyses/scope.cpp +++ b/thorin/analyses/scope.cpp @@ -45,7 +45,8 @@ void Scope::calc_bound() const { unique_queue queue(live); auto enqueue = [&](const Def* def) { - if (def == nullptr || def->dep_const()) return; + if (def == nullptr) return; + if (def->dep_const()) return; if (bound_.contains(def)) queue.push(def); diff --git a/thorin/analyses/scope.h b/thorin/analyses/scope.h index 3f793b4d8b..7ed0f8f3b0 100644 --- a/thorin/analyses/scope.h +++ b/thorin/analyses/scope.h @@ -34,7 +34,7 @@ class Scope { World& world() const { return world_; } Def* entry() const { return entry_; } Def* exit() const { return exit_; } - std::string name() const { return entry_->debug().name; } + Sym sym() const { return entry_->sym(); } ///@} /// @name Def%s bound/free in this Scope diff --git a/thorin/axiom.cpp b/thorin/axiom.cpp index 697c8773b9..7cefe5a5e0 100644 --- a/thorin/axiom.cpp +++ b/thorin/axiom.cpp @@ -1,18 +1,13 @@ #include "thorin/axiom.h" +#include "thorin/world.h" + using namespace std::literals; namespace thorin { -Axiom::Axiom(NormalizeFn normalizer, - u8 curry, - u8 trip, - const Def* type, - dialect_t dialect, - tag_t tag, - sub_t sub, - const Def* dbg) - : Def(Node, type, Defs{}, dialect | (flags_t(tag) << 8_u64) | flags_t(sub), dbg) { +Axiom::Axiom(NormalizeFn normalizer, u8 curry, u8 trip, const Def* type, dialect_t dialect, tag_t tag, sub_t sub) + : Def(Node, type, Defs{}, dialect | (flags_t(tag) << 8_u64) | flags_t(sub)) { normalizer_ = normalizer; curry_ = curry; trip_ = trip; @@ -48,8 +43,8 @@ std::tuple Axiom::get(const Def* def) { return {nullptr, 0, 0}; } -std::optional Axiom::mangle(std::string_view s) { - auto n = s.size(); +std::optional Axiom::mangle(Sym s) { + auto n = s->size(); if (n > Max_Dialect_Size) return {}; u64 result = 0; @@ -77,12 +72,12 @@ std::optional Axiom::mangle(std::string_view s) { return result << 16_u64; } -std::string Axiom::demangle(dialect_t u) { +Sym Axiom::demangle(World& world, dialect_t u) { std::string result; for (size_t i = 0; i != Max_Dialect_Size; ++i) { u64 c = (u & 0xfc00000000000000_u64) >> 58_u64; if (c == 0) { - return result; + return world.sym(result); } else if (c == 1) { result += '_'; } else if (2 <= c && c < 28) { @@ -96,38 +91,28 @@ std::string Axiom::demangle(dialect_t u) { u <<= 6_u64; } - return result; -} - -static std::string_view sub_view(std::string_view s, size_t i, size_t n = std::string_view::npos) { - n = std::min(n, s.size()); - return {s.data() + i, n - i}; + return world.sym(result); } -std::optional> Axiom::split(std::string_view s) { - if (s.empty()) return {}; +std::array Axiom::split(World& world, Sym s) { + if (!s) return {}; if (s[0] != '%') return {}; - s = sub_view(s, 1); + auto sv = subview(s, 1); - auto dot = s.find('.'); + auto dot = sv.find('.'); if (dot == std::string_view::npos) return {}; - auto dialect = sub_view(s, 0, dot); + auto dialect = world.sym(subview(sv, 0, dot)); if (!mangle(dialect)) return {}; - auto tag = sub_view(s, dot + 1); + auto tag = subview(sv, dot + 1); if (auto dot = tag.find('.'); dot != std::string_view::npos) { - auto sub = sub_view(tag, dot + 1); - tag = sub_view(tag, 0, dot); - return { - {dialect, tag, sub} - }; + auto sub = world.sym(subview(tag, dot + 1)); + tag = subview(tag, 0, dot); + return {dialect, world.sym(tag), sub}; } - if (tag.empty()) return {}; - return { - {dialect, tag, ""sv} - }; + return {dialect, world.sym(tag), {}}; } } // namespace thorin diff --git a/thorin/axiom.h b/thorin/axiom.h index 01a5a6c153..5a5841aa6e 100644 --- a/thorin/axiom.h +++ b/thorin/axiom.h @@ -8,7 +8,7 @@ namespace thorin { class Axiom : public Def { private: - Axiom(NormalizeFn, u8 curry, u8 trip, const Def* type, dialect_t, tag_t, sub_t, const Def* dbg); + Axiom(NormalizeFn, u8 curry, u8 trip, const Def* type, dialect_t, tag_t, sub_t); public: /// @name normalization @@ -49,7 +49,7 @@ class Axiom : public Def { /// %dialect.tag.sub /// | 48 | 8 | 8 | <-- Number of bits per field. /// ``` - /// * Def::name() retrieves the full name as `std::string`. + /// * Def::name() retrieves the full name as Sym. /// * Def::flags() retrieves the full name as Axiom::mangle%d 64-bit integer. /// Yields the `dialect` part of the name as integer. @@ -66,11 +66,6 @@ class Axiom : public Def { flags_t base() const { return flags() & ~0xff_u64; } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - /// @name Mangling Dialect Name ///@{ static constexpr size_t Max_Dialect_Size = 8; @@ -94,13 +89,13 @@ class Axiom : public Def { /// | 54-63: | `0`-`9` | /// The 0 is special and marks the end of the name if the name has less than 8 chars. /// @returns `std::nullopt` if encoding is not possible. - static std::optional mangle(std::string_view s); + static std::optional mangle(Sym s); - /// Reverts an Axiom::mangle%d string to a `std::string`. + /// Reverts an Axiom::mangle%d string to a Sym. /// Ignores lower 16-bit of @p u. - static std::string demangle(dialect_t u); + static Sym demangle(World&, dialect_t u); - static std::optional> split(std::string_view); + static std::array split(World&, Sym); ///@} /// @name Helpers for Matching @@ -122,8 +117,7 @@ class Axiom : public Def { }; ///@} - static constexpr auto Node = Node::Axiom; - friend class World; + THORIN_DEF_MIXIN(Axiom) }; // clang-format off diff --git a/thorin/be/dot/dot.cpp b/thorin/be/dot/dot.cpp index 24103cbf23..fcc17d9c44 100644 --- a/thorin/be/dot/dot.cpp +++ b/thorin/be/dot/dot.cpp @@ -78,7 +78,7 @@ void Emitter::emit_epilogue(Lam* lam) { } std::string Emitter::emit_bb(BB&, const Def* def) { - if (auto lam = def->isa()) return lam->name(); + if (auto lam = def->isa()) return lam->sym(); print(ostream_, "\"{}:{}\" [label=\"", def->node_name(), def->unique_name()); stream_def_(ostream_, def); @@ -100,7 +100,7 @@ std::string Emitter::prepare(const Scope& scope) { emit_cluster_start(ostream_, lam); - return lam->name(); + return lam->sym(); } void Emitter::finalize(const Scope&) { ostream_ << "}\n"; } diff --git a/thorin/be/h/bootstrapper.cpp b/thorin/be/h/bootstrapper.cpp index a1bb5398de..7da915576a 100644 --- a/thorin/be/h/bootstrapper.cpp +++ b/thorin/be/h/bootstrapper.cpp @@ -38,12 +38,12 @@ void Bootstrapper::emit(std::ostream& h) { tab.print(h, "{} = 0x{},\n", sub, ax_id++); for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub); - if (!ax.normalizer.empty()) + if (ax.normalizer) print(normalizers.emplace_back(), "normalizers[flags_t({}::{})] = &{}<{}::{}>;", ax.tag, sub, ax.normalizer, ax.tag, sub); } } else { - if (!ax.normalizer.empty()) + if (ax.normalizer) print(normalizers.emplace_back(), "normalizers[flags_t(Axiom::Base<{}>)] = &{};", ax.tag, ax.normalizer); } --tab; @@ -59,11 +59,11 @@ void Bootstrapper::emit(std::ostream& h) { print(outer_namespace.emplace_back(), "template<> constexpr size_t Axiom::Num<{}::{}> = {};\n", dialect_, ax.tag, ax.subs.size()); - if (!ax.normalizer.empty()) { + if (ax.normalizer) { if (auto& subs = ax.subs; !subs.empty()) { - tab.print(h, "template<{}>\nconst Def* {}(const Def*, const Def*, const Def*, const Def*);\n\n", ax.tag, ax.normalizer); + tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", ax.tag, ax.normalizer); } else { - tab.print(h, "const Def* {}(const Def*, const Def*, const Def*, const Def*);\n\n", ax.normalizer); + tab.print(h, "Ref {}(Ref, Ref, Ref);\n\n", ax.normalizer); } } } diff --git a/thorin/be/h/bootstrapper.h b/thorin/be/h/bootstrapper.h index 9ee686ce00..2d1f789267 100644 --- a/thorin/be/h/bootstrapper.h +++ b/thorin/be/h/bootstrapper.h @@ -6,34 +6,33 @@ #include #include "thorin/util/print.h" +#include "thorin/util/sym.h" #include "thorin/util/types.h" -#include "absl/container/flat_hash_map.h" - namespace thorin::h { struct AxiomInfo { flags_t tag_id; - std::string dialect; - std::string tag; - std::deque> subs; - std::string normalizer; + Sym dialect; + Sym tag; + std::deque> subs; + Sym normalizer; bool pi; }; class Bootstrapper { public: - Bootstrapper(std::string_view dialect) + Bootstrapper(Sym dialect) : dialect_(dialect) {} void emit(std::ostream&); - std::string_view dialect() const { return dialect_; } + Sym dialect() const { return dialect_; } - absl::flat_hash_map axioms; + SymMap axioms; Tab tab; private: - std::string dialect_; + Sym dialect_; }; } // namespace thorin::h diff --git a/thorin/check.cpp b/thorin/check.cpp index 47f3223a33..077c9c07c0 100644 --- a/thorin/check.cpp +++ b/thorin/check.cpp @@ -36,7 +36,7 @@ const Def* Infer::find(const Def* def) { return r; }); - if (update) return res->rebuild(res->world(), new_type, new_ops, res->dbg()); + if (update) return res->rebuild(res->world(), new_type, new_ops); } return res; @@ -45,8 +45,8 @@ const Def* Infer::find(const Def* def) { const Def* Infer::inflate(Ref ty, Defs elems_t) { auto& w = world(); if (!is_set()) { - DefArray infer_ops(elems_t.size(), [&](size_t i) { return w.nom_infer(elems_t[i], dbg()); }); - set(w.tuple(infer_ops, dbg())); + DefArray infer_ops(elems_t.size(), [&](size_t i) { return w.nom_infer(elems_t[i]); }); + set(w.tuple(infer_ops)); if (auto t = type()->isa_nom(); t && !t->is_set() && ty) t->set(ty); } @@ -57,8 +57,8 @@ const Def* Infer::inflate(Ref ty, Defs elems_t) { const Def* Infer::inflate(Ref ty, u64 n, Ref elem_t) { auto& w = world(); if (!is_set()) { - DefArray infer_ops(n, [&](size_t) { return w.nom_infer(elem_t, dbg()); }); - set(w.tuple(infer_ops, dbg())); + DefArray infer_ops(n, [&](size_t) { return w.nom_infer(elem_t); }); + set(w.tuple(infer_ops)); if (auto t = type()->isa_nom(); t && !t->is_set() && ty) t->set(ty); } @@ -69,7 +69,7 @@ const Def* Infer::inflate(Ref ty, u64 n, Ref elem_t) { * Checker */ -bool Checker::equiv(Ref r1, Ref r2, Ref dbg) { +bool Checker::equiv(Ref r1, Ref r2) { auto d1 = *r1; // find auto d2 = *r2; // find @@ -107,25 +107,25 @@ bool Checker::equiv(Ref r1, Ref r2, Ref dbg) { } } - bool res = equiv_internal(d1, d2, dbg); + bool res = equiv_internal(d1, d2); equiv_[std::pair(d1, d2)] = res ? Equiv::Equiv : Equiv::Distinct; return res; } -bool Checker::equiv_internal(Ref d1, Ref d2, Ref dbg) { - if (!equiv(d1->type(), d2->type(), dbg)) return false; - if (d1->isa() || d2->isa()) return equiv(d1->type(), d2->type(), dbg); +bool Checker::equiv_internal(Ref d1, Ref d2) { + if (!equiv(d1->type(), d2->type())) return false; + if (d1->isa() || d2->isa()) return equiv(d1->type(), d2->type()); if (auto n1 = d1->isa_nom()) { if (auto n2 = d2->isa_nom()) vars_.emplace_back(n1, n2); } if (d1->isa()) { - if (!equiv(d1->arity(), d2->arity(), dbg)) return false; + if (!equiv(d1->arity(), d2->arity())) return false; - if (auto a = isa_lit(d1->arity())) { + if (auto a = d1->isa_lit_arity()) { for (size_t i = 0; i != a; ++i) { - if (!equiv(d1->proj(*a, i), d2->proj(*a, i), dbg)) return false; + if (!equiv(d1->proj(*a, i), d2->proj(*a, i))) return false; } return true; } @@ -141,16 +141,16 @@ bool Checker::equiv_internal(Ref d1, Ref d2, Ref dbg) { return false; } - return std::ranges::equal(d1->ops(), d2->ops(), [&](auto op1, auto op2) { return equiv(op1, op2, dbg); }); + return std::ranges::equal(d1->ops(), d2->ops(), [&](auto op1, auto op2) { return equiv(op1, op2); }); } -bool Checker::assignable(Ref type, Ref val, Ref dbg /*= {}*/) { +bool Checker::assignable(Ref type, Ref val) { auto val_ty = refer(val->type()); if (type == val_ty) return true; auto infer = val->isa_nom(); if (auto sigma = type->isa()) { - if (!infer && !equiv(type->arity(), val_ty->arity(), dbg)) return false; + if (!infer && !equiv(type->arity(), val_ty->arity())) return false; size_t a = sigma->num_ops(); auto red = sigma->reduce(val); @@ -158,34 +158,34 @@ bool Checker::assignable(Ref type, Ref val, Ref dbg /*= {}*/) { if (infer) infer->inflate(sigma, red); for (size_t i = 0; i != a; ++i) { - if (!assignable(red[i], val->proj(a, i, dbg), dbg)) return false; + if (!assignable(red[i], val->proj(a, i))) return false; } return true; } else if (auto arr = type->isa()) { - if (!infer && !equiv(type->arity(), val_ty->arity(), dbg)) return false; + if (!infer && !equiv(type->arity(), val_ty->arity())) return false; if (auto a = isa_lit(arr->arity())) { if (infer) infer->inflate(arr, *a, arr->body()); for (size_t i = 0; i != *a; ++i) { - if (!assignable(arr->proj(*a, i), val->proj(*a, i, dbg), dbg)) return false; + if (!assignable(arr->proj(*a, i), val->proj(*a, i))) return false; } return true; } } else if (auto vel = val->isa()) { - if (assignable(type, vel->value(), dbg)) return true; + if (assignable(type, vel->value())) return true; } - return equiv(type, val_ty, dbg); + return equiv(type, val_ty); } -const Def* Checker::is_uniform(Defs defs, Ref dbg) { +const Def* Checker::is_uniform(Defs defs) { assert(!defs.empty()); auto first = defs.front(); auto ops = defs.skip_front(); - return std::ranges::all_of(ops, [&](auto op) { return equiv(first, op, dbg); }) ? first : nullptr; + return std::ranges::all_of(ops, [&](auto op) { return equiv(first, op); }) ? first : nullptr; } /* @@ -205,8 +205,8 @@ void Arr::check() { auto& w = world(); auto t = body()->unfold_type(); - if (!w.checker().equiv(t, type(), type()->dbg())) - err(dbg(), "declared sort '{}' of array does not match inferred one '{}'", type(), t); + if (!w.checker().equiv(t, type())) + err(type(), "declared sort '{}' of array does not match inferred one '{}'", type(), t); } void Sigma::check() { @@ -216,20 +216,19 @@ void Sigma::check() { void Lam::check() { auto& w = world(); return; // TODO - if (!w.checker().equiv(filter()->type(), w.type_bool(), filter()->dbg())) - err(filter()->dbg(), "filter '{}' of lambda is of type '{}' but must be of type '.Bool'", filter(), - filter()->type()); - if (!w.checker().equiv(body()->type(), codom(), body()->dbg())) - err(body()->dbg(), "body '{}' of lambda is of type '{}' but its codomain is of type '{}'", body(), - body()->type(), codom()); + if (!w.checker().equiv(filter()->type(), w.type_bool())) + err(filter(), "filter '{}' of lambda is of type '{}' but must be of type '.Bool'", filter(), filter()->type()); + if (!w.checker().equiv(body()->type(), codom())) + err(body(), "body '{}' of lambda is of type '{}' but its codomain is of type '{}'", body(), body()->type(), + codom()); } void Pi::check() { auto& w = world(); auto t = infer(dom(), codom()); - if (!w.checker().equiv(t, type(), type()->dbg())) - err(dbg(), "declared sort '{}' of function type does not match inferred one '{}'", type(), t); + if (!w.checker().equiv(t, type())) + err(type(), "declared sort '{}' of function type does not match inferred one '{}'", type(), t); } } // namespace thorin diff --git a/thorin/check.h b/thorin/check.h index d1833b1278..cbcb2c03fb 100644 --- a/thorin/check.h +++ b/thorin/check.h @@ -11,8 +11,8 @@ namespace thorin { /// If inference was successful, it's Infer::op will be set to the inferred Def. class Infer : public Def { private: - Infer(const Def* type, const Def* dbg) - : Def(Node, type, 1, 0, dbg) {} + Infer(const Def* type) + : Def(Node, type, 1, 0) {} public: /// @name op @@ -28,11 +28,6 @@ class Infer : public Def { const Def* inflate(Ref type, u64 n, Ref elem_t); ///@} - /// @name virtual methods - ///@{ - Infer* stub(World&, const Def*, const Def*) override; - ///@} - /// @name union-find ///@{ /// [Union-Find](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) to unify Infer nodes. @@ -45,8 +40,8 @@ class Infer : public Def { flags_t& rank() { return flags_; } ///@} - static constexpr auto Node = Node::Infer; - friend class World; + THORIN_DEF_MIXIN(Infer) + Infer* stub_(World&, Ref) override; friend class Checker; }; @@ -58,19 +53,19 @@ class Checker { World& world() const { return *world_; } /// Are @p d1 and @p d2 α-equivalent? - bool equiv(Ref d1, Ref d2, Ref dbg); + bool equiv(Ref d1, Ref d2); /// Can @p value be assigned to sth of @p type? - /// @note This is different from `equiv(type, value->type(), dbg)` since @p type may be dependent. - bool assignable(Ref type, Ref value, Ref dbg); + /// @note This is different from `equiv(type, value->type())` since @p type may be dependent. + bool assignable(Ref type, Ref value); /// Yields `defs.front()`, if all @p defs are α-equiv%alent and `nullptr` otherwise. - const Def* is_uniform(Defs defs, Ref dbg); + const Def* is_uniform(Defs defs); static void swap(Checker& c1, Checker& c2) { std::swap(c1.world_, c2.world_); } private: - bool equiv_internal(Ref, Ref, Ref); + bool equiv_internal(Ref, Ref); enum class Equiv { Distinct, diff --git a/thorin/debug.cpp b/thorin/debug.cpp deleted file mode 100644 index 2ab8e464a2..0000000000 --- a/thorin/debug.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "thorin/debug.h" - -#include "thorin/world.h" - -namespace thorin { - -/* - * c'tor - */ - -Pos::Pos(const Def* def) - : Pos(as_lit(def)) {} - -Loc::Loc(const Def* def) - : file(tuple2str(def->proj(3, 0_s))) - , begin(def->proj(3, 1_s)) - , finis(def->proj(3, 2_s)) {} - -Debug::Debug(const Def* def) - : name(def ? tuple2str(def->proj(3, 0_s)) : std::string()) - , loc(def ? def->proj(3, 1_s) : Loc()) - , meta(def ? def->proj(3, 2_s) : nullptr) {} - -/* - * conversion - */ - -const Def* Pos::def(World& w) const { return w.lit_nat(rowcol()); } - -const Def* Loc::def(World& w) const { - auto d_file = w.tuple_str(file); - auto d_begin = begin.def(w); - auto d_finis = finis.def(w); - return w.tuple({d_file, d_begin, d_finis}); -} - -const Def* Debug::def(World& w) const { - auto d_name = w.tuple_str(name); - auto d_loc = loc.def(w); - auto d_meta = meta ? meta : w.bot(w.type_bot()); - - return w.tuple({d_name, d_loc, d_meta}); -} - -/* - * Sym - */ - -size_t SymHash::operator()(Sym sym) const { return murmur3(sym.str()->gid()); } -std::string Sym::to_string() const { return tuple2str(str()); } - -bool Sym::is_anonymous() const { - if (auto lit = isa_lit(str())) return lit == '_'; - return false; -} - -/* - * ostream - */ - -std::ostream& operator<<(std::ostream& os, const Pos pos) { - if (pos.col != uint32_t(-1)) return os << pos.row << ':' << pos.col; - return os << pos.row; -} - -std::ostream& operator<<(std::ostream& os, const Loc loc) { - if (!loc.begin) return os << ""; - os << loc.file << ':' << loc.begin; - if (loc.begin != loc.finis) os << '-' << loc.finis; - return os; -} - -std::ostream& operator<<(std::ostream& os, const Sym sym) { return os << sym.to_string(); } - -} // namespace thorin diff --git a/thorin/debug.h b/thorin/debug.h deleted file mode 100644 index 0ff251e5f0..0000000000 --- a/thorin/debug.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "thorin/util/print.h" - -namespace thorin { - -class Def; -class World; - -struct Pos { - Pos() = default; - Pos(uint32_t row, uint32_t col) - : row(row) - , col(col) {} - Pos(uint64_t rowcol) - : row(rowcol >> uint64_t(32)) - , col(uint32_t(rowcol)) {} - Pos(const Def*); - - uint64_t rowcol() const { return (uint64_t(row) << uint64_t(32)) | uint64_t(col); } - const Def* def(World&) const; - explicit operator bool() const { return row != uint32_t(-1); } - - uint32_t row = -1; - uint32_t col = -1; -}; - -struct Loc { - Loc() = default; - Loc(std::string_view file, Pos begin, Pos finis) - : file(file) - , begin(begin) - , finis(finis) {} - Loc(std::string_view file, Pos pos) - : Loc(file, pos, pos) {} - Loc(const Def* dbg); - - Loc anew_begin() const { return {file, begin, begin}; } - Loc anew_finis() const { return {file, finis, finis}; } - const Def* def(World&) const; - explicit operator bool() const { return (bool)begin; } - - std::string file; - Pos begin = {uint32_t(-1), uint32_t(-1)}; - Pos finis = {uint32_t(-1), uint32_t(-1)}; - ///< It's called `finis` because it refers to the **last** character within this Loc%ation. - /// In the STL the word `end` refers to the position of something that is one element **past** the end. -}; - -template -[[noreturn]] void err(Loc loc, const char* fmt, Args&&... args) { - std::ostringstream oss; - print(oss, "{}: error: ", loc); - print(oss, fmt, std::forward(args)...); - throw T(oss.str()); -} - -class Sym { -public: - Sym() {} - Sym(const Def* str, const Def* loc) - : str_(str) - , loc_(loc) {} - - const Def* str() const { return str_; } - const Def* loc() const { return loc_; } - - std::string to_string() const; - Loc to_loc() const { return loc_ ? loc_ : Loc(); } - bool is_anonymous() const; - - operator std::string() const { return to_string(); } - operator Loc() const { return loc_; } - operator bool() const { return str_; } - -private: - const Def* str_ = nullptr; - const Def* loc_ = nullptr; -}; - -class Debug { -public: - Debug(std::string_view name, Loc loc = {}, const Def* meta = nullptr) - : name(name) - , loc(loc) - , meta(meta) {} - Debug(std::string name, Loc loc = {}, const Def* meta = nullptr) - : name(name) - , loc(loc) - , meta(meta) {} - Debug(const char* name, Loc loc = {}, const Def* meta = nullptr) - : Debug(std::string(name), loc, meta) {} - Debug(Sym sym, const Def* meta = nullptr) - : Debug(sym.to_string(), sym.to_loc(), meta) {} - Debug(Sym sym, Loc loc, const Def* meta = nullptr) - : Debug(sym.to_string(), loc, meta) {} - Debug(Loc loc) - : Debug(std::string(), loc) {} - Debug(const Def*); - - const Def* def(World&) const; - - std::string name; - Loc loc; - const Def* meta = nullptr; -}; - -std::ostream& operator<<(std::ostream&, const Pos); -std::ostream& operator<<(std::ostream&, const Loc); -std::ostream& operator<<(std::ostream&, const Sym); - -inline bool operator==(Sym s1, Sym s2) { return s1.str() == s2.str(); } // don't cmp loc -inline bool operator==(Pos p1, Pos p2) { return p1.row == p2.row && p1.col == p2.col; } -inline bool operator==(Loc l1, Loc l2) { return l1.begin == l2.begin && l1.finis == l2.finis && l1.file == l2.file; } - -struct SymHash { - size_t operator()(Sym) const; -}; - -template -using SymMap = absl::flat_hash_map; -using SymSet = absl::flat_hash_set; - -} // namespace thorin diff --git a/thorin/def.cpp b/thorin/def.cpp index 437bf62030..8fba5468c3 100644 --- a/thorin/def.cpp +++ b/thorin/def.cpp @@ -1,6 +1,7 @@ #include "thorin/def.h" #include +#include #include #include @@ -9,6 +10,8 @@ #include "thorin/analyses/scope.h" +using namespace std::literals; + namespace thorin { // Just assuming looking through the uses is faster if uses().size() is small. @@ -18,18 +21,18 @@ static constexpr int Search_In_Uses_Threshold = 8; * constructors */ -Def::Def(World* w, node_t node, const Def* type, Defs ops, flags_t flags, const Def* dbg) +Def::Def(World* w, node_t node, const Def* type, Defs ops, flags_t flags) : world_(w) , flags_(flags) , node_(unsigned(node)) , nom_(false) + , external_(false) , dep_(unsigned(node == Node::Axiom ? Dep::Axiom : node == Node::Infer ? Dep::Infer : node == Node::Proxy ? Dep::Proxy : node == Node::Var ? Dep::Var : Dep::None)) , num_ops_(ops.size()) - , dbg_(dbg) , type_(type) { std::ranges::copy(ops, ops_ptr()); gid_ = world().next_gid(); @@ -45,16 +48,16 @@ Def::Def(World* w, node_t node, const Def* type, Defs ops, flags_t flags, const } } -Def::Def(node_t n, const Def* type, Defs ops, flags_t flags, const Def* dbg) - : Def(nullptr, n, type, ops, flags, dbg) {} +Def::Def(node_t n, const Def* type, Defs ops, flags_t flags) + : Def(nullptr, n, type, ops, flags) {} -Def::Def(node_t node, const Def* type, size_t num_ops, flags_t flags, const Def* dbg) +Def::Def(node_t node, const Def* type, size_t num_ops, flags_t flags) : flags_(flags) , node_(node) , nom_(true) + , external_(false) , dep_(Dep::Nom | (node == Node::Infer ? Dep::Infer : Dep::None)) , num_ops_(num_ops) - , dbg_(dbg) , type_(type) { gid_ = world().next_gid(); hash_ = murmur3(gid()); @@ -63,10 +66,10 @@ Def::Def(node_t node, const Def* type, size_t num_ops, flags_t flags, const Def* } Nat::Nat(World& world) - : Def(Node, world.type(), Defs{}, 0, nullptr) {} + : Def(Node, world.type(), Defs{}, 0) {} -UMax::UMax(World& world, Defs ops, const Def* dbg) - : Def(Node, world.univ(), ops, 0, dbg) {} +UMax::UMax(World& world, Defs ops) + : Def(Node, world.univ(), ops, 0) {} // clang-format off @@ -74,70 +77,82 @@ UMax::UMax(World& world, Defs ops, const Def* dbg) * rebuild */ -const Def* Ac ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.ac(t, o, dbg); } -const Def* App ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.app(o[0], o[1], dbg); } -const Def* Arr ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.arr(o[0], o[1], dbg); } -const Def* Extract ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.extract(o[0], o[1], dbg); } -const Def* Insert ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.insert(o[0], o[1], o[2], dbg); } -const Def* Idx ::rebuild(World& w, const Def* , Defs , const Def* ) const { return w.type_idx(); } -const Def* Lam ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.lam(t->as(), o[0], o[1], dbg); } -const Def* Lit ::rebuild(World& w, const Def* t, Defs , const Def* dbg) const { return w.lit(t, get(), dbg); } -const Def* Nat ::rebuild(World& w, const Def* , Defs , const Def* ) const { return w.type_nat(); } -const Def* Pack ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.pack(t->arity(), o[0], dbg); } -const Def* Pi ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.pi(o[0], o[1], dbg); } -const Def* Pick ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.pick(t, o[0], dbg); } -const Def* Proxy ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.proxy(t, o, as()->pass(), as()->tag(), dbg); } -const Def* Sigma ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.sigma(o, dbg); } -const Def* Singleton::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.singleton(o[0], dbg); } -const Def* Type ::rebuild(World& w, const Def* , Defs o, const Def* ) const { return w.type(o[0]); } -const Def* Test ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.test(o[0], o[1], o[2], o[3], dbg); } -const Def* Tuple ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.tuple(t, o, dbg); } -const Def* UInc ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.uinc(o[0], offset(), dbg); } -const Def* UMax ::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.umax(o, dbg); } -const Def* Univ ::rebuild(World& w, const Def* , Defs , const Def* ) const { return w.univ(); } -const Def* Var ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.var(t, o[0]->as_nom(), dbg); } -const Def* Vel ::rebuild(World& w, const Def* t, Defs o, const Def* dbg) const { return w.vel(t, o[0], dbg); } - -const Def* Axiom ::rebuild(World& w, const Def* t, Defs , const Def* dbg) const { - if (&w != &world()) return w.axiom(normalizer(), curry(), trip(), t, dialect(), tag(), sub(), dbg); - assert(w.checker().equiv(t, type(), dbg)); +Ref Infer ::rebuild_(World&, Ref, Defs ) const { unreachable(); } +Ref Global ::rebuild_(World&, Ref, Defs ) const { unreachable(); } +Ref Ac ::rebuild_(World& w, Ref t, Defs o) const { return w.ac(t, o); } +Ref App ::rebuild_(World& w, Ref , Defs o) const { return w.app(o[0], o[1]); } +Ref Arr ::rebuild_(World& w, Ref , Defs o) const { return w.arr(o[0], o[1]); } +Ref Extract ::rebuild_(World& w, Ref , Defs o) const { return w.extract(o[0], o[1]); } +Ref Insert ::rebuild_(World& w, Ref , Defs o) const { return w.insert(o[0], o[1], o[2]); } +Ref Idx ::rebuild_(World& w, Ref , Defs ) const { return w.type_idx(); } +Ref Lam ::rebuild_(World& w, Ref t, Defs o) const { return w.lam(t->as(), o[0], o[1]); } +Ref Lit ::rebuild_(World& w, Ref t, Defs ) const { return w.lit(t, get()); } +Ref Nat ::rebuild_(World& w, Ref , Defs ) const { return w.type_nat(); } +Ref Pack ::rebuild_(World& w, Ref t, Defs o) const { return w.pack(t->arity(), o[0]); } +Ref Pi ::rebuild_(World& w, Ref , Defs o) const { return w.pi(o[0], o[1], implicit()); } +Ref Pick ::rebuild_(World& w, Ref t, Defs o) const { return w.pick(t, o[0]); } +Ref Proxy ::rebuild_(World& w, Ref t, Defs o) const { return w.proxy(t, o, as()->pass(), as()->tag()); } +Ref Sigma ::rebuild_(World& w, Ref , Defs o) const { return w.sigma(o); } +Ref Singleton::rebuild_(World& w, Ref , Defs o) const { return w.singleton(o[0]); } +Ref Type ::rebuild_(World& w, Ref , Defs o) const { return w.type(o[0]); } +Ref Test ::rebuild_(World& w, Ref , Defs o) const { return w.test(o[0], o[1], o[2], o[3]); } +Ref Tuple ::rebuild_(World& w, Ref t, Defs o) const { return w.tuple(t, o); } +Ref UInc ::rebuild_(World& w, Ref , Defs o) const { return w.uinc(o[0], offset()); } +Ref UMax ::rebuild_(World& w, Ref , Defs o) const { return w.umax(o); } +Ref Univ ::rebuild_(World& w, Ref , Defs ) const { return w.univ(); } +Ref Var ::rebuild_(World& w, Ref t, Defs o) const { return w.var(t, o[0]->as_nom()); } +Ref Vel ::rebuild_(World& w, Ref t, Defs o) const { return w.vel(t, o[0]); } + +Ref Axiom ::rebuild_(World& w, Ref t, Defs ) const { + if (&w != &world()) return w.axiom(normalizer(), curry(), trip(), t, dialect(), tag(), sub()); + assert(w.checker().equiv(t, type())); return this; } -template const Def* TExt ::rebuild(World& w, const Def* t, Defs , const Def* dbg) const { return w.ext (t, dbg); } -template const Def* TBound::rebuild(World& w, const Def* , Defs o, const Def* dbg) const { return w.bound( o, dbg); } +template Ref TExt ::rebuild_(World& w, Ref t, Defs ) const { return w.ext (t); } +template Ref TBound::rebuild_(World& w, Ref , Defs o) const { return w.bound(o); } /* * stub */ -Lam* Lam ::stub(World& w, const Def* t, const Def* dbg) { return w.nom_lam (t->as(), dbg); } -Pi* Pi ::stub(World& w, const Def* t, const Def* dbg) { return w.nom_pi (t, dbg); } -Sigma* Sigma ::stub(World& w, const Def* t, const Def* dbg) { return w.nom_sigma(t, num_ops(), dbg); } -Arr* Arr ::stub(World& w, const Def* t, const Def* dbg) { return w.nom_arr (t, dbg); } -Pack* Pack ::stub(World& w, const Def* t, const Def* dbg) { return w.nom_pack (t, dbg); } -Infer* Infer ::stub(World& w, const Def* t, const Def* dbg) { return w.nom_infer(t, dbg); } -Global* Global::stub(World& w, const Def* t, const Def* dbg) { return w.global(t, is_mutable(), dbg); } +Arr* Arr ::stub_(World& w, Ref t) { return w.nom_arr (t); } +Global* Global::stub_(World& w, Ref t) { return w.global(t, is_mutable()); } +Infer* Infer ::stub_(World& w, Ref t) { return w.nom_infer(t); } +Lam* Lam ::stub_(World& w, Ref t) { return w.nom_lam (t->as()); } +Pack* Pack ::stub_(World& w, Ref t) { return w.nom_pack (t); } +Pi* Pi ::stub_(World& w, Ref t) { return w.nom_pi (t, implicit()); } +Sigma* Sigma ::stub_(World& w, Ref t) { return w.nom_sigma(t, num_ops()); } -// clang-format on +template TBound* TBound::stub_(World& w, Ref t) { return w.nom_bound(t, num_ops()); } +template TExt * TExt ::stub_(World& , Ref ) { unreachable(); } -template -TBound* TBound::stub(World& w, const Def* t, const Def* dbg) { - return w.nom_bound(t, num_ops(), dbg); -} +/* + * instantiate templates + */ + +template Ref TExt ::rebuild_(World&, Ref, Defs) const; +template Ref TExt ::rebuild_(World&, Ref, Defs) const; +template Ref TBound::rebuild_(World&, Ref, Defs) const; +template Ref TBound::rebuild_(World&, Ref, Defs) const; +template TBound* TBound::stub_(World&, Ref); +template TBound* TBound::stub_(World&, Ref); +template TExt * TExt ::stub_(World&, Ref); +template TExt * TExt ::stub_(World&, Ref); +// clang-format on /* * restructure */ const Pi* Pi::restructure() { - if (!is_free(this, codom())) return world().pi(dom(), codom(), dbg()); + if (!is_free(this, codom())) return world().pi(dom(), codom()); return nullptr; } const Sigma* Sigma::restructure() { if (std::ranges::none_of(ops(), [this](auto op) { return is_free(this, op); })) - return static_cast(world().sigma(ops(), dbg())); + return static_cast(*world().sigma(ops())); return nullptr; } @@ -163,6 +178,10 @@ const Def* Pack::restructure() { * Def */ +Sym Def::get_sym(const char* s) const { return world().sym(s); } +Sym Def::get_sym(std::string_view s) const { return world().sym(s); } +Sym Def::get_sym(std::string s) const { return world().sym(std::move(s)); } + World& Def::world() const { if (isa()) return *world_; if (auto type = isa()) return type->level()->world(); @@ -191,13 +210,25 @@ std::string_view Def::node_name() const { Defs Def::extended_ops() const { if (isa() || isa()) return Defs(); - size_t offset = dbg() ? 2 : 1; - return Defs((is_set() ? num_ops_ : 0) + offset, ops_ptr() - offset); + assert(type()); + return Defs((is_set() ? num_ops_ : 0) + 1, ops_ptr() - 1); } +#ifndef NDEBUG +const Def* Def::debug_prefix(std::string prefix) const { + dbg_.sym = world().sym(prefix + *sym()); + return this; +} + +const Def* Def::debug_suffix(std::string suffix) const { + dbg_.sym = world().sym(*sym() + suffix); + return this; +} +#endif + // clang-format off -const Var* Def::var(const Def* dbg) { +const Var* Def::var() { auto& w = world(); if (w.is_frozen() || uses().size() < Search_In_Uses_Threshold) { @@ -208,12 +239,12 @@ const Var* Def::var(const Def* dbg) { if (w.is_frozen()) return nullptr; } - if (auto lam = isa()) return w.var(lam ->dom(), lam, dbg); - if (auto pi = isa()) return w.var(pi ->dom(), pi, dbg); - if (auto sig = isa()) return w.var(sig, sig, dbg); - if (auto arr = isa()) return w.var(w.type_idx(arr ->shape()), arr, dbg); // TODO shapes like (2, 3) - if (auto pack = isa()) return w.var(w.type_idx(pack->shape()), pack, dbg); // TODO shapes like (2, 3) - if (isa()) return w.var(this, this, dbg); + if (auto lam = isa()) return w.var(lam ->dom(), lam); + if (auto pi = isa()) return w.var(pi ->dom(), pi); + if (auto sig = isa()) return w.var(sig, sig); + if (auto arr = isa()) return w.var(w.type_idx(arr ->shape()), arr ); // TODO shapes like (2, 3) + if (auto pack = isa()) return w.var(w.type_idx(pack->shape()), pack); // TODO shapes like (2, 3) + if (isa()) return w.var(this, this); if (isa()) return nullptr; if (isa()) return nullptr; unreachable(); @@ -250,6 +281,13 @@ const Def* Def::arity() const { return world().lit_nat(1); } +std::optional Def::isa_lit_arity() const { + if (auto sigma = isa()) return sigma->num_ops(); + if (auto arr = isa()) return isa_lit(arr->shape()); + if (sort() == Sort::Term) return type()->isa_lit_arity(); + return 1; +} + // clang-format on bool Def::equal(const Def* other) const { @@ -263,26 +301,7 @@ bool Def::equal(const Def* other) const { return result; } -#ifndef NDEBUG -void Def::set_debug_name(std::string_view n) const { - auto& w = world(); - auto name = w.tuple_str(n); - - if (dbg_ == nullptr) { - auto file = w.tuple_str(""); - auto begin = w.lit_nat_max(); - auto finis = w.lit_nat_max(); - auto meta = w.bot(w.type_bot()); - dbg_ = w.tuple({name, w.tuple({file, begin, finis}), meta}); - } else { - dbg_ = w.insert(dbg_, 3_s, 0_s, name); - } -} -#endif - void Def::finalize() { - assert(!dbg() || !dbg()->dep()); - for (size_t i = 0, e = num_ops(); i != e; ++i) { dep_ |= op(i)->dep(); if (!op(i)->dep_const()) { @@ -352,9 +371,8 @@ bool Def::is_set() const { void Def::make_external() { return world().make_external(this); } void Def::make_internal() { return world().make_internal(this); } -bool Def::is_external() const { return world().is_external(this); } -std::string Def::unique_name() const { return name() + "_" + std::to_string(gid()); } +std::string Def::unique_name() const { return *sym() + "_"s + std::to_string(gid()); } DefArray Def::reduce(const Def* arg) const { if (auto nom = isa_nom()) return nom->reduce(arg); @@ -375,7 +393,7 @@ const Def* Def::reduce_rec() const { if (callee->isa_nom()) { def = callee->reduce(app->arg()).back(); } else { - def = callee != app->callee() ? world().app(callee, app->arg(), app->dbg()) : app; + def = callee != app->callee() ? world().app(callee, app->arg()) : app; break; } } @@ -385,10 +403,10 @@ const Def* Def::reduce_rec() const { const Def* Def::refine(size_t i, const Def* new_op) const { DefArray new_ops(ops()); new_ops[i] = new_op; - return rebuild(world(), type(), new_ops, dbg()); + return rebuild(world(), type(), new_ops); } -const Def* Def::proj(nat_t a, nat_t i, const Def* dbg) const { +const Def* Def::proj(nat_t a, nat_t i) const { if (a == 1) { if (!type()) return this; if (!isa_nom() && !type()->isa_nom()) return this; @@ -400,11 +418,11 @@ const Def* Def::proj(nat_t a, nat_t i, const Def* dbg) const { return op(i); } else if (auto arr = isa()) { if (arr->arity()->isa()) return arr->body(); - return arr->reduce(w.lit_idx(as_lit(arr->arity()), i)); + return arr->reduce(w.lit_idx(arr->as_lit_arity(), i)); } else if (auto pack = isa()) { if (pack->arity()->isa()) return pack->body(); assert(!w.is_frozen() && "TODO"); - return pack->reduce(w.lit_idx(as_lit(pack->arity()), i)); + return pack->reduce(w.lit_idx(pack->as_lit_arity(), i)); } else if (sort() == Sort::Term) { if (w.is_frozen() || uses().size() < Search_In_Uses_Threshold) { for (auto u : uses()) { @@ -416,7 +434,7 @@ const Def* Def::proj(nat_t a, nat_t i, const Def* dbg) const { if (w.is_frozen()) return nullptr; } - return w.extract(this, a, i, dbg); + return w.extract(this, a, i); } return nullptr; @@ -447,21 +465,6 @@ std::optional Idx::size2bitwidth(const Def* size) { const App* Global::type() const { return Def::type()->as(); } const Def* Global::alloced_type() const { return type()->arg(0); } -/* - * instantiate templates - */ - -// clang-format off - -template const Def* TExt ::rebuild(World&, const Def*, Defs, const Def*) const; -template const Def* TExt ::rebuild(World&, const Def*, Defs, const Def*) const; -template const Def* TBound::rebuild(World&, const Def*, Defs, const Def*) const; -template const Def* TBound::rebuild(World&, const Def*, Defs, const Def*) const; -template TBound* TBound::stub(World&, const Def*, const Def*); -template TBound* TBound::stub(World&, const Def*, const Def*); - -// clang-format on - std::pair> collect_args(const Def* def) { std::vector args; if (auto app = def->isa()) { diff --git a/thorin/def.h b/thorin/def.h index 7385024e8e..286e240a91 100644 --- a/thorin/def.h +++ b/thorin/def.h @@ -3,12 +3,11 @@ #include #include -#include "thorin/debug.h" - #include "thorin/util/array.h" #include "thorin/util/cast.h" #include "thorin/util/container.h" #include "thorin/util/hash.h" +#include "thorin/util/loc.h" #include "thorin/util/print.h" // clang-format off @@ -43,9 +42,8 @@ class Var; class Def; class World; -using Implicits = std::vector; -using Defs = Span; -using DefArray = Array; +using Defs = Span; +using DefArray = Array; //------------------------------------------------------------------------------ @@ -134,35 +132,61 @@ inline unsigned operator==(Dep d1, unsigned d2) { return unsigned(d1) == d2; } inline unsigned operator!=(Dep d1, unsigned d2) { return unsigned(d1) != d2; } /// Use as mixin to wrap all kind of Def::proj and Def::projs variants. -#define THORIN_PROJ(NAME, CONST) \ - nat_t num_##NAME##s() CONST { return ((const Def*)NAME())->num_projs(); } \ - const Def* NAME(nat_t a, nat_t i, const Def* dbg = {}) CONST { return ((const Def*)NAME())->proj(a, i, dbg); } \ - const Def* NAME(nat_t i, const Def* dbg = {}) CONST { return ((const Def*)NAME())->proj(i, dbg); } \ - template \ - auto NAME##s(F f, Defs dbgs = {}) CONST { \ - return ((const Def*)NAME())->projs(f, dbgs); \ - } \ - template \ - auto NAME##s(Defs dbgs = {}) CONST { \ - return ((const Def*)NAME())->projs(dbgs); \ - } \ - template \ - auto NAME##s(nat_t a, F f, Defs dbgs = {}) CONST { \ - return ((const Def*)NAME())->projs(a, f, dbgs); \ - } \ - auto NAME##s(nat_t a, Defs dbgs = {}) CONST { return ((const Def*)NAME())->projs(a, dbgs); } +#define THORIN_PROJ(NAME, CONST) \ + nat_t num_##NAME##s() CONST { return ((const Def*)NAME())->num_projs(); } \ + Ref NAME(nat_t a, nat_t i) CONST { return ((const Def*)NAME())->proj(a, i); } \ + Ref NAME(nat_t i) CONST { return ((const Def*)NAME())->proj(i); } \ + template \ + auto NAME##s(F f) CONST { \ + return ((const Def*)NAME())->projs(f); \ + } \ + template \ + auto NAME##s() CONST { \ + return ((const Def*)NAME())->projs(); \ + } \ + template \ + auto NAME##s(nat_t a, F f) CONST { \ + return ((const Def*)NAME())->projs(a, f); \ + } \ + auto NAME##s(nat_t a) CONST { return ((const Def*)NAME())->projs(a); } + +// clang-format off +/// Use as mixin to declare setters for Def::loc \& Def::name using a *covariant* return type. +#define THORIN_SETTERS(T) \ +public: \ + template const T* set(Loc l ) const { if (Ow || !dbg_.loc) dbg_.loc = l; return this; } \ + template T* set(Loc l ) { if (Ow || !dbg_.loc) dbg_.loc = l; return this; } \ + template const T* set( Sym s ) const { if (Ow || !dbg_.sym) dbg_.sym = s; return this; } \ + template T* set( Sym s ) { if (Ow || !dbg_.sym) dbg_.sym = s; return this; } \ + template const T* set( std::string s) const { set(get_sym(std::move(s))); return this; } \ + template T* set( std::string s) { set(get_sym(std::move(s))); return this; } \ + template const T* set(Loc l, Sym s ) const { set(l); set(s); return this; } \ + template T* set(Loc l, Sym s ) { set(l); set(s); return this; } \ + template const T* set(Loc l, std::string s) const { set(l); set(get_sym(std::move(s))); return this; } \ + template T* set(Loc l, std::string s) { set(l); set(get_sym(std::move(s))); return this; } \ + template const T* set(Dbg d) const { set(d.loc, d.sym); return this; } \ + template T* set(Dbg d) { set(d.loc, d.sym); return this; } +// clang-format on + +#define THORIN_DEF_MIXIN(T) \ + THORIN_SETTERS(T) \ + T* stub(World& w, const Def* type) { return stub_(w, type)->set(dbg())->as(); } \ + static constexpr auto Node = Node::T; \ +private: \ + Ref rebuild_(World&, Ref, Defs) const override; \ + friend class World; /// Base class for all Def%s. /// The data layout (see World::alloc and Def::partial_ops) looks like this: /// ``` -/// Def| dbg |type | op(0) ... op(num_ops-1) | -/// |--------------partial_ops------------| -/// |-------extended_ops------| +/// Def| type | op(0) ... op(num_ops-1) | +/// |---------partial_ops------------| +/// |-------extended_ops------| /// ``` /// @attention This means that any subclass of Def **must not** introduce additional members. class Def : public RuntimeCast { public: - using NormalizeFn = const Def* (*)(const Def*, const Def*, const Def*, const Def*); + using NormalizeFn = Ref (*)(Ref, Ref, Ref); private: Def& operator=(const Def&) = delete; @@ -170,10 +194,10 @@ class Def : public RuntimeCast { protected: /// Constructor for a structural Def. - Def(World*, node_t, const Def* type, Defs ops, flags_t flags, const Def* dbg); - Def(node_t n, const Def* type, Defs ops, flags_t flags, const Def* dbg); + Def(World*, node_t, const Def* type, Defs ops, flags_t flags); + Def(node_t n, const Def* type, Defs ops, flags_t flags); /// Constructor for a *nom*inal Def. - Def(node_t, const Def* type, size_t num_ops, flags_t flags, const Def* dbg); + Def(node_t, const Def* type, size_t num_ops, flags_t flags); virtual ~Def() = default; public: @@ -196,6 +220,12 @@ class Def : public RuntimeCast { const Def* unfold_type() const; Sort sort() const; const Def* arity() const; + std::optional isa_lit_arity() const; + nat_t as_lit_arity() const { + auto a = isa_lit_arity(); + assert(a.has_value()); + return *a; + } ///@} /// @name ops @@ -230,9 +260,11 @@ class Def : public RuntimeCast { } Def* set_type(const Def*); void unset_type(); + + /// Resolves Infer%s of this Def's type. void update() { if (auto r = refer(type()); r && r != type()) set_type(r); - } ///< Resolves Infer%s. + } /// Yields `true` if empty or the last op is set. bool is_set() const; @@ -240,8 +272,8 @@ class Def : public RuntimeCast { /// @name extended_ops ///@{ - /// Includes Def::dbg (if not `nullptr`), Def::type() (if not `nullptr`), - /// and then the other Def::ops() (if Def::is_set) in this order. + /// Includes Def::type() (if not `nullptr`) and then the other Def::ops() in this order. + /// Def::ops() is only included, if Def::is_set. Defs extended_ops() const; const Def* extended_op(size_t i) const { return extended_ops()[i]; } size_t num_extended_ops() const { return extended_ops().size(); } @@ -249,10 +281,10 @@ class Def : public RuntimeCast { /// @name partial_ops ///@{ - /// Includes Def::dbg, Def::type, and Def::ops (in this order). + /// Includes Def::type() and then the other Def::ops() in this order. /// Also works with partially set Def%s and doesn't assert. /// Unset operands are `nullptr`. - Defs partial_ops() const { return Defs(num_ops_ + 2, ops_ptr() - 2); } + Defs partial_ops() const { return Defs(num_ops_ + 1, ops_ptr() - 1); } const Def* partial_op(size_t i) const { return partial_ops()[i]; } size_t num_partial_ops() const { return partial_ops().size(); } ///@} @@ -279,15 +311,15 @@ class Def : public RuntimeCast { /// Yields Def::arity as_lit, if it is in fact a Lit, or `1` otherwise. nat_t num_projs() const { - if (auto a = isa_lit(arity())) return *a; + if (auto a = isa_lit_arity()) return *a; return 1; } /// Similar to World::extract while assuming an arity of @p a but also works on Sigma%s, and Arr%ays. /// If `this` is a Sort::Term (see Def::sort), Def::proj resorts to World::extract. - const Def* proj(nat_t a, nat_t i, const Def* dbg = {}) const; + const Def* proj(nat_t a, nat_t i) const; /// Same as above but takes Def::num_projs as arity. - const Def* proj(nat_t i, const Def* dbg = {}) const { return proj(num_projs(), i, dbg); } + const Def* proj(nat_t i) const { return proj(num_projs(), i); } /// Splits this Def via Def::proj%ections into an Arr%ay (if `A == -1_s`) or `std::array` (otherwise). /// Applies @p f to each element. @@ -302,57 +334,60 @@ class Def : public RuntimeCast { /// Array lits = def->projs(n, as_lit);// same as above but applies as_lit to each element /// ``` template - auto projs(F f, Defs dbgs = {}) const { + auto projs(F f) const { using R = std::decay_t; if constexpr (A == -1_s) { - return projs(num_projs(), f, dbgs); + return projs(num_projs(), f); } else { - assert(A == as_lit(arity())); + assert(A == as_lit_arity()); std::array array; - for (nat_t i = 0; i != A; ++i) array[i] = f(proj(A, i, dbgs.empty() ? nullptr : dbgs[i])); + for (nat_t i = 0; i != A; ++i) array[i] = f(proj(A, i)); return array; } } template - auto projs(nat_t a, F f, Defs dbgs = {}) const { + auto projs(nat_t a, F f) const { using R = std::decay_t; - return Array(a, [&](nat_t i) { return f(proj(a, i, dbgs.empty() ? nullptr : dbgs[i])); }); + return Array(a, [&](nat_t i) { return f(proj(a, i)); }); } template - auto projs(Defs dbgs = {}) const { - return projs([](const Def* def) { return def; }, dbgs); + auto projs() const { + return projs([](const Def* def) { return def; }); } - auto projs(nat_t a, Defs dbgs = {}) const { - return projs( - a, [](const Def* def) { return def; }, dbgs); + auto projs(nat_t a) const { + return projs(a, [](const Def* def) { return def; }); } ///@} /// @name externals ///@{ - bool is_external() const; - bool is_internal() const { return !is_external(); } ///< *Not* Def::is_external. + bool is_external() const { return external_; } + bool is_internal() const { return !is_external(); } ///< **Not** Def::is_external. void make_external(); void make_internal(); ///@} - /// @name debug + /// @name Dbg + ///@{ + std::string unique_name() const; ///< name + "_" + Def::gid + THORIN_SETTERS(Def) + Dbg dbg() const { return dbg_; } + Loc loc() const { return dbg_.loc; } + Sym sym() const { return dbg_.sym; } + ///@} + + /// @name debug prepend/append ///@{ - const Def* dbg() const { return dbg_; } ///< Returns debug information as Def. - Debug debug() const { return dbg_; } ///< Returns the debug information as Debug. - std::string name() const { return debug().name; } - Loc loc() const { return debug().loc; } - const Def* meta() const { return debug().meta; } - void set_dbg(const Def* dbg) const { dbg_ = dbg; } - /// Set Def::name in Debug build only; does nothing in Release build. + /// Prepends/Appends a prefix/suffix to Def::name - but only in **DEBUG** build. #ifndef NDEBUG - void set_debug_name(std::string_view) const; + const Def* debug_prefix(std::string) const; + const Def* debug_suffix(std::string) const; #else - void set_debug_name(std::string_view) const {} + const Def* debug_prefix(std::string) const { return this; } + const Def* debug_suffix(std::string) const { return this; } #endif - std::string unique_name() const; ///< name + "_" + Def::gid ///@} /// @name casts @@ -386,7 +421,7 @@ class Def : public RuntimeCast { /// @name var ///@{ /// Retrieve Var for *nominals*. - const Var* var(const Def* dbg = {}); + const Var* var(); THORIN_PROJ(var, ) ///@} @@ -400,14 +435,18 @@ class Def : public RuntimeCast { const Def* reduce_rec() const; ///@} + /// @name rebuild/stub/restr + ///@{ + Def* stub(World& w, Ref type) { return stub_(w, type)->set(dbg()); } + /// Def::rebuild%s this Def while using @p new_op as substitute for its @p i'th Def::op + Ref rebuild(World& w, Ref type, Defs ops) const { return rebuild_(w, type, ops)->set(dbg()); } + ///@} + /// @name virtual methods ///@{ virtual void check() {} virtual size_t first_dependend_op() { return 0; } - virtual const Def* rebuild(World&, const Def*, Defs, const Def*) const { unreachable(); } - /// Def::rebuild%s this Def while using @p new_op as substitute for its @p i'th Def::op const Def* refine(size_t i, const Def* new_op) const; - virtual Def* stub(World&, const Def*, const Def*) { unreachable(); } virtual const Def* restructure() { return nullptr; } ///@} @@ -422,6 +461,9 @@ class Def : public RuntimeCast { ///@} protected: + virtual Ref rebuild_(World&, Ref, Defs) const = 0; + virtual Def* stub_(World&, Ref) { unreachable(); } + const Def** ops_ptr() const { return reinterpret_cast(reinterpret_cast(const_cast(this + 1))); } @@ -434,18 +476,28 @@ class Def : public RuntimeCast { mutable World* world_; }; + /// @name wrappers for World::sym + ///@{ + /// These are here to have Def::set%ters inline without including `thorin/world.h`. + Sym get_sym(const char*) const; + Sym get_sym(std::string_view) const; + Sym get_sym(std::string) const; + ///@} + flags_t flags_; uint8_t node_; - unsigned nom_ : 1; - unsigned dep_ : 5; - unsigned pading_ : 2; + unsigned nom_ : 1; + unsigned external_ : 1; + unsigned dep_ : 5; + unsigned pading_ : 1; u8 curry_; u8 trip_; hash_t hash_; u32 gid_; u32 num_ops_; mutable Uses uses_; - mutable const Def* dbg_; + mutable Dbg dbg_; + const Def* type_; friend class World; @@ -465,14 +517,8 @@ const T* as([[maybe_unused]] flags_t f, const Def* def) { } template -[[noreturn]] void err(const Def* dbg, const char* fmt, Args&&... args) { - err(Debug(dbg).loc, fmt, std::forward(args)...); -} - -template -[[noreturn]] void err(const Def* dbg, const char* fmt, const Def* def, Args&&... args) { - Debug d(dbg ? dbg : def->dbg()); - err(d.loc, fmt, def, std::forward(args)...); +[[noreturn]] void err(const Def* def, const char* fmt, Args&&... args) { + err(def->loc(), fmt, std::forward(args)...); } //------------------------------------------------------------------------------ @@ -510,21 +556,16 @@ using Nom2Nom = NomMap; class Var : public Def { private: - Var(const Def* type, Def* nom, const Def* dbg) - : Def(Node, type, Defs{nom}, 0, dbg) {} + Var(const Def* type, Def* nom) + : Def(Node, type, Defs{nom}, 0) {} public: /// @name ops ///@{ Def* nom() const { return op(0)->as_nom(); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - static constexpr auto Node = Node::Var; - friend class World; + THORIN_DEF_MIXIN(Var) }; template @@ -535,38 +576,24 @@ using Var2Var = VarMap; class Univ : public Def { private: Univ(World& world) - : Def(&world, Node, nullptr, Defs{}, 0, nullptr) {} - -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} + : Def(&world, Node, nullptr, Defs{}, 0) {} - static constexpr auto Node = Node::Univ; - friend class World; + THORIN_DEF_MIXIN(Univ) }; class UMax : public Def { private: - UMax(World&, Defs ops, const Def* dbg); + UMax(World&, Defs ops); -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::UMax; - friend class World; + THORIN_DEF_MIXIN(UMax) }; using level_t = u64; class UInc : public Def { private: - UInc(const Def* op, level_t offset, const Def* dbg) - : Def(Node, op->type()->as(), {op}, offset, dbg) {} + UInc(const Def* op, level_t offset) + : Def(Node, op->type()->as(), {op}, offset) {} public: /// @name ops @@ -575,36 +602,24 @@ class UInc : public Def { level_t offset() const { return flags(); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::UInc; - friend class World; + THORIN_DEF_MIXIN(UInc) }; class Type : public Def { private: - Type(const Def* level, const Def* dbg) - : Def(Node, nullptr, {level}, 0, dbg) {} + Type(const Def* level) + : Def(Node, nullptr, {level}, 0) {} public: const Def* level() const { return op(0); } - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Type; - friend class World; + THORIN_DEF_MIXIN(Type) }; class Lit : public Def { private: - Lit(const Def* type, flags_t val, const Def* dbg) - : Def(Node, type, Defs{}, val, dbg) {} + Lit(const Def* type, flags_t val) + : Def(Node, type, Defs{}, val) {} public: template @@ -613,13 +628,7 @@ class Lit : public Def { return bitcast(flags_); } - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Lit; - friend class World; + THORIN_DEF_MIXIN(Lit) }; template @@ -638,28 +647,16 @@ class Nat : public Def { private: Nat(World& world); -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Nat; - friend class World; + THORIN_DEF_MIXIN(Nat) }; /// A built-in constant of type `.Nat -> *`. class Idx : public Def { private: Idx(const Def* type) - : Def(Node, type, Defs{}, 0, nullptr) {} + : Def(Node, type, Defs{}, 0) {} public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - /// Checks if @p def isa `.Idx s` and returns s or `nullptr` otherwise. static const Def* size(Ref def); @@ -672,14 +669,13 @@ class Idx : public Def { static std::optional size2bitwidth(const Def* size); ///@} - static constexpr auto Node = Node::Idx; - friend class World; + THORIN_DEF_MIXIN(Idx) }; class Proxy : public Def { private: - Proxy(const Def* type, Defs ops, u32 pass, u32 tag, const Def* dbg) - : Def(Node, type, ops, (u64(pass) << 32_u64) | u64(tag), dbg) {} + Proxy(const Def* type, Defs ops, u32 pass, u32 tag) + : Def(Node, type, ops, (u64(pass) << 32_u64) | u64(tag)) {} public: /// @name misc getters @@ -688,13 +684,7 @@ class Proxy : public Def { u32 tag() const { return u32(flags()); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Proxy; - friend class World; + THORIN_DEF_MIXIN(Proxy) }; /// @deprecated A global variable in the data segment. @@ -702,8 +692,8 @@ class Proxy : public Def { /// @attention WILL BE REMOVED. class Global : public Def { private: - Global(const Def* type, bool is_mutable, const Def* dbg) - : Def(Node, type, 1, is_mutable, dbg) {} + Global(const Def* type, bool is_mutable) + : Def(Node, type, 1, is_mutable) {} public: /// @name ops @@ -724,13 +714,8 @@ class Global : public Def { bool is_mutable() const { return flags(); } ///@} - /// @name virtual methods - ///@{ - Global* stub(World&, const Def*, const Def*) override; - ///@} - - static constexpr auto Node = Node::Global; - friend class World; + THORIN_DEF_MIXIN(Global) + Global* stub_(World&, Ref) override; }; hash_t UseHash::operator()(Use use) const { return hash_combine(hash_begin(u16(use.index())), hash_t(use->gid())); } diff --git a/thorin/driver.h b/thorin/driver.h new file mode 100644 index 0000000000..518f525213 --- /dev/null +++ b/thorin/driver.h @@ -0,0 +1,26 @@ +#pragma once + +#include "thorin/flags.h" +#include "thorin/world.h" + +#include "thorin/util/log.h" + +namespace thorin { + +/// Some "global" variables needed all over the place. +/// Well, there are not really global - that's the point of this class. +class Driver : public SymPool { +public: + Driver() + : log(*this) + , world(this) {} + + Flags flags; + Log log; +#if THORIN_ENABLE_CHECKS + absl::flat_hash_set breakpoints; +#endif + World world; +}; + +} // namespace thorin diff --git a/thorin/dump.cpp b/thorin/dump.cpp index ff80de3eb5..6aded3c376 100644 --- a/thorin/dump.cpp +++ b/thorin/dump.cpp @@ -25,13 +25,13 @@ namespace thorin { static Def* isa_decl(const Def* def) { if (auto nom = def->isa_nom()) { - if (nom->is_external() || nom->isa() || (!nom->name().empty() && nom->name() != "_"s)) return nom; + if (nom->is_external() || nom->isa() || (nom->sym() && nom->sym() != '_')) return nom; } return nullptr; } static std::string id(const Def* def) { - if (def->is_external() || (!def->is_set() && def->isa())) return def->name(); + if (def->is_external() || (!def->is_set() && def->isa())) return def->sym(); return def->unique_name(); } @@ -122,7 +122,7 @@ std::ostream& operator<<(std::ostream& os, Inline u) { } else if (auto top = u->isa()) { return print(os, "⊤:{}", top->type()); } else if (auto axiom = u->isa()) { - const auto& name = axiom->name(); + const auto name = axiom->sym(); return print(os, "{}{}", name[0] == '%' ? "" : "%", name); } else if (auto lit = u->isa()) { if (lit->type()->isa()) return print(os, "{}", lit->get()); @@ -372,7 +372,7 @@ void Def::write(int max) const { * World */ -void World::dump(std::ostream& os) const { +void World::dump(std::ostream& os) { auto freezer = World::Freezer(*this); auto old_gid = curr_gid(); @@ -391,18 +391,18 @@ void World::dump(std::ostream& os) const { assertf(old_gid == curr_gid(), "new nodes created during dump. old_gid: {}; curr_gid: {}", old_gid, curr_gid()); } -void World::dump() const { dump(std::cout); } +void World::dump() { dump(std::cout); } -void World::debug_dump() const { +void World::debug_dump() { if (log().level == Log::Level::Debug) dump(*log().ostream); } -void World::write(const char* file) const { +void World::write(const char* file) { auto ofs = std::ofstream(file); dump(ofs); } -void World::write() const { +void World::write() { auto file = std::string(name()) + ".thorin"s; write(file.c_str()); } diff --git a/thorin/fe/ast.cpp b/thorin/fe/ast.cpp index 59fc022b42..a70fffbe93 100644 --- a/thorin/fe/ast.cpp +++ b/thorin/fe/ast.cpp @@ -9,49 +9,48 @@ namespace thorin::fe { -const Def* Ptrn::dbg(World& world) { return world.dbg(Debug(sym(), loc())); } - /* * bind */ -void IdPtrn::bind(Scopes& scopes, const Def* def) const { scopes.bind(sym_, def, rebind()); } +void IdPtrn::bind(Scopes& scopes, const Def* def) const { scopes.bind(dbg(), def, rebind()); } void TuplePtrn::bind(Scopes& scopes, const Def* def) const { - World& w = def->world(); - scopes.bind(sym_, def, rebind()); - for (size_t i = 0, e = num_ptrns(); i != e; ++i) ptrn(i)->bind(scopes, def->proj(e, i, w.dbg(ptrn(i)->sym()))); + scopes.bind(dbg(), def, rebind()); + for (size_t i = 0, e = num_ptrns(); i != e; ++i) { + auto proj = def->proj(e, i)->set(ptrn(i)->loc(), ptrn(i)->sym()); + ptrn(i)->bind(scopes, proj); + } } /* * type */ -const Def* IdPtrn::type(World& world) const { +const Def* IdPtrn::type(World& world, Def2Fields&) const { if (type_) return type_; - return type_ = world.nom_infer_type(world.dbg(loc())); + return type_ = world.nom_infer_type()->set(loc()); } -const Def* TuplePtrn::type(World& world) const { +const Def* TuplePtrn::type(World& world, Def2Fields& def2fields) const { if (type_) return type_; auto n = num_ptrns(); - auto ops = Array(n, [&](size_t i) { return ptrn(i)->type(world); }); + auto ops = Array(n, [&](size_t i) { return ptrn(i)->type(world, def2fields); }); if (std::ranges::all_of(ptrns_, [](auto&& b) { return b->is_anonymous(); })) - return type_ = world.sigma(ops, world.dbg(loc())); + return type_ = world.sigma(ops)->set(loc()); assert(ptrns().size() > 0); - auto fields = Array(n, [&](size_t i) { return ptrn(i)->sym().str(); }); - auto type = world.umax(ops); - auto meta = world.tuple(fields); - auto debug = Debug(sym(), loc(), meta); - auto sigma = world.nom_sigma(type, n, world.dbg(debug)); + auto type = world.umax(ops); + auto sigma = world.nom_sigma(type, n)->set(loc(), sym()); + auto [_, ins] = def2fields.emplace(sigma, Array(n, [&](size_t i) { return ptrn(i)->sym(); })); + assert(ins); sigma->set(0, ops[0]); for (size_t i = 1; i != n; ++i) { - if (auto infer = infers_[i - 1]) infer->set(sigma->var(n, i - 1, world.dbg(ptrn(i - 1)->sym()))); + if (auto infer = infers_[i - 1]) infer->set(sigma->var(n, i - 1)->set(ptrn(i - 1)->sym())); sigma->set(i, ops[i]); } diff --git a/thorin/fe/ast.h b/thorin/fe/ast.h index 7190bd0e93..854b0f572c 100644 --- a/thorin/fe/ast.h +++ b/thorin/fe/ast.h @@ -3,51 +3,44 @@ #include #include +#include "thorin/def.h" + #include "thorin/fe/tok.h" namespace thorin { class Infer; class Sigma; +class World; namespace fe { class Scopes; - -class AST { -public: - AST(Loc loc) - : loc_(loc) {} - virtual ~AST(){}; - - Loc loc() const { return loc_; } - -private: - Loc loc_; -}; +using Def2Fields = DefMap>; /* * Pattern */ -class Ptrn : public AST { +class Ptrn { public: - Ptrn(Loc loc, bool rebind, Sym sym, const Def* type) - : AST(loc) + Ptrn(Dbg dbg, bool rebind, const Def* type) + : dbg_(dbg) , rebind_(rebind) - , sym_(sym) , type_(type) {} + virtual ~Ptrn() {} + Dbg dbg() const { return dbg_; } + Loc loc() const { return dbg_.loc; } + Sym sym() const { return dbg_.sym; } bool rebind() const { return rebind_; } - Sym sym() const { return sym_; } - bool is_anonymous() const { return sym_.is_anonymous(); } - virtual void bind(Scopes&, const Def*) const = 0; - virtual const Def* type(World&) const = 0; - const Def* dbg(World&); + bool is_anonymous() const { return sym() == '_'; } + virtual void bind(Scopes&, const Def*) const = 0; + virtual const Def* type(World&, Def2Fields&) const = 0; protected: + Dbg dbg_; bool rebind_; - Sym sym_; mutable const Def* type_; }; @@ -55,17 +48,17 @@ using Ptrns = std::deque>; class IdPtrn : public Ptrn { public: - IdPtrn(Loc loc, bool rebind, Sym sym, const Def* type) - : Ptrn(loc, rebind, sym, type) {} + IdPtrn(Dbg dbg, bool rebind, const Def* type) + : Ptrn(dbg, rebind, type) {} void bind(Scopes&, const Def*) const override; - const Def* type(World&) const override; + const Def* type(World&, Def2Fields&) const override; }; class TuplePtrn : public Ptrn { public: - TuplePtrn(Loc loc, bool rebind, Sym sym, Ptrns&& ptrns, const Def* type, std::vector&& infers) - : Ptrn(loc, rebind, sym, type) + TuplePtrn(Dbg dbg, bool rebind, Ptrns&& ptrns, const Def* type, std::vector&& infers) + : Ptrn(dbg, rebind, type) , ptrns_(std::move(ptrns)) , infers_(std::move(infers)) {} @@ -74,7 +67,7 @@ class TuplePtrn : public Ptrn { size_t num_ptrns() const { return ptrns().size(); } void bind(Scopes&, const Def*) const override; - const Def* type(World&) const override; + const Def* type(World&, Def2Fields&) const override; private: Ptrns ptrns_; diff --git a/thorin/fe/lexer.cpp b/thorin/fe/lexer.cpp index 49c2ebfa52..073eb233ee 100644 --- a/thorin/fe/lexer.cpp +++ b/thorin/fe/lexer.cpp @@ -9,16 +9,16 @@ namespace thorin::fe { static bool issign(char32_t i) { return i == '+' || i == '-'; } static bool issubscsr(char32_t i) { return U'₀' <= i && i <= U'₉'; } -Lexer::Lexer(World& world, std::string_view filename, std::istream& istream, std::ostream* md /*= nullptr*/) - : Super(filename, istream) +Lexer::Lexer(World& world, Sym file, std::istream& istream, std::ostream* md /*= nullptr*/) + : Super(file, istream) , world_(world) , md_(md) { -#define CODE(t, str) keywords_[str] = Tok::Tag::t; +#define CODE(t, str) keywords_[world.sym(str)] = Tok::Tag::t; THORIN_KEY(CODE) #undef CODE #define CODE(str, t) \ - if (Tok::Tag::t != Tok::Tag::Nil) keywords_[str] = Tok::Tag::t; + if (Tok::Tag::t != Tok::Tag::Nil) keywords_[world.sym(str)] = Tok::Tag::t; THORIN_SUBST(CODE) #undef CODE @@ -100,18 +100,19 @@ Tok Lexer::lex() { // clang-format on if (accept('%')) { - if (lex_id()) return {loc(), Tok::Tag::M_ax, world_.sym(str_, loc())}; + if (lex_id()) return {loc(), Tok::Tag::M_ax, world().sym(str_)}; err(loc_, "invalid axiom name '{}'", str_); } if (accept('.')) { if (lex_id()) { - if (auto i = keywords_.find(str_); i != keywords_.end()) return tok(i->second); + auto sym = world().sym(str_); + if (auto i = keywords_.find(sym); i != keywords_.end()) return tok(i->second); // Split non-keyword into T_dot and M_id; M_id goes into cache_ for next lex(). assert(!cache_.has_value()); auto id_loc = loc(); ++id_loc.begin.col; - cache_.emplace(id_loc, Tok::Tag::M_id, world_.sym(str_.substr(1), id_loc)); + cache_.emplace(id_loc, Tok::Tag::M_id, world().sym(str_.substr(1))); return {loc().anew_begin(), Tok::Tag::T_dot}; } @@ -124,7 +125,7 @@ Tok Lexer::lex() { return tok(Tok::Tag::T_dot); } - if (lex_id()) return {loc(), Tok::Tag::M_id, world_.sym(str_, loc())}; + if (lex_id()) return {loc(), Tok::Tag::M_id, world().sym(str_)}; if (isdigit(ahead()) || issign(ahead())) { if (auto lit = parse_lit()) return *lit; diff --git a/thorin/fe/lexer.h b/thorin/fe/lexer.h index 6dfc97dcde..a3fa48ca16 100644 --- a/thorin/fe/lexer.h +++ b/thorin/fe/lexer.h @@ -2,16 +2,14 @@ #include -#include "thorin/debug.h" - #include "thorin/fe/tok.h" #include "thorin/util/utf8.h" namespace thorin { - class World; +} -namespace fe { +namespace thorin::fe { class Lexer : public utf8::Lexer<3> { using Super = utf8::Lexer<3>; @@ -19,10 +17,10 @@ class Lexer : public utf8::Lexer<3> { public: /// Creates a lexer to read Thorin files (see [Lexical Structure](@ref lex)). /// If @p md is not `nullptr`, a Markdown output will be generated. - Lexer(World& world, std::string_view file, std::istream& istream, std::ostream* md = nullptr); + Lexer(World& world, Sym file, std::istream& istream, std::ostream* md = nullptr); World& world() { return world_; } - std::string_view file() const { return loc_.file; } + Sym file() const { return loc_.file; } Loc loc() const { return loc_; } Tok lex(); @@ -56,9 +54,8 @@ class Lexer : public utf8::Lexer<3> { World& world_; std::ostream* md_; bool out_ = true; - absl::flat_hash_map keywords_; + SymMap keywords_; std::optional cache_; }; -} // namespace fe -} // namespace thorin +} // namespace thorin::fe diff --git a/thorin/fe/parser.cpp b/thorin/fe/parser.cpp index 892adb8c0b..0981244378 100644 --- a/thorin/fe/parser.cpp +++ b/thorin/fe/parser.cpp @@ -32,16 +32,17 @@ using namespace std::string_literals; namespace thorin::fe { Parser::Parser(World& world, - std::string_view file, + Sym file, std::istream& istream, Span import_search_paths, const Normalizers* normalizers, std::ostream* md) : lexer_(world, file, istream, md) , prev_(lexer_.loc()) - , bootstrapper_(std::filesystem::path{file}.filename().replace_extension("").string()) + , bootstrapper_(world.sym(std::filesystem::path{*file}.filename().replace_extension("").string())) , user_search_paths_(import_search_paths.begin(), import_search_paths.end()) - , normalizers_(normalizers) { + , normalizers_(normalizers) + , anonymous_(world.sym("_")) { for (size_t i = 0; i != Max_Ahead; ++i) lex(); prev_ = Loc(file, {1, 1}, {1, 1}); } @@ -80,13 +81,11 @@ void Parser::syntax_err(std::string_view what, const Tok& tok, std::string_view * entry points */ -Parser Parser::import_module(World& world, - std::string_view name, - Span user_search_paths, - const Normalizers* normalizers) { +Parser +Parser::import_module(World& world, Sym name, Span user_search_paths, const Normalizers* normalizers) { auto search_paths = get_plugin_search_paths(user_search_paths); - auto file_name = std::string(name) + ".thorin"; + auto file_name = *name + ".thorin"; std::string input_path{}; for (const auto& path : search_paths) { @@ -102,7 +101,7 @@ Parser Parser::import_module(World& world, if (!ifs) throw std::runtime_error("could not find file '" + file_name + "'"); - thorin::fe::Parser parser(world, input_path, ifs, user_search_paths, normalizers); + thorin::fe::Parser parser(world, world.sym(input_path), ifs, user_search_paths, normalizers); parser.parse_module(); world.add_imported(name); @@ -127,27 +126,25 @@ void Parser::parse_import() { eat(Tok::Tag::K_import); auto name = expect(Tok::Tag::M_id, "import name"); expect(Tok::Tag::T_semicolon, "end of import"); - auto name_str = name.sym().to_string(); if (auto [_, ins] = imported_.emplace(name.sym()); !ins) return; // search file and import - auto parser = Parser::import_module(world(), name_str, user_search_paths_, normalizers_); + auto parser = Parser::import_module(world(), name.sym(), user_search_paths_, normalizers_); scopes_.merge(parser.scopes_); // transitvely remember which files we transitively imported imported_.merge(parser.imported_); } -Sym Parser::parse_sym(std::string_view ctxt) { - auto track = tracker(); - if (auto id = accept(Tok::Tag::M_id)) return id->sym(); +Dbg Parser::parse_sym(std::string_view ctxt) { + if (auto id = accept(Tok::Tag::M_id)) return {id->dbg()}; syntax_err("identifier", ctxt); - return world().sym("", world().dbg(track.loc())); + return {prev_, world().sym("")}; } -const Def* Parser::parse_type_ascr(std::string_view ctxt, Implicits* implicits) { - if (accept(Tok::Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot, implicits); +Ref Parser::parse_type_ascr(std::string_view ctxt) { + if (accept(Tok::Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot); if (ctxt.empty()) return nullptr; syntax_err("':'", ctxt); } @@ -156,13 +153,13 @@ const Def* Parser::parse_type_ascr(std::string_view ctxt, Implicits* implicits) * exprs */ -const Def* Parser::parse_expr(std::string_view ctxt, Tok::Prec p, Implicits* implicits) { +Ref Parser::parse_expr(std::string_view ctxt, Tok::Prec p) { auto track = tracker(); - auto lhs = parse_primary_expr(ctxt, implicits); - return parse_infix_expr(track, lhs, p, implicits); + auto lhs = parse_primary_expr(ctxt); + return parse_infix_expr(track, lhs, p); } -const Def* Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p, Implicits* implicits) { +Ref Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p) { while (true) { // If operator in ahead has less left precedence: reduce (break). if (ahead().isa(Tok::Tag::T_extract)) { @@ -171,17 +168,16 @@ const Def* Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p, else break; } else if (ahead().isa(Tok::Tag::T_arrow)) { - if (implicits) implicits->emplace_back(false); auto [l, r] = Tok::prec(Tok::Prec::Arrow); if (l < p) break; lex(); - auto rhs = parse_expr("right-hand side of an function type", r, implicits); - lhs = world().pi(lhs, rhs, track.dbg()); + auto rhs = parse_expr("right-hand side of an function type", r); + lhs = world().pi(lhs, rhs)->set(track.loc()); } else { auto [l, r] = Tok::prec(Tok::Prec::App); if (l < p) break; if (auto rhs = parse_expr({}, r)) { // if we can parse an expression, it's an App - lhs = world().iapp(lhs, rhs, track.loc()); + lhs = world().iapp(lhs, rhs)->set(track.loc()); } else { return lhs; } @@ -191,32 +187,32 @@ const Def* Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p, return lhs; } -const Def* Parser::parse_extract(Tracker track, const Def* lhs, Tok::Prec p) { +Ref Parser::parse_extract(Tracker track, const Def* lhs, Tok::Prec p) { auto [l, r] = Tok::prec(Tok::Prec::Extract); if (l < p) return nullptr; lex(); if (ahead().isa(Tok::Tag::M_id)) { if (auto sigma = lhs->type()->isa_nom()) { - auto sym = eat(Tok::Tag::M_id).sym(); - if (sym.is_anonymous()) err(sym.loc(), "you cannot use special symbol '_' as field access"); - - auto meta = sigma->meta(); - if (meta->arity() == sigma->arity()) { - size_t a = sigma->num_ops(); - for (size_t i = 0; i != a; ++i) { - if (meta->proj(a, i) == sym) return world().extract(lhs, a, i, track.dbg()); + auto tok = eat(Tok::Tag::M_id); + if (tok.sym() == '_') err(tok.loc(), "you cannot use special symbol '_' as field access"); + + if (auto i = def2fields_.find(sigma); i != def2fields_.end()) { + if (auto& fields = i->second; fields.size() == sigma->num_ops()) { + for (size_t i = 0, n = sigma->num_ops(); i != n; ++i) { + if (fields[i] == tok.sym()) return world().extract(lhs, n, i)->set(track.loc()); + } } } - err(sym.loc(), "could not find elemement '{}' to extract from '{}' of type '{}'", sym, lhs, sigma); + err(tok.loc(), "could not find elemement '{}' to extract from '{}' of type '{}'", tok.sym(), lhs, sigma); } } auto rhs = parse_expr("right-hand side of an extract", r); - return world().extract(lhs, rhs, track.dbg()); + return world().extract(lhs, rhs)->set(track.loc()); } -const Def* Parser::parse_insert() { +Ref Parser::parse_insert() { eat(Tok::Tag::K_ins); auto track = tracker(); @@ -228,10 +224,10 @@ const Def* Parser::parse_insert() { auto value = parse_expr("insert value"); expect(Tok::Tag::D_paren_r, "closing paren for insert arguments"); - return world().insert(tuple, index, value, track.dbg()); + return world().insert(tuple, index, value)->set(track.loc()); } -const Def* Parser::parse_primary_expr(std::string_view ctxt, Implicits* implicits) { +Ref Parser::parse_primary_expr(std::string_view ctxt) { // clang-format off switch (ahead().tag()) { case Tok::Tag::D_quote_l: return parse_arr(); @@ -247,7 +243,7 @@ const Def* Parser::parse_primary_expr(std::string_view ctxt, Implicits* implicit case Tok::Tag::K_Nat: lex(); return world().type_nat(); case Tok::Tag::K_ff: lex(); return world().lit_ff(); case Tok::Tag::K_tt: lex(); return world().lit_tt(); - case Tok::Tag::T_Pi: return parse_pi(implicits); + case Tok::Tag::T_Pi: return parse_pi(); case Tok::Tag::T_at: return parse_var(); case Tok::Tag::K_cn: case Tok::Tag::K_fn: @@ -262,11 +258,7 @@ const Def* Parser::parse_primary_expr(std::string_view ctxt, Implicits* implicit case Tok::Tag::M_id: return scopes_.find(parse_sym()); case Tok::Tag::M_i: return lex().index(); case Tok::Tag::K_ins: return parse_insert(); - case Tok::Tag::M_ax: { - auto tok = lex(); - auto s = tok.sym().to_string(); - return scopes_.find(tok.sym()); - } + case Tok::Tag::M_ax: return scopes_.find(lex().dbg()); default: if (ctxt.empty()) return nullptr; syntax_err("primary expression", ctxt); @@ -275,23 +267,22 @@ const Def* Parser::parse_primary_expr(std::string_view ctxt, Implicits* implicit return nullptr; } -const Def* Parser::parse_Cn() { +Ref Parser::parse_Cn() { auto track = tracker(); eat(Tok::Tag::K_Cn); auto dom = parse_ptrn(Tok::Tag::D_brckt_l, "domain of a continuation type"); - return world().cn(dom->type(world()), track.dbg()); + return world().cn(dom->type(world(), def2fields_))->set(track.loc()); } -const Def* Parser::parse_var() { - auto track = tracker(); +Ref Parser::parse_var() { eat(Tok::Tag::T_at); - auto sym = parse_sym("variable"); - auto nom = scopes_.find(sym)->isa_nom(); + auto dbg = parse_sym("variable"); + auto nom = scopes_.find(dbg)->isa_nom(); if (!nom) err(prev_, "variable must reference a nominal"); - return nom->var(track.named(sym)); + return nom->var()->set(dbg); } -const Def* Parser::parse_arr() { +Ref Parser::parse_arr() { auto track = tracker(); scopes_.push(); eat(Tok::Tag::D_quote_l); @@ -299,13 +290,13 @@ const Def* Parser::parse_arr() { const Def* shape = nullptr; Arr* arr = nullptr; if (ahead(0).isa(Tok::Tag::M_id) && ahead(1).isa(Tok::Tag::T_colon)) { - auto id = eat(Tok::Tag::M_id).sym(); + auto id = eat(Tok::Tag::M_id); eat(Tok::Tag::T_colon); auto shape = parse_expr("shape of an array"); auto type = world().nom_infer_univ(); arr = world().nom_arr(type)->set_shape(shape); - scopes_.bind(id, arr->var(world().dbg(id))); + scopes_.bind(id.dbg(), arr->var()->set(id.dbg())); } else { shape = parse_expr("shape of an array"); } @@ -316,10 +307,10 @@ const Def* Parser::parse_arr() { scopes_.pop(); if (arr) return arr->set_body(body); - return world().arr(shape, body, track.dbg()); + return world().arr(shape, body)->set(track.loc()); } -const Def* Parser::parse_pack() { +Ref Parser::parse_pack() { // TODO This doesn't work. Rework this! auto track = tracker(); scopes_.push(); @@ -328,12 +319,12 @@ const Def* Parser::parse_pack() { const Def* shape; // bool nom = false; if (ahead(0).isa(Tok::Tag::M_id) && ahead(1).isa(Tok::Tag::T_colon)) { - auto sym = eat(Tok::Tag::M_id).sym(); + auto id = eat(Tok::Tag::M_id); eat(Tok::Tag::T_colon); shape = parse_expr("shape of a pack"); - auto infer = world().nom_infer(world().type_idx(shape), sym); - scopes_.bind(sym, infer); + auto infer = world().nom_infer(world().type_idx(shape))->set(id.sym()); + scopes_.bind(id.dbg(), infer); } else { shape = parse_expr("shape of a pack"); } @@ -342,10 +333,10 @@ const Def* Parser::parse_pack() { auto body = parse_expr("body of a pack"); expect(Tok::Tag::D_angle_r, "closing delimiter of a pack"); scopes_.pop(); - return world().pack(shape, body, track.dbg()); + return world().pack(shape, body)->set(track.loc()); } -const Def* Parser::parse_block() { +Ref Parser::parse_block() { scopes_.push(); eat(Tok::Tag::D_brace_l); auto res = parse_decls("block expression"); @@ -354,28 +345,28 @@ const Def* Parser::parse_block() { return res; } -const Def* Parser::parse_sigma() { +Ref Parser::parse_sigma() { auto track = tracker(); - auto bndr = parse_tuple_ptrn(track, false, anonymous_sym()); - return bndr->type(world()); + auto bndr = parse_tuple_ptrn(track, false, anonymous_); + return bndr->type(world(), def2fields_); } -const Def* Parser::parse_tuple() { +Ref Parser::parse_tuple() { auto track = tracker(); DefVec ops; parse_list("tuple", Tok::Tag::D_paren_l, [&]() { ops.emplace_back(parse_expr("tuple element")); }); - return world().tuple(ops, track.dbg()); + return world().tuple(ops)->set(track.loc()); } -const Def* Parser::parse_type() { +Ref Parser::parse_type() { auto track = tracker(); eat(Tok::Tag::K_Type); auto [l, r] = Tok::prec(Tok::Prec::App); auto level = parse_expr("type level", r); - return world().type(level, track.dbg()); + return world().type(level)->set(track.loc()); } -const Def* Parser::parse_pi(Implicits* implicits) { +Ref Parser::parse_pi() { auto track = tracker(); eat(Tok::Tag::T_Pi); scopes_.push(); @@ -383,35 +374,31 @@ const Def* Parser::parse_pi(Implicits* implicits) { Pi* first = nullptr; std::deque pis; do { - auto dot = accept(Tok::Tag::T_dot); - if (implicits) - implicits->emplace_back(dot.has_value()); - else if (dot) - err(dot->loc(), "implicit not allowed in this context"); - - auto dom = parse_ptrn(Tok::Tag::D_brckt_l, "domain of a dependent function type", Tok::Prec::App); - auto pi = world().nom_pi(world().type_infer_univ(), dom->dbg(world()))->set_dom(dom->type(world())); - auto var = pi->var(world().dbg(dom->sym())); - first = first ? first : pi; + auto implicit = accept(Tok::Tag::T_dot).has_value(); + auto dom = parse_ptrn(Tok::Tag::D_brckt_l, "domain of a dependent function type", Tok::Prec::App); + auto pi = world().nom_pi(world().type_infer_univ(), implicit)->set_dom(dom->type(world(), def2fields_)); + auto var = pi->var()->set(dom->sym()); + first = first ? first : pi; + pi->set(dom->dbg()); dom->bind(scopes_, var); pis.emplace_back(pi); } while (!ahead().isa(Tok::Tag::T_arrow)); expect(Tok::Tag::T_arrow, "dependent function type"); - auto codom = parse_expr("codomain of a dependent function type", Tok::Prec::Arrow, implicits); + auto codom = parse_expr("codomain of a dependent function type", Tok::Prec::Arrow); for (auto pi : pis | std::ranges::views::reverse) { pi->set_codom(codom); codom = pi; } - first->set_dbg(track.dbg()); + first->set(track.loc()); scopes_.pop(); return first; } -const Def* Parser::parse_lit() { +Ref Parser::parse_lit() { auto track = tracker(); auto lit = lex(); auto [_, r] = Tok::prec(Tok::Prec::Lit); @@ -419,26 +406,25 @@ const Def* Parser::parse_lit() { if (accept(Tok::Tag::T_colon)) { auto type = parse_expr("literal", r); - const Def* meta = nullptr; // clang-format off switch (lit.tag()) { - case Tok::Tag::L_s: meta = world().lit_nat('s'); break; - case Tok::Tag::L_u: meta = world().lit_nat('u'); break; - case Tok::Tag::L_r: meta = world().lit_nat('r'); break; - case Tok::Tag::T_bot: return world().bot(type, track.dbg()); - case Tok::Tag::T_top: return world().top(type, track.dbg()); + case Tok::Tag::L_s: + case Tok::Tag::L_u: + case Tok::Tag::L_r: break; + case Tok::Tag::T_bot: return world().bot(type)->set(track.loc()); + case Tok::Tag::T_top: return world().top(type)->set(track.loc()); default: unreachable(); } // clang-format on - return world().lit(type, lit.u(), track.meta(meta)); + return world().lit(type, lit.u())->set(track.loc()); } - if (lit.tag() == Tok::Tag::T_bot) return world().bot(world().type(), track.dbg()); - if (lit.tag() == Tok::Tag::T_top) return world().top(world().type(), track.dbg()); + if (lit.tag() == Tok::Tag::T_bot) return world().bot(world().type())->set(track.loc()); + if (lit.tag() == Tok::Tag::T_top) return world().top(world().type())->set(track.loc()); if (lit.tag() == Tok::Tag::L_s) err(prev_, ".Nat literal specified as signed but must be unsigned"); if (lit.tag() == Tok::Tag::L_r) err(prev_, ".Nat literal specified as floating-point but must be unsigned"); - return world().lit_nat(lit.u(), track.dbg()); + return world().lit_nat(lit.u())->set(track.loc()); } /* @@ -447,7 +433,7 @@ const Def* Parser::parse_lit() { std::unique_ptr Parser::parse_ptrn(Tok::Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) { auto track = tracker(); - auto sym = anonymous_sym(); + auto sym = anonymous_; bool p = delim_l == Tok::Tag::D_paren_l; bool b = delim_l == Tok::Tag::D_brckt_l; assert((p ^ b) && "left delimiter must either be '(' or '['"); @@ -498,7 +484,7 @@ std::unique_ptr Parser::parse_ptrn(Tok::Tag delim_l, std::string_view ctxt sym = eat(Tok::Tag::M_id).sym(); eat(Tok::Tag::T_colon); auto type = parse_expr(ctxt, prec); - return std::make_unique(track.loc(), rebind, sym, type); + return std::make_unique(track.dbg(sym), rebind, type); } else { // p -> s b -> e where e == id // p -> 's @@ -506,18 +492,18 @@ std::unique_ptr Parser::parse_ptrn(Tok::Tag delim_l, std::string_view ctxt // p -> s // p -> 's sym = eat(Tok::Tag::M_id).sym(); - return std::make_unique(track.loc(), rebind, sym, nullptr); + return std::make_unique(track.dbg(sym), rebind, nullptr); } else { // b -> e where e == id auto type = parse_expr(ctxt, prec); - return std::make_unique(track.loc(), rebind, sym, type); + return std::make_unique(track.dbg(sym), rebind, type); } } } else if (b) { // b -> e where e != id if (apos) err(apos->loc(), "you can only prefix identifiers with apostrophe for rebinding"); auto type = parse_expr(ctxt, prec); - return std::make_unique(track.loc(), rebind, sym, type); + return std::make_unique(track.dbg(sym), rebind, type); } else if (!ctxt.empty()) { // p -> ↯ syntax_err("pattern", ctxt); @@ -533,7 +519,6 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, assert(p ^ b); std::deque> ptrns; - std::vector fields; std::vector infers; DefVec ops; @@ -543,32 +528,30 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, if (!ptrns.empty()) ptrns.back()->bind(scopes_, infers.back()); if (p && ahead(0).isa(Tok::Tag::M_id) && ahead(1).isa(Tok::Tag::M_id)) { - std::vector syms; - while (auto tok = accept(Tok::Tag::M_id)) syms.emplace_back(tok->sym()); + std::vector sym_toks; + while (auto tok = accept(Tok::Tag::M_id)) sym_toks.emplace_back(*tok); expect(Tok::Tag::T_colon, "type ascription of an identifier group within a tuple pattern"); auto type = parse_expr("type of an identifier group within a tuple pattern"); - for (auto sym : syms) { - infers.emplace_back(world().nom_infer(type, sym)); - fields.emplace_back(sym.str()); + for (auto tok : sym_toks) { + infers.emplace_back(world().nom_infer(type)->set(tok.dbg())); ops.emplace_back(type); - ptrns.emplace_back(std::make_unique(sym.loc(), false, sym, type)); + ptrns.emplace_back(std::make_unique(tok.dbg(), false, type)); } } else { auto ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); - auto type = ptrn->type(world()); + auto type = ptrn->type(world(), def2fields_); if (b) { // If we are able to parse more stuff, we got an expression instead of just a binder. if (auto expr = parse_infix_expr(track, type); expr != type) { - ptrn = std::make_unique(track.loc(), false, anonymous_sym(), expr); - type = ptrn->type(world()); + ptrn = std::make_unique(track.dbg(anonymous_), false, expr); + type = ptrn->type(world(), def2fields_); } } - infers.emplace_back(world().nom_infer(type, ptrn->sym())); - fields.emplace_back(ptrn->sym().str()); + infers.emplace_back(world().nom_infer(type)->set(ptrn->sym())); ops.emplace_back(type); ptrns.emplace_back(std::move(ptrn)); } @@ -576,14 +559,14 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, scopes_.pop(); // TODO parse type - return std::make_unique(track.loc(), rebind, sym, std::move(ptrns), nullptr, std::move(infers)); + return std::make_unique(track.dbg(sym), rebind, std::move(ptrns), nullptr, std::move(infers)); } /* * decls */ -const Def* Parser::parse_decls(std::string_view ctxt) { +Ref Parser::parse_decls(std::string_view ctxt) { while (true) { // clang-format off switch (ahead().tag()) { @@ -605,19 +588,15 @@ const Def* Parser::parse_decls(std::string_view ctxt) { } void Parser::parse_ax() { - using namespace std::string_view_literals; auto track = tracker(); eat(Tok::Tag::K_ax); - auto ax = expect(Tok::Tag::M_ax, "name of an axiom"); - auto ax_str = ax.sym().to_string(); - auto split = Axiom::split(ax_str); - if (!split) err(ax.loc(), "invalid axiom name '{}'", ax); - - auto [dialect, tag, sub] = *split; + auto ax = expect(Tok::Tag::M_ax, "name of an axiom"); + auto [dialect, tag, sub] = Axiom::split(world(), ax.sym()); - if (!sub.empty()) err(ax.loc(), "definition of axiom '{}' must not have sub in tag name", ax); + if (!dialect) err(ax.loc(), "invalid axiom name '{}'", ax); + if (sub) err(ax.loc(), "definition of axiom '{}' must not have sub in tag name", ax); - auto [it, is_new] = bootstrapper_.axioms.emplace(ax_str, h::AxiomInfo{}); + auto [it, is_new] = bootstrapper_.axioms.emplace(ax.sym(), h::AxiomInfo{}); auto& [key, info] = *it; if (is_new) { info.dialect = dialect; @@ -634,12 +613,16 @@ void Parser::parse_ax() { if (bootstrapper_.axioms.size() >= std::numeric_limits::max()) err(ax.loc(), "exceeded maxinum number of axioms in current dialect"); - std::deque> new_subs; + std::deque> new_subs; if (ahead().isa(Tok::Tag::D_paren_l)) { parse_list("tag list of an axiom", Tok::Tag::D_paren_l, [&]() { auto& aliases = new_subs.emplace_back(); - aliases.emplace_back(parse_sym("tag of an axiom")); - while (accept(Tok::Tag::T_assign)) aliases.emplace_back(parse_sym("alias of an axiom tag")); + auto [_, tag] = parse_sym("tag of an axiom"); + aliases.emplace_back(tag); + while (accept(Tok::Tag::T_assign)) { + auto [_, alias] = parse_sym("alias of an axiom tag"); + aliases.emplace_back(alias); + } }); } @@ -648,16 +631,14 @@ void Parser::parse_ax() { else if (!is_new && !new_subs.empty() && info.subs.empty()) err(ax.loc(), "cannot extend subs of axiom '{}' which does not have subs", ax); - Implicits implicits; - auto type = parse_type_ascr("type ascription of an axiom", &implicits); - auto meta = world().implicits2meta(implicits); + auto type = parse_type_ascr("type ascription of an axiom"); if (!is_new && info.pi != (type->isa() != nullptr)) err(ax.loc(), "all declarations of axiom '{}' have to be function types if any is", ax); info.pi = type->isa() != nullptr; - auto normalizer_name = (accept(Tok::Tag::T_comma) ? parse_sym("normalizer of an axiom") : Sym()).to_string(); - if (!is_new && !(info.normalizer.empty() || normalizer_name.empty()) && info.normalizer != normalizer_name) - err(ax.loc(), "all declarations of axiom '{}' have use the same normalizer name", ax); + auto normalizer_name = accept(Tok::Tag::T_comma) ? parse_sym("normalizer of an axiom").sym : Sym(); + if (!is_new && (info.normalizer && normalizer_name) && info.normalizer != normalizer_name) + err(ax.loc(), "all declarations of axiom '{}' must use the same normalizer name", ax); info.normalizer = normalizer_name; auto normalizer = [this](dialect_t d, tag_t t, sub_t s) -> Def::NormalizeFn { @@ -680,15 +661,15 @@ void Parser::parse_ax() { tag_t t = info.tag_id; sub_t s = info.subs.size(); if (new_subs.empty()) { - auto axiom = world().axiom(normalizer(d, t, 0), curry, trip, type, d, t, 0, track.named(ax.sym(), meta)); - scopes_.bind(ax.sym(), axiom); + auto axiom = world().axiom(normalizer(d, t, 0), curry, trip, type, d, t, 0)->set(ax.loc(), ax.sym()); + scopes_.bind(ax.dbg(), axiom); } else { for (const auto& sub : new_subs) { - auto dbg = track.named(ax_str + "."s + sub.front(), meta); - auto axiom = world().axiom(normalizer(d, t, s), curry, trip, type, d, t, s, dbg); + auto name = world().sym(*ax.sym() + "."s + *sub.front()); + auto axiom = world().axiom(normalizer(d, t, s), curry, trip, type, d, t, s)->set(track.loc(), name); for (auto& alias : sub) { - Sym name(world().tuple_str(ax_str + "."s + alias), prev_.def(world())); - scopes_.bind(name, axiom); + auto sym = world().sym(*ax.sym() + "."s + *alias); + scopes_.bind({prev_, sym}, axiom); } ++s; } @@ -710,7 +691,7 @@ void Parser::parse_nom() { auto track = tracker(); auto tag = lex().tag(); bool external = accept(Tok::Tag::K_extern).has_value(); - auto sym = parse_sym("nominal"); + auto dbg = parse_sym("nominal"); auto type = accept(Tok::Tag::T_colon) ? parse_expr("type of a nominal") : world().type(); Def* nom; @@ -718,32 +699,32 @@ void Parser::parse_nom() { case Tok::Tag::K_Sigma: { expect(Tok::Tag::T_comma, "nominal Sigma"); auto arity = expect(Tok::Tag::L_u, "arity of a nominal Sigma"); - nom = world().nom_sigma(type, arity.u(), track.named(sym)); + nom = world().nom_sigma(type, arity.u())->set(dbg); break; } case Tok::Tag::K_Arr: { expect(Tok::Tag::T_comma, "nominal array"); auto shape = parse_expr("shape of a nominal array"); - nom = world().nom_arr(type, track.dbg())->set_shape(shape); + nom = world().nom_arr(type)->set(track.loc())->set_shape(shape); break; } - case Tok::Tag::K_pack: nom = world().nom_pack(type, track.named(sym)); break; + case Tok::Tag::K_pack: nom = world().nom_pack(type)->set(dbg); break; case Tok::Tag::K_Pi: { expect(Tok::Tag::T_comma, "nominal Pi"); auto dom = parse_expr("domain of a nominal Pi"); - nom = world().nom_pi(type, track.named(sym))->set_dom(dom); + nom = world().nom_pi(type)->set(dbg)->set_dom(dom); break; } default: unreachable(); } - scopes_.bind(sym, nom); + scopes_.bind(dbg, nom); scopes_.push(); if (external) nom->make_external(); scopes_.push(); if (ahead().isa(Tok::Tag::T_assign)) - parse_def(sym); + parse_def(dbg); else expect(Tok::Tag::T_semicolon, "end of a nominal"); @@ -758,29 +739,25 @@ Lam* Parser::parse_lam(bool decl) { bool is_cn = tok.isa(Tok::Tag::K_cn) || tok.isa(Tok::Tag::K_con); auto prec = is_cn ? Tok::Prec::Bot : Tok::Prec::Pi; bool external = decl && accept(Tok::Tag::K_extern).has_value(); - Sym sym = decl ? parse_sym("nominal lambda") : anonymous_sym(); + auto dbg = decl ? parse_sym("nominal lambda") : Dbg{prev_, anonymous_}; auto outer = scopes_.curr(); scopes_.push(); std::deque> funs; Lam* first = nullptr; - Implicits implicits; - bool has_implicits = false; do { const Def* filter = world().lit_bool(accept(Tok::Tag::T_bang).has_value()); - bool dot = accept(Tok::Tag::T_dot).has_value(); + bool implicit = accept(Tok::Tag::T_dot).has_value(); auto dom_p = parse_ptrn(Tok::Tag::D_paren_l, "domain pattern of a lambda", prec); - auto dom_t = dom_p->type(world()); - auto pi = world().nom_pi(world().type_infer_univ())->set_dom(dom_t); - auto lam = world().nom_lam(pi, first == nullptr ? track.named(sym) : nullptr); - auto lam_var = lam->var(dom_p->dbg(world())); - - has_implicits |= dot; - implicits.emplace_back(dot); + auto dom_t = dom_p->type(world(), def2fields_); + auto pi = world().nom_pi(world().type_infer_univ(), implicit)->set_dom(dom_t); + auto lam = world().nom_lam(pi); + auto lam_var = lam->var()->set(dom_p->loc(), dom_p->sym()); if (first == nullptr) { first = lam; + lam->set(dbg.sym); if (external) first->make_external(); } @@ -801,12 +778,6 @@ Lam* Parser::parse_lam(bool decl) { } while (!ahead().isa(Tok::Tag::T_arrow) && !ahead().isa(Tok::Tag::T_assign) && !ahead().isa(Tok::Tag::T_semicolon)); - if (has_implicits) { - auto debug = first->debug(); - debug.meta = world().implicits2meta(implicits); - first->set_dbg(debug.def(world())); - } - auto codom = is_cn ? world().type_bot() : accept(Tok::Tag::T_arrow) ? parse_expr("return type of a lambda", Tok::Prec::Arrow) : world().nom_infer_type(); @@ -815,7 +786,7 @@ Lam* Parser::parse_lam(bool decl) { pi->set_codom(codom); Scope scope(lam); ScopeRewriter rw(world(), scope); - rw.map(lam->var(), pi->var(lam->var()->dbg())); + rw.map(lam->var(), pi->var()->set(lam->var()->dbg())); // Now update. codom = rw.rewrite(codom); @@ -824,7 +795,7 @@ Lam* Parser::parse_lam(bool decl) { codom = pi; } - scopes_.bind(outer, sym, first); + scopes_.bind(outer, dbg, first); auto body = accept(Tok::Tag::T_assign) ? parse_decls("body of a lambda") : nullptr; if (!body) { @@ -840,17 +811,19 @@ Lam* Parser::parse_lam(bool decl) { if (decl) expect(Tok::Tag::T_semicolon, "end of lambda"); + first->set(track.loc()); + scopes_.pop(); return first; } -void Parser::parse_def(Sym sym /*= {}*/) { - if (!sym) { +void Parser::parse_def(Dbg dbg /*= {}*/) { + if (!dbg.sym) { eat(Tok::Tag::K_def); - sym = parse_sym("nominal definition"); + dbg = parse_sym("nominal definition"); } - auto nom = scopes_.find(sym)->as_nom(); + auto nom = scopes_.find(dbg)->as_nom(); expect(Tok::Tag::T_assign, "nominal definition"); size_t i = nom->first_dependend_op(); diff --git a/thorin/fe/parser.h b/thorin/fe/parser.h index 916e5c1d44..8831193466 100644 --- a/thorin/fe/parser.h +++ b/thorin/fe/parser.h @@ -32,14 +32,13 @@ namespace thorin::fe { /// * If default argument is **provided** we have the same behavior as in 2. class Parser { public: - Parser(World&, std::string_view, std::istream&, Span, const Normalizers*, std::ostream* md = nullptr); + Parser(World&, Sym file, std::istream&, Span, const Normalizers*, std::ostream* md = nullptr); World& world() { return lexer_.world(); } /// @name entry points ///@{ - static Parser - import_module(World&, std::string_view, Span = {}, const Normalizers* normalizers = nullptr); + static Parser import_module(World&, Sym, Span = {}, const Normalizers* normalizers = nullptr); void parse_module(); void bootstrap(std::ostream&); ///@} @@ -55,44 +54,38 @@ class Parser { , pos_(pos) {} Loc loc() const { return {parser_.prev_.file, pos_, parser_.prev_.finis}; } - const Def* dbg(const Def* meta = {}) const { return parser_.world().dbg({"", loc(), meta}); } - const Def* meta(const Def* m) const { return parser_.world().dbg({"", loc(), m}); } - const Def* named(Sym sym) const { return parser_.world().dbg(sym, loc()); } - const Def* named(const std::string& str, const Def* meta = {}) const { - return parser_.world().dbg({str, loc(), meta}); - } + Dbg dbg(Sym sym) const { return {loc(), sym}; } private: Parser& parser_; Pos pos_; }; - Sym parse_sym(std::string_view ctxt = {}); - Sym anonymous_sym() { return {world().lit_nat('_'), nullptr}; } + Dbg parse_sym(std::string_view ctxt = {}); void parse_import(); - const Def* parse_type_ascr(std::string_view ctxt, Implicits*); + Ref parse_type_ascr(std::string_view ctxt); /// @name exprs ///@{ - const Def* parse_expr(std::string_view ctxt, Tok::Prec = Tok::Prec::Bot, Implicits* = {}); - const Def* parse_primary_expr(std::string_view ctxt, Implicits* = {}); - const Def* parse_infix_expr(Tracker, const Def* lhs, Tok::Prec = Tok::Prec::Bot, Implicits* = {}); - const Def* parse_extract(Tracker, const Def*, Tok::Prec); + Ref parse_expr(std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); + Ref parse_primary_expr(std::string_view ctxt); + Ref parse_infix_expr(Tracker, const Def* lhs, Tok::Prec = Tok::Prec::Bot); + Ref parse_extract(Tracker, const Def*, Tok::Prec); ///@} /// @name primary exprs ///@{ - const Def* parse_Cn(); - const Def* parse_arr(); - const Def* parse_pack(); - const Def* parse_block(); - const Def* parse_sigma(); - const Def* parse_tuple(); - const Def* parse_type(); - const Def* parse_pi(Implicits*); - const Def* parse_lit(); - const Def* parse_var(); - const Def* parse_insert(); + Ref parse_Cn(); + Ref parse_arr(); + Ref parse_pack(); + Ref parse_block(); + Ref parse_sigma(); + Ref parse_tuple(); + Ref parse_type(); + Ref parse_pi(); + Ref parse_lit(); + Ref parse_var(); + Ref parse_insert(); Lam* parse_lam(bool decl = false); ///@} @@ -106,13 +99,13 @@ class Parser { /// @name decls ///@{ - const Def* parse_decls(std::string_view ctxt); + Ref parse_decls(std::string_view ctxt); void parse_ax(); void parse_let(); void parse_nom(); /// If @p sym is **not** empty, this is an inline definition of @p sym, /// otherwise it's a standalone definition. - void parse_def(Sym sym = {}); + void parse_def(Dbg dbg = {}); ///@} template @@ -127,7 +120,6 @@ class Parser { /// Factory method to build a Parser::Tracker. Tracker tracker() { return Tracker(*this, ahead().loc().begin); } - const Def* dbg(Tracker t) { return world().dbg(t.loc()); } ///@} /// @name get next Tok @@ -167,6 +159,7 @@ class Parser { Lexer lexer_; Scopes scopes_; + Def2Fields def2fields_; Loc prev_; std::string dialect_; static constexpr size_t Max_Ahead = 2; ///< maximum lookahead @@ -175,6 +168,7 @@ class Parser { h::Bootstrapper bootstrapper_; std::vector user_search_paths_; const Normalizers* normalizers_; + Sym anonymous_; }; } // namespace thorin::fe diff --git a/thorin/fe/scopes.cpp b/thorin/fe/scopes.cpp index 11c07df062..2a7acaaea1 100644 --- a/thorin/fe/scopes.cpp +++ b/thorin/fe/scopes.cpp @@ -9,25 +9,26 @@ void Scopes::pop() { scopes_.pop_back(); } -const Def* Scopes::find(Sym sym) const { - if (sym.is_anonymous()) err(sym.loc(), "the symbol '_' is special and never binds to anything", sym); +const Def* Scopes::find(Dbg dbg) const { + auto [loc, sym] = dbg; + if (sym == '_') err(loc, "the symbol '_' is special and never binds to anything", sym); for (auto& scope : scopes_ | std::ranges::views::reverse) { - if (auto i = scope.find(sym); i != scope.end()) return i->second; + if (auto i = scope.find(sym); i != scope.end()) return i->second.second; } - err(sym.to_loc(), "symbol '{}' not found", sym); + err(loc, "symbol '{}' not found", sym); } -void Scopes::bind(Scope* scope, Sym sym, const Def* def, bool rebind) { - if (sym.is_anonymous()) return; // don't do anything with '_' +void Scopes::bind(Scope* scope, Dbg dbg, const Def* def, bool rebind) { + auto [loc, sym] = dbg; + if (sym == '_') return; // don't do anything with '_' if (rebind) { - (*scope)[sym] = def; - } else if (auto [i, ins] = scope->emplace(sym, def); !ins) { - auto curr = sym.to_loc(); - auto prev = i->first.to_loc(); - err(curr, "symbol '{}' already declared in the current scope here: {}", sym, prev); + (*scope)[sym] = std::pair(loc, def); + } else if (auto [i, ins] = scope->emplace(sym, std::pair(loc, def)); !ins) { + auto prev = i->second.first; + err(loc, "symbol '{}' already declared in the current scope here: {}", sym, prev); } } diff --git a/thorin/fe/scopes.h b/thorin/fe/scopes.h index 1c8a7da50a..509ab1fa08 100644 --- a/thorin/fe/scopes.h +++ b/thorin/fe/scopes.h @@ -2,22 +2,26 @@ #include -#include "thorin/debug.h" +#include "thorin/util/loc.h" -namespace thorin::fe { +namespace thorin { + +class Def; + +namespace fe { class Scopes { public: - using Scope = SymMap; + using Scope = SymMap>; Scopes() { push(); /* root scope */ } void push() { scopes_.emplace_back(); } void pop(); Scope* curr() { return &scopes_.back(); } - const Def* find(Sym) const; - void bind(Scope*, Sym sym, const Def*, bool rebind = false); - void bind(Sym sym, const Def* def, bool rebind = false) { bind(&scopes_.back(), sym, def, rebind); } + const Def* find(Dbg) const; + void bind(Scope*, Dbg, const Def*, bool rebind = false); + void bind(Dbg dbg, const Def* def, bool rebind = false) { bind(&scopes_.back(), dbg, def, rebind); } void merge(Scopes&); void swap(Scope& other) { std::swap(scopes_.back(), other); } @@ -25,4 +29,5 @@ class Scopes { std::deque scopes_; }; -} // namespace thorin::fe +} // namespace fe +} // namespace thorin diff --git a/thorin/fe/tok.h b/thorin/fe/tok.h index 7306f62528..a6ea5a38eb 100644 --- a/thorin/fe/tok.h +++ b/thorin/fe/tok.h @@ -1,11 +1,15 @@ #pragma once -#include "thorin/debug.h" - #include "thorin/util/assert.h" +#include "thorin/util/loc.h" +#include "thorin/util/sym.h" #include "thorin/util/types.h" -namespace thorin::fe { +namespace thorin { + +class Def; + +namespace fe { // clang-format off #define THORIN_KEY(m) \ @@ -161,9 +165,10 @@ class Tok { , tag_(Tag::M_i) , index_(index) {} - Loc loc() const { return loc_; } - Tag tag() const { return tag_; } bool isa(Tag tag) const { return tag == tag_; } + Tag tag() const { return tag_; } + Dbg dbg() const { return {loc(), sym()}; } + Loc loc() const { return loc_; } // clang-format off u64 u() const { assert(isa(Tag::L_u ) || isa(Tag::L_s) || isa(Tag::L_r)); return u_; } Sym sym() const { assert(isa(Tag::M_id) || isa(Tag::M_ax)); return sym_; } @@ -181,4 +186,5 @@ class Tok { }; }; -} // namespace thorin::fe +} // namespace fe +} // namespace thorin diff --git a/thorin/flags.h b/thorin/flags.h index 3182a49618..4206085a74 100644 --- a/thorin/flags.h +++ b/thorin/flags.h @@ -1,5 +1,7 @@ #pragma once +#include "thorin/config.h" + namespace thorin { // Compiler switches that must be saved and looked up in later phases of compilation. diff --git a/thorin/lam.cpp b/thorin/lam.cpp index 7aae6ee62b..e130b1942a 100644 --- a/thorin/lam.cpp +++ b/thorin/lam.cpp @@ -8,9 +8,9 @@ namespace thorin { * Pi */ -const Pi* Pi::ret_pi(const Def* dbg) const { +const Pi* Pi::ret_pi() const { if (num_doms() > 0) { - auto ret = dom(num_doms() - 1, dbg); + auto ret = dom(num_doms() - 1); if (auto pi = ret->isa(); pi != nullptr && pi->is_basicblock()) return pi; } @@ -24,7 +24,7 @@ bool Pi::is_cn() const { return codom()->isa(); } * Lam */ -const Def* Lam::ret_var(const Def* dbg) { return type()->ret_pi() ? var(num_vars() - 1, dbg) : nullptr; } +const Def* Lam::ret_var() { return type()->ret_pi() ? var(num_vars() - 1) : nullptr; } Lam* Lam::set_filter(Filter filter) { const Def* f; @@ -35,18 +35,18 @@ Lam* Lam::set_filter(Filter filter) { return Def::set(0, f)->as(); } -Lam* Lam::app(Filter f, const Def* callee, const Def* arg, const Def* dbg) { +Lam* Lam::app(Filter f, const Def* callee, const Def* arg) { assert(isa_nom() && !filter()); set_filter(f); - return set_body(world().app(callee, arg, dbg)); + return set_body(world().app(callee, arg)); } -Lam* Lam::app(Filter filter, const Def* callee, Defs args, const Def* dbg) { - return app(filter, callee, world().tuple(args), dbg); +Lam* Lam::app(Filter filter, const Def* callee, Defs args) { + return app(filter, callee, world().tuple(args)); } -Lam* Lam::branch(Filter filter, const Def* cond, const Def* t, const Def* f, const Def* mem, const Def* dbg) { - return app(filter, world().select(t, f, cond), mem, dbg); +Lam* Lam::branch(Filter filter, const Def* cond, const Def* t, const Def* f, const Def* mem) { + return app(filter, world().select(t, f, cond), mem); } Lam* Lam::test(Filter filter, @@ -54,9 +54,8 @@ Lam* Lam::test(Filter filter, const Def* index, const Def* match, const Def* clash, - const Def* mem, - const Def* dbg) { - return app(filter, world().test(value, index, match, clash), mem, dbg); + const Def* mem) { + return app(filter, world().test(value, index, match, clash), mem); } std::deque decurry(const Def* def) { diff --git a/thorin/lam.h b/thorin/lam.h index a8531a20b1..9c8e4eb6af 100644 --- a/thorin/lam.h +++ b/thorin/lam.h @@ -10,14 +10,14 @@ namespace thorin { class Pi : public Def { protected: /// Constructor for a *structural* Pi. - Pi(const Def* type, const Def* dom, const Def* codom, const Def* dbg) - : Def(Node, type, {dom, codom}, 0, dbg) {} + Pi(const Def* type, const Def* dom, const Def* codom, bool implicit) + : Def(Node, type, {dom, codom}, implicit ? 1 : 0) {} /// Constructor for a *nom*inal Pi. - Pi(const Def* type, const Def* dbg) - : Def(Node, type, 2, 0, dbg) {} + Pi(const Def* type, bool implicit) + : Def(Node, type, 2, implicit ? 1 : 0) {} public: - /// @name ops + /// @name getters ///@{ const Def* dom() const { return op(0); } THORIN_PROJ(dom, const) @@ -26,7 +26,8 @@ class Pi : public Def { bool is_cn() const; bool is_basicblock() const { return is_cn() && !ret_pi(); } bool is_returning() const { return is_cn() && ret_pi(); } - const Pi* ret_pi(const Def* dbg = {}) const; + const Pi* ret_pi() const; + bool implicit() const { return flags(); } ///@} /// @name setters @@ -40,23 +41,21 @@ class Pi : public Def { /// @name virtual methods ///@{ - size_t first_dependend_op() { return 1; } - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - Pi* stub(World&, const Def*, const Def*) override; + size_t first_dependend_op() override { return 1; } const Pi* restructure() override; void check() override; ///@} - static constexpr auto Node = Node::Pi; - friend class World; + THORIN_DEF_MIXIN(Pi) + Pi* stub_(World&, Ref) override; }; class Lam : public Def { private: - Lam(const Pi* pi, const Def* filter, const Def* body, const Def* dbg) - : Def(Node, pi, {filter, body}, 0, dbg) {} - Lam(const Pi* pi, const Def* dbg) - : Def(Node, pi, 2, 0, dbg) {} + Lam(const Pi* pi, const Def* filter, const Def* body) + : Def(Node, pi, {filter, body}, 0) {} + Lam(const Pi* pi) + : Def(Node, pi, 2, 0) {} public: /// @name type @@ -79,7 +78,7 @@ class Lam : public Def { /// @name vars ///@{ - const Def* ret_var(const Def* dbg = {}); + const Def* ret_var(); ///@} /// @name setters @@ -98,29 +97,21 @@ class Lam : public Def { Lam* set_filter(Filter); Lam* set_body(const Def* body) { return Def::set(1, body)->as(); } /// Set body to an App of @p callee and @p arg. - Lam* app(Filter filter, const Def* callee, const Def* arg, const Def* dbg = {}); + Lam* app(Filter filter, const Def* callee, const Def* arg); /// Set body to an App of @p callee and @p args. - Lam* app(Filter filter, const Def* callee, Defs args, const Def* dbg = {}); + Lam* app(Filter filter, const Def* callee, Defs args); /// Set body to an App of `(f, t)#cond mem`. - Lam* branch(Filter filter, const Def* cond, const Def* t, const Def* f, const Def* mem, const Def* dbg = {}); - Lam* test(Filter filter, - const Def* val, - const Def* idx, - const Def* match, - const Def* clash, - const Def* mem, - const Def* dbg = {}); + Lam* branch(Filter filter, const Def* cond, const Def* t, const Def* f, const Def* mem); + Lam* test(Filter filter, const Def* val, const Def* idx, const Def* match, const Def* clash, const Def* mem); ///@} /// @name virtual methods ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - Lam* stub(World&, const Def*, const Def*) override; void check() override; ///@} - static constexpr auto Node = Node::Lam; - friend class World; + THORIN_DEF_MIXIN(Lam) + Lam* stub_(World&, Ref) override; }; template @@ -130,8 +121,8 @@ using Lam2Lam = LamMap; class App : public Def { private: - App(const Axiom* axiom, u8 curry, u8 trip, const Def* type, const Def* callee, const Def* arg, const Def* dbg) - : Def(Node, type, {callee, arg}, 0, dbg) { + App(const Axiom* axiom, u8 curry, u8 trip, const Def* type, const Def* callee, const Def* arg) + : Def(Node, type, {callee, arg}, 0) { axiom_ = axiom; curry_ = curry; trip_ = trip; @@ -154,13 +145,7 @@ class App : public Def { u8 trip() const { return trip_; } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::App; - friend class World; + THORIN_DEF_MIXIN(App) }; /// These are Lam%s that are neither `nullptr`, nor Lam::is_external, nor Lam::is_unset. diff --git a/thorin/lattice.h b/thorin/lattice.h index 05551cd5e6..df295b6fae 100644 --- a/thorin/lattice.h +++ b/thorin/lattice.h @@ -11,40 +11,41 @@ class Sigma; class Bound : public Def { protected: /// Constructor for a *structural* Bound. - Bound(node_t node, const Def* type, Defs ops, const Def* dbg) - : Def(node, type, ops, 0, dbg) {} + Bound(node_t node, const Def* type, Defs ops) + : Def(node, type, ops, 0) {} /// Constructor for a *nom*inal Bound. - Bound(node_t node, const Def* type, size_t size, const Def* dbg) - : Def(node, type, size, 0, dbg) {} + Bound(node_t node, const Def* type, size_t size) + : Def(node, type, size, 0) {} public: size_t find(const Def* type) const; const Def* get(const Def* type) const { return op(find(type)); } }; -/// Specific [Bound](https://en.wikipedia.org/wiki/Join_and_meet) depending on @p up. -/// The name @p up refers to the property that a [Join](@ref thorin::Join) **ascends** in the underlying +/// Specific [Bound](https://en.wikipedia.org/wiki/Join_and_meet) depending on @p Up. +/// The name @p Up refers to the property that a [Join](@ref thorin::Join) **ascends** in the underlying /// [lattice](https://en.wikipedia.org/wiki/Lattice_(order)) while a [Meet](@ref thorin::Meet) descends. -/// * @p up = `true`: [Join](@ref thorin::Join) (aka least upper bound/supremum/union) -/// * @p up = `false`: [Meet](@ref thorin::Meet) (aka greatest lower bound/infimum/intersection) -template +/// * @p Up = `true`: [Join](@ref thorin::Join) (aka least Upper bound/supremum/union) +/// * @p Up = `false`: [Meet](@ref thorin::Meet) (aka greatest lower bound/infimum/intersection) +template class TBound : public Bound { private: /// Constructor for a *structural* Bound. - TBound(const Def* type, Defs ops, const Def* dbg) - : Bound(Node, type, ops, dbg) {} + TBound(const Def* type, Defs ops) + : Bound(Node, type, ops) {} /// Constructor for a *nom*inal Bound. - TBound(const Def* type, size_t size, const Def* dbg) - : Bound(Node, type, size, dbg) {} + TBound(const Def* type, size_t size) + : Bound(Node, type, size) {} -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - TBound* stub(World&, const Def*, const Def*) override; - ///@} + THORIN_SETTERS(TBound) + TBound* stub(World& w, const Def* type) { return stub_(w, type)->set(dbg())->template as(); } + + static constexpr auto Node = Up ? Node::Join : Node::Meet; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + TBound* stub_(World&, Ref) override; - static constexpr auto Node = up ? Node::Join : Node::Meet; friend class World; }; @@ -52,25 +53,18 @@ class TBound : public Bound { /// @remark [Ac](https://en.wikipedia.org/wiki/Wedge_(symbol)) is Latin and means *and*. class Ac : public Def { private: - Ac(const Def* type, Defs defs, const Def* dbg) - : Def(Node, type, defs, 0, dbg) {} - -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} + Ac(const Def* type, Defs defs) + : Def(Node, type, defs, 0) {} - static constexpr auto Node = Node::Ac; - friend class World; + THORIN_DEF_MIXIN(Ac) }; /// Constructs a [Join](@ref thorin::Join) **value**. /// @remark [Vel](https://en.wikipedia.org/wiki/Wedge_(symbol)) is Latin and means *or*. class Vel : public Def { private: - Vel(const Def* type, const Def* value, const Def* dbg) - : Def(Node, type, {value}, 0, dbg) {} + Vel(const Def* type, const Def* value) + : Def(Node, type, {value}, 0) {} public: /// @name ops @@ -78,33 +72,22 @@ class Vel : public Def { const Def* value() const { return op(0); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Vel; - friend class World; + THORIN_DEF_MIXIN(Vel) }; /// Picks the aspect of a Meet [value](Pick::value) by its [type](Def::type). class Pick : public Def { private: - Pick(const Def* type, const Def* value, const Def* dbg) - : Def(Node, type, {value}, 0, dbg) {} + Pick(const Def* type, const Def* value) + : Def(Node, type, {value}, 0) {} public: /// @name ops ///@{ const Def* value() const { return op(0); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - static constexpr auto Node = Node::Pick; - friend class World; + THORIN_DEF_MIXIN(Pick) }; /// `test value, probe, match, clash` tests whether Test::value currently holds **type** Test::probe. @@ -118,8 +101,8 @@ class Pick : public Def { /// @remark This operation is usually known as `case` but named `Test` since `case` is a keyword in C++. class Test : public Def { private: - Test(const Def* type, const Def* value, const Def* probe, const Def* match, const Def* clash, const Def* dbg) - : Def(Node, type, {value, probe, match, clash}, 0, dbg) {} + Test(const Def* type, const Def* value, const Def* probe, const Def* match, const Def* clash) + : Def(Node, type, {value, probe, match, clash}, 0) {} public: /// @name ops @@ -130,36 +113,32 @@ class Test : public Def { const Def* clash() const { return op(3); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Test; - friend class World; + THORIN_DEF_MIXIN(Test) }; /// Common base for TExt%remum. class Ext : public Def { protected: - Ext(node_t node, const Def* type, const Def* dbg) - : Def(node, type, Defs{}, 0, dbg) {} + Ext(node_t node, const Def* type) + : Def(node, type, Defs{}, 0) {} }; -/// Ext%remum. Either Top (@p up) or Bot%tom. -template +/// Ext%remum. Either Top (@p Up) or Bot%tom. +template class TExt : public Ext { private: - TExt(const Def* type, const Def* dbg) - : Ext(Node, type, dbg) {} + TExt(const Def* type) + : Ext(Node, type) {} -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} + THORIN_SETTERS(TExt) + TExt* stub(World& w, const Def* type) { return stub_(w, type)->set(dbg())->template as(); } + + static constexpr auto Node = Up ? Node::Top : Node::Bot; + +private: + Ref rebuild_(World&, Ref, Defs) const override; + TExt* stub_(World&, Ref) override; - static constexpr auto Node = up ? Node::Top : Node::Bot; friend class World; }; @@ -173,19 +152,13 @@ using Join = TBound; /// Use in conjunction with @ref thorin::Join. class Singleton : public Def { private: - Singleton(const Def* type, const Def* inner_type, const Def* dbg) - : Def(Node, type, {inner_type}, 0, dbg) {} + Singleton(const Def* type, const Def* inner_type) + : Def(Node, type, {inner_type}, 0) {} public: const Def* inhabitant() const { return op(0); } - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Singleton; - friend class World; + THORIN_DEF_MIXIN(Singleton) }; } // namespace thorin diff --git a/thorin/pass/fp/eta_exp.cpp b/thorin/pass/fp/eta_exp.cpp index c7d25ba51a..8b924e6b2c 100644 --- a/thorin/pass/fp/eta_exp.cpp +++ b/thorin/pass/fp/eta_exp.cpp @@ -2,6 +2,8 @@ #include "thorin/pass/fp/eta_red.h" +using namespace std::literals; + namespace thorin { Lam* EtaExp::new2old(Lam* new_lam) { @@ -35,14 +37,14 @@ const Def* EtaExp::rewrite(const Def* def) { } } - auto new_def = def->rebuild(world(), def->type(), new_ops, def->dbg()); + auto new_def = def->rebuild(world(), def->type(), new_ops); return old2new()[new_def] = new_def; } Lam* EtaExp::eta_exp(Lam* lam) { - auto exp = lam->stub(world(), lam->type(), lam->dbg()); + auto exp = lam->stub(world(), lam->type()); exp2orig_.emplace(exp, lam); - exp->set_debug_name(std::string("eta_") + lam->name()); + exp->debug_suffix("eta_"s + *lam->sym()); exp->app(false, lam, exp->var()); if (eta_red_) eta_red_->mark_irreducible(exp); return exp; diff --git a/thorin/pass/fp/tail_rec_elim.cpp b/thorin/pass/fp/tail_rec_elim.cpp index 043e5d98d7..3f77ff9489 100644 --- a/thorin/pass/fp/tail_rec_elim.cpp +++ b/thorin/pass/fp/tail_rec_elim.cpp @@ -24,10 +24,10 @@ undo_t TailRecElim::analyze(const Def* def) { if (auto ret_var = old->ret_var(); ret_var && app->args().back() == ret_var) { if (auto [i, ins] = old2rec_loop_.emplace(old, std::pair(nullptr, nullptr)); ins) { auto& [rec, loop] = i->second; - rec = old->stub(world(), old->type(), old->dbg()); + rec = old->stub(world(), old->type()); auto doms = rec->doms(); auto loop_dom = doms.skip_back(); - loop = rec->stub(world(), world().cn(loop_dom), rec->dbg()); + loop = rec->stub(world(), world().cn(loop_dom)); world().DLOG("old {} -> (rec: {}, loop: {})", old, rec, loop); auto n = rec->num_doms(); diff --git a/thorin/pass/optimize.cpp b/thorin/pass/optimize.cpp index b330dae725..243bd4a8e0 100644 --- a/thorin/pass/optimize.cpp +++ b/thorin/pass/optimize.cpp @@ -19,7 +19,8 @@ namespace thorin { /// See optimize.h for magic numbers void optimize(World& world, Passes& passes, std::vector& dialects) { - auto compilation_functions = {"_compile", "_default_compile", "_core_compile", "_fallback_compile"}; + auto compilation_functions = {world.sym("_compile"), world.sym("_default_compile"), world.sym("_core_compile"), + world.sym("_fallback_compile")}; const Def* compilation = nullptr; for (auto compilation_function : compilation_functions) { if (auto compilation_ = world.lookup(compilation_function)) { @@ -32,7 +33,7 @@ void optimize(World& world, Passes& passes, std::vector& dialects) { for (auto ext : world.externals()) { auto def = ext.second; if (auto lam = def->isa(); lam && lam->num_doms() == 0) { - if (lam->codom()->name() == "Pipeline") { + if (*lam->codom()->sym() == "Pipeline") { if (!compilation) { compilation = lam; } make_internal.push_back(def); } diff --git a/thorin/pass/pass.cpp b/thorin/pass/pass.cpp index 5abd02f9bb..e6d47d20cb 100644 --- a/thorin/pass/pass.cpp +++ b/thorin/pass/pass.cpp @@ -105,10 +105,9 @@ const Def* PassMan::rewrite(const Def* old_def) { } auto new_type = old_def->type() ? rewrite(old_def->type()) : nullptr; - auto new_dbg = old_def->dbg() ? rewrite(old_def->dbg()) : nullptr; DefArray new_ops(old_def->num_ops(), [&](size_t i) { return rewrite(old_def->op(i)); }); - auto new_def = old_def->rebuild(world(), new_type, new_ops, new_dbg); + auto new_def = old_def->rebuild(world(), new_type, new_ops); if (auto proxy = new_def->isa()) { if (auto&& pass = passes_[proxy->pass()]; pass->inspect()) { diff --git a/thorin/pass/pass.h b/thorin/pass/pass.h index a57e82b923..20ef163dd4 100644 --- a/thorin/pass/pass.h +++ b/thorin/pass/pass.h @@ -70,8 +70,8 @@ class Pass { /// @name proxy ///@{ - const Proxy* proxy(const Def* type, Defs ops, u32 tag = 0, const Def* dbg = {}) { - return world().proxy(type, ops, index(), tag, dbg); + const Proxy* proxy(const Def* type, Defs ops, u32 tag = 0) { + return world().proxy(type, ops, index(), tag); } /// Check whether given @p def is a Proxy whose Proxy::pass matches this Pass's @p IPass::index. const Proxy* isa_proxy(const Def* def, u32 tag = 0) { diff --git a/thorin/pass/rw/lam_spec.cpp b/thorin/pass/rw/lam_spec.cpp index d995cf8f58..1282e85b13 100644 --- a/thorin/pass/rw/lam_spec.cpp +++ b/thorin/pass/rw/lam_spec.cpp @@ -48,7 +48,7 @@ const Def* LamSpec::rewrite(const Def* def) { if (new_doms.size() == old_lam->num_doms()) return def; auto new_pi = world().cn(world().sigma(new_doms)); - auto new_lam = old_lam->stub(world(), new_pi, old_lam->dbg()); + auto new_lam = old_lam->stub(world(), new_pi); for (size_t arg_i = 0, var_i = 0, n = app->num_args() - skip; arg_i != n; ++arg_i) { auto arg = app->arg(arg_i); diff --git a/thorin/pass/rw/ret_wrap.cpp b/thorin/pass/rw/ret_wrap.cpp index 23f4095477..ffe4045a30 100644 --- a/thorin/pass/rw/ret_wrap.cpp +++ b/thorin/pass/rw/ret_wrap.cpp @@ -7,8 +7,8 @@ void RetWrap::enter() { if (!ret_var) return; // new wrapper that calls the return continuation - auto ret_cont = world().nom_lam(ret_var->type()->as(), ret_var->dbg()); - ret_cont->app(false, ret_var, ret_cont->var(), ret_var->dbg()); + auto ret_cont = world().nom_lam(ret_var->type()->as())->set(ret_var->dbg()); + ret_cont->app(false, ret_var, ret_cont->var())->set(ret_var->dbg()); // rebuild a new "var" that substitutes the actual ret_var with ret_cont auto new_vars = curr_nom()->vars(); diff --git a/thorin/pass/rw/scalarize.cpp b/thorin/pass/rw/scalarize.cpp index 67176665f9..e0deae9d32 100644 --- a/thorin/pass/rw/scalarize.cpp +++ b/thorin/pass/rw/scalarize.cpp @@ -38,7 +38,7 @@ Lam* Scalerize::make_scalar(const Def* def) { if (!todo) return tup2sca_[tup_lam] = tup_lam; auto pi = world().cn(world().sigma(types)); - auto sca_lam = tup_lam->stub(world(), pi, tup_lam->dbg()); + auto sca_lam = tup_lam->stub(world(), pi); if (eta_exp_) eta_exp_->new2old(sca_lam, tup_lam); size_t n = 0; world().DLOG("type {} ~> {}", tup_lam->type(), pi); diff --git a/thorin/phase/phase.cpp b/thorin/phase/phase.cpp index dc00e1dadb..b410c8e88d 100644 --- a/thorin/phase/phase.cpp +++ b/thorin/phase/phase.cpp @@ -28,7 +28,7 @@ void FPPhase::start() { } void Cleanup::start() { - World new_world(world().state()); + auto new_world = world().inherit(); Rewriter rewriter(new_world); for (const auto& [_, ax] : world().axioms()) rewriter.rewrite(ax); diff --git a/thorin/rewrite.cpp b/thorin/rewrite.cpp index 9d1d7622c3..d1368b3e11 100644 --- a/thorin/rewrite.cpp +++ b/thorin/rewrite.cpp @@ -18,15 +18,13 @@ const Def* Rewriter::rewrite(Ref old_def) { const Def* Rewriter::rewrite_structural(const Def* old_def) { auto new_type = rewrite(old_def->type()); - auto new_dbg = rewrite(old_def->dbg()); DefArray new_ops(old_def->num_ops(), [&](auto i) { return rewrite(old_def->op(i)); }); - return old_def->rebuild(world(), new_type, new_ops, new_dbg); + return old_def->rebuild(world(), new_type, new_ops); } const Def* Rewriter::rewrite_nom(Def* old_nom) { auto new_type = rewrite(old_nom->type()); - auto new_dbg = rewrite(old_nom->dbg()); - auto new_nom = old_nom->stub(world(), new_type, new_dbg); + auto new_nom = old_nom->stub(world(), new_type); map(old_nom, new_nom); if (old_nom->is_set()) { diff --git a/thorin/tuple.cpp b/thorin/tuple.cpp index a04fafeb22..de566cf910 100644 --- a/thorin/tuple.cpp +++ b/thorin/tuple.cpp @@ -19,8 +19,7 @@ static bool nom_val_or_typ(const Def* def) { } size_t flatten(DefVec& ops, const Def* def, bool flatten_noms) { - if (auto a = isa_lit(def->arity()); - a && *a != 1 && should_flatten(def) && flatten_noms == nom_val_or_typ(def)) { + if (auto a = def->isa_lit_arity(); a && *a != 1 && should_flatten(def) && flatten_noms == nom_val_or_typ(def)) { auto n = 0; for (size_t i = 0; i != *a; ++i) n += flatten(ops, def->proj(*a, i), flatten_noms); return n; @@ -34,13 +33,12 @@ const Def* flatten(const Def* def) { if (!should_flatten(def)) return def; DefVec ops; flatten(ops, def); - return def->sort() == Sort::Term ? def->world().tuple(def->type(), ops, def->dbg()) - : def->world().sigma(ops, def->dbg()); + return def->sort() == Sort::Term ? def->world().tuple(def->type(), ops) : def->world().sigma(ops); } static const Def* unflatten(Defs defs, const Def* type, size_t& j, bool flatten_noms) { if (!defs.empty() && defs[0]->type() == type) return defs[j++]; - if (auto a = isa_lit(type->arity()); flatten_noms == nom_val_or_typ(type) && a && *a != 1) { + if (auto a = type->isa_lit_arity(); flatten_noms == nom_val_or_typ(type) && a && *a != 1) { auto& world = type->world(); DefArray ops(*a, [&](size_t i) { return unflatten(defs, type->proj(*a, i), j, flatten_noms); }); return world.tuple(type, ops); diff --git a/thorin/tuple.h b/thorin/tuple.h index 05c78ab68d..b45d0c069d 100644 --- a/thorin/tuple.h +++ b/thorin/tuple.h @@ -7,11 +7,11 @@ namespace thorin { class Sigma : public Def { private: /// Constructor for a *structural* Sigma. - Sigma(const Def* type, Defs ops, const Def* dbg) - : Def(Node, type, ops, 0, dbg) {} + Sigma(const Def* type, Defs ops) + : Def(Node, type, ops, 0) {} /// Constructor for a *nom*inal Sigma. - Sigma(const Def* type, size_t size, const Def* dbg) - : Def(Node, type, size, 0, dbg) {} + Sigma(const Def* type, size_t size) + : Def(Node, type, size, 0) {} public: /// @name setters @@ -23,39 +23,30 @@ class Sigma : public Def { /// @name virtual methods ///@{ void check() override; - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - Sigma* stub(World&, const Def*, const Def*) override; const Sigma* restructure() override; ///@} - static constexpr auto Node = Node::Sigma; - friend class World; + THORIN_DEF_MIXIN(Sigma) + Sigma* stub_(World&, Ref) override; }; /// Data constructor for a Sigma. class Tuple : public Def { private: - Tuple(const Def* type, Defs args, const Def* dbg) - : Def(Node, type, args, 0, dbg) {} + Tuple(const Def* type, Defs args) + : Def(Node, type, args, 0) {} -public: - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Tuple; - friend class World; + THORIN_DEF_MIXIN(Tuple) }; class Arr : public Def { private: /// Constructor for a *structural* Arr. - Arr(const Def* type, const Def* shape, const Def* body, const Def* dbg) - : Def(Node, type, {shape, body}, 0, dbg) {} + Arr(const Def* type, const Def* shape, const Def* body) + : Def(Node, type, {shape, body}, 0) {} /// Constructor for a *nom*inaml Arr. - Arr(const Def* type, const Def* dbg) - : Def(Node, type, 2, 0, dbg) {} + Arr(const Def* type) + : Def(Node, type, 2, 0) {} public: /// @name ops @@ -71,24 +62,22 @@ class Arr : public Def { /// @name virtual methods ///@{ size_t first_dependend_op() override { return 1; } - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - Arr* stub(World&, const Def*, const Def*) override; const Def* restructure() override; void check() override; ///@} - static constexpr auto Node = Node::Arr; - friend class World; + THORIN_DEF_MIXIN(Arr) + Arr* stub_(World&, Ref) override; }; class Pack : public Def { private: /// Constructor for a *structural* Pack. - Pack(const Def* type, const Def* body, const Def* dbg) - : Def(Node, type, {body}, 0, dbg) {} + Pack(const Def* type, const Def* body) + : Def(Node, type, {body}, 0) {} /// Constructor for a *nom*inaml Pack. - Pack(const Def* type, const Def* dbg) - : Def(Node, type, 1, 0, dbg) {} + Pack(const Def* type) + : Def(Node, type, 1, 0) {} public: /// @name ops @@ -103,20 +92,18 @@ class Pack : public Def { /// @name virtual methods ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - Pack* stub(World&, const Def*, const Def*) override; const Def* restructure() override; ///@} - static constexpr auto Node = Node::Pack; - friend class World; + THORIN_DEF_MIXIN(Pack) + Pack* stub_(World&, Ref) override; }; /// Extracts from a Sigma or Arr-typed Extract::tuple the element at position Extract::index. class Extract : public Def { private: - Extract(const Def* type, const Def* tuple, const Def* index, const Def* dbg) - : Def(Node, type, {tuple, index}, 0, dbg) {} + Extract(const Def* type, const Def* tuple, const Def* index) + : Def(Node, type, {tuple, index}, 0) {} public: /// @name ops @@ -125,13 +112,7 @@ class Extract : public Def { const Def* index() const { return op(1); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Extract; - friend class World; + THORIN_DEF_MIXIN(Extract) }; /// Creates a new Tuple / Pack by inserting Insert::value at position Insert::index into Insert::tuple. @@ -140,8 +121,8 @@ class Extract : public Def { /// The Insert itself is a *new* Tuple / Pack which contains the inserted Insert::value. class Insert : public Def { private: - Insert(const Def* tuple, const Def* index, const Def* value, const Def* dbg) - : Def(Node, tuple->type(), {tuple, index, value}, 0, dbg) {} + Insert(const Def* tuple, const Def* index, const Def* value) + : Def(Node, tuple->type(), {tuple, index, value}, 0) {} public: /// @name ops @@ -151,13 +132,7 @@ class Insert : public Def { const Def* value() const { return op(2); } ///@} - /// @name virtual methods - ///@{ - const Def* rebuild(World&, const Def*, Defs, const Def*) const override; - ///@} - - static constexpr auto Node = Node::Insert; - friend class World; + THORIN_DEF_MIXIN(Insert) }; /// Flattens a sigma/array/pack/tuple. diff --git a/thorin/util/loc.cpp b/thorin/util/loc.cpp new file mode 100644 index 0000000000..23fdb944f8 --- /dev/null +++ b/thorin/util/loc.cpp @@ -0,0 +1,25 @@ +#include "thorin/util/loc.h" + +namespace thorin { + +std::ostream& operator<<(std::ostream& os, const Pos pos) { + if (pos.row) { + if (pos.col) return os << pos.row << ':' << pos.col; + return os << pos.row; + } + return os << ""; +} + +std::ostream& operator<<(std::ostream& os, const Loc loc) { + if (loc.begin) { + os << loc.file << ':' << loc.begin; + if (loc.begin != loc.finis) os << '-' << loc.finis; + return os; + } + return os << ""; +} + +void Pos::dump() { std::cout << *this << std::endl; } +void Loc::dump() { std::cout << *this << std::endl; } + +} // namespace thorin diff --git a/thorin/util/loc.h b/thorin/util/loc.h new file mode 100644 index 0000000000..c563eb3e27 --- /dev/null +++ b/thorin/util/loc.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +#include "thorin/util/print.h" +#include "thorin/util/sym.h" + +namespace thorin { + +struct Pos { + Pos() = default; + Pos(uint16_t row) + : row(row) {} + Pos(uint16_t row, uint16_t col) + : row(row) + , col(col) {} + + explicit operator bool() const { return row; } + void dump(); + + uint16_t row = 0; + uint16_t col = 0; +}; + +struct Loc { + Loc() = default; + Loc(Sym file, Pos begin, Pos finis) + : file(file) + , begin(begin) + , finis(finis) {} + Loc(Sym file, Pos pos) + : Loc(file, pos, pos) {} + + Loc anew_begin() const { return {file, begin, begin}; } + Loc anew_finis() const { return {file, finis, finis}; } + explicit operator bool() const { return (bool)begin; } + void dump(); + + Sym file; + Pos begin = {}; + Pos finis = {}; + ///< It's called `finis` because it refers to the **last** character within this Loc%ation. + /// In the STL the word `end` refers to the position of something that is one element **past** the end. +}; + +template +[[noreturn]] void err(Loc loc, const char* fmt, Args&&... args) { + std::ostringstream o; + print(o, "{}: error: ", loc); + print(o, fmt, std::forward(args)...); + throw T(o.str()); +} + +std::ostream& operator<<(std::ostream&, const Pos); +std::ostream& operator<<(std::ostream&, const Loc); + +inline bool operator==(Pos p1, Pos p2) { return p1.row == p2.row && p1.col == p2.col; } +inline bool operator==(Loc l1, Loc l2) { return l1.begin == l2.begin && l1.finis == l2.finis && l1.file == l2.file; } + +struct Dbg { + Loc loc; + Sym sym; +}; + +} // namespace thorin diff --git a/thorin/util/log.h b/thorin/util/log.h index bfce1366fb..ea44dc711d 100644 --- a/thorin/util/log.h +++ b/thorin/util/log.h @@ -1,14 +1,19 @@ #pragma once -#include "thorin/debug.h" - -#include "thorin/util/print.h" +#include "thorin/util/loc.h" namespace thorin { -struct Log { +class Log { +public: enum class Level { Error, Warn, Info, Verbose, Debug }; + Log(SymPool& sym_pool) + : sym_pool_(sym_pool) {} + + /// @name log + ///@{ + /// Output @p fmt to Log::ostream; does nothing if Log::ostream is `nullptr`. template void log(Level level, Loc loc, const char* fmt, Args&&... args) const { if (ostream && int(level) <= int(this->level)) { @@ -18,26 +23,39 @@ struct Log { print(*ostream, fmt, std::forward(args)...) << std::endl; } } - void log() const {} ///< Dummy for Debug build. + template + void log(Level level, const char* file, uint16_t line, const char* fmt, Args&&... args) { + log(level, Loc(sym_pool_.sym(file), line), fmt, std::forward(args)...); + } + ///@} + /// @name conversions + ///@{ static std::string_view level2acro(Level); static Level str2level(std::string_view); static int level2color(Level level); static std::string colorize(std::string_view str, int color); + ///@} + /// @name Log Level and output stream as public members + ///@{ std::ostream* ostream = nullptr; Level level = Level::Error; ///< **Maximum** log Level. + ///@} + +private: + SymPool& sym_pool_; }; // clang-format off -#define ELOG(...) log().log(thorin::Log::Level::Error, thorin::Loc(__FILE__, {__LINE__, thorin::u32(-1)}, {__LINE__, thorin::u32(-1)}), __VA_ARGS__) -#define WLOG(...) log().log(thorin::Log::Level::Warn, thorin::Loc(__FILE__, {__LINE__, thorin::u32(-1)}, {__LINE__, thorin::u32(-1)}), __VA_ARGS__) -#define ILOG(...) log().log(thorin::Log::Level::Info, thorin::Loc(__FILE__, {__LINE__, thorin::u32(-1)}, {__LINE__, thorin::u32(-1)}), __VA_ARGS__) -#define VLOG(...) log().log(thorin::Log::Level::Verbose, thorin::Loc(__FILE__, {__LINE__, thorin::u32(-1)}, {__LINE__, thorin::u32(-1)}), __VA_ARGS__) +#define ELOG(...) log().log(thorin::Log::Level::Error, __FILE__, __LINE__, __VA_ARGS__) +#define WLOG(...) log().log(thorin::Log::Level::Warn, __FILE__, __LINE__, __VA_ARGS__) +#define ILOG(...) log().log(thorin::Log::Level::Info, __FILE__, __LINE__, __VA_ARGS__) +#define VLOG(...) log().log(thorin::Log::Level::Verbose, __FILE__, __LINE__, __VA_ARGS__) #ifndef NDEBUG -#define DLOG(...) log().log(thorin::Log::Level::Debug, thorin::Loc(__FILE__, {__LINE__, thorin::u32(-1)}, {__LINE__, thorin::u32(-1)}), __VA_ARGS__) +#define DLOG(...) log().log(thorin::Log::Level::Debug, __FILE__, __LINE__, __VA_ARGS__) #else -#define DLOG(...) log().log() +#define DLOG(...) dummy() #endif // clang-format on diff --git a/thorin/util/sym.h b/thorin/util/sym.h new file mode 100644 index 0000000000..2fb63d8527 --- /dev/null +++ b/thorin/util/sym.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace thorin { + +/// A Sym%bol just wraps a `const std::string*`, so pass Sym itself around as value. +/// With the exception of the empty string, you should only create Sym%bols via SymPool::sym which in turn will toss all Sym%bols into a big hash set. +/// This makes Sym::operator== and Sym::operator!= an O(1) operation. +/// The empty string is internally handled as `nullptr`. +/// Thus, you can create a Sym%bol representing an empty string without having access to the SymPool. +/// The empty string, `nullptr`, and `"\0"` are all identified as `Sym::Sym()`. +class Sym { +private: + Sym(const std::string* ptr) + : ptr_(ptr) { + assert(ptr == nullptr || !ptr->empty()); + } + +public: + Sym() = default; + + /// @name begin/end + ///@{ + /// Useful for range-based for. + /// Will give you `std::string::const_iterator` - yes **const**; you are not supposed to mutate hashed strings. + auto begin() const { return (*this)->cbegin(); } + auto end() const { return (*this)->cend(); } + ///@} + + /// @name comparisions + ///@{ + bool operator==(char c) const { return (*this)->size() == 1 && (*this)[0] == c; } + bool operator!=(char c) const { return !((*this) == c); } + bool operator==(Sym other) const { return this->ptr_ == other.ptr_; } + bool operator!=(Sym other) const { return this->ptr_ != other.ptr_; } + auto operator<=>(Sym other) const { return *(*this) <=> *other; } + friend bool operator==(char c, Sym s) { return s == c; } + friend bool operator!=(char c, Sym s) { return s != c; } + ///@} + + /// @name cast operators + ///@{ + operator std::string_view() const { return ptr_ ? *ptr_ : std::string_view(); } + operator const std::string&() const { return *this->operator->(); } + explicit operator bool() const { return ptr_; } + ///@} + + /// @name access operators + ///@{ + char operator[](size_t i) const { return ((const std::string&)(*this))[i]; } + const std::string& operator*() const { return *this->operator->(); } + const std::string* operator->() const { + static std::string empty; + return ptr_ ? ptr_ : ∅ + } + ///@} + + template + friend H AbslHashValue(H h, Sym sym) { + return H::combine(std::move(h), sym.ptr_); + } + +private: + const std::string* ptr_ = nullptr; + + friend class SymPool; +}; + +inline std::ostream& operator<<(std::ostream& o, const Sym sym) { return o << *sym; } + +/// Hash set where all strings - wrapped in Sym%bol - live in. +/// You can access the SymPool from Driver. +class SymPool { +public: + SymPool() = default; + SymPool(const SymPool&) = delete; + SymPool(SymPool&& other) + : pool_(std::move(other.pool_)) {} + + Sym sym(std::string_view s) { return s.empty() ? Sym() : &*pool_.emplace(s).first; } + Sym sym(const char* s) { return s == nullptr || *s == '\0' ? Sym() : &*pool_.emplace(s).first; } + Sym sym(std::string s) { return s.empty() ? Sym() : &*pool_.emplace(std::move(s)).first; } + + friend void swap(SymPool& p1, SymPool& p2) { + using std::swap; + swap(p1.pool_, p2.pool_); + } + +private: + absl::node_hash_set pool_; +}; + +template +using SymMap = absl::flat_hash_map; +using SymSet = absl::flat_hash_set; +using Syms = std::deque; + +/// Like `std::string::substr`, but works on `std::string_view` instead. +inline std::string_view subview(std::string_view s, size_t i, size_t n = std::string_view::npos) { + n = std::min(n, s.size()); + return {s.data() + i, n - i}; +} + +} // namespace thorin diff --git a/thorin/util/utf8.h b/thorin/util/utf8.h index 29a06bbf9f..ed46623953 100644 --- a/thorin/util/utf8.h +++ b/thorin/util/utf8.h @@ -4,8 +4,7 @@ #include #include -#include "thorin/debug.h" - +#include "thorin/util/loc.h" #include "thorin/util/types.h" namespace thorin::utf8 { @@ -41,9 +40,9 @@ bool decode(std::ostream& os, char32_t c); template class Lexer { public: - Lexer(std::string_view filename, std::istream& istream) + Lexer(Sym file, std::istream& istream) : istream_(istream) - , loc_(filename, {0, 0}) { + , loc_(file, {0, 0}) { ahead_.back().pos = {1, 0}; for (size_t i = 0; i != Max_Ahead; ++i) next(); accept(BOM); // eat utf-8 BOM if present diff --git a/thorin/world.cpp b/thorin/world.cpp index adaa895239..b37a05b612 100644 --- a/thorin/world.cpp +++ b/thorin/world.cpp @@ -13,6 +13,7 @@ #include "thorin/check.h" #include "thorin/def.h" +#include "thorin/driver.h" #include "thorin/rewrite.h" #include "thorin/analyses/scope.h" @@ -32,53 +33,71 @@ bool World::Arena::Lock::guard_ = false; World::Move::Move(World& world) : checker(std::make_unique(world)) {} -World::World(const State& state) - : state_(state) +World::World(Driver* driver, const State& state) + : driver_(driver) + , state_(state) , move_(*this) { - data_.univ_ = insert(0, *this); - data_.lit_univ_0_ = lit_univ(0); - data_.lit_univ_1_ = lit_univ(1); - data_.type_0_ = type(lit_univ_0()); - data_.type_1_ = type(lit_univ_1()); - data_.type_bot_ = insert(0, type(), nullptr); - data_.sigma_ = insert(0, type(), Defs{}, nullptr)->as(); - data_.tuple_ = insert(0, sigma(), Defs{}, nullptr)->as(); - data_.type_nat_ = insert(0, *this); - data_.type_idx_ = insert(0, pi(type_nat(), type())); - data_.top_nat_ = insert(0, type_nat(), nullptr); - data_.lit_nat_0_ = lit_nat(0); - data_.lit_nat_1_ = lit_nat(1); - data_.type_bool_ = type_idx(2); - data_.lit_bool_[0] = lit_idx(2, 0_u64); - data_.lit_bool_[1] = lit_idx(2, 1_u64); - data_.lit_nat_max_ = lit_nat(nat_t(-1)); - data_.exit_ = nom_lam(cn(type_bot()), dbg("exit")); + data_.univ = insert(0, *this); + data_.lit_univ_0 = lit_univ(0); + data_.lit_univ_1 = lit_univ(1); + data_.type_0 = type(lit_univ_0()); + data_.type_1 = type(lit_univ_1()); + data_.type_bot = insert(0, type()); + data_.sigma = insert(0, type(), Defs{})->as(); + data_.tuple = insert(0, sigma(), Defs{})->as(); + data_.type_nat = insert(0, *this); + data_.type_idx = insert(0, pi(type_nat(), type())); + data_.top_nat = insert(0, type_nat()); + data_.lit_nat_0 = lit_nat(0); + data_.lit_nat_1 = lit_nat(1); + data_.type_bool = type_idx(2); + data_.lit_bool[0] = lit_idx(2, 0_u64); + data_.lit_bool[1] = lit_idx(2, 1_u64); + data_.lit_nat_max = lit_nat(nat_t(-1)); + data_.exit = nom_lam(cn(type_bot()))->set(sym("exit")); } -World::World(std::string_view name /* = {}*/) - : World(State(name)) {} +World::World(Driver* driver) + : World(driver, State()) {} World::~World() { for (auto def : move_.defs) def->~Def(); } -const Type* World::type(Ref level, Ref dbg) { +/* + * Driver + */ + +Log& World::log() { return driver().log; } +const Log& World::log() const { return driver().log; } +Flags& World::flags() { return driver().flags; } +const Flags& World::flags() const { return driver().flags; } + +Sym World::sym(const char* s) { return driver().sym(s); } +Sym World::sym(std::string_view s) { return driver().sym(s); } +Sym World::sym(std::string s) { return driver().sym(std::move(s)); } + +/* + * factory methods + */ + +const Type* World::type(Ref level) { if (!level->type()->isa()) - err(dbg, "argument `{}` to `.Type` must be of type `.Univ` but is of type `{}`", level, level->type()); + err(level, "argument `{}` to `.Type` must be of type `.Univ` but is of type `{}`", level, level->type()); - return unify(1, level, dbg)->as(); + return unify(1, level)->as(); } -const Def* World::uinc(Ref op, level_t offset, Ref dbg) { +Ref World::uinc(Ref op, level_t offset) { if (!op->type()->isa()) - err(dbg, "operand '{}' of a universe increment must be of type `.Univ` but is of type `{}`", op, op->type()); + err(op, "operand '{}' of a universe increment must be of type `.Univ` but is of type `{}`", op, op->type()); - if (auto l = isa_lit(op)) return lit_univ(*l, dbg); - return unify(1, op, offset, dbg); + if (auto l = isa_lit(op)) return lit_univ(*l); + return unify(1, op, offset); } template -const Def* World::umax(DefArray ops, Ref dbg) { +Ref World::umax(DefArray ops) { level_t lvl = 0; for (auto& op : ops) { Ref r = op; @@ -88,11 +107,11 @@ const Def* World::umax(DefArray ops, Ref dbg) { if (auto type = r->isa()) r = type->level(); else - err(dbg, "operand '{}' must be a .Type of some level", r); + err(r, "operand '{}' must be a .Type of some level", r); } if (!r->type()->isa()) - err(dbg, "operand '{}' of a universe max must be of type '.Univ' but is of type '{}'", r, r->type()); + err(r, "operand '{}' of a universe max must be of type '.Univ' but is of type '{}'", r, r->type()); op = r; @@ -102,74 +121,73 @@ const Def* World::umax(DefArray ops, Ref dbg) { lvl = level_t(-1); } - auto ldef = lvl == level_t(-1) ? (const Def*)unify(ops.size(), *this, ops, dbg) : lit_univ(lvl, dbg); + auto ldef = lvl == level_t(-1) ? (const Def*)unify(ops.size(), *this, ops) : lit_univ(lvl); std::ranges::sort(ops, [](auto op1, auto op2) { return op1->gid() < op2->gid(); }); - return sort == Sort::Univ ? ldef : type(ldef, dbg); + return sort == Sort::Univ ? ldef : type(ldef); } -const Def* World::app(Ref callee, Ref arg, Ref dbg) { +Ref World::app(Ref callee, Ref arg) { auto pi = callee->type()->isa(); // (a, b)#i arg where a = A -> B; b = A -> B if (auto extract = callee->type()->isa()) { if (auto tuple = extract->tuple()->isa()) { - if (auto uni = checker().is_uniform(tuple->ops(), dbg)) pi = uni->isa(); + if (auto uni = checker().is_uniform(tuple->ops())) pi = uni->isa(); } } - if (!pi) err(dbg, "called expression '{}' : '{}' is not of function type", callee, callee->type()); - if (!checker().assignable(pi->dom(), arg, dbg)) - err(dbg, "cannot pass argument '{}' of type '{}' to '{}' of domain '{}'", arg, arg->type(), callee, pi->dom()); + if (!pi) err(callee, "called expression '{}' : '{}' is not of function type", callee, callee->type()); + if (!checker().assignable(pi->dom(), arg)) + err(arg, "cannot pass argument '{}' of type '{}' to '{}' of domain '{}'", arg, arg->type(), callee, pi->dom()); if (auto lam = callee->isa(); lam && lam->is_set() && lam->codom()->sort() > Sort::Type) return lam->reduce(arg).back(); auto type = pi->reduce(arg).back(); - return raw_app(type, callee, arg, dbg); + return raw_app(type, callee, arg); } template -const Def* World::raw_app(Ref type, Ref callee, Ref arg, Ref dbg) { +Ref World::raw_app(Ref type, Ref callee, Ref arg) { auto [axiom, curry, trip] = Axiom::get(callee); if (axiom) { curry = curry == 0 ? trip : curry; curry = curry == Axiom::Trip_End ? curry : curry - 1; if (auto normalize = axiom->normalizer(); Normalize && normalize && curry == 0) - return normalize(type, callee, arg, dbg); + return normalize(type, callee, arg); } - return unify(2, axiom, curry, trip, type, callee, arg, dbg); + return unify(2, axiom, curry, trip, type, callee, arg); } -const Def* World::sigma(Defs ops, Ref dbg) { +Ref World::sigma(Defs ops) { auto n = ops.size(); if (n == 0) return sigma(); if (n == 1) return ops[0]; auto front = ops.front(); - if (std::ranges::all_of(ops.skip_front(), [front](auto op) { return front == op; })) return arr(n, front, dbg); - return unify(ops.size(), umax(ops, dbg), ops, dbg); + if (std::ranges::all_of(ops.skip_front(), [front](auto op) { return front == op; })) return arr(n, front); + return unify(ops.size(), umax(ops), ops); } static const Def* infer_sigma(World& world, Defs ops) { DefArray elems(ops.size()); for (size_t i = 0, e = ops.size(); i != e; ++i) elems[i] = ops[i]->type(); - return world.sigma(elems); } -const Def* World::tuple(Defs ops, Ref dbg) { +Ref World::tuple(Defs ops) { if (ops.size() == 1) return ops[0]; auto sigma = infer_sigma(*this, ops); - auto t = tuple(sigma, ops, dbg); - if (!checker().assignable(sigma, t, dbg)) - err(dbg, "cannot assign tuple '{}' of type '{}' to incompatible tuple type '{}'", t, t->type(), sigma); + auto t = tuple(sigma, ops); + if (!checker().assignable(sigma, t)) + err(t, "cannot assign tuple '{}' of type '{}' to incompatible tuple type '{}'", t, t->type(), sigma); return t; } -const Def* World::tuple(Ref type, Defs ops, Ref dbg) { +Ref World::tuple(Ref type, Defs ops) { // TODO type-check type vs inferred type auto n = ops.size(); @@ -177,7 +195,7 @@ const Def* World::tuple(Ref type, Defs ops, Ref dbg) { if (n == 0) return tuple(); if (n == 1) return ops[0]; auto front = ops.front(); - if (std::ranges::all_of(ops.skip_front(), [front](auto op) { return front == op; })) return pack(n, front, dbg); + if (std::ranges::all_of(ops.skip_front(), [front](auto op) { return front == op; })) return pack(n, front); } if (n != 0) { @@ -202,24 +220,18 @@ const Def* World::tuple(Ref type, Defs ops, Ref dbg) { } } - return unify(ops.size(), type, ops, dbg); + return unify(ops.size(), type, ops); } -const Def* World::tuple_str(std::string_view s, Ref dbg) { - DefVec ops; - for (auto c : s) ops.emplace_back(lit_nat(c)); - return tuple(ops, dbg); -} - -const Def* World::extract(Ref d, Ref index, Ref dbg) { +Ref World::extract(Ref d, Ref index) { if (index->isa()) { auto n = index->num_ops(); DefArray idx(n, [&](size_t i) { return index->op(i); }); DefArray ops(n, [&](size_t i) { return d->proj(n, as_lit(idx[i])); }); - return tuple(ops, dbg); + return tuple(ops); } else if (index->isa()) { - DefArray ops(as_lit(index->arity()), [&](size_t) { return extract(d, index->ops().back()); }); - return tuple(ops, dbg); + DefArray ops(index->as_lit_arity(), [&](size_t) { return extract(d, index->ops().back()); }); + return tuple(ops); } Ref size = Idx::size(index->type()); @@ -229,8 +241,8 @@ const Def* World::extract(Ref d, Ref index, Ref dbg) { if (auto l = isa_lit(size); l && *l == 1 && !d->type()->isa_nom()) return d; if (auto pack = d->isa_structural()) return pack->body(); - if (!checker().equiv(type->arity(), size, dbg)) - err(dbg, "index '{}' does not fit within arity '{}'", type->arity(), index); + if (!checker().equiv(type->arity(), size)) + err(index, "index '{}' does not fit within arity '{}'", type->arity(), index); // extract(insert(x, index, val), index) -> val if (auto insert = d->isa()) { @@ -242,17 +254,17 @@ const Def* World::extract(Ref d, Ref index, Ref dbg) { // extract(insert(x, j, val), i) -> extract(x, i) where i != j (guaranteed by rule above) if (auto insert = d->isa()) { - if (insert->index()->isa()) return extract(insert->tuple(), index, dbg); + if (insert->index()->isa()) return extract(insert->tuple(), index); } if (auto sigma = type->isa()) { if (auto nom_sigma = sigma->isa_nom()) { Scope scope(nom_sigma); auto t = rewrite(sigma->op(*i), nom_sigma->var(), d, scope); - return unify(2, t, d, index, dbg); + return unify(2, t, d, index); } - return unify(2, sigma->op(*i), d, index, dbg); + return unify(2, sigma->op(*i), d, index); } } @@ -260,30 +272,30 @@ const Def* World::extract(Ref d, Ref index, Ref dbg) { if (auto arr = type->isa()) elem_t = arr->reduce(index); else - elem_t = extract(tuple(type->as()->ops(), dbg), index, dbg); + elem_t = extract(tuple(type->as()->ops()), index); - return unify(2, elem_t, d, index, dbg); + return unify(2, elem_t, d, index); } -const Def* World::insert(Ref d, Ref index, Ref val, Ref dbg) { +Ref World::insert(Ref d, Ref index, Ref val) { auto type = d->unfold_type(); auto size = Idx::size(index->type()); - if (!checker().equiv(type->arity(), size, dbg)) - err(dbg, "index '{}' does not fit within arity '{}'", type->arity(), index); + if (!checker().equiv(type->arity(), size)) + err(index, "index '{}' does not fit within arity '{}'", type->arity(), index); if (auto l = isa_lit(size); l && *l == 1) - return tuple(d, {val}, dbg); // d could be nom - that's why the tuple ctor is needed + return tuple(d, {val}); // d could be nom - that's why the tuple ctor is needed // insert((a, b, c, d), 2, x) -> (a, b, x, d) if (auto t = d->isa()) return t->refine(as_lit(index), val); // insert(‹4; x›, 2, y) -> (x, x, y, x) if (auto pack = d->isa()) { - if (auto a = isa_lit(pack->arity())) { + if (auto a = pack->isa_lit_arity()) { DefArray new_ops(*a, pack->body()); new_ops[as_lit(index)] = val; - return tuple(type, new_ops, dbg); + return tuple(type, new_ops); } } @@ -292,7 +304,7 @@ const Def* World::insert(Ref d, Ref index, Ref val, Ref dbg) { if (insert->index() == index) d = insert->tuple(); } - return unify(3, d, index, val, dbg); + return unify(3, d, index, val); } bool is_shape(Ref s) { @@ -305,8 +317,8 @@ bool is_shape(Ref s) { } // TODO merge this code with pack -const Def* World::arr(Ref shape, Ref body, Ref dbg) { - if (!is_shape(shape->type())) err(dbg, "expected shape but got '{}' of type '{}'", shape, shape->type()); +Ref World::arr(Ref shape, Ref body) { + if (!is_shape(shape->type())) err(shape, "expected shape but got '{}' of type '{}'", shape, shape->type()); if (auto a = isa_lit(shape)) { if (*a == 0) return sigma(); @@ -317,23 +329,23 @@ const Def* World::arr(Ref shape, Ref body, Ref dbg) { if (auto ex = shape->isa()) { if (auto tup = ex->tuple()->isa()) { DefArray arrs(tup->num_ops(), [&](size_t i) { return arr(tup->op(i), body); }); - return extract(tuple(arrs), ex->index(), dbg); + return extract(tuple(arrs), ex->index()); } } // «(a, b, c); body» -> «a; «(b, c); body»» - if (auto tuple = shape->isa()) return arr(tuple->ops().front(), arr(tuple->ops().skip_front(), body), dbg); + if (auto tuple = shape->isa()) return arr(tuple->ops().front(), arr(tuple->ops().skip_front(), body)); // «; body» -> «x; «; body»» if (auto p = shape->isa()) { - if (auto s = isa_lit(p->shape())) return arr(*s, arr(pack(*s - 1, p->body()), body), dbg); + if (auto s = isa_lit(p->shape())) return arr(*s, arr(pack(*s - 1, p->body()), body)); } - return unify(2, body->unfold_type(), shape, body, dbg); + return unify(2, body->unfold_type(), shape, body); } -const Def* World::pack(Ref shape, Ref body, Ref dbg) { - if (!is_shape(shape->type())) err(dbg, "expected shape but got '{}' of type '{}'", shape, shape->type()); +Ref World::pack(Ref shape, Ref body) { + if (!is_shape(shape->type())) err(shape, "expected shape but got '{}' of type '{}'", shape, shape->type()); if (auto a = isa_lit(shape)) { if (*a == 0) return tuple(); @@ -341,60 +353,60 @@ const Def* World::pack(Ref shape, Ref body, Ref dbg) { } // <(a, b, c); body> -> > - if (auto tuple = shape->isa()) return pack(tuple->ops().front(), pack(tuple->ops().skip_front(), body), dbg); + if (auto tuple = shape->isa()) return pack(tuple->ops().front(), pack(tuple->ops().skip_front(), body)); // <; body> -> ; body>> if (auto p = shape->isa()) { - if (auto s = isa_lit(p->shape())) return pack(*s, pack(pack(*s - 1, p->body()), body), dbg); + if (auto s = isa_lit(p->shape())) return pack(*s, pack(pack(*s - 1, p->body()), body)); } auto type = arr(shape, body->type()); - return unify(1, type, body, dbg); + return unify(1, type, body); } -const Def* World::arr(Defs shape, Ref body, Ref dbg) { +Ref World::arr(Defs shape, Ref body) { if (shape.empty()) return body; - return arr(shape.skip_back(), arr(shape.back(), body, dbg), dbg); + return arr(shape.skip_back(), arr(shape.back(), body)); } -const Def* World::pack(Defs shape, Ref body, Ref dbg) { +Ref World::pack(Defs shape, Ref body) { if (shape.empty()) return body; - return pack(shape.skip_back(), pack(shape.back(), body, dbg), dbg); + return pack(shape.skip_back(), pack(shape.back(), body)); } -const Lit* World::lit(Ref type, u64 val, Ref dbg) { +const Lit* World::lit(Ref type, u64 val) { if (auto size = Idx::size(type)) { if (auto s = isa_lit(size)) { - if (*s != 0 && val >= *s) err(dbg, "index '{}' does not fit within arity '{}'", size, val); + if (*s != 0 && val >= *s) err(type, "index '{}' does not fit within arity '{}'", size, val); } else if (val != 0) { // 0 of any size is allowed - err(dbg, "cannot create literal '{}' of '.Idx {}' as size is unknown", val, size); + err(type, "cannot create literal '{}' of '.Idx {}' as size is unknown", val, size); } } - return unify(0, type, val, dbg); + return unify(0, type, val); } /* * set */ -template -const Def* World::ext(Ref type, Ref dbg) { - if (auto arr = type->isa()) return pack(arr->shape(), ext(arr->body()), dbg); +template +Ref World::ext(Ref type) { + if (auto arr = type->isa()) return pack(arr->shape(), ext(arr->body())); if (auto sigma = type->isa()) - return tuple(sigma, DefArray(sigma->num_ops(), [&](size_t i) { return ext(sigma->op(i), dbg); }), dbg); - return unify>(0, type, dbg); + return tuple(sigma, DefArray(sigma->num_ops(), [&](size_t i) { return ext(sigma->op(i)); })); + return unify>(0, type); } -template -const Def* World::bound(Defs ops, Ref dbg) { - auto kind = umax(ops, dbg); +template +Ref World::bound(Defs ops) { + auto kind = umax(ops); - // has ext value? - if (std::ranges::any_of(ops, [&](Ref op) { return up ? bool(op->isa()) : bool(op->isa()); })) - return ext(kind); + // has ext value? + if (std::ranges::any_of(ops, [&](Ref op) { return Up ? bool(op->isa()) : bool(op->isa()); })) + return ext(kind); - // ignore: ext + // ignore: ext DefArray cpy(ops); auto [_, end] = std::ranges::copy_if(ops, cpy.begin(), [&](Ref op) { return !op->isa(); }); @@ -403,93 +415,72 @@ const Def* World::bound(Defs ops, Ref dbg) { end = std::unique(cpy.begin(), end); cpy.shrink(std::distance(cpy.begin(), end)); - if (cpy.size() == 0) return ext(kind, dbg); + if (cpy.size() == 0) return ext(kind); if (cpy.size() == 1) return cpy[0]; // TODO simplify mixed terms with joins and meets - return unify>(cpy.size(), kind, cpy, dbg); + return unify>(cpy.size(), kind, cpy); } -const Def* World::ac(Ref type, Defs ops, Ref dbg) { +Ref World::ac(Ref type, Defs ops) { if (type->isa()) { DefArray types(ops.size(), [&](size_t i) { return ops[i]->type(); }); - return unify(ops.size(), meet(types), ops, dbg); + return unify(ops.size(), meet(types), ops); } assert(ops.size() == 1); return ops[0]; } -const Def* World::ac(Defs ops, Ref dbg /*= {}*/) { return ac(umax(ops, dbg), ops, dbg); } +Ref World::ac(Defs ops) { return ac(umax(ops), ops); } -const Def* World::vel(Ref type, Ref value, Ref dbg) { - if (type->isa()) return unify(1, type, value, dbg); +Ref World::vel(Ref type, Ref value) { + if (type->isa()) return unify(1, type, value); return value; } -const Def* World::pick(Ref type, Ref value, Ref dbg) { return unify(1, type, value, dbg); } +Ref World::pick(Ref type, Ref value) { return unify(1, type, value); } -const Def* World::test(Ref value, Ref probe, Ref match, Ref clash, Ref dbg) { +Ref World::test(Ref value, Ref probe, Ref match, Ref clash) { auto m_pi = match->type()->isa(); auto c_pi = clash->type()->isa(); // TODO proper error msg assert(m_pi && c_pi); - auto a = isa_lit(m_pi->dom()->arity()); + auto a = m_pi->dom()->isa_lit_arity(); assert_unused(a && *a == 2); - assert(checker().equiv(m_pi->dom(2, 0_s), c_pi->dom(), nullptr)); + assert(checker().equiv(m_pi->dom(2, 0_s), c_pi->dom())); auto codom = join({m_pi->codom(), c_pi->codom()}); - return unify(4, pi(c_pi->dom(), codom), value, probe, match, clash, dbg); + return unify(4, pi(c_pi->dom(), codom), value, probe, match, clash); } -const Def* World::singleton(Ref inner_type, Ref dbg) { return unify(1, this->type<1>(), inner_type, dbg); } +Ref World::singleton(Ref inner_type) { return unify(1, this->type<1>(), inner_type); } /* * implicits */ -const Def* World::implicits2meta(const Implicits& implicits) { - const Def* meta = bot(type_bool()); - for (auto b : implicits | std::ranges::views::reverse) meta = tuple({lit_bool(b), meta}); - return meta; -} - -/// Returns `{b, x}` from Thorin pair `(b, x)` or `std::nullopt` if @p def doesn't fit the bill. -static std::optional> peel(const Def* def) { - if (def) { - if (auto tuple = def->isa(); tuple && tuple->num_ops() == 2) { - if (auto b = isa_lit(tuple->op(0))) return {std::pair(*b, tuple->op(1))}; - } - } - return {}; -} - -const Def* World::iapp(Ref callee, Ref arg, Debug debug) { - Debug mdebug = debug; - while (auto implicit = peel(callee->meta())) { - bool dot; - std::tie(dot, mdebug.meta) = *implicit; - - if (dot) { - auto infer = nom_infer_entity(dbg(debug)); - auto d = dbg(mdebug); - auto a = app(callee, infer, d); +Ref World::iapp(Ref callee, Ref arg) { + while (auto pi = callee->type()->isa()) { + if (pi->implicit()) { + auto infer = nom_infer_entity(); + auto a = app(callee, infer); callee = a; } else { // resolve Infers now if possible before normalizers are run if (auto app = callee->isa(); app && app->curry() == 1) { - checker().assignable(callee->type()->as()->dom(), arg, callee->dbg()); + checker().assignable(callee->type()->as()->dom(), arg); auto apps = decurry(app); callee = apps.front()->callee(); - for (auto app : apps) callee = this->app(callee, refer(app->arg()), app->dbg()); + for (auto app : apps) callee = this->app(callee, refer(app->arg())); } break; } } - return app(callee, arg, dbg(mdebug)); + return app(callee, arg); } /* @@ -498,9 +489,10 @@ const Def* World::iapp(Ref callee, Ref arg, Debug debug) { #if THORIN_ENABLE_CHECKS -void World::breakpoint(size_t number) { state_.breakpoints.emplace(number); } +Breakpoints& World::breakpoints() { return driver().breakpoints; } +void World::breakpoint(size_t number) { breakpoints().emplace(number); } -const Def* World::gid2def(u32 gid) { +Ref World::gid2def(u32 gid) { auto i = std::ranges::find_if(move_.defs, [=](auto def) { return def->gid() == gid; }); if (i == move_.defs.end()) return nullptr; return *i; @@ -513,16 +505,16 @@ const Def* World::gid2def(u32 gid) { */ #ifndef DOXYGEN // Doxygen doesn't like this -template const Def* World::raw_app(Ref, Ref, Ref, Ref); -template const Def* World::raw_app(Ref, Ref, Ref, Ref); +template Ref World::raw_app(Ref, Ref, Ref); +template Ref World::raw_app(Ref, Ref, Ref); #endif -template const Def* World::umax(DefArray, Ref); -template const Def* World::umax(DefArray, Ref); -template const Def* World::umax(DefArray, Ref); -template const Def* World::umax(DefArray, Ref); -template const Def* World::ext(Ref, Ref); -template const Def* World::ext(Ref, Ref); -template const Def* World::bound(Defs, Ref); -template const Def* World::bound(Defs, Ref); +template Ref World::umax(DefArray); +template Ref World::umax(DefArray); +template Ref World::umax(DefArray); +template Ref World::umax(DefArray); +template Ref World::ext(Ref); +template Ref World::ext(Ref); +template Ref World::bound(Defs); +template Ref World::bound(Defs); } // namespace thorin diff --git a/thorin/world.h b/thorin/world.h index c611342463..b52fdf99e3 100644 --- a/thorin/world.h +++ b/thorin/world.h @@ -10,18 +10,19 @@ #include "thorin/axiom.h" #include "thorin/check.h" #include "thorin/config.h" -#include "thorin/debug.h" #include "thorin/flags.h" #include "thorin/lattice.h" #include "thorin/tuple.h" #include "thorin/util/hash.h" #include "thorin/util/log.h" +#include "thorin/util/sym.h" namespace thorin { - class Checker; -class Scope; +class Driver; + +using Breakpoints = absl::flat_hash_set; /// The World represents the whole program and manages creation of Thorin nodes (Def%s). /// *Structural* Def%s are hashed into an internal HashSet. @@ -38,32 +39,24 @@ class World { ///@{ struct State { State() = default; - State(std::string_view name) - : name(name) {} /// [Plain Old Data](https://en.cppreference.com/w/cpp/named_req/PODType) struct POD { - Log log; - Flags flags; - u32 curr_gid = 0; - u32 curr_sub = 0; + u32 curr_gid = 0; + u32 curr_sub = 0; + Loc loc; + Sym name; mutable bool frozen = false; } pod; - std::string name = "module"; - absl::btree_set imported_dialects; -#if THORIN_ENABLE_CHECKS - absl::flat_hash_set breakpoints; -#endif + absl::btree_set imported_dialects; + friend void swap(State& s1, State& s2) { using std::swap; + assert((!s1.pod.loc || !s2.pod.loc) && "Why is emit_loc() still set?"); // clang-format off swap(s1.pod, s2.pod); - swap(s1.name, s2.name); swap(s1.imported_dialects, s2.imported_dialects); -#if THORIN_ENABLE_CHECKS - swap(s1.breakpoints, s2.breakpoints); -#endif // clang-format on } }; @@ -73,12 +66,13 @@ class World { World& operator=(const World&) = delete; /// Inherits the @p state into the new World. - explicit World(const State&); - explicit World(std::string_view name = {}); + explicit World(Driver*); + World(Driver*, const State&); World(World&& other) - : World() { + : World(&other.driver(), other.state()) { swap(*this, other); } + World inherit() { return World(&driver(), state()); } ~World(); ///@} @@ -86,10 +80,13 @@ class World { ///@{ const State& state() const { return state_; } - std::string_view name() const { return state_.name; } - void set_name(std::string_view name) { state_.name = name; } + const Driver& driver() const { return *driver_; } + Driver& driver() { return *driver_; } + + Sym name() const { return state_.pod.name; } + void set(Sym name) { state_.pod.name = name; } - void add_imported(std::string_view name) { state_.imported_dialects.emplace(name); } + void add_imported(Sym name) { state_.imported_dialects.emplace(name); } const auto& imported() const { return state_.imported_dialects; } /// Manage global identifier - a unique number for each Def. @@ -97,15 +94,22 @@ class World { u32 next_gid() { return ++state_.pod.curr_gid; } /// Retrive compile Flags. - const Flags& flags() const { return state_.pod.flags; } - Flags& flags() { return state_.pod.flags; } + const Flags& flags() const; + Flags& flags(); Checker& checker() { assert(&move_.checker->world() == this); return *move_.checker; } + + Loc& emit_loc() { return state_.pod.loc; } ///@} + /// @name Sym + ///@{ + Sym sym(std::string_view); + Sym sym(const char*); + Sym sym(std::string); ///@} /// @name freeze @@ -135,8 +139,9 @@ class World { #if THORIN_ENABLE_CHECKS /// @name debugging features ///@{ + Breakpoints& breakpoints(); void breakpoint(size_t number); - const Def* gid2def(u32 gid); + Ref gid2def(u32 gid); ///@} #endif @@ -146,15 +151,17 @@ class World { const auto& externals() const { return move_.externals; } bool empty() { return move_.externals.empty(); } void make_external(Def* def) { - assert(!def->name().empty()); - auto name = def->name(); - move_.externals.emplace(def->name(), def); // TODO enable assert again - // auto [i, ins] = move_.externals.emplace(def->name(), def); + def->external_ = true; + assert(def->sym()); + move_.externals.emplace(def->sym(), def); // TODO enable assert again + // auto [i, ins] = move_.externals.emplace(name, def); // assert((ins || (def == i->second)) && "two different externals registered with the same name"); } - void make_internal(Def* def) { move_.externals.erase(def->name()); } - bool is_external(Ref def) { return move_.externals.contains(def->name()); } - Def* lookup(const std::string& name) { + void make_internal(Def* def) { + def->external_ = false; + move_.externals.erase(def->sym()); + } + Def* lookup(Sym name) { auto i = move_.externals.find(name); return i != move_.externals.end() ? i->second : nullptr; } @@ -162,35 +169,34 @@ class World { /// @name Univ, Type, Var, Proxy, Infer ///@{ - const Univ* univ() { return data_.univ_; } - const Def* uinc(Ref op, level_t offset = 1, Ref dbg = {}); + const Univ* univ() { return data_.univ; } + Ref uinc(Ref op, level_t offset = 1); template - const Def* umax(DefArray, Ref dbg = {}); - const Type* type(Ref level, Ref dbg = {}); - const Type* type_infer_univ(Ref dbg = {}) { return type(nom_infer_univ(dbg), dbg); } + Ref umax(DefArray); + const Type* type(Ref level); + const Type* type_infer_univ() { return type(nom_infer_univ()); } template - const Type* type(Ref dbg = {}) { + const Type* type() { if constexpr (level == 0) - return data_.type_0_; + return data_.type_0; else if constexpr (level == 1) - return data_.type_1_; + return data_.type_1; else - return type(lit_univ(level), dbg); + return type(lit_univ(level)); } - const Var* var(Ref type, Def* nom, Ref dbg = {}) { return unify(1, type, nom, dbg); } - const Proxy* proxy(Ref type, Defs ops, u32 index, u32 tag, Ref dbg = {}) { - return unify(ops.size(), type, ops, index, tag, dbg); + const Var* var(Ref type, Def* nom) { return unify(1, type, nom); } + const Proxy* proxy(Ref type, Defs ops, u32 index, u32 tag) { + return unify(ops.size(), type, ops, index, tag); } - Infer* nom_infer(Ref type, Ref dbg = {}) { return insert(1, type, dbg); } - Infer* nom_infer(Ref type, Sym sym) { return insert(1, type, dbg(sym)); } - Infer* nom_infer_univ(Ref dbg = {}) { return nom_infer(univ(), dbg); } - Infer* nom_infer_type(Ref dbg = {}) { return nom_infer(type_infer_univ(dbg), dbg); } + Infer* nom_infer(Ref type) { return insert(1, type); } + Infer* nom_infer_univ() { return nom_infer(univ()); } + Infer* nom_infer_type() { return nom_infer(type_infer_univ()); } /// Either a value `?:?:.Type ?` or a type `?:.Type ?:.Type ?`. - Infer* nom_infer_entity(Ref dbg = {}) { + Infer* nom_infer_entity() { auto t = type_infer_univ(); - auto res = nom_infer(nom_infer(t), dbg); + auto res = nom_infer(nom_infer(t)); assert(this == &res->world()); return res; } @@ -198,272 +204,257 @@ class World { /// @name Axiom ///@{ - const Axiom* axiom(Def::NormalizeFn n, u8 curry, u8 trip, Ref type, dialect_t d, tag_t t, sub_t s, Ref dbg = {}) { - auto ax = unify(0, n, curry, trip, type, d, t, s, dbg); + const Axiom* axiom(Def::NormalizeFn n, u8 curry, u8 trip, Ref type, dialect_t d, tag_t t, sub_t s) { + auto ax = unify(0, n, curry, trip, type, d, t, s); return move_.axioms[ax->flags()] = ax; } - const Axiom* axiom(Ref type, dialect_t d, tag_t t, sub_t s, Ref dbg = {}) { - return axiom(nullptr, 0, 0, type, d, t, s, dbg); - } + const Axiom* axiom(Ref type, dialect_t d, tag_t t, sub_t s) { return axiom(nullptr, 0, 0, type, d, t, s); } /// Builds a fresh Axiom with descending Axiom::sub. /// This is useful during testing to come up with some entitiy of a specific type. /// It uses the dialect Axiom::Global_Dialect and starts with `0` for Axiom::sub and counts up from there. /// The Axiom::tag is set to `0` and the Axiom::normalizer to `nullptr`. - const Axiom* axiom(Def::NormalizeFn n, u8 curry, u8 trip, Ref type, Ref dbg = {}) { - return axiom(n, curry, trip, type, Axiom::Global_Dialect, 0, state_.pod.curr_sub++, dbg); + const Axiom* axiom(Def::NormalizeFn n, u8 curry, u8 trip, Ref type) { + return axiom(n, curry, trip, type, Axiom::Global_Dialect, 0, state_.pod.curr_sub++); } - const Axiom* axiom(Ref type, Ref dbg = {}) { return axiom(nullptr, 0, 0, type, dbg); } ///< See above. + const Axiom* axiom(Ref type) { return axiom(nullptr, 0, 0, type); } ///< See above. /// Get Axiom from a dialect. /// Use this to get an Axiom via Axiom::id. template - const Axiom* ax(Id id) const { + const Axiom* ax(Id id) { u64 flags = static_cast(id); if (auto i = move_.axioms.find(flags); i != move_.axioms.end()) return i->second; - err("Axiom with ID '{}' not found; demangled dialect name is '{}'", flags, Axiom::demangle(flags)); + err("Axiom with ID '{}' not found; demangled dialect name is '{}'", flags, Axiom::demangle(*this, flags)); } /// Get Axiom from a dialect. /// Can be used to get an Axiom without sub-tags. /// E.g. use `w.ax();` to get the `%mem.M` Axiom. template - const Axiom* ax() const { + const Axiom* ax() { return ax(Axiom::Base); } ///@} /// @name Pi ///@{ - const Pi* pi(Ref dom, Ref codom, Ref dbg = {}) { return unify(2, Pi::infer(dom, codom), dom, codom, dbg); } - const Pi* pi(Defs dom, Ref codom, Ref dbg = {}) { return pi(sigma(dom), codom, dbg); } - Pi* nom_pi(Ref type, Ref dbg = {}) { return insert(2, type, dbg); } + const Pi* pi(Ref dom, Ref codom, bool implicit = false) { + return unify(2, Pi::infer(dom, codom), dom, codom, implicit); + } + const Pi* pi(Defs dom, Ref codom, bool implicit = false) { return pi(sigma(dom), codom, implicit); } + Pi* nom_pi(Ref type, bool implicit = false) { return insert(2, type, implicit); } ///@} /// @name Cn (Pi with codom Bot) ///@{ const Pi* cn() { return cn(sigma()); } - const Pi* cn(Ref dom, Ref dbg = {}) { return pi(dom, type_bot(), dbg); } - const Pi* cn(Defs doms, Ref dbg = {}) { return cn(sigma(doms), dbg); } + const Pi* cn(Ref dom) { return pi(dom, type_bot()); } + const Pi* cn(Defs doms) { return cn(sigma(doms)); } ///@} /// @name Lam ///@{ - Lam* nom_lam(const Pi* cn, Ref dbg = {}) { return insert(2, cn, dbg); } - const Lam* lam(const Pi* pi, Ref filter, Ref body, Ref dbg) { return unify(2, pi, filter, body, dbg); } - const Lam* lam(const Pi* pi, Ref body, Ref dbg) { return lam(pi, lit_tt(), body, dbg); } - Lam* exit() { return data_.exit_; } ///< Used as a dummy exit node within Scope. + Lam* nom_lam(const Pi* cn) { return insert(2, cn); } + const Lam* lam(const Pi* pi, Ref filter, Ref body) { return unify(2, pi, filter, body); } + const Lam* lam(const Pi* pi, Ref body) { return lam(pi, lit_tt(), body); } + Lam* exit() { return data_.exit; } ///< Used as a dummy exit node within Scope. ///@} /// @name App ///@{ - const Def* app(Ref callee, Ref arg, Ref dbg = {}); - const Def* app(Ref callee, Defs args, Ref dbg = {}) { return app(callee, tuple(args), dbg); } + Ref app(Ref callee, Ref arg); + Ref app(Ref callee, Defs args) { return app(callee, tuple(args)); } template - const Def* raw_app(Ref type, Ref callee, Ref arg, Ref dbg = {}); + Ref raw_app(Ref type, Ref callee, Ref arg); template - const Def* raw_app(Ref type, Ref callee, Defs args, Ref dbg = {}) { - return raw_app(type, callee, tuple(args), dbg); + Ref raw_app(Ref type, Ref callee, Defs args) { + return raw_app(type, callee, tuple(args)); } ///@} /// @name Sigma ///@{ - Sigma* nom_sigma(Ref type, size_t size, Ref dbg = {}) { return insert(size, type, size, dbg); } + Sigma* nom_sigma(Ref type, size_t size) { return insert(size, type, size); } /// A *nom*inal Sigma of type @p level. template - Sigma* nom_sigma(size_t size, Ref dbg = {}) { - return nom_sigma(type(), size, dbg); + Sigma* nom_sigma(size_t size) { + return nom_sigma(type(), size); } - const Def* sigma(Defs ops, Ref dbg = {}); - const Sigma* sigma() { return data_.sigma_; } ///< The unit type within Type 0. + Ref sigma(Defs ops); + const Sigma* sigma() { return data_.sigma; } ///< The unit type within Type 0. ///@} /// @name Arr ///@{ - Arr* nom_arr(Ref type, Ref dbg = {}) { return insert(2, type, dbg); } + Arr* nom_arr(Ref type) { return insert(2, type); } template - Arr* nom_arr(Ref dbg = {}) { - return nom_arr(type(), dbg); + Arr* nom_arr() { + return nom_arr(type()); } - const Def* arr(Ref shape, Ref body, Ref dbg = {}); - const Def* arr(Defs shape, Ref body, Ref dbg = {}); - const Def* arr(u64 n, Ref body, Ref dbg = {}) { return arr(lit_nat(n), body, dbg); } - const Def* arr(Span shape, Ref body, Ref dbg = {}) { - return arr(DefArray(shape.size(), [&](size_t i) { return lit_nat(shape[i], dbg); }), body, dbg); + Ref arr(Ref shape, Ref body); + Ref arr(Defs shape, Ref body); + Ref arr(u64 n, Ref body) { return arr(lit_nat(n), body); } + Ref arr(Span shape, Ref body) { + return arr(DefArray(shape.size(), [&](size_t i) { return lit_nat(shape[i]); }), body); } - const Def* arr_unsafe(Ref body, Ref dbg = {}) { return arr(top_nat(), body, dbg); } + Ref arr_unsafe(Ref body) { return arr(top_nat(), body); } ///@} /// @name Tuple ///@{ - const Def* tuple(Defs ops, Ref dbg = {}); + Ref tuple(Defs ops); /// Ascribes @p type to this tuple - needed for dependently typed and nominal Sigma%s. - const Def* tuple(Ref type, Defs ops, Ref dbg = {}); - const Def* tuple_str(std::string_view s, Ref dbg = {}); - Sym sym(std::string_view s, Loc loc) { return {tuple_str(s, dbg(loc)), loc.def(*this)}; } - const Tuple* tuple() { return data_.tuple_; } ///< the unit value of type `[]` + Ref tuple(Ref type, Defs ops); + const Tuple* tuple() { return data_.tuple; } ///< the unit value of type `[]` ///@} /// @name Pack ///@{ - Pack* nom_pack(Ref type, Ref dbg = {}) { return insert(1, type, dbg); } - const Def* pack(Ref arity, Ref body, Ref dbg = {}); - const Def* pack(Defs shape, Ref body, Ref dbg = {}); - const Def* pack(u64 n, Ref body, Ref dbg = {}) { return pack(lit_nat(n), body, dbg); } - const Def* pack(Span shape, Ref body, Ref dbg = {}) { - return pack(DefArray(shape.size(), [&](auto i) { return lit_nat(shape[i], dbg); }), body, dbg); + Pack* nom_pack(Ref type) { return insert(1, type); } + Ref pack(Ref arity, Ref body); + Ref pack(Defs shape, Ref body); + Ref pack(u64 n, Ref body) { return pack(lit_nat(n), body); } + Ref pack(Span shape, Ref body) { + return pack(DefArray(shape.size(), [&](auto i) { return lit_nat(shape[i]); }), body); } ///@} /// @name Extract /// @sa core::extract_unsafe ///@{ - const Def* extract(Ref d, Ref i, Ref dbg = {}); - const Def* extract(Ref d, u64 a, u64 i, Ref dbg = {}) { return extract(d, lit_idx(a, i), dbg); } - const Def* extract(Ref d, u64 i, Ref dbg = {}) { return extract(d, as_lit(d->arity()), i, dbg); } + Ref extract(Ref d, Ref i); + Ref extract(Ref d, u64 a, u64 i) { return extract(d, lit_idx(a, i)); } + Ref extract(Ref d, u64 i) { return extract(d, d->as_lit_arity(), i); } /// Builds `(f, t)cond`. /// **Note** that select expects @p t as first argument and @p f as second one. - const Def* select(Ref t, Ref f, Ref cond, Ref dbg = {}) { return extract(tuple({f, t}), cond, dbg); } + Ref select(Ref t, Ref f, Ref cond) { return extract(tuple({f, t}), cond); } ///@} /// @name Insert /// @sa core::insert_unsafe ///@{ - const Def* insert(Ref d, Ref i, Ref val, Ref dbg = {}); - const Def* insert(Ref d, u64 a, u64 i, Ref val, Ref dbg = {}) { return insert(d, lit_idx(a, i), val, dbg); } - const Def* insert(Ref d, u64 i, Ref val, Ref dbg = {}) { return insert(d, as_lit(d->arity()), i, val, dbg); } + Ref insert(Ref d, Ref i, Ref val); + Ref insert(Ref d, u64 a, u64 i, Ref val) { return insert(d, lit_idx(a, i), val); } + Ref insert(Ref d, u64 i, Ref val) { return insert(d, d->as_lit_arity(), i, val); } ///@} /// @name Lit ///@{ - const Lit* lit(Ref type, u64 val, Ref dbg = {}); - const Lit* lit_univ(u64 level, Ref dbg = {}) { return lit(univ(), level, dbg); } - const Lit* lit_univ_0() { return data_.lit_univ_0_; } - const Lit* lit_univ_1() { return data_.lit_univ_1_; } - const Lit* lit_nat(nat_t a, Ref dbg = {}) { return lit(type_nat(), a, dbg); } - const Lit* lit_nat_0() { return data_.lit_nat_0_; } - const Lit* lit_nat_1() { return data_.lit_nat_1_; } - const Lit* lit_nat_max() { return data_.lit_nat_max_; } + const Lit* lit(Ref type, u64 val); + const Lit* lit_univ(u64 level) { return lit(univ(), level); } + const Lit* lit_univ_0() { return data_.lit_univ_0; } + const Lit* lit_univ_1() { return data_.lit_univ_1; } + const Lit* lit_nat(nat_t a) { return lit(type_nat(), a); } + const Lit* lit_nat_0() { return data_.lit_nat_0; } + const Lit* lit_nat_1() { return data_.lit_nat_1; } + const Lit* lit_nat_max() { return data_.lit_nat_max; } /// Constructs a Lit of type Idx of size @p size. /// @note `size = 0` means `2^64`. - const Lit* lit_idx(nat_t size, u64 val, Ref dbg = {}) { return lit(type_idx(size), val, dbg); } + const Lit* lit_idx(nat_t size, u64 val) { return lit(type_idx(size), val); } template - const Lit* lit_idx(I val, Ref dbg = {}) { + const Lit* lit_idx(I val) { static_assert(std::is_integral()); - return lit_idx(Idx::bitwidth2size(sizeof(I) * 8), val, dbg); + return lit_idx(Idx::bitwidth2size(sizeof(I) * 8), val); } /// Constructs a Lit @p of type Idx of size $2^width$. /// `val = 64` will be automatically converted to size `0` - the encoding for $2^64$. - const Lit* lit_int(nat_t width, u64 val, Ref dbg = {}) { return lit_idx(Idx::bitwidth2size(width), val, dbg); } + const Lit* lit_int(nat_t width, u64 val) { return lit_idx(Idx::bitwidth2size(width), val); } /// Constructs a Lit of type Idx of size @p mod. /// The value @p val will be adjusted modulo @p mod. /// @note `mod == 0` is the special case for $2^64$ and no modulo will be performed on @p val. - const Lit* lit_idx_mod(nat_t mod, u64 val, Ref dbg = {}) { return lit_idx(mod, mod == 0 ? val : (val % mod), dbg); } + const Lit* lit_idx_mod(nat_t mod, u64 val) { return lit_idx(mod, mod == 0 ? val : (val % mod)); } - const Lit* lit_bool(bool val) { return data_.lit_bool_[size_t(val)]; } - const Lit* lit_ff() { return data_.lit_bool_[0]; } - const Lit* lit_tt() { return data_.lit_bool_[1]; } + const Lit* lit_bool(bool val) { return data_.lit_bool[size_t(val)]; } + const Lit* lit_ff() { return data_.lit_bool[0]; } + const Lit* lit_tt() { return data_.lit_bool[1]; } // clang-format off ///@} /// @name lattice ///@{ - template - const Def* ext(Ref type, Ref dbg = {}); - const Def* bot(Ref type, Ref dbg = {}) { return ext(type, dbg); } - const Def* top(Ref type, Ref dbg = {}) { return ext(type, dbg); } - const Def* type_bot() { return data_.type_bot_; } - const Def* top_nat() { return data_.top_nat_; } - template TBound* nom_bound(Ref type, size_t size, Ref dbg = {}) { return insert>(size, type, size, dbg); } + template + Ref ext(Ref type); + Ref bot(Ref type) { return ext(type); } + Ref top(Ref type) { return ext(type); } + Ref type_bot() { return data_.type_bot; } + Ref top_nat() { return data_.top_nat; } + template TBound* nom_bound(Ref type, size_t size) { return insert>(size, type, size); } /// A *nom*inal Bound of Type @p l%evel. - template TBound* nom_bound(size_t size, Ref dbg = {}) { return nom_bound(type(), size, dbg); } - template const Def* bound(Defs ops, Ref dbg = {}); - Join* nom_join(Ref type, size_t size, Ref dbg = {}) { return nom_bound(type, size, dbg); } - Meet* nom_meet(Ref type, size_t size, Ref dbg = {}) { return nom_bound(type, size, dbg); } - template Join* nom_join(size_t size, Ref dbg = {}) { return nom_join(type(), size, dbg); } - template Meet* nom_meet(size_t size, Ref dbg = {}) { return nom_meet(type(), size, dbg); } - const Def* join(Defs ops, Ref dbg = {}) { return bound(ops, dbg); } - const Def* meet(Defs ops, Ref dbg = {}) { return bound(ops, dbg); } - const Def* ac(Ref type, Defs ops, Ref dbg = {}); + template TBound* nom_bound(size_t size) { return nom_bound(type(), size); } + template Ref bound(Defs ops); + Join* nom_join(Ref type, size_t size) { return nom_bound(type, size); } + Meet* nom_meet(Ref type, size_t size) { return nom_bound(type, size); } + template Join* nom_join(size_t size) { return nom_join(type(), size); } + template Meet* nom_meet(size_t size) { return nom_meet(type(), size); } + Ref join(Defs ops) { return bound(ops); } + Ref meet(Defs ops) { return bound(ops); } + Ref ac(Ref type, Defs ops); /// Infers the type using a *structural* Meet. - const Def* ac(Defs ops, Ref dbg = {}); - const Def* vel(Ref type, Ref value, Ref dbg = {}); - const Def* pick(Ref type, Ref value, Ref dbg = {}); - const Def* test(Ref value, Ref probe, Ref match, Ref clash, Ref dbg = {}); - const Def* singleton(Ref inner_type, Ref dbg = {}); + Ref ac(Defs ops); + Ref vel(Ref type, Ref value); + Ref pick(Ref type, Ref value); + Ref test(Ref value, Ref probe, Ref match, Ref clash); + Ref singleton(Ref inner_type); ///@} /// @name globals -- depdrecated; will be removed ///@{ - Global* global(Ref type, bool is_mutable = true, Ref dbg = {}) { return insert(1, type, is_mutable, dbg); } + Global* global(Ref type, bool is_mutable = true) { return insert(1, type, is_mutable); } ///@} // clang-format on /// @name types ///@{ - const Nat* type_nat() { return data_.type_nat_; } - const Idx* type_idx() { return data_.type_idx_; } + const Nat* type_nat() { return data_.type_nat; } + const Idx* type_idx() { return data_.type_idx; } /// @note `size = 0` means `2^64`. - const Def* type_idx(Ref size, Ref dbg = {}) { return app(type_idx(), size, dbg); } + Ref type_idx(Ref size) { return app(type_idx(), size); } /// @note `size = 0` means `2^64`. - const Def* type_idx(nat_t size) { return type_idx(lit_nat(size)); } + Ref type_idx(nat_t size) { return type_idx(lit_nat(size)); } /// Constructs a type Idx of size $2^width$. /// `width = 64` will be automatically converted to size `0` - the encoding for $2^64$. - const Def* type_int(nat_t width) { return type_idx(lit_nat(Idx::bitwidth2size(width))); } - const Def* type_bool() { return data_.type_bool_; } + Ref type_int(nat_t width) { return type_idx(lit_nat(Idx::bitwidth2size(width))); } + Ref type_bool() { return data_.type_bool; } ///@} /// @name cope with implicit arguments ///@{ /// Places Infer arguments as demanded by @p debug.meta and then apps @p arg. - const Def* iapp(Ref callee, Ref arg, Debug debug); - const Def* iapp(Ref callee, Defs args, Debug debug) { return iapp(callee, tuple(args), debug); } - const Def* iapp(Ref callee, nat_t arg, Debug debug) { return iapp(callee, lit_nat(arg), debug); } - - /// Converts C++ vector `{true, false, false}` to nested Thorin nested pairs `(.tt, (.ff, (.ff, ⊥)))`. - const Def* implicits2meta(const Implicits&); + Ref iapp(Ref callee, Ref arg); + Ref iapp(Ref callee, Defs args) { return iapp(callee, tuple(args)); } + Ref iapp(Ref callee, nat_t arg) { return iapp(callee, lit_nat(arg)); } // clang-format off - template const Def* call(Id id, Args&&... args) { return dcall_({}, ax(id), std::forward(args)...); } - template const Def* call( Args&&... args) { return dcall_({}, ax(), std::forward(args)...); } - template const Def* dcall(Ref dbg, Id id, Args&&... args) { return dcall_(dbg, ax(id), std::forward(args)...); } - template const Def* dcall(Ref dbg, Args&&... args) { return dcall_(dbg, ax(), std::forward(args)...); } - template const Def* dcall_(Ref dbg, Ref callee, T arg, Args&&... args) { return dcall_(dbg, iapp(callee, arg, Debug(dbg)), std::forward(args)...); } - template const Def* dcall_(Ref dbg, Ref callee, T arg) { return iapp(callee, arg, Debug(dbg)); } + template const Def* call(Id id, Args&&... args) { return call_(ax(id), std::forward(args)...); } + template const Def* call( Args&&... args) { return call_(ax(), std::forward(args)...); } + template const Def* call_(Ref callee, T arg, Args&&... args) { return call_(iapp(callee, arg), std::forward(args)...); } + template const Def* call_(Ref callee, T arg) { return iapp(callee, arg); } // clang-format on ///@} /// @name helpers ///@{ - const Def* dbg(Debug d) { return d.def(*this); } - const Def* dbg(Sym sym, Loc loc, const Def* meta = {}) { - meta = meta ? meta : bot(type_bot()); - return tuple({sym.str(), loc.def(*this), meta}); - } - const Def* dbg(Sym sym, const Def* meta = {}) { - auto loc = sym.loc() ? sym.loc() : Loc().def(*this); - meta = meta ? meta : bot(type_bot()); - return tuple({sym.str(), loc, meta}); - } - const Def* iinfer(Ref def) { return Idx::size(def->type()); } + Ref iinfer(Ref def) { return Idx::size(def->type()); } ///@} /// @name dumping/logging ///@{ - const Log& log() const { return state_.pod.log; } - Log& log() { return state_.pod.log; } - void dump(std::ostream& os) const; ///< Dump to @p os. - void dump() const; ///< Dump to `std::cout`. - void debug_dump() const; ///< Dump in Debug build if World::log::level is Log::Level::Debug. - void write(const char* file) const; ///< Write to a file named @p file; defaults to World::name. - void write() const; ///< Same above but file name defaults to World::name. + const Log& log() const; + Log& log(); + void dummy() {} + + void dump(std::ostream& os); ///< Dump to @p os. + void dump(); ///< Dump to `std::cout`. + void debug_dump(); ///< Dump in Debug build if World::log::level is Log::Level::Debug. + void write(const char* file); ///< Write to a file named @p file. + void write(); ///< Same above but file name defaults to World::name. ///@} private: @@ -472,10 +463,11 @@ class World { template const T* unify(size_t num_ops, Args&&... args) { auto def = arena_.allocate(num_ops, std::forward(args)...); + if (auto loc = emit_loc()) def->set(loc); assert(!def->isa_nom()); #if THORIN_ENABLE_CHECKS - if (flags().trace_gids) outln("{}: {}", def->node_name(), def->gid()); - if (flags().reeval_breakpoints && state_.breakpoints.contains(def->gid())) thorin::breakpoint(); + if (flags().trace_gids) outln("{}: {} - {}", def->node_name(), def->gid(), def->flags()); + if (flags().reeval_breakpoints && breakpoints().contains(def->gid())) thorin::breakpoint(); #endif if (is_frozen()) { --state_.pod.curr_gid; @@ -490,7 +482,7 @@ class World { return static_cast(*i); } #if THORIN_ENABLE_CHECKS - if (!flags().reeval_breakpoints && state_.breakpoints.contains(def->gid())) thorin::breakpoint(); + if (!flags().reeval_breakpoints && breakpoints().contains(def->gid())) thorin::breakpoint(); #endif def->finalize(); return def; @@ -499,9 +491,10 @@ class World { template T* insert(size_t num_ops, Args&&... args) { auto def = arena_.allocate(num_ops, std::forward(args)...); + if (auto loc = emit_loc()) def->set(loc); #if THORIN_ENABLE_CHECKS - if (flags().trace_gids) outln("{}: {}", def->node_name(), def->gid()); - if (state_.breakpoints.contains(def->gid())) thorin::breakpoint(); + if (flags().trace_gids) outln("{}: {} - {}", def->node_name(), def->gid(), def->flags()); + if (breakpoints().contains(def->gid())) thorin::breakpoint(); #endif auto [_, ins] = move_.defs.emplace(def); assert_unused(ins); @@ -509,6 +502,7 @@ class World { } ///@} + Driver* driver_; State state_; class Arena { @@ -572,7 +566,7 @@ class World { template static constexpr inline size_t num_bytes_of(size_t num_ops) { - size_t result = sizeof(Def) + sizeof(const Def*) * num_ops; + size_t result = sizeof(Def) + sizeof(void*) * num_ops; return align(result); } @@ -599,50 +593,50 @@ class World { bool operator()(const Def* d1, const Def* d2) const { return d1->equal(d2); } }; - struct { - const Univ* univ_; - const Type* type_0_; - const Type* type_1_; - const Bot* type_bot_; - const Def* type_bool_; - const Top* top_nat_; - const Sigma* sigma_; - const Tuple* tuple_; - const Nat* type_nat_; - const Idx* type_idx_; - const Def* table_id; - const Def* table_not; - std::array lit_bool_; - const Lit* lit_nat_0_; - const Lit* lit_nat_1_; - const Lit* lit_nat_max_; - const Lit* lit_univ_0_; - const Lit* lit_univ_1_; - Lam* exit_; - } data_; - struct Move { Move(World&); + std::unique_ptr checker; absl::btree_map axioms; - absl::btree_map externals; + absl::btree_map externals; absl::flat_hash_set defs; DefDefMap cache; - std::unique_ptr checker; friend void swap(Move& m1, Move& m2) { using std::swap; // clang-format off + swap(m1.checker, m2.checker); swap(m1.axioms, m2.axioms); swap(m1.externals, m2.externals); swap(m1.defs, m2.defs); swap(m1.cache, m2.cache); - swap(m1.checker, m2.checker); // clang-format on Checker::swap(*m1.checker, *m2.checker); } } move_; + struct { + const Univ* univ; + const Type* type_0; + const Type* type_1; + const Bot* type_bot; + const Def* type_bool; + const Top* top_nat; + const Sigma* sigma; + const Tuple* tuple; + const Nat* type_nat; + const Idx* type_idx; + const Def* table_id; + const Def* table_not; + std::array lit_bool; + const Lit* lit_nat_0; + const Lit* lit_nat_1; + const Lit* lit_nat_max; + const Lit* lit_univ_0; + const Lit* lit_univ_1; + Lam* exit; + } data_; + friend void swap(World& w1, World& w2) { using std::swap; // clang-format off @@ -652,7 +646,7 @@ class World { swap(w1.move_, w2.move_ ); // clang-format on - swap(w1.data_.univ_->world_, w2.data_.univ_->world_); + swap(w1.data_.univ->world_, w2.data_.univ->world_); assert(&w1.univ()->world() == &w1); assert(&w2.univ()->world() == &w2); }