diff --git a/.gitignore b/.gitignore index d1fadabc8e..55fd1b130f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,5 @@ *.s .DS_Store .cache -build* +build*/ vgcore.* diff --git a/cli/main.cpp b/cli/main.cpp index 490059e0c5..f7e657daa1 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -20,7 +20,7 @@ using namespace thorin; using namespace std::literals; -enum Backends { Dot, H, LL, Md, Thorin, Num_Backends }; +enum Backends { Dot, H, LL, CustBE, Custom, Md, Thorin, Num_Backends }; int main(int argc, char** argv) { try { @@ -48,6 +48,8 @@ int main(int argc, char** argv) { | lyra::opt(dialect_paths, "path" )["-D"]["--dialect-path" ]("Path to search dialects in.") | lyra::opt(inc_verbose )["-V"]["--verbose" ]("Verbose mode. Multiple -V options increase the verbosity. The maximum is 4.").cardinality(0, 4) | lyra::opt(opt, "level" )["-O"]["--optimize" ]("Optimization level (default: 2).") + | lyra::opt(output[CustBE ], "dialect") ["--backend" ]("Sets the backend to use.") + | lyra::opt(output[Custom ], "file" ) ["--output" ]("Output file for the custom backend.") | lyra::opt(output[Dot ], "file" ) ["--output-dot" ]("Emits the Thorin program as a graph using Graphviz' DOT language.") | lyra::opt(output[H ], "file" ) ["--output-h" ]("Emits a header file to be used to interface with a dialect in C++.") | lyra::opt(output[LL ], "file" ) ["--output-ll" ]("Compiles the Thorin program to LLVM.") @@ -88,6 +90,7 @@ int main(int argc, char** argv) { std::array os; os.fill(nullptr); for (size_t be = 0; be != Num_Backends; ++be) { + if (be == CustBE) continue; if (output[be].empty()) continue; if (output[be] == "-") { os[be] = &std::cout; @@ -98,7 +101,7 @@ int main(int argc, char** argv) { } // we always need core and mem, as long as we are not in bootstrap mode.. - if (!os[H]) dialect_plugins.insert(dialect_plugins.end(), {"core", "mem", "compile"}); + if (!os[H]) dialect_plugins.insert(dialect_plugins.end(), {"core", "mem", "compile", "opt"}); std::vector dialects; thorin::Backends backends; @@ -129,18 +132,16 @@ int main(int argc, char** argv) { fe::Parser parser(world, input, ifs, dialect_paths, &normalizers, os[Md]); parser.parse_module(); - if (os[H]) parser.bootstrap(*os[H]); - - PipelineBuilder builder; - for (const auto& dialect : dialects) dialect.add_passes(builder); - - if (os[H]) opt = std::min(opt, 1); + if (os[H]) { + parser.bootstrap(*os[H]); + opt = std::min(opt, 1); + } // clang-format off switch (opt) { case 0: break; case 1: Phase::run(world); break; - case 2: optimize(world, passes, builder); break; + case 2: optimize(world, passes, dialects); break; default: errln("error: illegal optimization level '{}'", opt); } // clang-format on @@ -149,10 +150,19 @@ int main(int argc, char** argv) { if (os[Dot]) dot::emit(world, *os[Dot]); if (os[LL]) { - if (auto it = backends.find("ll"); it != backends.end()) { - it->second(world, *os[LL]); + os[Custom] = os[LL]; + output[CustBE] = "ll"; + } + + if (os[Custom]) { + auto backendId = output[CustBE]; + if (auto it = backends.find(backendId); it != backends.end()) { + auto backend = it->second; + // auto backendExtensions = extensions["ll"]; + backend(world, *os[Custom]); + //, extensions.contains(backendId) ? (extensions[backendId]) : Extensions{}); } else - errln("error: 'll' emitter not loaded. Try loading 'mem' dialect."); + errln("error: '{}' emitter not loaded.", backendId); } } catch (const std::exception& e) { errln("{}", e.what()); diff --git a/dialects/CMakeLists.txt b/dialects/CMakeLists.txt index 3cc5af3db6..67e30ad7b5 100644 --- a/dialects/CMakeLists.txt +++ b/dialects/CMakeLists.txt @@ -54,11 +54,14 @@ add_thorin_dialect(clos clos/pass/rw/clos2sjlj.h clos/pass/rw/clos_conv_prep.cpp clos/pass/rw/clos_conv_prep.h + clos/pass/rw/phase_wrapper.h clos/phase/clos_conv.cpp clos/phase/clos_conv.h clos/phase/lower_typed_clos.cpp clos/phase/lower_typed_clos.h mem/passes/fp/copy_prop.cpp + mem/passes/rw/reshape.cpp + mem/phases/rw/add_mem.cpp DEPENDS mem affine @@ -74,6 +77,8 @@ add_thorin_dialect(compile compile/normalizers.cpp compile/passes/debug_print.cpp compile/passes/debug_print.h + compile/passes/internal_cleanup.cpp + compile/passes/internal_cleanup.h INSTALL ) @@ -110,6 +115,25 @@ add_thorin_dialect(direct INSTALL ) +add_thorin_dialect(backend + SOURCES + backend/backend.cpp + backend/backend.h + backend/be/ocaml_emit.h + backend/be/ocaml_emit.cpp + backend/be/ocaml_emitter.cpp + backend/be/haskell_emit.h + backend/be/haskell_emit.cpp + backend/be/rust_emit.h + backend/be/rust_emit.cpp + DEPENDS + compile + core + math + mem + INSTALL +) + add_thorin_dialect(math SOURCES math/math.cpp @@ -131,6 +155,8 @@ add_thorin_dialect(mem mem/passes/rw/alloc2malloc.h mem/passes/rw/remem_elim.cpp mem/passes/rw/remem_elim.h + mem/passes/rw/reshape.cpp + mem/passes/rw/reshape.h mem/phases/rw/add_mem.cpp mem/phases/rw/add_mem.h DEPENDS @@ -140,12 +166,25 @@ add_thorin_dialect(mem INSTALL ) +add_thorin_dialect(opt + SOURCES + opt/opt.cpp + opt/opt.h + opt/normalizers.cpp + DEPENDS + compile + mem + core + INSTALL +) + add_thorin_dialect(refly SOURCES refly/refly.h refly/refly.cpp refly/passes/remove_perm.h refly/passes/remove_perm.cpp + refly/passes/debug_dump.h refly/normalizers.cpp INSTALL ) diff --git a/dialects/affine/affine.cpp b/dialects/affine/affine.cpp index cc7a241a2f..f4da349c40 100644 --- a/dialects/affine/affine.cpp +++ b/dialects/affine/affine.cpp @@ -10,9 +10,6 @@ using namespace thorin; extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { - return {"affine", - [](thorin::PipelineBuilder& builder) { - builder.extend_opt_phase([](thorin::PassMan& man) { man.add(); }); - }, - [](Passes& passes) { register_pass(passes); }, nullptr, nullptr}; + return {"affine", [](Passes& passes) { register_pass(passes); }, nullptr, + nullptr}; } diff --git a/dialects/affine/passes/lower_for.cpp b/dialects/affine/passes/lower_for.cpp index 188a408fec..1197dcf36d 100644 --- a/dialects/affine/passes/lower_for.cpp +++ b/dialects/affine/passes/lower_for.cpp @@ -37,16 +37,16 @@ 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()); - new_body->set(nom_body->reduce(w.tuple({iter, acc, yield_lam}))); + auto new_body = nom_body->stub(w, w.cn(acc->type()), body->dbg()); + new_body->set(nom_body->reduce(w.tuple({iter, new_body->var(), yield_lam}))); // break - auto if_else_cn = w.cn(w.sigma()); + auto if_else_cn = w.cn(acc->type()); auto if_else = w.nom_lam(if_else_cn, nullptr); - if_else->app(false, brk, acc); + if_else->app(false, brk, if_else->var()); auto cmp = core::op(core::icmp::ul, iter, end); - for_lam->branch(false, cmp, new_body, if_else, w.tuple()); + for_lam->branch(false, cmp, new_body, if_else, acc); } DefArray for_args{for_ax->num_args() - 2, [&](size_t i) { return for_ax->arg(i); }}; diff --git a/dialects/autodiff/autodiff.cpp b/dialects/autodiff/autodiff.cpp index e3b1f01736..6c85ad2c6b 100644 --- a/dialects/autodiff/autodiff.cpp +++ b/dialects/autodiff/autodiff.cpp @@ -13,28 +13,8 @@ using namespace thorin; -/// optimization idea: -/// * optimize [100] -/// * perform ad [105] -/// * resolve unsolved zeros (not added) [111] -/// * optimize further, cleanup direct style [115-120] (in direct) -/// * cleanup (zeros, externals) [299] extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { return {"autodiff", - [](thorin::PipelineBuilder& builder) { - builder.add_opt(110); - builder.extend_opt_phase(105, [](thorin::PassMan& man) { man.add(); }); - builder.extend_opt_phase(111, [](thorin::PassMan& man) { - // in theory only after partial eval (beta, ...) - // but before other simplification - // zero and add need to be close together - man.add(); - }); - builder.extend_opt_phase(299, [](PassMan& man) { - man.add(); - man.add(); - }); - }, [](Passes& passes) { register_pass(passes); register_pass(passes); diff --git a/dialects/backend/backend.cpp b/dialects/backend/backend.cpp new file mode 100644 index 0000000000..bbaf39fd1d --- /dev/null +++ b/dialects/backend/backend.cpp @@ -0,0 +1,26 @@ +#include "dialects/backend/backend.h" + +#include +#include + +#include "thorin/dialects.h" + +#include "dialects/backend/be/haskell_emit.h" +#include "dialects/backend/be/ocaml_emit.h" +#include "dialects/backend/be/rust_emit.h" + +using namespace thorin; + +extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { + return {"backend", + [](Passes& passes) { + register_phase(passes); //, std::cout); + }, + [](Backends& backends) { + // backends["ml"] = &backend::ocaml::emit; + backends["ml"] = &backend::ocaml::emit2; + backends["hs"] = &backend::haskell::emit; + backends["rs"] = &backend::rust::emit; + }, + nullptr}; +} diff --git a/dialects/backend/backend.h b/dialects/backend/backend.h new file mode 100644 index 0000000000..94c822f50e --- /dev/null +++ b/dialects/backend/backend.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#include "dialects/backend/autogen.h" diff --git a/dialects/backend/backend.thorin b/dialects/backend/backend.thorin new file mode 100644 index 0000000000..3c8d9860eb --- /dev/null +++ b/dialects/backend/backend.thorin @@ -0,0 +1,15 @@ +/// # The backend Dialect {#backend} +/// +/// TODO: +/// +/// [TOC] +/// +/// ## Dependencies +/// +.import compile; +/// +/// ## Compilation Passes and Phases +/// +/// ### Phases +/// +.ax %backend.ocaml_phase: %compile.Phase; diff --git a/dialects/backend/be/haskell_emit.cpp b/dialects/backend/be/haskell_emit.cpp new file mode 100644 index 0000000000..ba905dca4f --- /dev/null +++ b/dialects/backend/be/haskell_emit.cpp @@ -0,0 +1,456 @@ +#include "dialects/backend/be/haskell_emit.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "thorin/axiom.h" +#include "thorin/def.h" +#include "thorin/tuple.h" + +#include "thorin/analyses/cfg.h" +#include "thorin/analyses/deptree.h" +#include "thorin/be/emitter.h" +#include "thorin/fe/tok.h" +#include "thorin/util/assert.h" +#include "thorin/util/print.h" +#include "thorin/util/sys.h" + +#include "absl/container/flat_hash_map.h" +#include "dialects/core/autogen.h" +#include "dialects/core/core.h" +#include "dialects/math/math.h" +#include "dialects/mem/autogen.h" +#include "dialects/mem/mem.h" + +using namespace std::string_literals; + +/* + +TODO: +* mutual recursion +* operations + +*/ + +namespace thorin::backend::haskell { + +const char* PREFACE = R"( +{-# LANGUAGE ScopedTypeVariables #-} +{-# OPTIONS_GHC -Wno-incomplete-patterns #-} +import Data.IORef +bool2bit x = if x then 1 else 0 +get_0_of_2 (x, _) = x +get_1_of_2 (_, x) = x +get_0_of_3 (x, _, _) = x +get_1_of_3 (_, x, _) = x +get_2_of_3 (_, _, x) = x +magic a = magic a + +)"; + +/* + * helper + */ + +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; + } + return nullptr; +} + +absl::flat_hash_map names; +static std::string id(const Def* def) { + if (def->is_external() || (!def->is_set() && def->isa())) return def->name(); + + if (auto name = names.find(def); name != names.end()) return name->second; + + return def->unique_name(); +} + +static std::string_view external(const Def* def) { + if (def->is_external()) return "-- external \n"; + return ""; +} + +/* + * Inline + LRPrec + */ + +/// This is a wrapper to dump a Def "inline" and print it with all of its operands. +struct Inline2 { + Inline2(const Def* def, int dump_gid) + : def_(def) + , dump_gid_(dump_gid) {} + Inline2(const Def* def) + : Inline2(def, def->world().flags().dump_gid) {} + + const Def* operator->() const { return def_; }; + const Def* operator*() const { return def_; }; + explicit operator bool() const { + if (def_->dep_const()) return true; + + if (auto nom = def_->isa_nom()) { + if (isa_decl(nom)) return false; + return true; + } + + if (auto app = def_->isa()) { + if (app->type()->isa()) return true; // curried apps are printed inline + if (app->type()->isa()) return true; + if (app->callee()->isa()) { return app->callee_type()->num_doms() <= 1; } + return false; + } + + return true; + } + + friend std::ostream& operator<<(std::ostream&, Inline2); + +private: + const Def* def_; + const int dump_gid_; +}; + +static std::string id(Inline2 u) { return id(*u); } + +// TODO prec is currently broken +template +struct LRPrec2 { + LRPrec2(const Def* l, const Def* r) + : l(l) + , r(r) {} + + friend std::ostream& operator<<(std::ostream& os, const LRPrec2& p) { + if constexpr (L) { + if (Inline2(p.l) && fe::Tok::prec(fe::Tok::prec(p.r))[0] > fe::Tok::prec(p.r)) + return print(os, "({})", Inline2(p.l)); + return print(os, "{}", Inline2(p.l)); + } else { + if (Inline2(p.r) && fe::Tok::prec(p.l) > fe::Tok::prec(fe::Tok::prec(p.l))[1]) + return print(os, "({})", Inline2(p.r)); + return print(os, "{}", Inline2(p.r)); + } + } + +private: + const Def* l; + const Def* r; +}; + +using LPrec = LRPrec2; +using RPrec = LRPrec2; + +DefSet let_emitted; + +std::ostream& operator<<(std::ostream& os, Inline2 u) { + if (u.dump_gid_ == 2 || (u.dump_gid_ == 1 && !u->isa() && u->num_ops() != 0)) print(os, "/*{}*/", u->gid()); + + if (let_emitted.contains(u.def_)) { return print(os, "{}", id(u)); } + + // Ptr -> Ref + Option for uninitialized + // Arr -> List (need persistent) + if (auto ptr = match(*u)) { + auto type = ptr->arg(0); + return print(os, "(IORef {})", Inline2(type)); + } + if (auto mem = match(*u)) { return print(os, "unit"); } + // TODO: ptr(arr) -> array (but how to handle lea) + + if (auto arith = match(*u)) { + auto [a, b] = arith->args<2>(); + const char* op; + switch (arith.id()) { + case core::nop::add: op = "+"; break; + case core::nop::mul: op = "*"; break; + } + return print(os, "({} {} {})", Inline2(a), op, Inline2(b)); + } + if (auto arith = match(*u)) { + auto [a, b] = arith->args<2>(); + if (arith.id() == core::wrap::shl) { return print(os, "(Int.shift_left {} {})", Inline2(a), Inline2(b)); } + const char* op; + switch (arith.id()) { + case core::wrap::add: op = "+"; break; + case core::wrap::sub: op = "-"; break; + case core::wrap::mul: op = "*"; break; + case core::wrap::shl: unreachable(); + } + return print(os, "({} {} {})", Inline2(a), op, Inline2(b)); + } + if (auto icmp = match(*u)) { + auto [a, b] = icmp->args<2>(); + const char* op; + // TODO: signed unsigned difference + switch (icmp.id()) { + case core::icmp::e: op = "=="; break; + case core::icmp::sl: op = "<"; break; + case core::icmp::sle: op = "<="; break; + case core::icmp::ug: op = ">"; break; + case core::icmp::uge: op = ">="; break; + case core::icmp::ul: op = "<"; break; + case core::icmp::ule: op = "<="; break; + case core::icmp::sg: op = ">"; break; + case core::icmp::sge: op = ">="; break; + case core::icmp::ne: op = "!="; break; + case core::icmp::f: + case core::icmp::t: unreachable(); + default: assert(false && "unhandled icmp"); + } + return print(os, "(bool2bit ({} {} {}))", Inline2(a), op, Inline2(b)); + } + + if (auto app = u->isa()) { + auto callee = app->callee(); + if (callee->isa()) { return print(os, "Int"); } + return print(os, "({} {})", Inline2(app->callee()), Inline2(app->arg())); + } + + if (auto type = u->isa()) { + auto level = as_lit(type->level()); // TODO other levels + return print(os, level == 0 ? "★" : "□"); + } else if (u->isa()) { + return print(os, "Integer"); + } else if (u->isa()) { + assert(false && "unapplied idx"); + } else if (auto bot = u->isa()) { + if (bot->type()->isa()) return print(os, "a"); + return print(os, "magic"); + } else if (auto top = u->isa()) { + if (top->type()->isa()) return print(os, "a"); + return print(os, "()"); + } else if (auto axiom = u->isa()) { + const auto& name = axiom->name(); + return print(os, "{}{}", name[0] == '%' ? "" : "%", name); + } else if (auto lit = u->isa()) { + long value = lit->get(); + if (lit->type()->isa()) return print(os, "{}", lit->get()); + if (value == 4294967295) { value = -1; } + // TODO: 4294967295 => -1 / add modulo at operations (probably better) + if (lit->type()->isa()) + return print(os, "({}::{})", value, Inline2(lit->type())); // HACK prec magic is broken + return print(os, "{}::{}", lit->get(), Inline2(lit->type())); + } else if (auto ex = u->isa()) { + if (ex->tuple()->isa() && ex->index()->isa()) return print(os, "{}", id(ex)); + if (ex->tuple()->type()->isa()) { + return print(os, "({} !! {})", Inline2(ex->tuple()), Inline2(ex->index())); + } else { + auto extract_fun = "get_" + std::to_string(ex->index()->as()->get()) + "_of_" + + std::to_string(ex->tuple()->num_ops()); + return print(os, "({} {})", extract_fun, Inline2(ex->tuple())); + } + } else if (auto var = u->isa()) { + return print(os, "{}", id(var)); + } else if (auto pi = u->isa()) { + if (auto nom = pi->isa_nom(); nom && nom->var()) assert(false && "nom pi"); + return print(os, "({} -> {})", Inline2(pi->dom()), Inline2(pi->codom())); + } else if (auto lam = u->isa()) { + return print(os, "{}", lam); + } else if (auto sigma = u->isa()) { + if (auto nom = sigma->isa_nom(); nom && nom->var()) { + size_t i = 0; + return print(os, "({, })", Elem(sigma->ops(), [&](auto op) { + if (auto v = nom->var(i++)) + print(os, "{}:: {}", v, Inline2(op)); + else + print(os, "_:: {}", Inline2(op)); + })); + } + if (sigma->num_ops() == 0) return print(os, "unit"); + return print(os, "({ , })", Elem(sigma->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + } else if (auto tuple = u->isa()) { + if (tuple->type()->isa()) { + print(os, "[{, }]", Elem(tuple->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + return os; + } else { + print(os, "({, })", Elem(tuple->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + return os; + } + } else if (auto arr = u->isa()) { + if (auto nom = arr->isa_nom(); nom && nom->var()) assert(false && "nom arr"); + return print(os, "[{}]", Inline2(arr->body())); + } else if (auto pack = u->isa()) { + if (auto nom = pack->isa_nom(); nom && nom->var()) + return print(os, "[{} | {} <- [1..{}]]", Inline2(nom->body()), Inline2(nom->var()), Inline2(nom->shape())); + return print(os, "(replicate {} {})", Inline2(pack->shape()), Inline2(pack->body())); + + } else if (auto proxy = u->isa()) { + assert(0); + } else if (auto bound = u->isa()) { + assert(0); + } + + // TODO: other + if (u->flags() == 0) return print(os, ".{} ({, })", u->node_name(), u->ops()); + return print(os, ".{}#{} ({, })", u->node_name(), u->flags(), u->ops()); +} + +/* + * Dumper + */ + +/// This thing operates in two modes: +/// 1. The output of decls is driven by the DepTree. +/// 2. Alternatively, decls are output as soon as they appear somewhere during recurse%ing. +/// Then, they are pushed to Dumper::noms. +class Dumper { +public: + Dumper(std::ostream& os, const DepTree* dep = nullptr) + : os(os) + , dep(dep) {} + + void dump(Def*); + void dump(Lam*); + void dump_let(const Def*); + void dump_ptrn(const Def*, const Def*, bool toplevel = true); + void recurse(const DepNode*); + void recurse(const Def*, bool first = false); + + std::ostream& os; + const DepTree* dep; + Tab tab; + unique_queue noms; + DefSet defs; +}; + +void Dumper::dump(Def* nom) { + if (auto lam = nom->isa()) { + dump(lam); + return; + } + + auto nom_prefix = [&](const Def* def) { + if (def->isa()) return ".Sigma"; + if (def->isa()) return ".Arr"; + if (def->isa()) return ".pack"; + if (def->isa()) return ".Pi"; + unreachable(); + }; + + auto nom_op0 = [&](const Def* def) -> std::ostream& { + if (auto sig = def->isa()) return print(os, ", {}", sig->num_ops()); + if (auto arr = def->isa()) return print(os, ", {}", arr->shape()); + if (auto pack = def->isa()) return print(os, ", {}", pack->shape()); + if (auto pi = def->isa()) return print(os, ", {}", pi->dom()); + unreachable(); + }; + + if (!nom->is_set()) { + tab.print(os, "{}: {} = {{ }};", id(nom), nom->type()); + return; + } + + tab.print(os, "{} {}{}: {}", nom_prefix(nom), external(nom), id(nom), nom->type()); + nom_op0(nom); + if (nom->var()) { // TODO rewrite with dedicated methods + if (auto e = nom->num_vars(); e != 1) { + print(os, "{, }", Elem(nom->vars(), [&](auto def) { + if (def) + os << id(def); + else + os << ""; + })); + } else { + print(os, ", @{}", id(nom->var())); + } + } + tab.println(os, " = {{"); + ++tab; + ++tab; + if (dep) recurse(dep->nom2node(nom)); + recurse(nom); + tab.print(os, "{, }\n", nom->ops()); + --tab; + --tab; + tab.print(os, "}};\n"); +} + +void Dumper::dump(Lam* lam) { + auto ptrn = [&](auto&) { dump_ptrn(lam->var(), lam->type()->dom()); }; + + // TODO: handle mutual recursion + auto name = id(lam); + if (name == "main") name = "thorin_main"; + auto prefix = tab.indent() > 0 ? "let " : ""; + tab.println(os, "{}{}{} {} = ", external(lam), prefix, name, ptrn); + + ++tab; + ++tab; + if (lam->is_set()) { + if (dep) recurse(dep->nom2node(lam)); + recurse(lam->filter()); + recurse(lam->body(), true); + tab.print(os, "{}\n", Inline2(lam->body())); + } else { + tab.print(os, " \n"); + } + --tab; + --tab; + + // TODO: not for toplevel in a more semantic manner + if (tab.indent() > 0) tab.print(os, "in\n"); +} + +void Dumper::dump_let(const Def* def) { + tab.print(os, "let {} :: {} = {} in\n", id(def), Inline2(def->type()), Inline2(def, 0)); + let_emitted.insert(def); +} + +void Dumper::dump_ptrn(const Def* def, const Def* type, bool toplevel) { + if (!def) { + os << "_"; + } else { + auto projs = def->projs(); + if ((projs.size() == 1 || std::ranges::all_of(projs, [](auto def) { return !def; }))) { + if (toplevel) { + print(os, "({} :: {})", id(def), Inline2(type)); + } else { + print(os, "{}", id(def)); + } + } else { + size_t i = 0; + const char* pattern = "(({}@({, })):: {})"; + if (def->type()->isa()) pattern = "(({}@[{, }]):: {})"; + print(os, pattern, id(def), Elem(projs, [&](auto proj) { dump_ptrn(proj, type->proj(i++), false); }), + Inline2(type)); + } + } +} + +void Dumper::recurse(const DepNode* node) { + for (auto child : node->children()) { + if (auto nom = isa_decl(child->nom())) dump(nom); + } +} + +void Dumper::recurse(const Def* def, bool first /*= false*/) { + if (auto nom = isa_decl(def)) { + if (!dep) noms.push(nom); + return; + } + + if (!defs.emplace(def).second) return; + + for (auto op : def->partial_ops().skip_front()) { // ignore dbg + if (!op) continue; + recurse(op); + } + + if (!first && !Inline2(def)) dump_let(def); +} + +void emit(World& w, std::ostream& os) { + auto freezer = World::Freezer(w); + auto dep = DepTree(w); + auto dumper = Dumper(os, &dep); + + os << PREFACE << "\n"; + dumper.recurse(dep.root()); +} + +} // namespace thorin::backend::haskell diff --git a/dialects/backend/be/haskell_emit.h b/dialects/backend/be/haskell_emit.h new file mode 100644 index 0000000000..abf2a2b7f5 --- /dev/null +++ b/dialects/backend/be/haskell_emit.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "thorin/phase/phase.h" + +namespace thorin { + +class World; + +namespace backend { + +namespace haskell { +void emit(World&, std::ostream&); +} + +class HaskellEmitter : public Phase { +public: + HaskellEmitter(World& world) + : Phase(world, "haskell_emitter", false) + , os_(std::move(std::cout)) {} + + void start() override { haskell::emit(world(), os_); } + +private: + std::ostream&& os_; +}; + +} // namespace backend +} // namespace thorin diff --git a/dialects/backend/be/ocaml_emit.cpp b/dialects/backend/be/ocaml_emit.cpp new file mode 100644 index 0000000000..129a52194c --- /dev/null +++ b/dialects/backend/be/ocaml_emit.cpp @@ -0,0 +1,474 @@ +#include "dialects/backend/be/ocaml_emit.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "thorin/axiom.h" +#include "thorin/def.h" +#include "thorin/tuple.h" + +#include "thorin/analyses/cfg.h" +#include "thorin/analyses/deptree.h" +#include "thorin/be/emitter.h" +#include "thorin/fe/tok.h" +#include "thorin/util/assert.h" +#include "thorin/util/print.h" +#include "thorin/util/sys.h" + +#include "absl/container/flat_hash_map.h" +#include "dialects/core/autogen.h" +#include "dialects/core/core.h" +#include "dialects/math/math.h" +#include "dialects/mem/autogen.h" +#include "dialects/mem/mem.h" + +using namespace std::string_literals; + +/* + +TODO: +* mutual recursion +* operations +*/ + +namespace thorin::backend::ocaml { + +const char* PREFACE = R"( +let bool2bit x = if x then 1 else 0 +(* handle uninitialized values *) +(* let rec magic () : 'a = magic () *) +let unpack m = match m with + | Some x -> x + | None -> failwith "expected Some, got None" +let get_0_of_2 (x, _) = x (* fst *) +let get_1_of_2 (_, x) = x (* snd *) +let get_0_of_3 (x, _, _) = x +let get_1_of_3 (_, x, _) = x +let get_2_of_3 (_, _, x) = x +[@@@warning "-partial-match"] + +)"; + +/* + * helper + */ + +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; + } + return nullptr; +} + +absl::flat_hash_map names; +static std::string id(const Def* def) { + if (def->is_external() || (!def->is_set() && def->isa())) return def->name(); + + if (auto name = names.find(def); name != names.end()) return name->second; + + return def->unique_name(); +} + +static std::string_view external(const Def* def) { + if (def->is_external()) return "(* external *)\n"; + return ""; +} + +/* + * Inline + LRPrec + */ + +/// This is a wrapper to dump a Def "inline" and print it with all of its operands. +struct Inline2 { + Inline2(const Def* def, int dump_gid) + : def_(def) + , dump_gid_(dump_gid) {} + Inline2(const Def* def) + : Inline2(def, def->world().flags().dump_gid) {} + + const Def* operator->() const { return def_; }; + const Def* operator*() const { return def_; }; + explicit operator bool() const { + if (def_->dep_const()) return true; + + if (auto nom = def_->isa_nom()) { + if (isa_decl(nom)) return false; + return true; + } + + if (auto app = def_->isa()) { + if (app->type()->isa()) return true; // curried apps are printed inline + if (app->type()->isa()) return true; + if (app->callee()->isa()) { return app->callee_type()->num_doms() <= 1; } + return false; + } + + return true; + } + + friend std::ostream& operator<<(std::ostream&, Inline2); + +private: + const Def* def_; + const int dump_gid_; +}; + +static std::string id(Inline2 u) { return id(*u); } + +// TODO prec is currently broken +template +struct LRPrec2 { + LRPrec2(const Def* l, const Def* r) + : l(l) + , r(r) {} + + friend std::ostream& operator<<(std::ostream& os, const LRPrec2& p) { + if constexpr (L) { + if (Inline2(p.l) && fe::Tok::prec(fe::Tok::prec(p.r))[0] > fe::Tok::prec(p.r)) + return print(os, "({})", Inline2(p.l)); + return print(os, "{}", Inline2(p.l)); + } else { + if (Inline2(p.r) && fe::Tok::prec(p.l) > fe::Tok::prec(fe::Tok::prec(p.l))[1]) + return print(os, "({})", Inline2(p.r)); + return print(os, "{}", Inline2(p.r)); + } + } + +private: + const Def* l; + const Def* r; +}; + +using LPrec = LRPrec2; +using RPrec = LRPrec2; + +DefSet let_emitted; + +// TODO: [@warning "-partial-match"] + +std::ostream& operator<<(std::ostream& os, Inline2 u) { + if (u.dump_gid_ == 2 || (u.dump_gid_ == 1 && !u->isa() && u->num_ops() != 0)) print(os, "/*{}*/", u->gid()); + + if (let_emitted.contains(u.def_)) { return print(os, "{}", id(u)); } + + // Ptr -> Ref + Option for uninitialized + // Arr -> List (need persistent) + if (auto ptr = match(*u)) { + auto type = ptr->arg(0); + return print(os, "({} option ref)", Inline2(type)); + } + if (auto mem = match(*u)) { return print(os, "unit"); } + // TODO: ptr(arr) -> array (but how to handle lea) + + if (auto arith = match(*u)) { + auto [a, b] = arith->args<2>(); + const char* op; + switch (arith.id()) { + case core::nop::add: op = "+"; break; + case core::nop::mul: op = "*"; break; + } + return print(os, "({} {} {})", Inline2(a), op, Inline2(b)); + } + if (auto arith = match(*u)) { + auto [a, b] = arith->args<2>(); + // or use op+-* for others + if (arith.id() == core::wrap::shl) { return print(os, "(Int.shift_left {} {})", Inline2(a), Inline2(b)); } + const char* op; + switch (arith.id()) { + case core::wrap::add: op = "+"; break; + case core::wrap::sub: op = "-"; break; + case core::wrap::mul: op = "*"; break; + case core::wrap::shl: unreachable(); + } + return print(os, "({} {} {})", Inline2(a), op, Inline2(b)); + } + if (auto icmp = match(*u)) { + auto [a, b] = icmp->args<2>(); + // or use op+-* for others + const char* op; + // TODO: signed unsigned difference + switch (icmp.id()) { + case core::icmp::e: op = "="; break; + case core::icmp::sl: op = "<"; break; + case core::icmp::sle: op = "<="; break; + case core::icmp::ug: op = ">"; break; + case core::icmp::uge: op = ">="; break; + case core::icmp::ul: op = "<"; break; + case core::icmp::ule: op = "<="; break; + case core::icmp::sg: op = ">"; break; + case core::icmp::sge: op = ">="; break; + case core::icmp::ne: op = "!="; break; + case core::icmp::f: + case core::icmp::t: unreachable(); + default: assert(false && "unhandled icmp"); + } + return print(os, "(bool2bit ({} {} {}))", Inline2(a), op, Inline2(b)); + } + + // div -> / + // cmp -> bool2bit (...) + + if (auto app = u->isa()) { + auto callee = app->callee(); + if (callee->isa()) { return print(os, "int"); } + + return print(os, "({} {})", Inline2(app->callee()), Inline2(app->arg())); + } + + if (auto type = u->isa()) { + auto level = as_lit(type->level()); // TODO other levels + return print(os, level == 0 ? "★" : "□"); + } else if (u->isa()) { + return print(os, "int"); + } else if (u->isa()) { + assert(false && "idx should be handled by app"); + } else if (auto bot = u->isa()) { + if (bot->type()->isa()) return print(os, "'a"); + return print(os, "()"); + } else if (auto top = u->isa()) { + if (top->type()->isa()) return print(os, "'a"); + return print(os, "()"); + } else if (auto axiom = u->isa()) { + const auto& name = axiom->name(); + return print(os, "{}{}", name[0] == '%' ? "" : "%", name); + } else if (auto lit = u->isa()) { + long value = lit->get(); + if (lit->type()->isa()) return print(os, "{}", lit->get()); + if (value == 4294967295) { value = -1; } + // TODO: 4294967295 => -1 / add modulo at operations (probably better) + if (lit->type()->isa()) + return print(os, "({}:{})", value, Inline2(lit->type())); // HACK prec magic is broken + return print(os, "{}:{}", lit->get(), Inline2(lit->type())); + } else if (auto ex = u->isa()) { + if (ex->tuple()->isa() && ex->index()->isa()) return print(os, "{}", id(ex)); + if (ex->tuple()->type()->isa()) { + return print(os, "List.nth {} {}", Inline2(ex->tuple()), Inline2(ex->index())); + } else { + // TODO: extract from tuple (const index) + auto extract_fun = "get_" + std::to_string(ex->index()->as()->get()) + "_of_" + + std::to_string(ex->tuple()->num_ops()); + return print(os, "({} {})", extract_fun, Inline2(ex->tuple())); + } + } else if (auto var = u->isa()) { + return print(os, "{}", id(var)); + } else if (auto pi = u->isa()) { + if (auto nom = pi->isa_nom(); nom && nom->var()) assert(false && "nom pi"); + return print(os, "({} -> {})", Inline2(pi->dom()), Inline2(pi->codom())); + } else if (auto lam = u->isa()) { + // TODO: lam vs lam->body() vs Inline(...) vs name vs unique_name + return print(os, "{}", lam); + } else if (auto sigma = u->isa()) { + if (auto nom = sigma->isa_nom(); nom && nom->var()) { + size_t i = 0; + return print(os, "({, })", Elem(sigma->ops(), [&](auto op) { + if (auto v = nom->var(i++)) + print(os, "{}: {}", v, Inline2(op)); + else + print(os, "_: {}", Inline2(op)); + })); + } + // TODO: add extra parens? + if (sigma->num_ops() == 0) return print(os, "unit"); + return print(os, "({ * })", Elem(sigma->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + } else if (auto tuple = u->isa()) { + if (tuple->type()->isa()) { + print(os, "[{; }]", Elem(tuple->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + return os; + // TODO: nom + } else { + print(os, "({, })", Elem(tuple->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + return os; + } + } else if (auto arr = u->isa()) { + if (auto nom = arr->isa_nom(); nom && nom->var()) + // TODO: impossible? + return print(os, "«{}: {}; {}»", nom->var(), nom->shape(), nom->body()); + return print(os, "({} list)", Inline2(arr->body())); + } else if (auto pack = u->isa()) { + // TODO: generate list + if (auto nom = pack->isa_nom(); nom && nom->var()) + return print(os, "(List.init {} (fun {} -> {}))", Inline2(nom->shape()), Inline2(nom->var()), + Inline2(nom->body())); + return print(os, "(List.init {} (fun _ -> {}))", Inline2(pack->shape()), Inline2(pack->body())); + + } else if (auto proxy = u->isa()) { + // TODO: + assert(0); + } else if (auto bound = u->isa()) { + // TODO: + assert(0); + } + + // other + if (u->flags() == 0) return print(os, ".{} ({, })", u->node_name(), u->ops()); + return print(os, ".{}#{} ({, })", u->node_name(), u->flags(), u->ops()); +} + +/* + * Dumper + */ + +/// This thing operates in two modes: +/// 1. The output of decls is driven by the DepTree. +/// 2. Alternatively, decls are output as soon as they appear somewhere during recurse%ing. +/// Then, they are pushed to Dumper::noms. +class Dumper { +public: + Dumper(std::ostream& os, const DepTree* dep = nullptr) + : os(os) + , dep(dep) {} + + void dump(Def*); + void dump(Lam*); + void dump_let(const Def*); + void dump_ptrn(const Def*, const Def*, bool toplevel = true); + void recurse(const DepNode*); + void recurse(const Def*, bool first = false); + + std::ostream& os; + const DepTree* dep; + Tab tab; + unique_queue noms; + DefSet defs; +}; + +void Dumper::dump(Def* nom) { + if (auto lam = nom->isa()) { + dump(lam); + return; + } + + auto nom_prefix = [&](const Def* def) { + if (def->isa()) return ".Sigma"; + if (def->isa()) return ".Arr"; + if (def->isa()) return ".pack"; + if (def->isa()) return ".Pi"; + unreachable(); + }; + + auto nom_op0 = [&](const Def* def) -> std::ostream& { + if (auto sig = def->isa()) return print(os, ", {}", sig->num_ops()); + if (auto arr = def->isa()) return print(os, ", {}", arr->shape()); + if (auto pack = def->isa()) return print(os, ", {}", pack->shape()); + if (auto pi = def->isa()) return print(os, ", {}", pi->dom()); + unreachable(); + }; + + if (!nom->is_set()) { + tab.print(os, "{}: {} = {{ }};", id(nom), nom->type()); + return; + } + + tab.print(os, "{} {}{}: {}", nom_prefix(nom), external(nom), id(nom), nom->type()); + nom_op0(nom); + if (nom->var()) { // TODO rewrite with dedicated methods + if (auto e = nom->num_vars(); e != 1) { + print(os, "{, }", Elem(nom->vars(), [&](auto def) { + if (def) + os << id(def); + else + os << ""; + })); + } else { + print(os, ", @{}", id(nom->var())); + } + } + tab.println(os, " = {{"); + ++tab; + if (dep) recurse(dep->nom2node(nom)); + recurse(nom); + tab.print(os, "{, }\n", nom->ops()); + --tab; + tab.print(os, "}};\n"); +} + +void Dumper::dump(Lam* lam) { + auto ptrn = [&](auto&) { dump_ptrn(lam->var(), lam->type()->dom()); }; + + // TODO: handle mutual recursion + auto name = id(lam); + if (name == "main") name = "thorin_main"; + tab.println(os, "{}let rec {} {} = ", external(lam), name, ptrn); //, lam->type()->codom()); + // } + + ++tab; + if (lam->is_set()) { + if (dep) recurse(dep->nom2node(lam)); + recurse(lam->filter()); + recurse(lam->body(), true); + // TODO: + tab.print(os, "{}\n", Inline2(lam->body())); + } else { + tab.print(os, " \n"); + } + --tab; + + // TODO: not for toplevel in a more semantic manner + if (tab.indent() > 0) tab.print(os, "in\n"); +} + +void Dumper::dump_let(const Def* def) { + // TODO: type vs Inline type + tab.print(os, "let {}: {} = {} in\n", id(def), Inline2(def->type()), Inline2(def, 0)); + let_emitted.insert(def); +} + +void Dumper::dump_ptrn(const Def* def, const Def* type, bool toplevel) { + if (!def) { + os << "_"; + } else { + auto projs = def->projs(); + if ((projs.size() == 1 || std::ranges::all_of(projs, [](auto def) { return !def; }))) { + if (toplevel) { + print(os, "({} : {})", id(def), Inline2(type)); + } else { + print(os, "{}", id(def)); + } + } else { + size_t i = 0; + const char* pattern = "((({, }) as {}): {})"; + if (def->type()->isa()) pattern = "(([{; }] as {}): {})"; + print(os, pattern, Elem(projs, [&](auto proj) { dump_ptrn(proj, type->proj(i++), false); }), id(def), + Inline2(type)); + } + } +} + +void Dumper::recurse(const DepNode* node) { + for (auto child : node->children()) { + if (auto nom = isa_decl(child->nom())) dump(nom); + } +} + +void Dumper::recurse(const Def* def, bool first /*= false*/) { + if (auto nom = isa_decl(def)) { + if (!dep) noms.push(nom); + return; + } + + if (!defs.emplace(def).second) return; + + for (auto op : def->partial_ops().skip_front()) { // ignore dbg + if (!op) continue; + recurse(op); + } + + if (!first && !Inline2(def)) dump_let(def); +} + +void emit(World& w, std::ostream& os) { + auto freezer = World::Freezer(w); + + auto dep = DepTree(w); + auto dumper = Dumper(os, &dep); + + os << PREFACE << "\n"; + dumper.recurse(dep.root()); +} + +} // namespace thorin::backend::ocaml diff --git a/dialects/backend/be/ocaml_emit.h b/dialects/backend/be/ocaml_emit.h new file mode 100644 index 0000000000..0a4eff259f --- /dev/null +++ b/dialects/backend/be/ocaml_emit.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "thorin/phase/phase.h" + +namespace thorin { + +class World; + +namespace backend { + +namespace ocaml { +void emit(World&, std::ostream&); +void emit2(World&, std::ostream&); +} // namespace ocaml + +class OCamlEmitter : public Phase { +public: + OCamlEmitter(World& world) + : Phase(world, "ocaml_emitter", false) + , os_(std::move(std::cout)) {} + + void start() override { ocaml::emit(world(), os_); } + +private: + std::ostream&& os_; +}; + +} // namespace backend +} // namespace thorin diff --git a/dialects/backend/be/ocaml_emitter.cpp b/dialects/backend/be/ocaml_emitter.cpp new file mode 100644 index 0000000000..ce8c81b606 --- /dev/null +++ b/dialects/backend/be/ocaml_emitter.cpp @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "thorin/axiom.h" +#include "thorin/def.h" +#include "thorin/tuple.h" + +#include "thorin/analyses/cfg.h" +#include "thorin/analyses/deptree.h" +#include "thorin/be/emitter.h" +#include "thorin/fe/tok.h" +#include "thorin/util/assert.h" +#include "thorin/util/print.h" +#include "thorin/util/sys.h" + +#include "absl/container/flat_hash_map.h" +#include "dialects/backend/be/ocaml_emit.h" +#include "dialects/core/autogen.h" +#include "dialects/core/core.h" +#include "dialects/math/math.h" +#include "dialects/mem/autogen.h" +#include "dialects/mem/mem.h" + +using namespace std::string_literals; + +namespace thorin::backend::ocaml { + +const char* PREFACE_CODE = R"( +let bool2bit x = if x then 1 else 0 +(* handle uninitialized values *) +(* let rec magic () : 'a = magic () *) +let unpack m = match m with + | Some x -> x + | None -> failwith "expected Some, got None" +let get_0_of_2 (x, _) = x (* fst *) +let get_1_of_2 (_, x) = x (* snd *) +let get_0_of_3 (x, _, _) = x +let get_1_of_3 (_, x, _) = x +let get_2_of_3 (_, _, x) = x +[@@@warning "-partial-match"] + +)"; + +// test via: +// ./build/bin/thorin -d backend --backend ml --output - lit/backend/pow.thorin + +struct unit {}; + +class Emitter : public thorin::Emitter { +public: + using Super = thorin::Emitter; + + Emitter(World& world, std::ostream& ostream) + : Super(world, "ocaml_emitter", ostream) {} + + bool is_valid(std::string_view s) { return !s.empty(); } + void start() override; + void emit_imported(Lam*); + void emit_epilogue(Lam*); + std::string emit_bb(unit&, const Def*); + std::string prepare(const Scope&); + void prepare(Lam*, std::string_view); + void finalize(const Scope&); + + template + void declare(const char* s, Args&&... args) { + std::ostringstream decl; + print(decl << "declare ", s, std::forward(args)...); + decls_.emplace(decl.str()); + } + +private: + std::string id(const Def*, bool force_bb = false) const; + std::string convert(const Def*); + std::string convert_ret_pi(const Pi*); + + absl::btree_set decls_; + std::ostringstream type_decls_; + std::ostringstream vars_decls_; + std::ostringstream func_decls_; + std::ostringstream func_impls_; +}; + +void emit2(World& world, std::ostream& ostream) { Emitter(world, ostream).run(); } + +std::string Emitter::id(const Def* def, bool force_bb /*= false*/) const { + return "id"; + // std::string s("id"); + // return s; + // return ""; + // std::ostringstream s; + // s << "id"; + // return s.str(); +} + +std::string Emitter::convert(const Def* type) { return "convert_placeholder"; } + +void Emitter::start() { + Super::start(); + ostream() << type_decls_.str() << '\n'; + for (auto&& decl : decls_) ostream() << decl << '\n'; + ostream() << func_decls_.str() << '\n'; + ostream() << vars_decls_.str() << '\n'; + ostream() << func_impls_.str() << '\n'; +} + +void Emitter::emit_imported(Lam* lam) {} + +std::string Emitter::prepare(const Scope& scope) { return "prepare_placeholder"; } + +void Emitter::finalize(const Scope& scope) {} + +void Emitter::emit_epilogue(Lam* lam) {} + +std::string Emitter::emit_bb(unit& bb, const Def* def) { return "bb_placeholder"; } + +} // namespace thorin::backend::ocaml diff --git a/dialects/backend/be/rust_emit.cpp b/dialects/backend/be/rust_emit.cpp new file mode 100644 index 0000000000..9c6e29838c --- /dev/null +++ b/dialects/backend/be/rust_emit.cpp @@ -0,0 +1,459 @@ +#include "dialects/backend/be/rust_emit.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "thorin/axiom.h" +#include "thorin/def.h" +#include "thorin/tuple.h" + +#include "thorin/analyses/cfg.h" +#include "thorin/analyses/deptree.h" +#include "thorin/be/emitter.h" +#include "thorin/fe/tok.h" +#include "thorin/util/assert.h" +#include "thorin/util/print.h" +#include "thorin/util/sys.h" + +#include "absl/container/flat_hash_map.h" +#include "dialects/core/autogen.h" +#include "dialects/core/core.h" +#include "dialects/math/math.h" +#include "dialects/mem/autogen.h" +#include "dialects/mem/mem.h" + +using namespace std::string_literals; + +namespace thorin::backend::rust { + +const char* PREFACE = R"( +#![allow(arithmetic_overflow)] +fn bool2bit(b: bool) -> i32 { + if b { + 1 + } else { + 0 + } +} + +)"; + +/* + * helper + */ + +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; + } + return nullptr; +} + +absl::flat_hash_map names; +static std::string id(const Def* def) { + if (def->is_external() || (!def->is_set() && def->isa())) return def->name(); + + if (auto name = names.find(def); name != names.end()) return name->second; + + return def->unique_name(); +} + +static std::string_view external(const Def* def) { + if (def->is_external()) return "// external \n"; + return ""; +} + +/* + * Inline + LRPrec + */ + +/// This is a wrapper to dump a Def "inline" and print it with all of its operands. +struct Inline2 { + Inline2(const Def* def, int dump_gid) + : def_(def) + , dump_gid_(dump_gid) {} + Inline2(const Def* def) + : Inline2(def, def->world().flags().dump_gid) {} + + const Def* operator->() const { return def_; }; + const Def* operator*() const { return def_; }; + explicit operator bool() const { + if (def_->dep_const()) return true; + + if (auto nom = def_->isa_nom()) { + if (isa_decl(nom)) return false; + return true; + } + + if (auto app = def_->isa()) { + if (app->type()->isa()) return true; // curried apps are printed inline + if (app->type()->isa()) return true; + if (app->callee()->isa()) { return app->callee_type()->num_doms() <= 1; } + return false; + } + + return true; + } + + friend std::ostream& operator<<(std::ostream&, Inline2); + +private: + const Def* def_; + const int dump_gid_; +}; + +static std::string id(Inline2 u) { return id(*u); } + +// TODO prec is currently broken +template +struct LRPrec2 { + LRPrec2(const Def* l, const Def* r) + : l(l) + , r(r) {} + + friend std::ostream& operator<<(std::ostream& os, const LRPrec2& p) { + if constexpr (L) { + if (Inline2(p.l) && fe::Tok::prec(fe::Tok::prec(p.r))[0] > fe::Tok::prec(p.r)) + return print(os, "({})", Inline2(p.l)); + return print(os, "{}", Inline2(p.l)); + } else { + if (Inline2(p.r) && fe::Tok::prec(p.l) > fe::Tok::prec(fe::Tok::prec(p.l))[1]) + return print(os, "({})", Inline2(p.r)); + return print(os, "{}", Inline2(p.r)); + } + } + +private: + const Def* l; + const Def* r; +}; + +using LPrec = LRPrec2; +using RPrec = LRPrec2; + +DefSet let_emitted; + +std::ostream& operator<<(std::ostream& os, Inline2 u) { + if (u.dump_gid_ == 2 || (u.dump_gid_ == 1 && !u->isa() && u->num_ops() != 0)) print(os, "/*{}*/", u->gid()); + + if (let_emitted.contains(u.def_)) { return print(os, "{}", id(u)); } + + // Ptr -> Ref + Option for uninitialized + // Arr -> List (need persistent) + if (auto ptr = match(*u)) { + auto type = ptr->arg(0); + return print(os, "&({})", Inline2(type)); + } + if (auto mem = match(*u)) { return print(os, "()"); } + // TODO: ptr(arr) -> array (but how to handle lea) + + if (auto arith = match(*u)) { + auto [a, b] = arith->args<2>(); + const char* op; + switch (arith.id()) { + case core::nop::add: op = "+"; break; + case core::nop::mul: op = "*"; break; + } + return print(os, "({} {} {})", Inline2(a), op, Inline2(b)); + } + if (auto arith = match(*u)) { + auto [a, b] = arith->args<2>(); + if (arith.id() == core::wrap::shl) { return print(os, "({} << {})", Inline2(a), Inline2(b)); } + const char* op; + switch (arith.id()) { + case core::wrap::add: op = "+"; break; + case core::wrap::sub: op = "-"; break; + case core::wrap::mul: op = "*"; break; + case core::wrap::shl: assert(false && "shl unhandled"); break; + } + return print(os, "({} {} {})", Inline2(a), op, Inline2(b)); + } + if (auto icmp = match(*u)) { + auto [a, b] = icmp->args<2>(); + const char* op; + // TODO: signed unsigned difference + switch (icmp.id()) { + case core::icmp::e: op = "=="; break; + case core::icmp::sl: op = "<"; break; + case core::icmp::sle: op = "<="; break; + case core::icmp::ug: op = ">"; break; + case core::icmp::uge: op = ">="; break; + case core::icmp::ul: op = "<"; break; + case core::icmp::ule: op = "<="; break; + case core::icmp::sg: op = ">"; break; + case core::icmp::sge: op = ">="; break; + case core::icmp::ne: op = "!="; break; + case core::icmp::f: + case core::icmp::t: assert(false && "t, f comparison unhandled"); + default: assert(false && "unhandled icmp"); + } + return print(os, "(bool2bit ({} {} {}))", Inline2(a), op, Inline2(b)); + } + + if (auto app = u->isa()) { + auto callee = app->callee(); + if (callee->isa()) { return print(os, "i32"); } + + return print(os, "({} {})", Inline2(app->callee()), Inline2(app->arg())); + } + + if (auto type = u->isa()) { + auto level = as_lit(type->level()); // TODO other levels + return print(os, level == 0 ? "★" : "□"); + } else if (u->isa()) { + return print(os, "i32"); + } else if (u->isa()) { + assert(false && "unapplied idx"); + } else if (auto bot = u->isa()) { + if (bot->type()->isa()) return print(os, "T"); + return print(os, "magic"); + } else if (auto top = u->isa()) { + if (top->type()->isa()) return print(os, "T"); + return print(os, "()"); + } else if (auto axiom = u->isa()) { + const auto& name = axiom->name(); + return print(os, "{}{}", name[0] == '%' ? "" : "%", name); + } else if (auto lit = u->isa()) { + long value = lit->get(); + if (lit->type()->isa()) return print(os, "{}", lit->get()); + // TODO: maybe handle using overflow + if (value == 4294967295) { value = -1; } + if (lit->type()->isa()) + return print(os, "({}:{})", value, Inline2(lit->type())); // HACK prec magic is broken + return print(os, "{}:{}", lit->get(), Inline2(lit->type())); + } else if (auto ex = u->isa()) { + if (ex->tuple()->isa() && ex->index()->isa()) return print(os, "{}", id(ex)); + if (ex->tuple()->type()->isa()) { + return print(os, "({}[{}])", Inline2(ex->tuple()), Inline2(ex->index())); + } else { + return print(os, "({}.{})", Inline2(ex->tuple()), ex->index()->as()->get()); + } + } else if (auto var = u->isa()) { + return print(os, "{}", id(var)); + } else if (auto pi = u->isa()) { + if (auto nom = pi->isa_nom(); nom && nom->var()) assert(false && "nom pi"); + return print(os, "Box {}>", Inline2(pi->dom()), Inline2(pi->codom())); + } else if (auto lam = u->isa()) { + // TODO: lam vs lam->body() vs Inline(...) vs name vs unique_name + return print(os, "{}", lam); + } else if (auto sigma = u->isa()) { + if (auto nom = sigma->isa_nom(); nom && nom->var()) { + size_t i = 0; + return print(os, "({, })", Elem(sigma->ops(), [&](auto op) { + if (auto v = nom->var(i++)) + print(os, "{}: {}", v, Inline2(op)); + else + print(os, "_: {}", Inline2(op)); + })); + } + if (sigma->num_ops() == 0) return print(os, "()"); + return print(os, "({ , })", Elem(sigma->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + } else if (auto tuple = u->isa()) { + if (tuple->type()->isa()) { + // TODO: nom + print(os, "[{, }]", Elem(tuple->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + return os; + } else { + print(os, "({, })", Elem(tuple->ops(), [&](auto op) { print(os, "{}", Inline2(op)); })); + return os; + } + } else if (auto arr = u->isa()) { + if (auto nom = arr->isa_nom(); nom && nom->var()) assert(false && "nom arr"); + return print(os, "[{};{}]", Inline2(arr->body()), Inline2(arr->shape())); + } else if (auto pack = u->isa()) { + if (auto nom = pack->isa_nom(); nom && nom->var()) assert(false && "nom pack"); + return print(os, "[{}; {}]", Inline2(pack->body()), Inline2(pack->shape())); + + } else if (auto proxy = u->isa()) { + // TODO: + assert(0); + } else if (auto bound = u->isa()) { + // TODO: + assert(0); + } + + // other + assert(false && "unknown def"); + if (u->flags() == 0) return print(os, ".{} ({, })", u->node_name(), u->ops()); + return print(os, ".{}#{} ({, })", u->node_name(), u->flags(), u->ops()); +} + +/* + * Dumper + */ + +/// This thing operates in two modes: +/// 1. The output of decls is driven by the DepTree. +/// 2. Alternatively, decls are output as soon as they appear somewhere during recurse%ing. +/// Then, they are pushed to Dumper::noms. +class Dumper { +public: + Dumper(std::ostream& os, const DepTree* dep = nullptr) + : os(os) + , dep(dep) {} + + void dump(Def*); + void dump(Lam*); + void dump_let(const Def*); + void dump_ptrn(const Def*, const Def*, bool toplevel = true); + void recurse(const DepNode*); + void recurse(const Def*, bool first = false); + + std::ostream& os; + const DepTree* dep; + Tab tab; + unique_queue noms; + DefSet defs; +}; + +void Dumper::dump(Def* nom) { + if (auto lam = nom->isa()) { + dump(lam); + return; + } + + auto nom_prefix = [&](const Def* def) { + if (def->isa()) return ".Sigma"; + if (def->isa()) return ".Arr"; + if (def->isa()) return ".pack"; + if (def->isa()) return ".Pi"; + assert(false && "unknown nom prefix"); + }; + + auto nom_op0 = [&](const Def* def) -> std::ostream& { + if (auto sig = def->isa()) return print(os, ", {}", sig->num_ops()); + if (auto arr = def->isa()) return print(os, ", {}", arr->shape()); + if (auto pack = def->isa()) return print(os, ", {}", pack->shape()); + if (auto pi = def->isa()) return print(os, ", {}", pi->dom()); + assert(false && "unknown nom"); + }; + + if (!nom->is_set()) { + tab.print(os, "{}: {} = {{ }};", id(nom), nom->type()); + return; + } + + tab.print(os, "{} {}{}: {}", nom_prefix(nom), external(nom), id(nom), nom->type()); + nom_op0(nom); + if (nom->var()) { // TODO rewrite with dedicated methods + if (auto e = nom->num_vars(); e != 1) { + print(os, "{, }", Elem(nom->vars(), [&](auto def) { + if (def) + os << id(def); + else + os << ""; + })); + } else { + print(os, ", @{}", id(nom->var())); + } + } + tab.println(os, " = {{"); + ++tab; + ++tab; + if (dep) recurse(dep->nom2node(nom)); + recurse(nom); + tab.print(os, "{, }\n", nom->ops()); + --tab; + --tab; + tab.print(os, "}};\n"); +} + +void Dumper::dump(Lam* lam) { + // TODO filter + auto ptrn = [&](auto&) { dump_ptrn(lam->var(), lam->type()->dom()); }; + + // TODO: handle mutual recursion + auto name = id(lam); + if (name == "main") name = "thorin_main"; + if (tab.indent() == 0) { + tab.println(os, "{}fn {}({}) -> T {{", external(lam), name, ptrn); + } else { + tab.println(os, "{}let {} = Box::new(move |{}| {{ ", external(lam), name, ptrn); + } + + ++tab; + ++tab; + if (lam->is_set()) { + if (dep) recurse(dep->nom2node(lam)); + recurse(lam->filter()); + recurse(lam->body(), true); + tab.print(os, "{}\n", Inline2(lam->body())); + } else { + tab.print(os, " \n"); + } + --tab; + --tab; + + // TODO: not for toplevel in a more semantic manner + if (tab.indent() == 0) { + tab.println(os, "}}\n"); + } else { + tab.println(os, "}});\n"); + // TODO: + } +} + +void Dumper::dump_let(const Def* def) { + tab.print(os, "let {} : {} = {};\n", id(def), Inline2(def->type()), Inline2(def, 0)); + let_emitted.insert(def); +} + +void Dumper::dump_ptrn(const Def* def, const Def* type, bool toplevel) { + if (!def) { + os << "_"; + } else { + auto projs = def->projs(); + if ((projs.size() == 1 || std::ranges::all_of(projs, [](auto def) { return !def; }))) { + if (toplevel) { + print(os, "({} : {})", id(def), Inline2(type)); + } else { + print(os, "{}", id(def)); + } + } else { + size_t i = 0; + const char* pattern = "(({}@({, })): {})"; + if (def->type()->isa()) pattern = "(({}@[{, }]): {})"; + print(os, pattern, id(def), Elem(projs, [&](auto proj) { dump_ptrn(proj, type->proj(i++), false); }), + Inline2(type)); + } + } +} + +void Dumper::recurse(const DepNode* node) { + for (auto child : node->children()) { + if (auto nom = isa_decl(child->nom())) dump(nom); + } +} + +void Dumper::recurse(const Def* def, bool first /*= false*/) { + if (auto nom = isa_decl(def)) { + if (!dep) noms.push(nom); + return; + } + + if (!defs.emplace(def).second) return; + + for (auto op : def->partial_ops().skip_front()) { // ignore dbg + if (!op) continue; + recurse(op); + } + + if (!first && !Inline2(def)) dump_let(def); +} + +void emit(World& w, std::ostream& os) { + auto freezer = World::Freezer(w); + + auto dep = DepTree(w); + auto dumper = Dumper(os, &dep); + + os << PREFACE << "\n"; + dumper.recurse(dep.root()); +} + +} // namespace thorin::backend::rust diff --git a/dialects/backend/be/rust_emit.h b/dialects/backend/be/rust_emit.h new file mode 100644 index 0000000000..924ff58316 --- /dev/null +++ b/dialects/backend/be/rust_emit.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "thorin/phase/phase.h" + +namespace thorin { + +class World; + +namespace backend { + +namespace rust { +void emit(World&, std::ostream&); +} + +class RustEmitter : public Phase { +public: + RustEmitter(World& world) + : Phase(world, "rust_emitter", false) + , os_(std::move(std::cout)) {} + + void start() override { rust::emit(world(), os_); } + +private: + std::ostream&& os_; +}; + +} // namespace backend +} // namespace thorin diff --git a/dialects/clos/clos.cpp b/dialects/clos/clos.cpp index fef4ad1ebf..ae2e498407 100644 --- a/dialects/clos/clos.cpp +++ b/dialects/clos/clos.cpp @@ -13,10 +13,12 @@ #include "dialects/clos/pass/rw/branch_clos_elim.h" #include "dialects/clos/pass/rw/clos2sjlj.h" #include "dialects/clos/pass/rw/clos_conv_prep.h" -#include "dialects/clos/phase/clos_conv.h" -#include "dialects/clos/phase/lower_typed_clos.h" +#include "dialects/clos/pass/rw/phase_wrapper.h" #include "dialects/mem/mem.h" #include "dialects/mem/passes/fp/copy_prop.h" +#include "dialects/mem/passes/rw/reshape.h" +#include "dialects/mem/phases/rw/add_mem.h" +#include "dialects/refly/passes/debug_dump.h" namespace thorin::clos { @@ -131,53 +133,26 @@ const Def* ctype(World& w, Defs doms, const Def* env_type) { [&](auto i) { return clos_insert_env(i, env_type, [&](auto j) { return doms[j]; }); })); } -/* - * Pass Wrappers - */ - -class ClosConvWrapper : public RWPass { -public: - ClosConvWrapper(PassMan& man) - : RWPass(man, "clos_conv") {} - - void prepare() override { ClosConv(world()).run(); } -}; - -class LowerTypedClosWrapper : public RWPass { -public: - LowerTypedClosWrapper(PassMan& man) - : RWPass(man, "lower_typed_clos") {} - - void prepare() override { LowerTypedClos(world()).run(); } -}; - } // namespace thorin::clos using namespace thorin; extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { return {"clos", - [](PipelineBuilder& builder) { - int base = 121; - // closure_conv - builder.extend_opt_phase(base++, [](PassMan& man) { man.add(nullptr); }); - builder.extend_opt_phase(base++, [](PassMan& man) { man.add(nullptr); }); - builder.extend_opt_phase(base++, [](PassMan& man) { man.add(); }); - builder.extend_opt_phase(base++, [](PassMan& man) { - auto er = man.add(true); - auto ee = man.add(er); - man.add(ee); - }); - // lower_closures - builder.extend_opt_phase(base++, [](PassMan& man) { - man.add(nullptr); - man.add(); - man.add(nullptr, nullptr, true); - man.add(); - man.add(); - }); - - builder.extend_opt_phase(base++, [](PassMan& man) { man.add(); }); + [](Passes& passes) { + register_pass(passes, nullptr); + register_pass(passes); + register_pass(passes); + register_pass(passes); + register_pass(passes); + register_pass(passes); + // TODO:; remove after ho_codegen merge + passes[flags_t(Axiom::Base)] = [&](World& world, PipelineBuilder& builder, + const Def* app) { + auto bb = app->as()->arg(); + auto bb_only = bb->as()->get(); + builder.add_pass(app, bb_only); + }; }, - nullptr, nullptr, [](Normalizers& normalizers) { clos::register_normalizers(normalizers); }}; + nullptr, [](Normalizers& normalizers) { clos::register_normalizers(normalizers); }}; } diff --git a/dialects/clos/clos.thorin b/dialects/clos/clos.thorin index fc791f90cd..a2b7c6b0d4 100644 --- a/dialects/clos/clos.thorin +++ b/dialects/clos/clos.thorin @@ -5,6 +5,7 @@ /// ## Dependencies /// .import mem; +.import compile; /// /// ## Operations related to longjmp /// @@ -23,3 +24,54 @@ /// * `esc`: lambda that escapes its parent scope /// * `bot`: no special use .ax %clos.attr(ret, freeBB, fstclassBB, esc, bot): Π T: * -> T -> T, normalize_clos; +/// +/// ## Compilation Passes and Phases +/// +/// ### Passes +/// +.ax %clos.clos_conv_prep_pass: %compile.Pass; +.ax %clos.clos_conv_pass: %compile.Pass; +.ax %clos.branch_clos_pass: %compile.Pass; +.ax %clos.lower_typed_clos_prep_pass: %compile.Pass; +.ax %clos.clos2sjlj_pass: %compile.Pass; +.ax %clos.lower_typed_clos_pass: %compile.Pass; +.ax %clos.eta_red_bool_pass: .Bool -> %compile.Pass; +/// +/// ### Phases +/// +.let clos_opt1_phase = { + .let eta_red = (%clos.eta_red_bool_pass (1:.Bool) ); + .let eta_exp = %compile.eta_exp_pass eta_red; + %compile.pass_phase (%compile.pass_list + eta_red + eta_exp + (%compile.scalerize_pass eta_exp) + ) +}; +.let clos_opt2_phase = { + .let nullptr = %compile.nullptr_pass; + %compile.pass_phase (%compile.pass_list + nullptr + (%compile.scalerize_pass nullptr) + %clos.branch_clos_pass + (%mem.copy_prop_pass (nullptr, nullptr, 1:(.Idx 2))) + %clos.lower_typed_clos_prep_pass + %clos.clos2sjlj_pass + ) +}; +.let clos_phases = { + .let nullptr = %compile.nullptr_pass; + %compile.combined_phase + (%compile.phase_list + (%compile.single_pass_phase nullptr) + optimization_phase + (%compile.single_pass_phase (%mem.reshape_pass %mem.reshape_flat)) + (%compile.single_pass_phase %mem.add_mem_pass) + (%compile.single_pass_phase %clos.clos_conv_prep_pass) + (%compile.single_pass_phase (%compile.eta_exp_pass nullptr)) + (%compile.single_pass_phase %clos.clos_conv_pass) + clos_opt1_phase + clos_opt2_phase + (%compile.single_pass_phase %clos.lower_typed_clos_pass) + ) +}; diff --git a/dialects/clos/pass/rw/clos_conv_prep.cpp b/dialects/clos/pass/rw/clos_conv_prep.cpp index 2d780a7221..6e1d11bb71 100644 --- a/dialects/clos/pass/rw/clos_conv_prep.cpp +++ b/dialects/clos/pass/rw/clos_conv_prep.cpp @@ -45,11 +45,10 @@ void ClosConvPrep::enter() { } } } - if (auto body = curr_nom()->body()->isa(); - !wrapper_.contains(curr_nom()) && body && body->callee_type()->is_cn()) - ignore_ = false; - else - ignore_ = true; + + auto body = curr_nom()->body()->isa(); + // Skip if the nominal is already wrapped or the body is undefined/no continuation. + ignore_ = !(body && body->callee_type()->is_cn()) || wrapper_.contains(curr_nom()); } const App* ClosConvPrep::rewrite_arg(const App* app) { diff --git a/dialects/clos/pass/rw/phase_wrapper.h b/dialects/clos/pass/rw/phase_wrapper.h new file mode 100644 index 0000000000..df6003b496 --- /dev/null +++ b/dialects/clos/pass/rw/phase_wrapper.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "thorin/dialects.h" + +#include "dialects/clos/phase/clos_conv.h" +#include "dialects/clos/phase/lower_typed_clos.h" + +using namespace thorin; + +class ClosConvWrapper : public RWPass { +public: + ClosConvWrapper(PassMan& man) + : RWPass(man, "clos_conv") {} + + void prepare() override { clos::ClosConv(world()).run(); } +}; + +class LowerTypedClosWrapper : public RWPass { +public: + LowerTypedClosWrapper(PassMan& man) + : RWPass(man, "lower_typed_clos") {} + + void prepare() override { clos::LowerTypedClos(world()).run(); } +}; diff --git a/dialects/compile/compile.cpp b/dialects/compile/compile.cpp index 592cb3d677..bf497d3587 100644 --- a/dialects/compile/compile.cpp +++ b/dialects/compile/compile.cpp @@ -4,6 +4,8 @@ #include #include +#include "thorin/error.h" + #include "thorin/pass/fp/beta_red.h" #include "thorin/pass/fp/eta_exp.h" #include "thorin/pass/fp/eta_red.h" @@ -16,25 +18,12 @@ #include "dialects/compile/autogen.h" #include "dialects/compile/passes/debug_print.h" +#include "dialects/compile/passes/internal_cleanup.h" using namespace thorin; void add_phases(DefVec& phases, World& world, Passes& passes, PipelineBuilder& builder) { - for (auto phase : phases) { - auto [phase_def, phase_args] = collect_args(phase); - world.DLOG("phase: {}", phase_def); - if (auto phase_ax = phase_def->isa()) { - auto flag = phase_ax->flags(); - if (passes.contains(flag)) { - auto phase_fun = passes[flag]; - phase_fun(world, builder, phase); - } else { - world.WLOG("phase '{}' not found", phase_ax->name()); - } - } else { - world.WLOG("phase '{}' is not an axiom", phase_def); - } - } + for (auto phase : phases) { compile::handle_optimization_part(phase, world, passes, builder); } } void add_passes(World& world, PipelineBuilder& builder, Passes& passes, DefVec& pass_list) { @@ -42,34 +31,21 @@ void add_passes(World& world, PipelineBuilder& builder, Passes& passes, DefVec& // This pass then calls the registered passes in the order they were registered in the last phase. // We create a new dummy phase in which the passes should be inserted. - builder.append_phase_end([](Pipeline&) {}); - - for (auto pass : pass_list) { - auto [pass_def, pass_args] = collect_args(pass); - world.DLOG("pass: {}", pass_def); - if (auto pass_ax = pass_def->isa()) { - auto flag = pass_ax->flags(); - if (passes.contains(flag)) { - auto pass_fun = passes[flag]; - pass_fun(world, builder, pass); - } else { - world.ELOG("pass '{}' not found", pass_ax->name()); - } - } else { - world.ELOG("pass '{}' is not an axiom", pass_def); - } - } + // builder.append_phase_end([](Pipeline&) {}); + builder.begin_pass_phase(); + for (auto pass : pass_list) { compile::handle_optimization_part(pass, world, passes, builder); } + builder.end_pass_phase(); } extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { - return {"compile", nullptr, + return {"compile", [](Passes& passes) { auto debug_phase_flag = flags_t(Axiom::Base); passes[debug_phase_flag] = [](World& world, PipelineBuilder& builder, const Def* app) { world.DLOG("Generate debug_phase: {}", app); int level = (int)(app->as()->arg(0)->as()->get()); world.DLOG(" Level: {}", level); - builder.append_pass_after_end([=](PassMan& man) { man.add(level); }); + builder.add_phase(level); }; passes[flags_t(Axiom::Base)] = @@ -104,6 +80,7 @@ extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { register_pass(passes); register_pass(passes); + register_pass(passes); register_pass_with_arg(passes); register_pass_with_arg(passes); diff --git a/dialects/compile/compile.h b/dialects/compile/compile.h index 8805b61824..03c8f53744 100644 --- a/dialects/compile/compile.h +++ b/dialects/compile/compile.h @@ -2,4 +2,35 @@ #include +#include "thorin/pass/pipelinebuilder.h" + #include "dialects/compile/autogen.h" + +namespace thorin::compile { +inline void handle_optimization_part(const Def* part, World& world, Passes& passes, PipelineBuilder& builder) { + if (auto app = part->isa()) { + if (auto lam = app->callee()->isa()) { + part = lam->reduce(app->arg())[1]; + world.DLOG("reduce pass/phase lambda {} to {} : {}", lam, part, part->type()); + } + } + + auto [phase_def, phase_args] = collect_args(part); + world.DLOG("pass/phase: {}", phase_def); + if (auto phase_ax = phase_def->isa()) { + auto flag = phase_ax->flags(); + if (passes.contains(flag)) { + auto phase_fun = passes[flag]; + phase_fun(world, builder, part); + } else { + world.WLOG("pass/phase '{}' not found", phase_ax->name()); + assert(passes.contains(flag) && "pass/phase not found"); + } + } else if (auto lam = phase_def->isa()) { + assert(0 && "curried lambas are not supported"); + } else { + world.WLOG("pass/phase '{}' is not an axiom", phase_def); + assert(phase_def->isa() && "pass/phase is not an axiom"); + } +} +} // namespace thorin::compile diff --git a/dialects/compile/compile.thorin b/dialects/compile/compile.thorin index dea4d97af4..c23fe6cfd5 100644 --- a/dialects/compile/compile.thorin +++ b/dialects/compile/compile.thorin @@ -53,6 +53,7 @@ /// `combine_pass_list K (pass_list pass11 ... pass1N) ... (pass_list passK1 ... passKM) = pass_list pass11 ... p1N ... passK1 ... passKM` .ax %compile.combine_pass_list: Π [n:.Nat] -> «n; PassList» -> PassList, normalize_combine_pass_list; /// `single_pass_phase pass = passes_to_phase 1 pass` +// TODO: as let instead of axiom .ax %compile.single_pass_phase: %compile.Pass -> %compile.Phase, normalize_single_pass_phase; /// /// ### %compile.combined_phase @@ -81,6 +82,7 @@ .ax %compile.ret_wrap_pass: %compile.Pass; /// has to be registered in the pipeline .ax %compile.nullptr_pass: %compile.Pass; +.ax %compile.internal_cleanup_pass: %compile.Pass; /// /// ### Phases /// @@ -102,7 +104,7 @@ /// /// ### Pipelines /// -.let default_pipeline = { +.let default_core_pipeline = { .let nullptr = %compile.nullptr_pass; %compile.pipe (%compile.single_pass_phase nullptr) @@ -110,10 +112,11 @@ (%compile.single_pass_phase %compile.eta_red_pass) (%compile.single_pass_phase (%compile.tail_rec_elim_pass nullptr)) optimization_phase + (%compile.single_pass_phase %compile.internal_cleanup_pass) (%compile.single_pass_phase %compile.lam_spec_pass) (%compile.single_pass_phase %compile.ret_wrap_pass) }; +.lam .extern _fallback_compile [] -> Pipeline = { + default_core_pipeline +}; -// .lam .extern _default_compile [] -> Pipeline = { -// default_pipeline -// }; diff --git a/dialects/compile/normalizers.cpp b/dialects/compile/normalizers.cpp index 85d90eedb3..55c52e13ac 100644 --- a/dialects/compile/normalizers.cpp +++ b/dialects/compile/normalizers.cpp @@ -4,42 +4,48 @@ 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) { +const Def* normalize_pass_phase(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { auto& world = type->world(); auto [ax, _] = collect_args(arg); - assert(ax->flags() == flags_t(Axiom::Base) && "pass_phase expected a pass_list (after normalization)"); + if (ax->flags() != flags_t(Axiom::Base)) { + // return world.raw_app(callee, arg, dbg); + // 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()); + } else { + world.ELOG("pass_phase expects a pass_list as argument but got {}", arg); + } + } auto [f_ax, pass_list_defs] = collect_args(arg); assert(f_ax->flags() == flags_t(Axiom::Base)); auto n = pass_list_defs.size(); - auto pass2phase = world.raw_app(type, world.ax(), world.lit_nat(n)); - return world.raw_app(type, pass2phase, world.tuple(pass_list_defs), dbg); + return world.app(world.app(world.ax(), world.lit_nat(n)), world.tuple(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) { +const Def* normalize_combined_phase(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { 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(); - auto pass2phase = world.raw_app(type, world.ax(), world.lit_nat(n)); - return world.raw_app(type, pass2phase, world.tuple(phase_list_defs), dbg); + return world.app(world.app(world.ax(), world.lit_nat(n)), world.tuple(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) { - auto& world = type->world(); - auto pass2phase = world.raw_app(type, world.ax(), world.lit_nat_1()); - return world.raw_app(type, pass2phase, arg, dbg); +const Def* normalize_single_pass_phase(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { + auto& world = type->world(); + 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) { +const Def* normalize_combine_pass_list(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { auto& world = type->world(); auto pass_lists = arg->projs(); DefVec passes; @@ -49,7 +55,9 @@ 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()); } - return world.raw_app(type, world.ax(), world.tuple(passes), dbg); + const Def* app_list = world.ax(); + for (auto pass : passes) { app_list = world.app(app_list, pass); } + return app_list; } THORIN_compile_NORMALIZER_IMPL diff --git a/dialects/compile/passes/internal_cleanup.cpp b/dialects/compile/passes/internal_cleanup.cpp new file mode 100644 index 0000000000..41fe2af2fd --- /dev/null +++ b/dialects/compile/passes/internal_cleanup.cpp @@ -0,0 +1,17 @@ +#include "dialects/compile/passes/internal_cleanup.h" + +#include + +#include + +namespace thorin::compile { + +void InternalCleanup::enter() { + Lam* lam = curr_nom(); + if (lam->name().starts_with(prefix_)) { + lam->make_internal(); + world().DLOG("internalized {}", lam); + } +} + +} // namespace thorin::compile diff --git a/dialects/compile/passes/internal_cleanup.h b/dialects/compile/passes/internal_cleanup.h new file mode 100644 index 0000000000..1b3107d2d4 --- /dev/null +++ b/dialects/compile/passes/internal_cleanup.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace thorin::compile { + +class InternalCleanup : public RWPass { +public: + InternalCleanup(PassMan& man, const char* prefix = "internal_") + : RWPass(man, "internal_cleanup") + , prefix_(prefix) {} + + void enter() override; + +private: + const char* prefix_; +}; + +} // namespace thorin::compile diff --git a/dialects/core/be/ll/ll.cpp b/dialects/core/be/ll/ll.cpp index 8e74a5292c..779847bd60 100644 --- a/dialects/core/be/ll/ll.cpp +++ b/dialects/core/be/ll/ll.cpp @@ -193,17 +193,9 @@ std::string Emitter::convert(const Def* type) { } std::string Emitter::convert_ret_pi(const Pi* pi) { - switch (pi->num_doms()) { - case 0: return "void"; - case 1: - if (match(pi->dom())) return "void"; - return convert(pi->dom()); - case 2: - if (match(pi->dom(0))) return convert(pi->dom(1)); - if (match(pi->dom(1))) return convert(pi->dom(0)); - [[fallthrough]]; - default: return convert(pi->dom()); - } + auto dom = mem::strip_mem_ty(pi->dom()); + if (dom == world().sigma()) { return "void"; } + return convert(dom); } /* @@ -318,7 +310,27 @@ void Emitter::emit_epilogue(Lam* lam) { } } } else if (auto ex = app->callee()->isa(); ex && app->callee_type()->is_basicblock()) { - emit_unsafe(app->arg()); + // A call to an extract like constructed for conditionals (else,then)#cond (args) + // TODO: we can not rely on the structure of the extract (it might be a nested extract) + for (auto callee_def : ex->tuple()->projs()) { + // dissect the tuple of lambdas + auto callee = callee_def->isa_nom(); + assert(callee); + // each callees type should agree with the argument type (should be checked by type checking). + // Especially, the number of vars should be the number of arguments. + // TODO: does not hold for complex arguments that are not tuples. + assert(callee->num_vars() == app->num_args()); + for (size_t i = 0, e = callee->num_vars(); i != e; ++i) { + // emits the arguments one by one (TODO: handle together like before) + if (auto arg = emit_unsafe(app->arg(i)); !arg.empty()) { + auto phi = callee->var(i); + assert(!match(phi->type())); + lam2bb_[callee].phis[phi].emplace_back(arg, id(lam, true)); + locals_[phi] = id(phi); + } + } + } + auto c = emit(ex->index()); if (ex->tuple()->num_projs() == 2) { auto [f, t] = ex->tuple()->projs<2>([this](auto def) { return emit(def); }); @@ -453,12 +465,14 @@ std::string Emitter::emit_bb(BB& bb, const Def* def) { std::string prev = "undef"; auto t = convert(tuple->type()); - for (size_t i = 0, n = tuple->num_projs(); i != n; ++i) { - auto e = tuple->proj(n, i); - if (auto v_elem = emit_unsafe(e); !v_elem.empty()) { - auto t_elem = convert(e->type()); - auto namei = name + "." + std::to_string(i); - prev = bb.assign(namei, "insertvalue {} {}, {} {}, {}", t, prev, t_elem, v_elem, i); + for (size_t src = 0, dst = 0, n = tuple->num_projs(); src != n; ++src) { + auto e = tuple->proj(n, src); + if (auto elem = emit_unsafe(e); !elem.empty()) { + auto elem_t = convert(e->type()); + // TODO: check dst vs src + auto namei = name + "." + std::to_string(dst); + prev = bb.assign(namei, "insertvalue {} {}, {} {}, {}", t, prev, elem_t, elem, dst); + dst++; } } return prev; @@ -741,10 +755,19 @@ std::string Emitter::emit_bb(BB& bb, const Def* def) { declare("i8* @malloc(i64)"); emit_unsafe(malloc->arg(0)); - auto v_size = emit(malloc->arg(1)); - auto t_ptr = convert(force(def->proj(1)->type())); - bb.assign(name + ".i8", "call i8* @malloc(i64 {})", v_size); - return bb.assign(name, "bitcast i8* {} to {}", name + ".i8", t_ptr); + auto size = emit(malloc->arg(1)); + auto ptr_t = convert(force(def->proj(1)->type())); + bb.assign(name + ".i8", "call i8* @malloc(i64 {})", size); + return bb.assign(name, "bitcast i8* {} to {}", name + ".i8", ptr_t); + } else if (auto free = match(def)) { + declare("void @free(i8*)"); + emit_unsafe(free->arg(0)); + auto ptr = emit(free->arg(1)); + auto ptr_t = convert(force(free->arg(1)->type())); + + bb.assign(name + ".i8", "bitcast {} {} to i8*", ptr_t, ptr); + bb.tail("call void @free(i8* {})", name + ".i8"); + return {}; } else if (auto mslot = match(def)) { emit_unsafe(mslot->arg(0)); // TODO array with size @@ -795,6 +818,26 @@ std::string Emitter::emit_bb(BB& bb, const Def* def) { auto t = convert(arith->type()); auto mode = as_lit(arith->decurry()->arg()); + // # if 0 + // // TODO this was von closure-conv branch which I need to double-check + // if (tuple->isa()) { + // // computing the index may crash, so we bail out + // assert(match(extract->type()) && "only mem-var should not be mapped"); + // return {}; + // } + // # endif + + // auto ll_tup = emit_unsafe(tuple); + + // // this exact location is important: after emitting the tuple -> ordering of mem ops + // // before emitting the index, as it might be a weird value for mem vars. + // if (match(extract->type())) return {}; + + // auto ll_idx = emit_unsafe(index); + + // if (tuple->num_projs() == 2) { + // if (match(tuple->proj(2, 0_s)->type())) return ll_tup; + // if (match(tuple->proj(2, 1_s)->type())) return ll_tup; switch (arith.id()) { case math::arith::add: op = "fadd"; break; case math::arith::sub: op = "fsub"; break; @@ -949,6 +992,9 @@ std::string Emitter::emit_bb(BB& bb, const Def* def) { return bb.assign(name, "{} {} {} to {}", op, t_src, v_src, t_dst); } + auto& world = def->world(); + world.DLOG("unhandled def: {} : {}", def, def->type()); + def->dump(); unreachable(); // not yet implemented } diff --git a/dialects/core/core.cpp b/dialects/core/core.cpp index 61cd72ed91..b23fc09c0c 100644 --- a/dialects/core/core.cpp +++ b/dialects/core/core.cpp @@ -10,7 +10,7 @@ using namespace thorin; extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { - return {"core", nullptr, nullptr, [](Backends& backends) { backends["ll"] = &ll::emit; }, + return {"core", nullptr, [](Backends& backends) { backends["ll"] = &ll::emit; }, [](Normalizers& normalizers) { core::register_normalizers(normalizers); }}; } diff --git a/dialects/demo/demo.cpp b/dialects/demo/demo.cpp index fdb0dfa819..7471ef2ca7 100644 --- a/dialects/demo/demo.cpp +++ b/dialects/demo/demo.cpp @@ -10,6 +10,5 @@ using namespace thorin; /// registers passes in the different optimization phases /// as well as normalizers for the axioms extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { - return {"demo", nullptr, nullptr, nullptr, - [](Normalizers& normalizers) { demo::register_normalizers(normalizers); }}; + return {"demo", nullptr, nullptr, [](Normalizers& normalizers) { demo::register_normalizers(normalizers); }}; } diff --git a/dialects/direct/direct.cpp b/dialects/direct/direct.cpp index 37c3a426f5..f292a90344 100644 --- a/dialects/direct/direct.cpp +++ b/dialects/direct/direct.cpp @@ -19,11 +19,6 @@ using namespace thorin; extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { return {"direct", - [](thorin::PipelineBuilder& builder) { - builder.extend_opt_phase(115, [](thorin::PassMan& man) { man.add(); }); - builder.extend_opt_phase(116, [](thorin::PassMan& man) { man.add(); }); - builder.add_opt(120); - }, [](Passes& passes) { register_pass(passes); register_pass(passes); diff --git a/dialects/direct/passes/cps2ds.cpp b/dialects/direct/passes/cps2ds.cpp index cc54a82dc0..c2a812e115 100644 --- a/dialects/direct/passes/cps2ds.cpp +++ b/dialects/direct/passes/cps2ds.cpp @@ -10,42 +10,68 @@ namespace thorin::direct { void CPS2DS::enter() { Lam* lam = curr_nom(); + rewrite_lam(lam); +} + +void CPS2DS::rewrite_lam(Lam* lam) { + if (rewritten_lams.contains(lam)) return; + rewritten_lams.insert(lam); + if (!lam->isa_nom()) { lam->world().DLOG("skipped non-nom {}", lam); return; } - world().DLOG("CPS2DS: {}", lam->name()); - rewrite_lam(lam); -} + if (!lam->is_set()) { + lam->world().DLOG("skipped non-set {}", lam); + return; + } + if (lam->codom()->isa()) { + world().DLOG("skipped type {}", lam); + return; + } -void CPS2DS::rewrite_lam(Lam* lam) { + lam->world().DLOG("Rewrite lam: {}", lam->name()); + + lam_stack.push_back(curr_lam_); curr_lam_ = lam; auto result = rewrite_body(curr_lam_->body()); + // curr_lam_ might be different at this point (newly introduced continuation). + auto& w = curr_lam_->world(); + w.DLOG("Result of rewrite {} in {}", lam, curr_lam_); curr_lam_->set_body(result); + + curr_lam_ = lam_stack.back(); + lam_stack.pop_back(); } const Def* CPS2DS::rewrite_body(const Def* def) { if (auto i = rewritten_.find(def); i != rewritten_.end()) return i->second; - rewritten_[def] = rewrite_body_(def); + auto new_def = rewrite_body_(def); + rewritten_[def] = new_def; return rewritten_[def]; } const Def* CPS2DS::rewrite_body_(const Def* def) { auto& world = def->world(); if (auto app = def->isa()) { - auto callee = app->callee(); - auto args = app->arg(); - world.DLOG("rewrite callee {} : {}", callee, callee->type()); - world.DLOG("rewrite args {} : {}", args, args->type()); - auto new_arg = rewrite_body(app->arg()); + auto callee = app->callee(); + auto args = app->arg(); + auto new_callee = rewrite_body(callee); + auto new_arg = rewrite_body(app->arg()); - if (auto fun_app = callee->isa()) { + if (auto fun_app = new_callee->isa()) { if (auto ty_app = fun_app->callee()->isa(); ty_app) { if (auto axiom = ty_app->callee()->isa()) { if (axiom->flags() == ((flags_t)Axiom::Base)) { + world.DLOG("rewrite callee {} : {}", callee, callee->type()); + world.DLOG("rewrite args {} : {}", args, args->type()); world.DLOG("rewrite cps axiom {} : {}", ty_app, ty_app->type()); + // TODO: rewrite function? auto cps_fun = fun_app->arg(); + cps_fun = rewrite_body(cps_fun); + // if (!cps_fun->isa_nom()) { world.DLOG("cps_fun {} is not a lambda", cps_fun); } + // rewrite_lam(cps_fun->as_nom()); world.DLOG("function: {} : {}", cps_fun, cps_fun->type()); // ``` @@ -75,6 +101,7 @@ const Def* CPS2DS::rewrite_body_(const Def* def) { world.DLOG("new arguments {} : {}", new_arg, new_arg->type()); world.DLOG("ret_ty {}", ret_ty); + // TODO: use reduce (beta reduction) const Def* inst_ret_ty; if (auto ty_pi = ty->isa_nom()) { auto ty_dom = ty_pi->var(); @@ -88,8 +115,28 @@ const Def* CPS2DS::rewrite_body_(const Def* def) { inst_ret_ty = ret_ty; } + auto new_name = curr_lam_->name(); + // append _cps_cont + // if name contains _cps_cont append _1 + // if it contains _[n] append _[n+1] + std::string append = "_cps_cont"; + auto pos = new_name.find(append); + if (pos != std::string::npos) { + auto num = new_name.substr(pos + append.size()); + if (num.empty()) { + new_name += "_1"; + } else { + num = num.substr(1); + num = std::to_string(std::stoi(num) + 1); + new_name = new_name.substr(0, pos + append.size()) + "_" + num; + } + } else { + new_name += append; + } + // 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), world.dbg(new_name)); + rewritten_lams.insert(fun_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()); @@ -97,6 +144,7 @@ const Def* CPS2DS::rewrite_body_(const Def* def) { // Fixme: would be great to PE the newly added overhead away.. // The current PE just does not terminate on loops.. :/ + // TODO: Set filter (inline call wrapper) // curr_lam_->set_filter(true); // The filter can only be set here (not earlier) as otherwise a debug print causes the "some @@ -117,20 +165,43 @@ const Def* CPS2DS::rewrite_body_(const Def* def) { } } - auto new_calle = rewrite_body(app->callee()); - return world.app(new_calle, new_arg); + // auto new_callee = rewrite_body(app->callee()); + // auto new_callee = app->callee(); + return world.app(new_callee, new_arg); } // TODO: are ops rewrites + app calle/arg rewrites all possible combinations? // TODO: check if lam is necessary or if var is enough + if (auto lam = def->isa_nom()) { + rewrite_lam(lam); + return lam; + } + // We need this case to not descend into infinite chains through function - if (auto var = def->isa()) { return var; } + // if (auto var = def->isa()) { return var; } - if (auto old_nom = def->isa_nom()) { return old_nom; } + if (auto tuple = def->isa()) { + DefArray elements(tuple->ops(), [&](const Def* op) { return rewrite_body(op); }); + return world.tuple(elements, tuple->dbg()); + } + + // 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()); - return def->rebuild(world, def->type(), new_ops, def->dbg()); + // auto new_dbg = rewrite_body(def->dbg()); + // auto new_type = rewrite_body(def->type()); + auto new_dbg = def->dbg(); + + world.DLOG("def {} : {} [{}]", def, def->type(), def->node_name()); + + // TODO: where does this come from? + // example: ./build/bin/thorin -d matrix -d affine -d direct lit/matrix/read_transpose.thorin -o - -VVVV + if (def->isa()) { + world.WLOG("infer node {} : {} [{}]", def, def->type(), def->node_name()); + return def; + } + + return def->rebuild(world, def->type(), new_ops, new_dbg); } } // namespace thorin::direct diff --git a/dialects/direct/passes/cps2ds.h b/dialects/direct/passes/cps2ds.h index ffd7644753..40ea0cc1fe 100644 --- a/dialects/direct/passes/cps2ds.h +++ b/dialects/direct/passes/cps2ds.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -16,8 +18,10 @@ class CPS2DS : public RWPass { void enter() override; private: - Def2Def rewritten_lams; + // Def2Def rewritten_lams; Def2Def rewritten_; + DefSet rewritten_lams; + std::vector lam_stack; Lam* curr_lam_ = nullptr; void rewrite_lam(Lam* lam); diff --git a/dialects/math/math.cpp b/dialects/math/math.cpp index 08de79022a..326c17d156 100644 --- a/dialects/math/math.cpp +++ b/dialects/math/math.cpp @@ -8,6 +8,6 @@ using namespace thorin; extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { - return {"math", nullptr, nullptr, [](Backends&) {}, + return {"math", nullptr, [](Backends&) {}, [](Normalizers& normalizers) { math::register_normalizers(normalizers); }}; } diff --git a/dialects/mem/mem.cpp b/dialects/mem/mem.cpp index 8900d6959e..cb6de73761 100644 --- a/dialects/mem/mem.cpp +++ b/dialects/mem/mem.cpp @@ -13,33 +13,22 @@ #include "thorin/pass/rw/ret_wrap.h" #include "thorin/pass/rw/scalarize.h" +#include "dialects/mem/autogen.h" #include "dialects/mem/passes/fp/copy_prop.h" #include "dialects/mem/passes/fp/ssa_constr.h" #include "dialects/mem/passes/rw/alloc2malloc.h" #include "dialects/mem/passes/rw/remem_elim.h" +#include "dialects/mem/passes/rw/reshape.h" #include "dialects/mem/phases/rw/add_mem.h" using namespace thorin; extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { return {"mem", - [](PipelineBuilder& builder) { - builder.extend_opt_phase([](PassMan& man) { - auto br = man.add(); - auto er = man.add(); - auto ee = man.add(er); - man.add(ee); - man.add(br, ee); - }); - builder.extend_codegen_prep_phase([](PassMan& man) { - man.add(); - man.add(); - }); - }, [](Passes& passes) { register_pass_with_arg(passes); register_pass(passes); - register_pass(passes); + register_pass(passes); // TODO: generalize register_pass_with_arg passes[flags_t(Axiom::Base)] = [&](World& world, PipelineBuilder& builder, @@ -52,6 +41,14 @@ extern "C" THORIN_EXPORT DialectInfo thorin_get_dialect_info() { world.DLOG("registering copy_prop with br = {}, ee = {}, bb_only = {}", br, ee, bb_only); builder.add_pass(app, br_pass, ee_pass, bb_only); }; + passes[flags_t(Axiom::Base)] = [&](World&, PipelineBuilder& builder, + const Def* app) { + auto mode_ax = app->as()->arg()->as(); + auto mode = mode_ax->flags() == flags_t(Axiom::Base) ? mem::Reshape::Arg + : mem::Reshape::Flat; + builder.add_pass(app, mode); + }; + register_pass(passes); }, nullptr, [](Normalizers& normalizers) { mem::register_normalizers(normalizers); }}; } diff --git a/dialects/mem/mem.h b/dialects/mem/mem.h index 53db697324..792d6169ae 100644 --- a/dialects/mem/mem.h +++ b/dialects/mem/mem.h @@ -125,7 +125,83 @@ inline const Def* op_free(const Def* mem, const Def* ptr, const Def* dbg = {}) { return w.app(w.app(w.ax(), {pointee, w.lit_nat_0()}), {mem, ptr}, dbg); } -inline const Def* mem_var(Lam* lam, const Def* dbg = nullptr) { - return match(lam->var(0_s)->type()) ? lam->var(0, dbg) : nullptr; +/// Returns the (first) element of type mem::M from the given tuple. +static const Def* mem_def(const Def* def, const Def* dbg = {}) { + if (match(def->type())) { return def; } + + if (def->num_projs() > 1) { + for (auto proj : def->projs()) { + if (auto mem = mem_def(proj)) { return mem; } + } + } + + return nullptr; +} + +/// Returns the memory argument of a function if it has one. +inline const Def* mem_var(Lam* lam, const Def* dbg = nullptr) { return mem_def(lam->var(), dbg); } + +/// Swapps the memory occurrences in the given def with the given memory. +inline const Def* replace_mem(const Def* mem, const Def* arg) { + // TODO: maybe use rebuild instead? + if (arg->num_projs() > 1) { + auto& w = mem->world(); + return w.tuple(DefArray(arg->num_projs(), [&](auto i) { return replace_mem(mem, arg->proj(i)); })); + } + + if (match(arg->type())) { return mem; } + + return arg; +} + +/// Removes recusively all occurences of mem from a type (sigma). +static const Def* strip_mem_ty(const Def* def) { + auto& world = def->world(); + + if (auto sigma = def->isa()) { + DefVec newOps; + for (auto op : sigma->ops()) { + auto newOp = strip_mem_ty(op); + if (newOp != world.sigma()) { newOps.push_back(newOp); } + } + + return world.sigma(newOps); + } else if (match(def)) { + return world.sigma(); + } + + return def; +} + +/// Removes recusively all occurences of mem from a tuple. +/// Returns an empty tuple if applied with mem alone. +static const Def* strip_mem(const Def* def) { + auto& world = def->world(); + + if (auto tuple = def->isa()) { + DefVec newOps; + for (auto op : tuple->ops()) { + auto newOp = strip_mem(op); + if (newOp != world.tuple()) { newOps.push_back(newOp); } + } + + return world.tuple(newOps); + } else if (match(def->type())) { + return world.tuple(); + } else if (auto extract = def->isa()) { + // The case that this one element is a mem and should return () is handled above. + if (extract->num_projs() == 1) { return extract; } + + DefVec newOps; + for (auto op : extract->projs()) { + auto newOp = strip_mem(op); + if (newOp != world.tuple()) { newOps.push_back(newOp); } + } + + return world.tuple(newOps); + } + + return def; } + } // namespace thorin::mem diff --git a/dialects/mem/mem.thorin b/dialects/mem/mem.thorin index fba5da8c3b..8216c2a58a 100644 --- a/dialects/mem/mem.thorin +++ b/dialects/mem/mem.thorin @@ -78,6 +78,14 @@ /// /// ## Compilation Passes and Phases /// +/// ### Misc +/// +/// Reshape mode enum. +/// +.ax %mem.reshape_mode: *; +.ax %mem.reshape_flat: %mem.reshape_mode; +.ax %mem.reshape_arg: %mem.reshape_mode; +/// /// ### Passes /// /// The SSA expects the eta expansion as argument @@ -86,6 +94,8 @@ .ax %mem.copy_prop_pass: [%compile.Pass,%compile.Pass, .Bool] -> %compile.Pass; .ax %mem.remem_elim_pass: %compile.Pass; .ax %mem.alloc2malloc_pass: %compile.Pass; +.ax %mem.reshape_pass: %mem.reshape_mode -> %compile.Pass; +.ax %mem.add_mem_pass: %compile.Pass; /// /// ### Phases /// @@ -98,7 +108,7 @@ eta_red eta_exp (%mem.ssa_pass eta_exp) - (%mem.copy_prop_pass (beta_red, eta_exp, (0:(.Idx 2)))) + (%mem.copy_prop_pass (beta_red, eta_exp, (0:.Bool))) }; .let mem_opt_phase = { %compile.pass_phase mem_opt_pass_list diff --git a/dialects/mem/passes/rw/reshape.cpp b/dialects/mem/passes/rw/reshape.cpp new file mode 100644 index 0000000000..442abb404e --- /dev/null +++ b/dialects/mem/passes/rw/reshape.cpp @@ -0,0 +1,339 @@ +#include "dialects/mem/passes/rw/reshape.h" + +#include +#include +#include + +#include "thorin/check.h" +#include "thorin/def.h" +#include "thorin/tuple.h" + +#include "dialects/mem/mem.h" + +namespace thorin::mem { + +void Reshape::enter() { rewrite_def(curr_nom()); } + +const Def* Reshape::rewrite_def(const Def* def) { + if (auto i = old2new_.find(def); i != old2new_.end()) return i->second; + auto new_def = rewrite_def_(def); + old2new_[def] = new_def; + return new_def; +} + +bool should_flatten(const Def* T) { + // handle [] cases + if (T->isa()) return true; + // also handle normalized tuple-arrays ((a:I32,b:I32) : <<2;I32>>) + // TODO: handle better than with magic number + // (do we want to flatten any array with more than 2 elements?) + // (2 elements are needed for conditionals) + // TODO: e.g. lea explicitely does not want to flatten + + // TODO: annotate with test cases that need these special cases + // Problem with 2 Arr -> flatten + // lea (2, <<2;I32>>, ...) -> lea (2, I32, I32, ...) + if (auto lit = T->arity()->isa(); lit && lit->get() <= 2) { + if (auto arr = T->isa(); arr && arr->body()->isa()) { return lit->get() > 1; } + } + return false; +} + +const Def* Reshape::rewrite_def_(const Def* def) { + // We ignore types. + switch (def->node()) { + // TODO: check if bot: Cn[[A,B],Cn[Ret]] is handled correctly + // case Node::Bot: + // case Node::Top: + case Node::Type: + case Node::Univ: + case Node::Nat: return def; + } + + // ignore axioms + if (def->isa()) { return def; } + + // This is dead code for debugging purposes. + // It allows for inspection of the current def. + std::stringstream ss; + ss << def << " : " << def->type() << " [" << def->node_name() << "]"; + std::string str = ss.str(); + + // vars are handled by association. + if (def->isa()) { world().ELOG("Var: {}", def); } + assert(!def->isa()); + + auto& w = world(); + + if (auto app = def->isa()) { + auto callee = rewrite_def(app->callee()); + auto arg = rewrite_def(app->arg()); + + world().DLOG("callee: {} : {}", callee, callee->type()); + + // Reshape normally (not to callee) to ensure that callee is reshaped correctly. + auto reshaped_arg = reshape(arg); + world().DLOG("reshape arg {} : {}", arg, arg->type()); + world().DLOG("into arg {} : {}", reshaped_arg, reshaped_arg->type()); + auto new_app = w.app(callee, reshaped_arg); + return new_app; + } else if (auto lam = def->isa_nom()) { + world().DLOG("rewrite_def lam {} : {}", def, def->type()); + auto new_lam = reshape_lam(lam); + world().DLOG("rewrote lam {} : {}", def, def->type()); + world().DLOG("into lam {} : {}", new_lam, new_lam->type()); + return new_lam; + } else if (auto tuple = def->isa()) { + DefArray elements(tuple->ops(), [&](const Def* op) { return rewrite_def(op); }); + return w.tuple(elements); + } else { + auto new_ops = DefArray(def->num_ops(), [&](auto i) { return rewrite_def(def->op(i)); }); + // Warning: if the new_type is not correct, inconcistencies will arise. + auto new_type = rewrite_def(def->type()); + auto new_dbg = def->dbg() ? rewrite_def(def->dbg()) : nullptr; + + auto new_def = def->rebuild(w, new_type, new_ops, new_dbg); + return new_def; + } +} + +Lam* Reshape::reshape_lam(Lam* def) { + auto& w = def->world(); + if (!def->is_set()) { + w.DLOG("reshape_lam: {} is not a set", def); + return def; + } + auto pi_ty = def->type(); + auto new_ty = reshape_type(pi_ty)->as(); + + Lam* new_lam; + auto name = def->name(); + + if (name != "main") { + name = name + "_reshape"; + new_lam = w.nom_lam(new_ty, w.dbg(name)); + old2new_[def] = new_lam; + } else { + new_lam = def; + } + + w.DLOG("Reshape lam: {} : {}", def, pi_ty); + w.DLOG(" to: {} : {}", new_lam, new_ty); + + // We associate the arguments (reshape the old vars). + // Alternatively, we could use beta reduction (reduce) to do this for us. + auto new_arg = new_lam->var(); + + // We deeply associate `def->var()` with `new_arg` in a reconstructed shape. + // Idea: first make new_arg into "atomic" def list, then recrusively imitate `def->var`. + auto reformed_new_arg = reshape(new_arg, def->var()->type()); // `def->var()->type() = pi_ty` + w.DLOG("var {} : {}", def->var(), def->var()->type()); + w.DLOG("new var {} : {}", new_arg, new_arg->type()); + w.DLOG("reshaped new_var {} : {}", reformed_new_arg, reformed_new_arg->type()); + w.DLOG("{}", def->var()->type()); + w.DLOG("{}", reformed_new_arg->type()); + old2new_[def->var()] = reformed_new_arg; + // TODO: add if necessary. This probably was an issue with unintended overriding due to bad previous naming. + // TODO: Remove after testing. + // old2new_[new_arg] = new_arg; + + auto new_body = rewrite_def(def->body()); + new_lam->set_body(new_body); + new_lam->set_filter(true); + + if (def->is_external()) { + def->make_internal(); + new_lam->make_external(); + } + + w.DLOG("finished transforming: {} : {}", new_lam, new_ty); + return new_lam; +} + +std::vector flatten_ty(const Def* T) { + std::vector types; + if (should_flatten(T)) { + for (auto P : T->projs()) { + auto inner_types = flatten_ty(P); + types.insert(types.end(), inner_types.begin(), inner_types.end()); + } + } else { + types.push_back(T); + } + return types; +} + +bool is_mem_ty(const Def* T) { return match(T); } +DefArray vec2array(const std::vector& vec) { return DefArray(vec.begin(), vec.end()); } + +const Def* Reshape::reshape_type(const Def* T) { + auto& w = T->world(); + // w.DLOG("reshape_type: {}", T); + + if (auto pi = T->isa()) { + auto new_dom = reshape_type(pi->dom()); + auto new_cod = reshape_type(pi->codom()); + return w.pi(new_dom, new_cod); + } else if (auto sigma = T->isa()) { + auto flat_types = flatten_ty(sigma); + std::vector new_types(flat_types.size()); + std::transform(flat_types.begin(), flat_types.end(), new_types.begin(), + [&](auto T) { return reshape_type(T); }); + // w.DLOG("flat types {,}", flat_types); + if (mode_ == Mode::Flat) { + const Def* mem = nullptr; + // find mem + for (auto i = new_types.begin(); i != new_types.end(); i++) { + if (is_mem_ty(*i) && !mem) { mem = *i; } + } + // filter out mems + new_types.erase(std::remove_if(new_types.begin(), new_types.end(), is_mem_ty), new_types.end()); + // readd mem in the front + if (mem) new_types.insert(new_types.begin(), mem); + // w.DLOG("flat types2 {,}", flat_types); + auto reshaped_type = w.sigma(vec2array(new_types)); + // w.DLOG("new sigma: reshape_type({}) = {}", T, reshaped_type); + return reshaped_type; + } else { + if (new_types.size() == 0) return w.sigma(); + if (new_types.size() == 1) return new_types[0]; + const Def* mem = nullptr; + const Def* ret = nullptr; + // find mem + for (auto i = new_types.begin(); i != new_types.end(); i++) { + if (is_mem_ty(*i) && !mem) { mem = *i; } + } + // filter out mems + new_types.erase(std::remove_if(new_types.begin(), new_types.end(), is_mem_ty), new_types.end()); + // find mem, erase all mems + // for (auto i = new_types.begin(); i != new_types.end(); i++) { + // if (is_mem_ty(*i)) { + // if (!mem) mem = *i; + // new_types.erase(i); + // } + // } + // TODO: more fine-grained test + if (new_types.back()->isa()) { + ret = new_types.back(); + new_types.pop_back(); + } + // Create the arg form `[[mem,args],ret]` + const Def* args = w.sigma(vec2array(new_types)); + if (mem) { args = w.sigma({mem, args}); } + if (ret) { args = w.sigma({args, ret}); } + return args; + } + } else { + return T; + } +} + +std::vector flatten_def(const Def* def) { + std::vector defs; + if (should_flatten(def->type())) { + auto& w = def->world(); + for (auto P : def->projs()) { + auto inner_defs = flatten_def(P); + defs.insert(defs.end(), inner_defs.begin(), inner_defs.end()); + } + } else { + defs.push_back(def); + } + return defs; +} + +const Def* Reshape::reshape(std::vector& defs, const Def* T, const Def* mem) { + auto& world = T->world(); + if (should_flatten(T)) { + DefArray tuples(T->projs(), [&](auto P) { return reshape(defs, P, mem); }); + return world.tuple(tuples); + } else { + const Def* def; + if (is_mem_ty(T)) { + assert(mem != nullptr && "Reshape: mems not found"); + def = mem; + } else { + do { + assert(defs.size() > 0 && "Reshape: not enough arguments"); + def = defs.front(); + defs.erase(defs.begin()); + } while (is_mem_ty(def->type())); + } + // For inner function types, we override the type + if (!def->type()->isa()) { + if (!world.checker().equiv(def->type(), T, {})) { + world.ELOG("reconstruct T {} from def {}", T, def->type()); + } + assert(world.checker().equiv(def->type(), T, {}) && "Reshape: argument type mismatch"); + } + return def; + } +} + +const Def* Reshape::reshape(const Def* def, const Def* target) { + def->world().DLOG("reshape:\n {} =>\n {}", def->type(), target); + auto flat_defs = flatten_def(def); + const Def* mem = nullptr; + // find mem + for (auto i = flat_defs.begin(); i != flat_defs.end(); i++) { + if (is_mem_ty((*i)->type()) && !mem) { mem = *i; } + } + def->world().DLOG("mem: {}", mem); + return reshape(flat_defs, target, mem); +} + +// called for new lambda arguments, app arguments +// We can not (directly) replace it with the more general version above due to the mem erasure. +// TODO: ignore mem erase, replace with more general +// TODO: capture names +const Def* Reshape::reshape(const Def* def) { + auto& w = def->world(); + + auto flat_defs = flatten_def(def); + if (flat_defs.size() == 1) return flat_defs[0]; + // TODO: move mem removal to flatten_def + if (mode_ == Mode::Flat) { + const Def* mem = nullptr; + // find mem + for (auto i = flat_defs.begin(); i != flat_defs.end(); i++) { + if (is_mem_ty((*i)->type()) && !mem) { mem = *i; } + } + // filter out mems + flat_defs.erase( + std::remove_if(flat_defs.begin(), flat_defs.end(), [](const Def* def) { return is_mem_ty(def->type()); }), + flat_defs.end()); + // insert mem + if (mem) { flat_defs.insert(flat_defs.begin(), mem); } + return w.tuple(vec2array(flat_defs)); + } else { + // arg style + // [[mem,args],ret] + const Def* mem = nullptr; + const Def* ret = nullptr; + // find mem + for (auto i = flat_defs.begin(); i != flat_defs.end(); i++) { + if (is_mem_ty((*i)->type()) && !mem) { mem = *i; } + } + // filter out mems + flat_defs.erase( + std::remove_if(flat_defs.begin(), flat_defs.end(), [](const Def* def) { return is_mem_ty(def->type()); }), + flat_defs.end()); + // find mem, erase all mems + // for (auto i = flat_defs.begin(); i != flat_defs.end(); i++) { + // if (is_mem_ty((*i)->type())) { + // if (!mem) mem = *i; + // flat_defs.erase(i); + // } + // } + if (flat_defs.back()->type()->isa()) { + ret = flat_defs.back(); + flat_defs.pop_back(); + } + const Def* args = w.tuple(vec2array(flat_defs)); + if (mem) { args = w.tuple({mem, args}); } + if (ret) { args = w.tuple({args, ret}); } + return args; + } +} + +} // namespace thorin::mem diff --git a/dialects/mem/passes/rw/reshape.h b/dialects/mem/passes/rw/reshape.h new file mode 100644 index 0000000000..d1425e0a85 --- /dev/null +++ b/dialects/mem/passes/rw/reshape.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +#include "thorin/phase/phase.h" + +namespace thorin::mem { + +using DefQueue = std::deque; + +static int i = 0; + +/// The general idea of this pass/phase is to change the shape of signatures of functions. +/// Example: `Cn[ [mem, A, B], C , ret]` +/// Arg : `Cn[ [mem, [A, B , C]], ret]` (general `Cn[ [mem, args], ret]`) +/// Flat : `Cn[ mem, A, B , C , ret]` (general `Cn[mem, ...args, ret]`) +/// For convenience, we want Arg-style for optimizations. +/// The invariant is that every closed function has at most one "real" argument and a return-continuation. +/// If memory is present, the argument is a pair of memory and the remaining arguments. +/// However, flat style is required for code generation. Especially in the closure conversion. +/// +/// The concept is to rewrite all signatures of functions with consistent reassociation of arguments. +/// This change is propagated to (nested) applications. +// TODO: use RWPhase instead +class Reshape : public RWPass { +public: + enum Mode { Flat, Arg }; + + Reshape(PassMan& man, Mode mode) + : RWPass(man, "reshape") + , mode_(mode) {} + + /// Fall-through to `rewrite_def` which falls through to `rewrite_lam`. + void enter() override; + +private: + /// Memoized version of `rewrite_def_` + const Def* rewrite_def(const Def* def); + /// Replace lambas with reshaped versions, shape application arguments, and replace vars and already rewritten + /// lambdas. + const Def* rewrite_def_(const Def* def); + /// Create a new lambda with the reshaped signature and rewrite its body. + /// The old var is associated with a reshaped version of the new var in `old2new_`. + Lam* reshape_lam(Lam* def); + + /// Reshapes a type into its flat or arg representation. + const Def* reshape_type(const Def* T); + /// Reshapes a def into its flat or arg representation. + const Def* reshape(const Def* def); + // This generalized version of reshape transforms def to match the shape of target. + const Def* reshape(const Def* def, const Def* target); + /// Reconstructs the target type by taking defs out of the queue. + const Def* reshape(std::vector& def, const Def* target, const Def* mem); + + /// Keeps track of the replacements. + Def2Def old2new_; + /// The mode to rewrite all lambas to. Either flat or arg. + Mode mode_; +}; + +} // namespace thorin::mem diff --git a/dialects/mem/phases/rw/add_mem.cpp b/dialects/mem/phases/rw/add_mem.cpp index 517bc630e0..4e9acb3c04 100644 --- a/dialects/mem/phases/rw/add_mem.cpp +++ b/dialects/mem/phases/rw/add_mem.cpp @@ -61,6 +61,7 @@ static const Def* rewrite_apped_nom_lam_in_tuple(const Def* def, return app->rebuild(w, app->type(), {callee, arg}, app->dbg()); } +// Entry point of the phase. void AddMem::visit(const Scope& scope) { if (auto entry = scope.entry()->isa_nom()) { scope.free_noms(); // cache this. @@ -70,8 +71,16 @@ void AddMem::visit(const Scope& scope) { } const Def* AddMem::mem_for_lam(Lam* lam) const { - if (auto it = mem_rewritten_.find(lam); it != mem_rewritten_.end()) lam = it->second->as_nom(); - if (auto it = val2mem_.find(lam); it != val2mem_.end()) return it->second; + if (auto it = mem_rewritten_.find(lam); it != mem_rewritten_.end()) { + // We created a new lambda. Therefore, we want to lookup the mem for the new lambda. + lam = it->second->as_nom(); + } + if (auto it = val2mem_.find(lam); it != val2mem_.end()) { + lam->world().DLOG("found mem for {} in val2mem_ : {}", lam, it->second); + // We found a (overwritten) memory in the lambda. + return it->second; + } + // As a fallback, we lookup the memory in vars of the lambda. auto mem = mem::mem_var(lam); assert(mem && "nom must have mem!"); return mem; @@ -102,7 +111,7 @@ const Def* AddMem::rewrite_pi(const Pi* pi) { const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { auto place = static_cast(sched_.smart(def)); - world().DLOG("rewriting {} : {} in {}", def, def->type(), place); + // world().DLOG("rewriting {} : {} in {}", def, def->type(), place); if (auto nom_lam = def->isa_nom(); nom_lam && !nom_lam->is_set()) return def; if (auto ax = def->isa()) return ax; @@ -110,10 +119,12 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { auto tmp = it->second; if (match(def->type())) { world().DLOG("already known mem {} in {}", def, curr_lam); - return mem_for_lam(curr_lam); + auto new_mem = mem_for_lam(curr_lam); + world().DLOG("new mem {} in {}", new_mem, curr_lam); + return new_mem; } if (curr_lam != def) { - world().DLOG("rewritten def: {} : {} in {}", tmp, tmp->type(), curr_lam); + // world().DLOG("rewritten def: {} : {} in {}", tmp, tmp->type(), curr_lam); return tmp; } } @@ -216,8 +227,12 @@ 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()); - if (match(rewritten->type())) val2mem_[place] = rewritten; + if (match(rewritten->type())) { + world().DLOG("memory from axiom {} : {}", rewritten, rewritten->type()); + val2mem_[place] = rewritten; + } if (rewritten->num_projs() > 0 && match(rewritten->proj(0)->type())) { + world().DLOG("memory from axiom 2 {} : {}", rewritten, rewritten->type()); mem_rewritten_[rewritten->proj(0)] = rewritten->proj(0); val2mem_[place] = rewritten->proj(0); } @@ -231,8 +246,12 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { 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()); - if (match(rewritten->type())) val2mem_[place] = rewritten; + if (match(rewritten->type())) { + world().DLOG("memory from other {} : {}", rewritten, rewritten->type()); + val2mem_[place] = rewritten; + } if (rewritten->num_projs() > 0 && match(rewritten->proj(0)->type())) { + world().DLOG("memory from other 2 {} : {}", rewritten, rewritten->type()); mem_rewritten_[rewritten->proj(0)] = rewritten->proj(0); val2mem_[place] = rewritten->proj(0); } @@ -249,11 +268,15 @@ const Def* AddMem::add_mem_to_lams(Lam* curr_lam, const Def* def) { }}; auto tmp = mem_rewritten_[def] = def->rebuild(world(), rewrite_type(def->type()), new_ops, def->dbg()); - 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); - val2mem_[place] = tmp->proj(0); - } + // if (match(tmp->type())) { + // world().DLOG("memory from other op 1 {} : {}", tmp, tmp->type()); + // val2mem_[place] = tmp; + // } + // if (tmp->num_projs() > 0 && match(tmp->proj(0)->type())) { + // world().DLOG("memory from other op 2 {} : {}", tmp, tmp->type()); + // mem_rewritten_[tmp->proj(0)] = tmp->proj(0); + // val2mem_[place] = tmp->proj(0); + // } return tmp; } diff --git a/dialects/mem/phases/rw/add_mem.h b/dialects/mem/phases/rw/add_mem.h index 5e3dff6c01..24e89a617e 100644 --- a/dialects/mem/phases/rw/add_mem.h +++ b/dialects/mem/phases/rw/add_mem.h @@ -21,10 +21,13 @@ class AddMem : public ScopePhase { const Def* add_mem_to_lams(Lam*, const Def*); const Def* rewrite_type(const Def*); const Def* rewrite_pi(const Pi*); + /// Return the most recent memory for the given lambda. const Def* mem_for_lam(Lam*) const; Scheduler sched_; + // Stores the most recent memory for a lambda. Def2Def val2mem_; + // Memoization & Association for rewritten defs. Def2Def mem_rewritten_; }; diff --git a/dialects/opt/normalizers.cpp b/dialects/opt/normalizers.cpp new file mode 100644 index 0000000000..28280c9416 --- /dev/null +++ b/dialects/opt/normalizers.cpp @@ -0,0 +1,17 @@ +#include "thorin/world.h" + +#include "dialects/opt/opt.h" + +namespace thorin::opt { + +const Def* normalize_is_loaded(const Def* type, const Def* callee, const Def* arg, const Def* dbg) { + auto& world = arg->world(); + + world.DLOG("normalize is_loaded: {}", arg); + + return world.raw_app(callee, arg, dbg); +} + +THORIN_opt_NORMALIZER_IMPL + +} // namespace thorin::opt diff --git a/dialects/opt/opt.cpp b/dialects/opt/opt.cpp new file mode 100644 index 0000000000..124059cbf2 --- /dev/null +++ b/dialects/opt/opt.cpp @@ -0,0 +1,44 @@ +#include "dialects/opt/opt.h" + +#include + +#include +#include +#include + +#include "dialects/compile/compile.h" +#include "dialects/opt/autogen.h" + +using namespace thorin; + +extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { + return {"opt", + [](Passes& passes) { + passes[flags_t(Axiom::Base)] = [&](World& world, PipelineBuilder& builder, + const Def* app) { + auto [ax, args] = collect_args(app); + auto dialect_axiom = args[1]->as(); + auto then_phase = args[2]; + auto else_phase = args[3]; + world.DLOG("dialect_phase for: {}", dialect_axiom->name()); + + // 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 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); + } + }; + }, + nullptr, [](Normalizers& normalizers) { opt::register_normalizers(normalizers); }}; +} diff --git a/dialects/opt/opt.h b/dialects/opt/opt.h new file mode 100644 index 0000000000..6e98afac46 --- /dev/null +++ b/dialects/opt/opt.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#include "dialects/opt/autogen.h" diff --git a/dialects/opt/opt.thorin b/dialects/opt/opt.thorin new file mode 100644 index 0000000000..09305f0a61 --- /dev/null +++ b/dialects/opt/opt.thorin @@ -0,0 +1,116 @@ +/// # The opt dialect {#opt} +/// +/// [TOC] +/// +/// Manages the default compilation pipeline of Thorin programs using dialects. +/// +/// ## Dependencies +/// +.import compile; +.import core; +.import mem; +/// supported dialects with passes +.import affine; +.import autodiff; +.import clos; +.import direct; +.import refly; +/// +/// ## Types +/// +/// ### %opt.Dialect +/// +.ax %opt.Dialect: *; +/// +/// ## Operations +/// +/// ### registered dialects +/// +/// We expect the name in the tag before the `_` to be the name of the dialect (as given in `DialectInfo.plugin_name`). +/// +.ax %opt.core_dialect : %opt.Dialect; +.ax %opt.mem_dialect : %opt.Dialect; +.ax %opt.demo_dialect : %opt.Dialect; +.ax %opt.affine_dialect : %opt.Dialect; +.ax %opt.autodiff_dialect: %opt.Dialect; +.ax %opt.clos_dialect : %opt.Dialect; +.ax %opt.direct_dialect : %opt.Dialect; +.ax %opt.refly_dialect : %opt.Dialect; +/// +/// ### %opt.is_loaded +/// +/// Indicates whether a dialect is loaded. +/// The normalizer will statically evaluate this expression to a constant boolean. +/// TODO: find correct point (not at parsing but before compilation) +/// +.ax %opt.is_loaded: %opt.Dialect -> .Bool, normalize_is_loaded; +/// +/// ## Compilation passes, phases, and pipelines +/// +/// ### Phases +/// +.let empty_pass = %compile.nullptr_pass; +.let empty_phase = %compile.passes_to_phase 0 (); +.ax %opt.dialect_select: Π [T:*] -> %opt.Dialect -> T -> T -> T; +.let dialect_phase = %opt.dialect_select %compile.Phase; +.let dialect_pass = %opt.dialect_select %compile.Pass; +.lam dialect_cond_phase ![dialect: %opt.Dialect,phase: %compile.Phase] -> %compile.Phase = { + dialect_phase dialect phase empty_phase +}; +.lam dialect_cond_pass ![dialect: %opt.Dialect,pass: %compile.Pass] -> %compile.Pass = { + dialect_pass dialect pass empty_pass +}; +/// +/// ### Pipelines +/// +.lam .extern _default_compile [] -> Pipeline = { + .let nullptr = %compile.nullptr_pass; + .let nullphase = %compile.single_pass_phase nullptr; + %compile.pipe + nullphase + (%compile.single_pass_phase (%compile.scalerize_pass nullptr)) + (%compile.single_pass_phase %compile.eta_red_pass) + (%compile.single_pass_phase (%compile.tail_rec_elim_pass nullptr)) + // optimize + (%compile.pass_phase + (%compile.combine_pass_list (3:.Nat) + ( + optimization_pass_list, + %compile.pass_list + (dialect_cond_pass (%opt.affine_dialect, %affine.lower_for_pass)), + mem_opt_pass_list + )) + ) + (dialect_cond_phase (%opt.autodiff_dialect, + %compile.combined_phase (%compile.phase_list + (%compile.single_pass_phase %autodiff.ad_eval_pass) + // optimization_phase + (%compile.single_pass_phase %autodiff.ad_zero_pass) + ) + )) + (dialect_cond_phase (%opt.direct_dialect, + direct_phases + )) + (%compile.single_pass_phase %compile.internal_cleanup_pass) + (dialect_cond_phase (%opt.clos_dialect, + clos_phases + )) + (%compile.single_pass_phase %compile.lam_spec_pass) + (dialect_cond_phase (%opt.autodiff_dialect, + ad_cleanup_phase + )) + // CodeGenPrep + (%compile.pass_phase + (%compile.combine_pass_list (3:.Nat) + ( + %compile.pass_list + %compile.ret_wrap_pass, + // mem + %compile.pass_list + %mem.remem_elim_pass + %mem.alloc2malloc_pass, + %compile.pass_list + (dialect_cond_pass (%opt.refly_dialect, %refly.remove_dbg_perm_pass)), + )) + ) +}; diff --git a/dialects/refly/passes/debug_dump.h b/dialects/refly/passes/debug_dump.h new file mode 100644 index 0000000000..508a37d5cc --- /dev/null +++ b/dialects/refly/passes/debug_dump.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +using namespace thorin; + +/// A pass that just dumps the world. +class DebugDump : public RWPass { +public: + DebugDump(PassMan& man) + : RWPass(man, "print_wrapper") {} + + void prepare() override { world().debug_dump(); } +}; diff --git a/dialects/refly/refly.cpp b/dialects/refly/refly.cpp index 88e2d05bb5..8fff862484 100644 --- a/dialects/refly/refly.cpp +++ b/dialects/refly/refly.cpp @@ -12,11 +12,8 @@ using namespace thorin; /// registers passes in the different optimization phases /// as well as normalizers for the axioms extern "C" THORIN_EXPORT thorin::DialectInfo thorin_get_dialect_info() { - return {"refly", - [](thorin::PipelineBuilder& builder) { - builder.extend_codegen_prep_phase([](PassMan& man) { man.add(); }); - }, - nullptr, nullptr, [](Normalizers& normalizers) { refly::register_normalizers(normalizers); }}; + return {"refly", [](Passes& passes) { register_pass(passes); }, + nullptr, [](Normalizers& normalizers) { refly::register_normalizers(normalizers); }}; } // TODO: check (and fix) for windows diff --git a/dialects/refly/refly.thorin b/dialects/refly/refly.thorin index 789cadd9a4..022bc05a6d 100644 --- a/dialects/refly/refly.thorin +++ b/dialects/refly/refly.thorin @@ -4,6 +4,10 @@ /// /// [TOC] /// +/// ## Dependencies +/// +.import compile; +/// /// ## Types /// .ax %refly.Code: *; @@ -42,3 +46,9 @@ /// /// Sets the `i`th operand of the reified Code `e` to `x`. .ax %refly.refine: [e: %refly.Code, i: .Nat, x: %refly.Code] -> %refly.Code, normalize_refine; +/// +/// ## Compilation Passes and Phases +/// +/// ### Passes +/// +.ax %refly.remove_dbg_perm_pass: %compile.Pass; diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 60defca8e2..a318ddec81 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -866,7 +866,7 @@ WARN_NO_PARAMDOC = NO # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. -WARN_AS_ERROR = YES +WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which diff --git a/error.sh b/error.sh new file mode 100755 index 0000000000..149b1326bd --- /dev/null +++ b/error.sh @@ -0,0 +1,49 @@ +# call `./error.sh [-o] -n [output lines] [command]` + +if [ "$1" = "-o" ]; then + out_only=true + shift +else + out_only=false +fi + +if [ "$1" = "-n" ]; then + lines=$2 + shift 2 +else + lines=20 +fi + +command="$@" +current_dir=$(pwd) + +# Run the command, store the output and the exit code +if [ "$out_only" = true ]; then + output=$($command 2> /dev/null) +else + output=$($command 2>&1) +fi +exit_code=$? + +# get the last 5 lines of the output +output=$(echo "$output" | tail -n $lines) + +# replace current directory with $PWD +output=${output//$current_dir/\$PWD} + +# get current branch and repository url +branch=$(git rev-parse --abbrev-ref HEAD) +url=$(git config --get remote.origin.url) + +echo "
" +echo "Information" +echo "" +echo "Branch: $branch" +echo "Repository: $url" +echo "" +echo "Call: \`$command\`" +echo "" +echo "\`\`\`rust" +echo "$output" +echo "\`\`\`" +echo "
" diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index ba59196a63..9adde7fd70 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -235,24 +236,28 @@ TEST(RestrictedDependentTypes, join_singleton) { TEST(RestrictedDependentTypes, ll) { World w; - Normalizers normalizers; - Passes passes; - auto compile_d = Dialect::load("compile", {}); - compile_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "compile", {}, &normalizers); + std::vector dialect_plugins = { + "compile", + "mem", + "core", + "math", + }; + std::vector dialect_paths = {}; - auto mem_d = Dialect::load("mem", {}); - mem_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "mem", {}, &normalizers); + std::vector dialects; + thorin::Backends backends; + Normalizers normalizers; + Passes passes; - auto core_d = Dialect::load("core", {}); - core_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "core", {}, &normalizers); + for (const auto& dialect : dialect_plugins) { + dialects.push_back(Dialect::load(dialect, dialect_paths)); + dialects.back().register_backends(backends); + dialects.back().register_normalizers(normalizers); + dialects.back().register_passes(passes); + } - auto math_d = Dialect::load("math", {}); - math_d.register_normalizers(normalizers); - fe::Parser::import_module(w, "math", {}, &normalizers); + for (const auto& dialect : dialects) fe::Parser::import_module(w, dialect.name(), dialect_paths, &normalizers); auto mem_t = mem::type_mem(w); auto i32_t = w.type_int(32); @@ -292,11 +297,7 @@ TEST(RestrictedDependentTypes, ll) { main->app(false, exp_lam, {main->var(0_s), i32_t, R, core::op_bitcast(app_exp, main->var(1)), main->var(3)}); } - PipelineBuilder builder; - mem_d.add_passes(builder); - optimize(w, passes, builder); + optimize(w, passes, dialects); - Backends backends; - core_d.register_backends(backends); backends["ll"](w, std::cout); } diff --git a/lit/affine/lower_for.thorin b/lit/affine/lower_for.thorin index b1b8bacff9..ae87d435a7 100644 --- a/lit/affine/lower_for.thorin +++ b/lit/affine/lower_for.thorin @@ -19,21 +19,18 @@ %affine.For (4294967296, 1, (.Idx 4294967296)) (0:(.Idx 4294967296), argc, 1:(.Idx 4294967296), (0:(.Idx 4294967296)), for_body, for_exit) }; -// CHECK-DAG: .con .extern main _[[mainVar:[0-9_]+]]::[mem_[[memVar:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _[[mainVar:[0-9_]+]]::[mem_[[memVar:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // 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: _[[cmpId:[0-9_]+]]: .Idx 2 = %core.icmp.XygLe -// CHECK-DAG: (_[[falseId:[0-9_]+]], for_body_[[bodyId:[0-9_]+]])#_[[cmpId]] +// CHECK-DAG: ([[falseId:[a-z0-9_]+]], for_body_[[bodyId:[0-9_]+]])#_[[cmpId]] -// CHECK-DAG: .con _{{[0-9]+}} [] -// CHECK-DAG: return_[[returnId]] (mem_[[memVar]], _{{[0-9]+}}) - -// CHECK-DAG: .con for_body_[[bodyId]] [] +// CHECK-DAG: .con for_body_[[bodyId]] // CHECK-DAG: = %core.wrap.add // CHECK-DAG: = %core.wrap.add // CHECK-DAG: for_[[forId]] -// CHECK-DAG: for_[[forId]] +// CHECK DAG: for_[[forId]] // CHECK-NOT: %affine.For diff --git a/lit/autodiff/general/invoke_ds.thorin b/lit/autodiff/general/invoke_ds.thorin index 802c76410e..0fee6cf60c 100644 --- a/lit/autodiff/general/invoke_ds.thorin +++ b/lit/autodiff/general/invoke_ds.thorin @@ -1,5 +1,6 @@ // RUN: rm -f %t.ll ; \ -// RUN: %thorin -d direct -d autodiff %s --output-ll %t.ll -o - | FileCheck %s +// RUN: %thorin -d direct -d autodiff %s -o - | FileCheck %s +// TODO: fix add of mem, re-add --output-ll %t.ll .import core; .import direct; diff --git a/lit/backend/ad/gmm_compiled.thorin b/lit/backend/ad/gmm_compiled.thorin new file mode 100644 index 0000000000..0b88b905fd --- /dev/null +++ b/lit/backend/ad/gmm_compiled.thorin @@ -0,0 +1,642 @@ + +// f64 +// f64 +// f64 +.cn .extern const _232551::[mem_232557: %mem.M, size_232600: .Idx 4294967296, a_232637: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), value_232681: %math.F (52, 11), return_232726: .Cn %mem.M] = { + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), size_232600, 1:(.Idx 4294967296), mem_232557, lambda_233145, break_232768) +}; +.cn .extern gmm _233234::[mem_233240: %mem.M, d_233277: .Idx 4294967296, k_233314: .Idx 4294967296, n_233351: .Idx 4294967296, wishartM_233398: .Idx 4294967296, wishartGamma_233449: %math.F (52, 11), alphas_233494: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), means_233538: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), icf_233580: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), x_233617: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_233662: .Cn [%mem.M, %math.F (52, 11)]] = { + .let _234601: .Idx 0 = %core.conv.u2u 4294967296 0 k_233314; + .let _234608: .Nat = %core.bitcast (.Nat, .Idx 0) _234601; + .let _234758: .Idx 0 = %core.conv.u2u 4294967296 0 d_233277; + .let _234765: .Nat = %core.bitcast (.Nat, .Idx 0) _234758; + .let _234423: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_233277, k_233314); + .let _234430: .Idx 0 = %core.conv.u2u 4294967296 0 _234423; + .let _234438: .Nat = %core.bitcast (.Nat, .Idx 0) _234430; + .let _234512: [%mem.M, %mem.Ptr (<<_234438; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_234438; %math.F (52, 11)>>, 0) mem_233240; + .let _234682: [%mem.M, %mem.Ptr (<<_234608; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_234608; %math.F (52, 11)>>, 0) _234512#0:(.Idx 2); + .let _234839: [%mem.M, %mem.Ptr (<<_234765; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_234765; %math.F (52, 11)>>, 0) _234682#0:(.Idx 2); + .let _234991: [%mem.M, %mem.Ptr (<<_234765; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_234765; %math.F (52, 11)>>, 0) _234839#0:(.Idx 2); + .let _235143: [%mem.M, %mem.Ptr (<<_234608; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_234608; %math.F (52, 11)>>, 0) _234991#0:(.Idx 2); + .let _234710: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _234682#1:(.Idx 2); + .let _234541: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _234512#1:(.Idx 2); + preprocess_qs_216266 (_235143#0:(.Idx 2), d_233277, k_233314, icf_233580, _234710, _234541, preprocess_qs_cont_235348) +}; +.cn .extern main _247506::[mem_247512: %mem.M, argc_247555: .Idx 4294967296, argv_247598: %mem.Ptr (<<.top:.Nat; %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0)>>, 0), return_247643: .Cn [%mem.M, .Idx 4294967296]] = { + .let _247869: .Idx 2 = %core.icmp.xYgLe 4294967296 (argc_247555, 2:(.Idx 4294967296)); + (if_else_247729, if_then_247688)#_247869 mem_247512 +}; +.cn .extern print _231851::[mem_231857: %mem.M, size_231900: .Idx 4294967296, a_231937: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_231982: .Cn %mem.M] = { + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), size_231900, 1:(.Idx 4294967296), mem_231857, lambda_232462, break_232024) +}; +.cn lambda_233145 _233146::[_233152: .Idx 4294967296, _233157: %mem.M, _233162: .Cn %mem.M] = { + lambda_232860 (_233157, _233152, _233162) +}; +.cn break_232768 _232786: %mem.M = { + return_232726 _232786 +}; +.cn preprocess_qs_216266 _216934::[mem_216940: %mem.M, d_216977: .Idx 4294967296, k_217014: .Idx 4294967296, icf_217056: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), sum_qs_217101: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), Qdiags_217146: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_217191: .Cn %mem.M] = { + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), k_217014, 1:(.Idx 4294967296), mem_216940, lambda_219026, break_217432) +}; +.cn preprocess_qs_cont_235348 _235366: %mem.M = { + .let slse_235460: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (_235366, 235449); + .let _235517: %mem.M = %mem.store (%math.F (52, 11), 0) (slse_235460#0:(.Idx 2), slse_235460#1:(.Idx 2), 0:(%math.F (52, 11))); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), n_233351, 1:(.Idx 4294967296), _235517, lambda_237921, break_235556) +}; +.cn if_else_247729 _248891: %mem.M = { + .let _248960: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat 1:(.Idx 4294967296); + .let _249016: %mem.Ptr (%mem.Ptr (<<.top:.Nat; .Idx 256>>, 0), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0)>, 0) (argv_247598, _248960); + .let _249072: [%mem.M, %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0)] = %mem.load (%mem.Ptr (<<.top:.Nat; .Idx 256>>, 0), 0) (_248891, _249016); + initBenchmark_216858 (_249072#0:(.Idx 2), _249072#1:(.Idx 2), initBenchmark_cont_249136) +}; +.cn if_then_247688 _247905: %mem.M = { + .let _248777: %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0)> .global ((78:(.Idx 256), 111:(.Idx 256), 32:(.Idx 256), 66:(.Idx 256), 101:(.Idx 256), 110:(.Idx 256), 99:(.Idx 256), 104:(.Idx 256), 109:(.Idx 256), 97:(.Idx 256), 114:(.Idx 256), 107:(.Idx 256), 32:(.Idx 256), 115:(.Idx 256), 112:(.Idx 256), 101:(.Idx 256), 99:(.Idx 256), 105:(.Idx 256), 102:(.Idx 256), 105:(.Idx 256), 101:(.Idx 256), 100:(.Idx 256), 0:(.Idx 256))); + printString (_247905, _248777, printString_cont_248828) +}; +.cn lambda_232462 _232463::[_232469: .Idx 4294967296, _232474: %mem.M, _232479: .Cn %mem.M] = { + lambda_232116 (_232474, _232469, _232479) +}; +.cn break_232024 _232042: %mem.M = { + return_231982 _232042 +}; +.cn lambda_232860 _232878::[mem_232884: %mem.M, i_232921: .Idx 4294967296, continue_232968: .Cn %mem.M] = { + .let _233036: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat i_232921; + .let _233061: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (a_232637, _233036); + .let _233107: %mem.M = %mem.store (%math.F (52, 11), 0) (mem_232884, _233061, value_232681); + continue_232968 _233107 +}; +.cn lambda_219026 _219027::[_219033: .Idx 4294967296, _219038: %mem.M, _219043: .Cn %mem.M] = { + lambda_217524 (_219038, _219033, _219043) +}; +.cn break_217432 _217450: %mem.M = { + return_217191 _217450 +}; +.cn lambda_237921 _237922::[_237928: .Idx 4294967296, _237933: %mem.M, _237938: .Cn %mem.M] = { + lambda_235648 (_237933, _237928, _237938) +}; +.cn break_235556 _235574: %mem.M = { + logsumexp_216523 (_235574, k_233314, alphas_233494, logsumexp_cont_238013) +}; +.cn initBenchmark_216858 _241008::[mem_241014: %mem.M, file_241057: %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0), return_241102: .Cn %mem.M] = { + .let d_241180: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.slot (.Idx 4294967296, 0) (mem_241014, 241169); + .let _241237: %mem.M = %mem.store (.Idx 4294967296, 0) (d_241180#0:(.Idx 2), d_241180#1:(.Idx 2), 2:(.Idx 4294967296)); + .let k_241312: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.slot (.Idx 4294967296, 0) (_241237, 241301); + .let _241369: %mem.M = %mem.store (.Idx 4294967296, 0) (k_241312#0:(.Idx 2), k_241312#1:(.Idx 2), 5:(.Idx 4294967296)); + .let n_241444: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.slot (.Idx 4294967296, 0) (_241369, 241433); + .let _241501: %mem.M = %mem.store (.Idx 4294967296, 0) (n_241444#0:(.Idx 2), n_241444#1:(.Idx 2), 1000:(.Idx 4294967296)); + read_gmm_size (_241501, file_241057, d_241180#1:(.Idx 2), k_241312#1:(.Idx 2), n_241444#1:(.Idx 2), read_gmm_size_cont_241554) +}; +.cn initBenchmark_cont_249136 _249154: %mem.M = { + if_join_247774 (_249154, ()) +}; +.cn printString [%mem.M, %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0), .Cn %mem.M] = { + +}; +.cn printString_cont_248828 _248846: %mem.M = { + if_join_247774 (_248846, ()) +}; +.cn lambda_232116 _232134::[mem_232140: %mem.M, i_232177: .Idx 4294967296, continue_232224: .Cn %mem.M] = { + .let _232262: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat i_232177; + .let _232287: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (a_231937, _232262); + .let _232334: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_232140, _232287); + printDouble (_232334#0:(.Idx 2), _232334#1:(.Idx 2), printDouble_cont_232397) +}; +.cn lambda_217524 _217542::[mem_217548: %mem.M, ik_217590: .Idx 4294967296, continue_217637: .Cn %mem.M] = { + .let _217713: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat ik_217590; + .let _217769: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (sum_qs_217101, _217713); + .let _217858: %mem.M = %mem.store (%math.F (52, 11), 0) (mem_217548, _217769, 0:(%math.F (52, 11))); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), d_216977, 1:(.Idx 4294967296), _217858, lambda_218912, break_217897) +}; +.cn lambda_235648 _235666::[mem_235672: %mem.M, ix_235713: .Idx 4294967296, continue_235760: .Cn %mem.M] = { + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), k_233314, 1:(.Idx 4294967296), mem_235672, lambda_237570, break_235943) +}; +.cn logsumexp_216523 _226128::[mem_226134: %mem.M, n_226171: .Idx 4294967296, x_226208: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_226253: .Cn [%mem.M, %math.F (52, 11)]] = { + arr_max_216480 (mem_226134, n_226171, x_226208, arr_max_cont_226306) +}; +.cn logsumexp_cont_238013 _238031::[mem_238037: %mem.M, logsumexp_238048: %math.F (52, 11)] = { + .let _238186: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_238037, slse_235460#1:(.Idx 2)); + log_wishart_prior_216634 (_238186#0:(.Idx 2), d_233277, k_233314, wishartM_233398, wishartGamma_233449, _234710, _234541, icf_233580, log_wishart_prior_cont_238430) +}; +.cn read_gmm_size [%mem.M, %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0), %mem.Ptr (.Idx 4294967296, 0), %mem.Ptr (.Idx 4294967296, 0), %mem.Ptr (.Idx 4294967296, 0), .Cn %mem.M] = { + +}; +.cn read_gmm_size_cont_241554 _241572: %mem.M = { + .let wishartM_241666: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.slot (.Idx 4294967296, 0) (_241572, 241655); + .let _241723: %mem.M = %mem.store (.Idx 4294967296, 0) (wishartM_241666#0:(.Idx 2), wishartM_241666#1:(.Idx 2), 0:(.Idx 4294967296)); + .let wishartGamma_241816: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (_241723, 241805); + .let _241873: %mem.M = %mem.store (%math.F (52, 11), 0) (wishartGamma_241816#0:(.Idx 2), wishartGamma_241816#1:(.Idx 2), 4607182418800017408:(%math.F (52, 11))); + .let _241920: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_241873, k_241312#1:(.Idx 2)); + .let _242008: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_241920#0:(.Idx 2), d_241180#1:(.Idx 2)); + .let _242066: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_242008#0:(.Idx 2), k_241312#1:(.Idx 2)); + .let _242166: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_242066#0:(.Idx 2), k_241312#1:(.Idx 2)); + .let _242284: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_242166#0:(.Idx 2), d_241180#1:(.Idx 2)); + .let _242372: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_242284#0:(.Idx 2), d_241180#1:(.Idx 2)); + .let _242430: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), _242372#1:(.Idx 2)); + .let _242442: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_242284#1:(.Idx 2), _242430); + .let _242488: [%mem.M, .Idx 4294967296] = %core.div.sdiv 4294967296 (_242372#0:(.Idx 2), _242442, 2:(.Idx 4294967296)); + .let _242513: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_242166#1:(.Idx 2), _242488#1:(.Idx 2)); + .let _242089: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_242008#1:(.Idx 2), _242066#1:(.Idx 2)); + .let _242743: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (_241920#1:(.Idx 2), _242089); + .let _242755: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (_242513, _242743); + .let _243388: .Idx 0 = %core.conv.u2u 4294967296 0 _242755; + .let _243395: .Nat = %core.bitcast (.Nat, .Idx 0) _243388; + .let _242590: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_242488#0:(.Idx 2), d_241180#1:(.Idx 2)); + .let _242648: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_242590#0:(.Idx 2), n_241444#1:(.Idx 2)); + .let _242671: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_242590#1:(.Idx 2), _242648#1:(.Idx 2)); + .let _243231: .Idx 0 = %core.conv.u2u 4294967296 0 _242671; + .let _243238: .Nat = %core.bitcast (.Nat, .Idx 0) _243231; + .let _243074: .Idx 0 = %core.conv.u2u 4294967296 0 _242513; + .let _243081: .Nat = %core.bitcast (.Nat, .Idx 0) _243074; + .let _242917: .Idx 0 = %core.conv.u2u 4294967296 0 _242089; + .let _242924: .Nat = %core.bitcast (.Nat, .Idx 0) _242917; + .let _242760: .Idx 0 = %core.conv.u2u 4294967296 0 _241920#1:(.Idx 2); + .let _242767: .Nat = %core.bitcast (.Nat, .Idx 0) _242760; + .let _242841: [%mem.M, %mem.Ptr (<<_242767; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_242767; %math.F (52, 11)>>, 0) _242648#0:(.Idx 2); + .let _242998: [%mem.M, %mem.Ptr (<<_242924; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_242924; %math.F (52, 11)>>, 0) _242841#0:(.Idx 2); + .let _243155: [%mem.M, %mem.Ptr (<<_243081; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_243081; %math.F (52, 11)>>, 0) _242998#0:(.Idx 2); + .let _243312: [%mem.M, %mem.Ptr (<<_243238; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_243238; %math.F (52, 11)>>, 0) _243155#0:(.Idx 2); + .let _243469: [%mem.M, %mem.Ptr (<<_243395; %math.F (52, 11)>>, 0)] = %mem.alloc (<<_243395; %math.F (52, 11)>>, 0) _243312#0:(.Idx 2); + .let _242869: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _242841#1:(.Idx 2); + .let _243026: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _242998#1:(.Idx 2); + .let _243183: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _243155#1:(.Idx 2); + .let _243340: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _243312#1:(.Idx 2); + read_gmm (_243469#0:(.Idx 2), file_241057, d_241180#1:(.Idx 2), k_241312#1:(.Idx 2), n_241444#1:(.Idx 2), wishartM_241666#1:(.Idx 2), wishartGamma_241816#1:(.Idx 2), _242869, _243026, _243183, _243340, read_gmm_cont_243942) +}; +.cn if_join_247774 _247792::[mem_247798: %mem.M, _249205: []] = { + return_247643 (mem_247798, 0:(.Idx 4294967296)) +}; +.cn printDouble [%mem.M, %math.F (52, 11), .Cn %mem.M] = { + +}; +.cn printDouble_cont_232397 _232415: %mem.M = { + continue_232224 _232415 +}; +.cn lambda_218912 _218913::[_218919: .Idx 4294967296, _218924: %mem.M, _218929: .Cn %mem.M] = { + lambda_217989 (_218924, _218919, _218929) +}; +.cn break_217897 _217915: %mem.M = { + continue_217637 _217915 +}; +.cn lambda_237570 _237571::[_237577: .Idx 4294967296, _237582: %mem.M, _237587: .Cn %mem.M] = { + lambda_236035 (_237582, _237577, _237587) +}; +.cn break_235943 _235961: %mem.M = { + .let _235171: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _235143#1:(.Idx 2); + logsumexp_216523 (_235961, k_233314, _235171, logsumexp_cont_237733) +}; +.cn arr_max_216480 _224753::[mem_224759: %mem.M, n_224796: .Idx 4294967296, x_224833: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_224878: .Cn [%mem.M, %math.F (52, 11)]] = { + .let _224949: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat 0:(.Idx 4294967296); + .let _224974: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_224833, _224949); + .let _225021: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_224759, _224974); + .let m_225074: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (_225021#0:(.Idx 2), 225063); + .let _225131: %mem.M = %mem.store (%math.F (52, 11), 0) (m_225074#0:(.Idx 2), m_225074#1:(.Idx 2), _225021#1:(.Idx 2)); + %affine.For (4294967296, 1, %mem.M) (1:(.Idx 4294967296), n_224796, 1:(.Idx 4294967296), _225131, lambda_225978, break_225170) +}; +.cn arr_max_cont_226306 _226324::[mem_226330: %mem.M, arr_max_226341: %math.F (52, 11)] = { + .let semx_226427: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (mem_226330, 226416); + .let _226484: %mem.M = %mem.store (%math.F (52, 11), 0) (semx_226427#0:(.Idx 2), semx_226427#1:(.Idx 2), 0:(%math.F (52, 11))); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), n_226171, 1:(.Idx 4294967296), _226484, lambda_227100, break_226523) +}; +.cn log_wishart_prior_216634 _228685::[mem_228691: %mem.M, p_228728: .Idx 4294967296, k_228765: .Idx 4294967296, wishartM_228812: .Idx 4294967296, wishartGamma_228863: %math.F (52, 11), sum_qs_228908: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), Qdiags_228953: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), icf_228995: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_229040: .Cn [%mem.M, %math.F (52, 11)]] = { + .let _229205: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (p_228728, wishartM_228812); + .let _229252: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), _229205); + .let _229566: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) _229252; + .let _229948: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4602678819172646912:(%math.F (52, 11)), _229566); + log_gamma_distrib_216579 (mem_228691, _229948, p_228728, log_gamma_distrib_cont_230009) +}; +.cn log_wishart_prior_cont_238430 _238448::[mem_238454: %mem.M, log_wishart_prior_238465: %math.F (52, 11)] = { + .let _238562: %mem.M = %mem.free (<<.top:.Nat; %math.F (52, 11)>>, 0) (mem_238454, _234541); + .let _238643: %mem.M = %mem.free (<<.top:.Nat; %math.F (52, 11)>>, 0) (_238562, _234710); + .let _234867: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _234839#1:(.Idx 2); + .let _238724: %mem.M = %mem.free (<<.top:.Nat; %math.F (52, 11)>>, 0) (_238643, _234867); + .let _235019: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _234991#1:(.Idx 2); + .let _238805: %mem.M = %mem.free (<<.top:.Nat; %math.F (52, 11)>>, 0) (_238724, _235019); + .let _238886: %mem.M = %mem.free (<<.top:.Nat; %math.F (52, 11)>>, 0) (_238805, _235171); + .let _233965: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) n_233351; + .let _233982: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (9223372036854775808:(%math.F (52, 11)), _233965); + .let _234015: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) d_233277; + .let _234025: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_233982, _234015); + .let _234072: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4602678819172646912:(%math.F (52, 11)), _234025); + .let _234190: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4610955881644081117:(%math.F (52, 11)), _234072); + .let _238207: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_234190, _238186#1:(.Idx 2)); + .let _238280: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_233965, logsumexp_238048); + .let _238290: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_238207, _238280); + .let _238476: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_238290, log_wishart_prior_238465); + return_233662 (_238886, _238476) +}; +.cn read_gmm [%mem.M, %mem.Ptr (<<.top:.Nat; .Idx 256>>, 0), %mem.Ptr (.Idx 4294967296, 0), %mem.Ptr (.Idx 4294967296, 0), %mem.Ptr (.Idx 4294967296, 0), %mem.Ptr (.Idx 4294967296, 0), %mem.Ptr (%math.F (52, 11), 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), .Cn %mem.M] = { + +}; +.cn read_gmm_cont_243942 _243960: %mem.M = { + .let time_sum_244195: [%mem.M, %mem.Ptr (.Idx 0, 0)] = %mem.slot (.Idx 0, 0) (_243960, 244179); + .let _244258: %mem.M = %mem.store (.Idx 0, 0) (time_sum_244195#0:(.Idx 2), time_sum_244195#1:(.Idx 2), 0:(.Idx 0)); + .let count_244340: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.slot (.Idx 4294967296, 0) (_244258, 244329); + .let _244397: %mem.M = %mem.store (.Idx 4294967296, 0) (count_244340#0:(.Idx 2), count_244340#1:(.Idx 2), 0:(.Idx 4294967296)); + .let min_runtime_244562: [%mem.M, %mem.Ptr (.Idx 0, 0)] = %mem.slot (.Idx 0, 0) (_244397, 244551); + .let _244619: %mem.M = %mem.store (.Idx 0, 0) (min_runtime_244562#0:(.Idx 2), min_runtime_244562#1:(.Idx 2), 4294967295:(.Idx 0)); + while_head_244664 _244619 +}; +.cn lambda_217989 _218007::[mem_218013: %mem.M, id_218054: .Idx 4294967296, continue_218101: .Cn %mem.M] = { + .let _217336: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), d_216977); + .let _217348: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_216977, _217336); + .let _217393: .Idx 4294967296 = %core.shr.a 4294967296 (_217348, 1:(.Idx 4294967296)); + .let _218206: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_217393, ik_217590); + .let _218218: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (id_218054, _218206); + .let _218223: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _218218; + .let _218248: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (icf_217056, _218223); + .let _218304: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_218013, _218248); + .let _218542: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_218304#0:(.Idx 2), _217769); + .let _218569: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_218304#1:(.Idx 2), _218542#1:(.Idx 2)); + .let _218615: %mem.M = %mem.store (%math.F (52, 11), 0) (_218542#0:(.Idx 2), _217769, _218569); + .let _218749: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_216977, ik_217590); + .let _218761: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (id_218054, _218749); + .let _218766: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _218761; + .let _218791: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (Qdiags_217146, _218766); + .let _218828: %math.F (52, 11) = %math.exp.bl (52, 11) 127 _218304#1:(.Idx 2); + .let _218874: %mem.M = %mem.store (%math.F (52, 11), 0) (_218615, _218791, _218828); + continue_218101 _218874 +}; +.cn lambda_236035 _236053::[mem_236059: %mem.M, ik_236100: .Idx 4294967296, continue_236147: .Cn %mem.M] = { + .let _235837: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_233277, ix_235713); + .let _235842: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _235837; + .let _235867: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_233617, _235842); + .let _235904: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _235867; + .let _236222: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_233277, ik_236100); + .let _236227: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _236222; + .let _236391: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (means_233538, _236227); + .let _236428: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _236391; + subtract_216312 (mem_236059, d_233277, _235904, _236428, _234867, subtract_cont_236697) +}; +.cn logsumexp_cont_237733 _237751::[mem_237757: %mem.M, logsumexp_237768: %math.F (52, 11)] = { + .let _237816: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_237757, slse_235460#1:(.Idx 2)); + .let _237837: %math.F (52, 11) = %math.arith.add (52, 11) 0 (logsumexp_237768, _237816#1:(.Idx 2)); + .let _237883: %mem.M = %mem.store (%math.F (52, 11), 0) (_237816#0:(.Idx 2), slse_235460#1:(.Idx 2), _237837); + continue_235760 _237883 +}; +.cn lambda_225978 _225979::[_225985: .Idx 4294967296, _225990: %mem.M, _225995: .Cn %mem.M] = { + lambda_225262 (_225990, _225985, _225995) +}; +.cn break_225170 _225188: %mem.M = { + .let _226065: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_225188, m_225074#1:(.Idx 2)); + return_224878 _226065 +}; +.cn lambda_227100 _227101::[_227107: .Idx 4294967296, _227112: %mem.M, _227117: .Cn %mem.M] = { + lambda_226615 (_227112, _227107, _227117) +}; +.cn break_226523 _226541: %mem.M = { + .let _227247: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_226541, semx_226427#1:(.Idx 2)); + .let _227262: %math.F (52, 11) = %math.exp.bL (52, 11) 127 _227247#1:(.Idx 2); + .let _227272: %math.F (52, 11) = %math.arith.add (52, 11) 0 (arr_max_226341, _227262); + return_226253 (_227247#0:(.Idx 2), _227272) +}; +.cn log_gamma_distrib_216579 _227325::[mem_227331: %mem.M, a_227368: %math.F (52, 11), p_227405: .Idx 4294967296, return_227450: .Cn [%mem.M, %math.F (52, 11)]] = { + .let out_227867: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (mem_227331, 227856); + .let _227706: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (4294967295:(.Idx 4294967296), p_227405); + .let _227718: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (p_227405, _227706); + .let _227766: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) _227718; + .let _227776: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4598175219545276416:(%math.F (52, 11)), _227766); + .let _227820: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4607834224259998438:(%math.F (52, 11)), _227776); + .let _227924: %mem.M = %mem.store (%math.F (52, 11), 0) (out_227867#0:(.Idx 2), out_227867#1:(.Idx 2), _227820); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), p_227405, 1:(.Idx 4294967296), _227924, lambda_228535, break_227963) +}; +.cn log_gamma_distrib_cont_230009 _230027::[mem_230033: %mem.M, log_gamma_distrib_230044: %math.F (52, 11)] = { + .let out_230139: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (mem_230033, 230128); + .let _230196: %mem.M = %mem.store (%math.F (52, 11), 0) (out_230139#0:(.Idx 2), out_230139#1:(.Idx 2), 0:(%math.F (52, 11))); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), k_228765, 1:(.Idx 4294967296), _230196, lambda_231587, break_230235) +}; +.cn while_head_244664 _244682: %mem.M = { + .let _245048: [%mem.M, .Idx 0] = %mem.load (.Idx 0, 0) (_244682, time_sum_244195#1:(.Idx 2)); + .let _245139: .Idx 2 = %core.icmp.xYgLe 0 (_245048#1:(.Idx 2), 10000:(.Idx 0)); + (while_exit_244772, and_t_244962)#_245139 _245048#0:(.Idx 2) +}; +.cn subtract_216312 _219115::[mem_219121: %mem.M, d_219158: .Idx 4294967296, x_219195: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), y_219232: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), out_219274: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_219319: .Cn %mem.M] = { + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), d_219158, 1:(.Idx 4294967296), mem_219121, lambda_220018, break_219361) +}; +.cn subtract_cont_236697 _236715: %mem.M = { + .let _236252: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (_234541, _236227); + .let _236289: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _236252; + .let _234327: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), d_233277); + .let _234339: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_233277, _234327); + .let _234381: .Idx 4294967296 = %core.shr.a 4294967296 (_234339, 1:(.Idx 4294967296)); + .let _236530: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_234381, ik_236100); + .let _236542: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (d_233277, _236530); + .let _236547: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _236542; + .let _236572: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (icf_233580, _236547); + .let _236609: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _236572; + Qtimesx_216358 (_236715, d_233277, _236289, _236609, _234867, _235019, Qtimesx_cont_236851) +}; +.cn lambda_225262 _225280::[mem_225286: %mem.M, i_225323: .Idx 4294967296, continue_225370: .Cn %mem.M] = { + .let _225408: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat i_225323; + .let _225433: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_224833, _225408); + .let _225480: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_225286, _225433); + .let _225722: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_225480#0:(.Idx 2), m_225074#1:(.Idx 2)); + .let _225748: .Idx 2 = %math.cmp.ugLe (52, 11) 0 (_225722#1:(.Idx 2), _225480#1:(.Idx 2)); + (if_else_225574, if_then_225533)#_225748 _225722#0:(.Idx 2) +}; +.cn lambda_226615 _226633::[mem_226639: %mem.M, i_226676: .Idx 4294967296, continue_226723: .Cn %mem.M] = { + .let _226851: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat i_226676; + .let _226876: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_226208, _226851); + .let _226923: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_226639, _226876); + .let _226995: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_226923#0:(.Idx 2), semx_226427#1:(.Idx 2)); + .let _226944: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_226923#1:(.Idx 2), arr_max_226341); + .let _226948: %math.F (52, 11) = %math.exp.bl (52, 11) 127 _226944; + .let _227016: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_226948, _226995#1:(.Idx 2)); + .let _227062: %mem.M = %mem.store (%math.F (52, 11), 0) (_226995#0:(.Idx 2), semx_226427#1:(.Idx 2), _227016); + continue_226723 _227062 +}; +.cn lambda_228535 _228536::[_228542: .Idx 4294967296, _228547: %mem.M, _228552: .Cn %mem.M] = { + lambda_228055 (_228547, _228542, _228552) +}; +.cn break_227963 _227981: %mem.M = { + .let _228622: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_227981, out_227867#1:(.Idx 2)); + return_227450 _228622 +}; +.cn lambda_231587 _231588::[_231594: .Idx 4294967296, _231599: %mem.M, _231604: .Cn %mem.M] = { + lambda_230327 (_231599, _231594, _231604) +}; +.cn break_230235 _230253: %mem.M = { + .let _231704: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_230253, out_230139#1:(.Idx 2)); + .let _229599: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) p_228728; + .let _229609: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_229566, _229599); + .let _229673: %math.F (52, 11) = %math.exp.bL (52, 11) 127 wishartGamma_228863; + .let _229828: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_229673, 4599914934686071279:(%math.F (52, 11))); + .let _229838: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_229609, _229828); + .let _230055: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_229838, log_gamma_distrib_230044); + .let _231778: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) k_228765; + .let _231788: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_230055, _231778); + .let _231798: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_231704#1:(.Idx 2), _231788); + return_229040 (_231704#0:(.Idx 2), _231798) +}; +.cn while_exit_244772 _247178: %mem.M = { + break_244872 _247178 +}; +.cn and_t_244962 _245175: %mem.M = { + .let _245291: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_245175, count_244340#1:(.Idx 2)); + .let _245314: .Idx 2 = %core.icmp.xYgLe 4294967296 (_245291#1:(.Idx 2), 10:(.Idx 4294967296)); + (or_f_245214, while_body_244728)#_245314 _245291#0:(.Idx 2) +}; +.cn lambda_220018 _220019::[_220025: .Idx 4294967296, _220030: %mem.M, _220035: .Cn %mem.M] = { + lambda_219453 (_220030, _220025, _220035) +}; +.cn break_219361 _219379: %mem.M = { + return_219319 _219379 +}; +.cn Qtimesx_216358 _220107::[mem_220113: %mem.M, d_220150: .Idx 4294967296, Qdiag_220194: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), ltri_220237: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), x_220274: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), out_220316: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_220361: .Cn %mem.M] = { + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), d_220150, 1:(.Idx 4294967296), mem_220113, lambda_221060, break_220403) +}; +.cn Qtimesx_cont_236851 _236869: %mem.M = { + .let _236943: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat ik_236100; + .let _237088: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (alphas_233494, _236943); + .let _237135: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_236869, _237088); + .let _237206: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (_234710, _236943); + .let _237253: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_237135#0:(.Idx 2), _237206); + sqnorm_216402 (_237253#0:(.Idx 2), d_233277, _235019, sqnorm_cont_237430) +}; +.cn if_else_225574 _225897: %mem.M = { + if_join_225621 (_225897, ()) +}; +.cn if_then_225533 _225784: %mem.M = { + .let _225861: %mem.M = %mem.store (%math.F (52, 11), 0) (_225784, m_225074#1:(.Idx 2), _225480#1:(.Idx 2)); + if_join_225621 (_225861, ()) +}; +.cn lambda_228055 _228073::[mem_228079: %mem.M, j_228116: .Idx 4294967296, continue_228163: .Cn %mem.M] = { + .let _228430: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_228079, out_227867#1:(.Idx 2)); + .let _228356: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) j_228116; + .let _228366: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4602678819172646912:(%math.F (52, 11)), _228356); + .let _228376: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (a_227368, _228366); + .let _228383: %math.F (52, 11) = %math.gamma.l (52, 11) 127 _228376; + .let _228451: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_228383, _228430#1:(.Idx 2)); + .let _228497: %mem.M = %mem.store (%math.F (52, 11), 0) (_228430#0:(.Idx 2), out_227867#1:(.Idx 2), _228451); + continue_228163 _228497 +}; +.cn lambda_230327 _230345::[mem_230351: %mem.M, ik_230392: .Idx 4294967296, continue_230439: .Cn %mem.M] = { + .let _230516: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (p_228728, ik_230392); + .let _230521: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _230516; + .let _230546: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (Qdiags_228953, _230521); + .let _230584: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _230546; + sqnorm_216402 (mem_230351, p_228728, _230584, sqnorm_cont_230844) +}; +.cn break_244872 _244890: %mem.M = { + .let _247258: [%mem.M, .Idx 0] = %mem.load (.Idx 0, 0) (_244890, min_runtime_244562#1:(.Idx 2)); + printLong (_247258#0:(.Idx 2), _247258#1:(.Idx 2), printLong_cont_247318) +}; +.cn or_f_245214 _245350: %mem.M = { + .let _245428: [%mem.M, .Idx 0] = %mem.load (.Idx 0, 0) (_245350, time_sum_244195#1:(.Idx 2)); + .let _245447: .Idx 2 = %core.icmp.xYgLe 0 (_245428#1:(.Idx 2), 500:(.Idx 0)); + (while_exit_244772, while_body_244728)#_245447 _245428#0:(.Idx 2) +}; +.cn while_body_244728 _245483: %mem.M = { + .let _245531: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_245483, d_241180#1:(.Idx 2)); + .let _245589: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_245531#0:(.Idx 2), k_241312#1:(.Idx 2)); + .let _245647: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_245589#0:(.Idx 2), n_241444#1:(.Idx 2)); + .let _245705: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_245647#0:(.Idx 2), wishartM_241666#1:(.Idx 2)); + .let _245763: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_245705#0:(.Idx 2), wishartGamma_241816#1:(.Idx 2)); + .let _243497: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast <2; %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)> _243469#1:(.Idx 2); + .let _243575: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _241920#1:(.Idx 2); + .let _243600: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (_243497, _243575); + .let _243637: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _243600; + .let _243672: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _242089; + .let _243697: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (_243637, _243672); + .let _243734: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _243697; + runBenchmark_216811 (_245763#0:(.Idx 2), _245531#1:(.Idx 2), _245589#1:(.Idx 2), _245647#1:(.Idx 2), _245705#1:(.Idx 2), _245763#1:(.Idx 2), _242869, _243497, _243026, _243637, _243183, _243734, _243340, runBenchmark_cont_246029) +}; +.cn lambda_219453 _219471::[mem_219477: %mem.M, id_219518: .Idx 4294967296, continue_219565: .Cn %mem.M] = { + .let _219633: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat id_219518; + .let _219748: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_219195, _219633); + .let _219795: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_219477, _219748); + .let _219866: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (y_219232, _219633); + .let _219913: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_219795#0:(.Idx 2), _219866); + .let _219658: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (out_219274, _219633); + .let _219934: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_219795#1:(.Idx 2), _219913#1:(.Idx 2)); + .let _219980: %mem.M = %mem.store (%math.F (52, 11), 0) (_219913#0:(.Idx 2), _219658, _219934); + continue_219565 _219980 +}; +.cn lambda_221060 _221061::[_221067: .Idx 4294967296, _221072: %mem.M, _221077: .Cn %mem.M] = { + lambda_220495 (_221072, _221067, _221077) +}; +.cn break_220403 _220421: %mem.M = { + .let Lparamsidx_221192: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.slot (.Idx 4294967296, 0) (_220421, 221176); + .let _221255: %mem.M = %mem.store (.Idx 4294967296, 0) (Lparamsidx_221192#0:(.Idx 2), Lparamsidx_221192#1:(.Idx 2), 0:(.Idx 4294967296)); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), d_220150, 1:(.Idx 4294967296), _221255, lambda_222687, break_221294) +}; +.cn sqnorm_216402 _222776::[mem_222782: %mem.M, d_222819: .Idx 4294967296, v_222856: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_222901: .Cn [%mem.M, %math.F (52, 11)]] = { + .let sum_222993: [%mem.M, %mem.Ptr (%math.F (52, 11), 0)] = %mem.slot (%math.F (52, 11), 0) (mem_222782, 222977); + .let _223050: %mem.M = %mem.store (%math.F (52, 11), 0) (sum_222993#0:(.Idx 2), sum_222993#1:(.Idx 2), 0:(%math.F (52, 11))); + %affine.For (4294967296, 1, %mem.M) (0:(.Idx 4294967296), d_222819, 1:(.Idx 4294967296), _223050, lambda_223642, break_223089) +}; +.cn sqnorm_cont_237430 _237448::[mem_237454: %mem.M, sqnorm_237465: %math.F (52, 11)] = { + .let _236968: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (_235171, _236943); + .let _237274: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_237135#1:(.Idx 2), _237253#1:(.Idx 2)); + .let _237476: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4602678819172646912:(%math.F (52, 11)), sqnorm_237465); + .let _237486: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_237274, _237476); + .let _237532: %mem.M = %mem.store (%math.F (52, 11), 0) (mem_237454, _236968, _237486); + continue_236147 _237532 +}; +.cn if_join_225621 _225639::[mem_225645: %mem.M, _225940: []] = { + continue_225370 mem_225645 +}; +.cn sqnorm_cont_230844 _230862::[mem_230868: %mem.M, sqnorm_230879: %math.F (52, 11)] = { + .let _229389: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), p_228728); + .let _229401: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (p_228728, _229389); + .let _229443: .Idx 4294967296 = %core.shr.a 4294967296 (_229401, 1:(.Idx 4294967296)); + .let _230922: .Idx 4294967296 = %core.wrap.sub (1, 4294967296) (_229443, p_228728); + .let _230686: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (_229443, ik_230392); + .let _230698: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (p_228728, _230686); + .let _230703: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _230698; + .let _230728: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (icf_228995, _230703); + .let _230765: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (%math.F (52, 11), 0)) _230728; + sqnorm_216402 (mem_230868, _230922, _230765, sqnorm_cont_230971) +}; +.cn printLong [%mem.M, .Idx 0, .Cn %mem.M] = { + +}; +.cn printLong_cont_247318 _247336: %mem.M = { + print (_247336, _242755, _243497, print_cont_247430) +}; +.cn runBenchmark_216811 _238939::[mem_238945: %mem.M, d_238982: .Idx 4294967296, k_239019: .Idx 4294967296, n_239056: .Idx 4294967296, wishartM_239103: .Idx 4294967296, wishartGamma_239154: %math.F (52, 11), alphas_239199: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), alphas_d_239246: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), means_239290: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), means_d_239336: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), icf_239378: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), icf_d_239422: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), x_239459: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), return_239504: .Cn [%mem.M, .Idx 0]] = { + .let _239856: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), d_238982); + .let _239868: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_238982, _239856); + .let _239922: [%mem.M, .Idx 4294967296] = %core.div.sdiv 4294967296 (mem_238945, _239868, 2:(.Idx 4294967296)); + const (_239922#0:(.Idx 2), k_239019, alphas_d_239246, 0:(%math.F (52, 11)), const_cont_240071) +}; +.cn runBenchmark_cont_246029 _246047::[mem_246053: %mem.M, runBenchmark_246064: .Idx 0] = { + .let _246332: [%mem.M, .Idx 0] = %mem.load (.Idx 0, 0) (mem_246053, min_runtime_244562#1:(.Idx 2)); + .let _246461: .Idx 2 = %core.icmp.xyglE 0 (4294967295:(.Idx 0), _246332#1:(.Idx 2)); + (or_f_246255, if_then_246107)#_246461 _246332#0:(.Idx 2) +}; +.cn lambda_220495 _220513::[mem_220519: %mem.M, id_220560: .Idx 4294967296, continue_220607: .Cn %mem.M] = { + .let _220675: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat id_220560; + .let _220790: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (Qdiag_220194, _220675); + .let _220837: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_220519, _220790); + .let _220908: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_220274, _220675); + .let _220955: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_220837#0:(.Idx 2), _220908); + .let _220700: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (out_220316, _220675); + .let _220976: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_220837#1:(.Idx 2), _220955#1:(.Idx 2)); + .let _221022: %mem.M = %mem.store (%math.F (52, 11), 0) (_220955#0:(.Idx 2), _220700, _220976); + continue_220607 _221022 +}; +.cn lambda_222687 _222688::[_222694: .Idx 4294967296, _222699: %mem.M, _222704: .Cn %mem.M] = { + lambda_221386 (_222699, _222694, _222704) +}; +.cn break_221294 _221312: %mem.M = { + return_220361 _221312 +}; +.cn lambda_223642 _223643::[_223649: .Idx 4294967296, _223654: %mem.M, _223659: .Cn %mem.M] = { + lambda_223181 (_223654, _223649, _223659) +}; +.cn break_223089 _223107: %mem.M = { + .let _223729: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_223107, sum_222993#1:(.Idx 2)); + return_222901 _223729 +}; +.cn sqnorm_cont_230971 _230989::[mem_230995: %mem.M, sqnorm_231006: %math.F (52, 11)] = { + .let _231332: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat ik_230392; + .let _231357: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (sum_qs_228908, _231332); + .let _231404: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_230995, _231357); + .let _231482: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_231404#0:(.Idx 2), out_230139#1:(.Idx 2)); + .let _231017: %math.F (52, 11) = %math.arith.add (52, 11) 0 (sqnorm_230879, sqnorm_231006); + .let _231214: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (4602678819172646912:(%math.F (52, 11)), wishartGamma_228863); + .let _231224: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (wishartGamma_228863, _231214); + .let _231234: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_231017, _231224); + .let _231297: %math.F (52, 11) = %math.conv.s2f 4294967296 (52, 11) wishartM_228812; + .let _231425: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_231297, _231404#1:(.Idx 2)); + .let _231435: %math.F (52, 11) = %math.arith.sub (52, 11) 0 (_231234, _231425); + .let _231503: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_231435, _231482#1:(.Idx 2)); + .let _231549: %mem.M = %mem.store (%math.F (52, 11), 0) (_231482#0:(.Idx 2), out_230139#1:(.Idx 2), _231503); + continue_230439 _231549 +}; +.cn print_cont_247430 _247448: %mem.M = { + return_241102 _247448 +}; +.cn const_cont_240071 _240089: %mem.M = { + .let _239689: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (d_238982, k_239019); + const (_240089, _239689, means_d_239336, 0:(%math.F (52, 11)), const_cont_240180) +}; +.cn or_f_246255 _246497: %mem.M = { + .let _246575: [%mem.M, .Idx 0] = %mem.load (.Idx 0, 0) (_246497, min_runtime_244562#1:(.Idx 2)); + .let _246594: .Idx 2 = %core.icmp.xYgLe 0 (runBenchmark_246064, _246575#1:(.Idx 2)); + (if_else_246148, if_then_246107)#_246594 _246575#0:(.Idx 2) +}; +.cn if_then_246107 _246630: %mem.M = { + .let _246707: %mem.M = %mem.store (.Idx 0, 0) (_246630, min_runtime_244562#1:(.Idx 2), runBenchmark_246064); + if_join_246193 (_246707, ()) +}; +.cn lambda_221386 _221404::[mem_221410: %mem.M, i_221447: .Idx 4294967296, continue_221494: .Cn %mem.M] = { + .let _221750: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), i_221447); + .let _221532: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat i_221447; + .let _221557: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (x_220274, _221532); + .let _221604: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_221410, _221557); + %affine.For (4294967296, 1, %mem.M) (_221750, d_220150, 1:(.Idx 4294967296), _221604#0:(.Idx 2), lambda_222609, break_221654) +}; +.cn lambda_223181 _223199::[mem_223205: %mem.M, i_223242: .Idx 4294967296, continue_223289: .Cn %mem.M] = { + .let _223327: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat i_223242; + .let _223352: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (v_222856, _223327); + .let _223399: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (mem_223205, _223352); + .let _223537: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_223399#0:(.Idx 2), sum_222993#1:(.Idx 2)); + .let _223490: %math.F (52, 11) = %math.arith.mul (52, 11) 0 <2; _223399#1:(.Idx 2)>; + .let _223558: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_223490, _223537#1:(.Idx 2)); + .let _223604: %mem.M = %mem.store (%math.F (52, 11), 0) (_223537#0:(.Idx 2), sum_222993#1:(.Idx 2), _223558); + continue_223289 _223604 +}; +.cn const_cont_240180 _240198: %mem.M = { + .let _239947: .Idx 4294967296 = %core.wrap.mul (1, 4294967296) (k_239019, _239922#1:(.Idx 2)); + const (_240198, _239947, icf_d_239422, 0:(%math.F (52, 11)), const_cont_240289) +}; +.cn if_else_246148 _246743: %mem.M = { + if_join_246193 (_246743, ()) +}; +.cn if_join_246193 _246211::[mem_246217: %mem.M, _246786: []] = { + .let _246863: [%mem.M, .Idx 0] = %mem.load (.Idx 0, 0) (mem_246217, time_sum_244195#1:(.Idx 2)); + .let _246889: .Idx 0 = %core.wrap.add (1, 0) (runBenchmark_246064, _246863#1:(.Idx 2)); + .let _246935: %mem.M = %mem.store (.Idx 0, 0) (_246863#0:(.Idx 2), time_sum_244195#1:(.Idx 2), _246889); + .let _246982: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_246935, count_244340#1:(.Idx 2)); + .let _247068: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), _246982#1:(.Idx 2)); + .let _247114: %mem.M = %mem.store (.Idx 4294967296, 0) (_246982#0:(.Idx 2), count_244340#1:(.Idx 2), _247068); + continue_244814 _247114 +}; +.cn lambda_222609 _222610::[_222616: .Idx 4294967296, _222621: %mem.M, _222626: .Cn %mem.M] = { + lambda_221790 (_222621, _222616, _222626) +}; +.cn break_221654 _221672: %mem.M = { + continue_221494 _221672 +}; +.cn const_cont_240289 _240307: %mem.M = { + begin (_240307, begin_cont_240441) +}; +.cn continue_244814 _244832: %mem.M = { + while_head_244664 _244832 +}; +.cn lambda_221790 _221808::[mem_221814: %mem.M, j_221851: .Idx 4294967296, continue_221898: .Cn %mem.M] = { + .let _222107: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (mem_221814, Lparamsidx_221192#1:(.Idx 2)); + .let _222123: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat _222107#1:(.Idx 2); + .let _222148: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (ltri_220237, _222123); + .let _222195: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_222107#0:(.Idx 2), _222148); + .let _221966: .Idx .top:.Nat = %core.conv.u2u 4294967296 .top:.Nat j_221851; + .let _221991: %mem.Ptr (%math.F (52, 11), 0) = %mem.lea (.top:.Nat, <.top:.Nat; %math.F (52, 11)>, 0) (out_220316, _221966); + .let _222325: [%mem.M, %math.F (52, 11)] = %mem.load (%math.F (52, 11), 0) (_222195#0:(.Idx 2), _221991); + .let _222218: %math.F (52, 11) = %math.arith.mul (52, 11) 0 (_221604#1:(.Idx 2), _222195#1:(.Idx 2)); + .let _222346: %math.F (52, 11) = %math.arith.add (52, 11) 0 (_222218, _222325#1:(.Idx 2)); + .let _222392: %mem.M = %mem.store (%math.F (52, 11), 0) (_222325#0:(.Idx 2), _221991, _222346); + .let _222439: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_222392, Lparamsidx_221192#1:(.Idx 2)); + .let _222525: .Idx 4294967296 = %core.wrap.add (1, 4294967296) (1:(.Idx 4294967296), _222439#1:(.Idx 2)); + .let _222571: %mem.M = %mem.store (.Idx 4294967296, 0) (_222439#0:(.Idx 2), Lparamsidx_221192#1:(.Idx 2), _222525); + continue_221898 _222571 +}; +.cn begin [%mem.M, .Cn %mem.M] = { + +}; +.cn begin_cont_240441 _240459: %mem.M = { + .let _240539: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0) = %core.bitcast (%mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), .Idx 4294967296) 0:(.Idx 4294967296); + %autodiff.ad .Cn [%mem.M, .Idx 4294967296, .Idx 4294967296, .Idx 4294967296, .Idx 4294967296, %math.F (52, 11), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), .Cn [%mem.M, %math.F (52, 11)]] gmm (_240459, d_238982, k_239019, n_239056, wishartM_239103, wishartGamma_239154, alphas_239199, alphas_d_239246, means_239290, means_d_239336, icf_239378, icf_d_239422, x_239459, _240539, _cont_240585) +}; +.cn _cont_240585 _240603::[mem_240609: %mem.M, _240622: %math.F (52, 11), _240628: .Cn [%mem.M, %math.F (52, 11), .Cn [%mem.M, .Idx 4294967296, .Idx 4294967296, .Idx 4294967296, .Idx 4294967296, %math.F (52, 11), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)]]] = { + _240628 (mem_240609, 4607182418800017408:(%math.F (52, 11)), _cont_240781) +}; +.cn _cont_240781 _240799::[mem_240805: %mem.M, _240818: .Idx 4294967296, _240824: .Idx 4294967296, _240830: .Idx 4294967296, _240836: .Idx 4294967296, _240842: %math.F (52, 11), _240848: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), _240854: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), _240860: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0), _240866: %mem.Ptr (<<.top:.Nat; %math.F (52, 11)>>, 0)] = { + eval (mem_240805, eval_cont_240920) +}; +.cn eval [%mem.M, .Cn [%mem.M, .Idx 0]] = { + +}; +.cn eval_cont_240920 _240938::[mem_240944: %mem.M, eval_240955: .Idx 0] = { + return_239504 _240938 +}; diff --git a/lit/backend/ad/pow_ad.thorin b/lit/backend/ad/pow_ad.thorin new file mode 100644 index 0000000000..9cb788efdd --- /dev/null +++ b/lit/backend/ad/pow_ad.thorin @@ -0,0 +1,114 @@ +// RUN: rm -f %t.hs ; \ +// RUN: %thorin -d backend %s --backend ml --output - +// RUN: ocaml %s_test.ml +// RUN: rm -f %s.ml + +.import core; +.import mem; + +.con zero_pb_5474158 _5474160::[.Idx 4294967296, _5474162: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _5474159 [_5474163: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _5474162 _5474163 + }; + _5474159 ‹2; 0:(.Idx 4294967296)› +}; +.con eta_tup_pb_5474192 _5474196::[[], tup_ret_cont_5474198: .Cn «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + .con tup_ret_cont_5474195 [_5474199: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + tup_ret_cont_5474198 _5474199 + }; + tup_ret_cont_5474195 ‹2; 0:(.Idx 4294967296)› +}; +.con eta_tup_pb_5474273 _5474275::[[], tup_ret_cont_5474277: .Cn «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + .con tup_ret_cont_5474274 [_5474278: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + tup_ret_cont_5474277 _5474278 + }; + tup_ret_cont_5474274 ‹2; 0:(.Idx 4294967296)› +}; +.con f_deriv_5474001 _5474075::[_5474077: .Idx 4294967296, _5474204: .Idx 4294967296, _5474215: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con aug_f_5474023 _5474045::[_5474047: .Idx 4294967296, _5474060: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con _5474058 [_5474061: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + _5474060 _5474061 + }; + .con aug_pow_cont_5474057 _5474078::[_5474080: .Idx 4294967296, _5474090: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con comp_tup_pb__5474088 _5474095::[_5474097: .Idx 4294967296, _5474111: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _5474109 [_5474112: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _5474111 _5474112 + }; + .con inner_cont_5474108 _5474136::[_5474137: .Idx 4294967296, _5474143: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5474135: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_5474080, _5474097); + .let _5474142: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5474135, _5474137); + _5474109 (_5474142, _5474143) + }; + .let _5474102: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_5474077, _5474097); + _5474090 (_5474102, inner_cont_5474108) + }; + .let _5474085: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_5474077, _5474080); + _5474058 (_5474085, comp_tup_pb__5474088) + }; + .con aug_pow_else_5474024 [.Cn [[], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .let _5474054: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _5474047); + aug_f_5474023 (_5474054, aug_pow_cont_5474057) + }; + .con aug_pow_then_5474154 [.Cn [[], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + _5474058 (1:(.Idx 4294967296), zero_pb_5474158) + }; + .let _5474188: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _5474047); + (aug_pow_else_5474024, aug_pow_then_5474154)#_5474188 eta_tup_pb_5474192 + }; + .con _5474213 [_5474216: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + _5474215 _5474216 + }; + .con aug_pow_cont_5474212 _5474218::[_5474220: .Idx 4294967296, _5474228: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con comp_tup_pb__5474226 _5474229::[_5474231: .Idx 4294967296, _5474240: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _5474238 [_5474241: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _5474240 _5474241 + }; + .con inner_cont_5474237 _5474248::[_5474249: .Idx 4294967296, _5474255: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5474247: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_5474220, _5474231); + .let _5474254: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5474247, _5474249); + _5474238 (_5474254, _5474255) + }; + .let _5474236: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_5474077, _5474231); + _5474228 (_5474236, inner_cont_5474237) + }; + .let _5474225: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_5474077, _5474220); + _5474213 (_5474225, comp_tup_pb__5474226) + }; + .con aug_pow_else_5474013 [.Cn [[], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .let _5474211: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _5474204); + aug_f_5474023 (_5474211, aug_pow_cont_5474212) + }; + .con aug_pow_then_5474264 [.Cn [[], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + _5474213 (1:(.Idx 4294967296), zero_pb_5474158) + }; + .let _5474271: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _5474204); + (aug_pow_else_5474013, aug_pow_then_5474264)#_5474271 eta_tup_pb_5474273 +}; +.con .extern f_diffed __5474282::[__5474284::[_5474285: .Idx 4294967296, _5474286: .Idx 4294967296], ret_5474337: .Cn [.Idx 4294967296, «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con ret_5474335 [_5474338: [.Idx 4294967296, «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + ret_5474337 _5474338 + }; + .con ret_cont_5474294 __5474306::[r_5474350: .Idx 4294967296, pb_5474308: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_5474323 [__5474351: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + ret_5474335 (r_5474350, __5474351) + }; + pb_5474308 (1:(.Idx 4294967296), pb_ret_cont_5474323) + }; + f_deriv_5474001 (__5474284#0:(.Idx 2), __5474284#1:(.Idx 2), ret_cont_5474294) +}; +.con .extern main __5474458::[mem_5474471: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_5474460: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_5474457 [_5474461: [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + return_5474460 _5474461 + }; + .con ret_cont_5474429 __5474438::[r_5474505: .Idx 4294967296, pb_5474440: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_5474448 __5474524::[pr_a_5474546: .Idx 4294967296, pr_b_5474525: .Idx 4294967296] @(0:(.Idx 2)) = { + .let _5474512: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_5474505); + .let _5474553: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_5474546); + .let _5474558: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_5474525, _5474553); + .let _5474563: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5474512, _5474558); + return_5474457 (mem_5474471, _5474563) + }; + pb_5474440 (1:(.Idx 4294967296), pb_ret_cont_5474448) + }; + f_deriv_5474001 (42:(.Idx 4294967296), 3:(.Idx 4294967296), ret_cont_5474429) +}; diff --git a/lit/backend/ad/pow_ad.thorin_test.ml b/lit/backend/ad/pow_ad.thorin_test.ml new file mode 100644 index 0000000000..e57374537d --- /dev/null +++ b/lit/backend/ad/pow_ad.thorin_test.ml @@ -0,0 +1,43 @@ +#use "pow_ad.thorin.ml";; +(* #use "pow_ad_preopt_fix.ml";; *) + +let pow_ds (a,b) = + let (r,[da;db]) = f_diffed ([a;b], Fun.id) in + (r,(da,db)) + +let test ?(verbose=false) a b = + let (r,(da,db)) = pow_ds (a,b) in + let expected = int_of_float (float_of_int a ** float_of_int b) in + let expected_diff = int_of_float (float_of_int b *. (float_of_int a ** float_of_int (b-1))) in + let test = (da = expected_diff && r = expected) in + (if verbose then + Printf.printf "%d ^ %d = %d, diff = %d (%s)\n" a b r da (if test then "OK" else "FAIL") + else + ()) + ; + test + +let tests = [ + (42,2); + (42,3) +] + +let _ = List.iter (fun (a,b) -> + assert (test ~verbose:true a b) + ) tests + + +(* timing tests *) +let time f x = + let t = Sys.time() in + let fx = f x in + Printf.printf "Execution time: %fs\n" (Sys.time() -. t); + fx + +let auto_tests = + (* List.init 100000 (fun _ -> (Random.int 1000, Random.int 100)) *) + List.init 100000 (fun i -> ((i*37+12) mod 10000, i mod 100)) + +let _ = time (fun _ -> List.iter (fun (a,b) -> + test a b |> ignore + ) auto_tests) () diff --git a/lit/backend/ad/pow_ad_2.thorin b/lit/backend/ad/pow_ad_2.thorin new file mode 100644 index 0000000000..38db20afbf --- /dev/null +++ b/lit/backend/ad/pow_ad_2.thorin @@ -0,0 +1,66 @@ +// RUN: rm -f %t.hs ; \ +// RUN: %thorin -d backend %s --backend ml --output - + +.import core; +.import mem; + +.con zero_pb_2612673 _2612675::[.Idx 4294967296, _2612677: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _2612674 [_2612678: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _2612677 _2612678 + }; + _2612674 ‹2; 0:(.Idx 4294967296)› +}; +.con tup_pb_2612711 _2612713::[[], _2612715: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _2612712 [_2612716: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _2612715 _2612716 + }; + _2612712 ‹2; 0:(.Idx 4294967296)› +}; +.con aug_f_2612486 _2612521::[_2612523: .Idx 4294967296, _2612536: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con _2612534 _2612537:: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + _2612536 _2612537 + }; + .con aug_pow_cont_2612533 _2612559::[_2612561: .Idx 4294967296, _2612579: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con comp_tup_pb__2612571 _2612584::[_2612586: .Idx 4294967296, _2612603: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _2612601 [_2612604: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _2612603 _2612604 + }; + .con tup_pb_cps_cont_1_2612600 _2612645::[_2612646: .Idx 4294967296, _2612652: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _2612644: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_2612561, _2612586); + .let _2612651: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_2612644, _2612646); + _2612601 (_2612651, _2612652) + }; + .let _2612593: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _2612586); + _2612579 (_2612593, tup_pb_cps_cont_1_2612600) + }; + .let _2612568: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _2612561); + _2612534 (_2612568, comp_tup_pb__2612571) + }; + .con aug_pow_else_2612501 [.Cn [[], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .let _2612530: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _2612523); + aug_f_2612486 (_2612530, aug_pow_cont_2612533) + }; + .con aug_pow_then_2612663 [.Cn [[], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + _2612534 (1:(.Idx 4294967296), zero_pb_2612673) + }; + .let _2612703: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _2612523); + (aug_pow_else_2612501, aug_pow_then_2612663)#_2612703 tup_pb_2612711 +}; +.con .extern main __2612735::[mem_2612758: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_2612739: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_2612734 _2612740:: [%mem.M, .Idx 4294967296] @(0:(.Idx 2)) = { + return_2612739 _2612740 + }; + .con aug_pow_cont_2612721 _2612722::[_2612789: .Idx 4294967296, _2612724: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con tup_pb_cps_cont_1_2612725 _2612807::[_2612821: .Idx 4294967296, _2612808: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _2612796: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _2612789); + .let _2612803: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), _2612796); + .let _2612833: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_2612789, _2612821); + .let _2612840: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), _2612833); + .let _2612845: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_2612808, _2612840); + .let _2612850: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_2612803, _2612845); + return_2612734 (mem_2612758, _2612850) + }; + _2612724 (4:(.Idx 4294967296), tup_pb_cps_cont_1_2612725) + }; + aug_f_2612486 (2:(.Idx 4294967296), aug_pow_cont_2612721) +}; diff --git a/lit/backend/ad/pow_ad_fix.hs b/lit/backend/ad/pow_ad_fix.hs new file mode 100644 index 0000000000..bacc19b8fe --- /dev/null +++ b/lit/backend/ad/pow_ad_fix.hs @@ -0,0 +1,116 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# OPTIONS_GHC -Wno-incomplete-patterns #-} +module Opt where + +import Data.IORef +bool2bit x = if x then 1 else 0 +get_0_of_2 (x, _) = x +get_1_of_2 (_, x) = x +get_0_of_3 (x, _, _) = x +get_1_of_3 (_, x, _) = x +get_2_of_3 (_, _, x) = x +magic a = magic a + + +zero_pb_5474158_1228720 ((_5474160_1228727@(_, _5474162_1228729)):: (Int , ([Int] -> a))) = + let _5474162_1228725 (_1228730 :: [Int]) = + (_5474162_1228729 _1228730) + in + (_5474162_1228725 (replicate 2 (0::Int))) +eta_tup_pb_5474192_1228771 ((_5474196_1228779@(_, tup_ret_cont_5474198_1228781)):: (unit , ([Int] -> a))) = + let tup_ret_cont_5474198_1228777 (_1228782 :: [Int]) = + (tup_ret_cont_5474198_1228781 _1228782) + in + (tup_ret_cont_5474198_1228777 (replicate 2 (0::Int))) +eta_tup_pb_5474273_1229021 ((_5474275_1229038@(_, tup_ret_cont_5474277_1229040)):: (unit , ([Int] -> a))) = + let tup_ret_cont_5474277_1229031 (_1229041 :: [Int]) = + (tup_ret_cont_5474277_1229040 _1229041) + in + (tup_ret_cont_5474277_1229031 (replicate 2 (0::Int))) +f_deriv_5474001_1228345 ((_5474075_1228547@(_5474077_1228549, _5474204_1228798, _5474215_1228823)):: (Int , Int , ((Int , ((Int , ([Int] -> a)) -> a)) -> a))) = + let aug_f_5474023_1228437 ((_5474045_1228497@(_5474047_1228499, _5474060_1228523)):: (Int , ((Int , ((Int , ([Int] -> a)) -> a)) -> a))) = + let _5474060_1228521 (_1228524 :: (Int , ((Int , ([Int] -> a)) -> a))) = + (_5474060_1228523 _1228524) + in + let aug_pow_cont_5474057_1228515 ((_5474078_1228561@(_5474080_1228563, _5474090_1228588)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let comp_tup_pb__5474088_1228578 ((_5474095_1228610@(_5474097_1228612, _5474111_1228641)):: (Int , ([Int] -> a))) = + let _5474111_1228639 (_1228642 :: [Int]) = + (_5474111_1228641 _1228642) + in + let inner_cont_5474108_1228629 ((_5474136_1228672@[_5474137_1228673, _5474143_1228685]):: [Int]) = + let _1228660 :: Int = (_5474080_1228563 * _5474097_1228612) in + let _1228678 :: Int = (_1228660 + _5474137_1228673) in + (_5474111_1228639 [_1228678, _5474143_1228685]) + in + let _1228617 :: Int = (_5474077_1228549 * _5474097_1228612) in + (_5474090_1228588 (_1228617, inner_cont_5474108_1228629)) + in + let _1228568 :: Int = (_5474077_1228549 * _5474080_1228563) in + (_5474060_1228521 (_1228568, comp_tup_pb__5474088_1228578)) + in + let aug_pow_else_5474024_1228457 _ = + let _1228506 :: Int = ((-1::Int) + (_5474047_1228499)) in + (aug_f_5474023_1228437 (_1228506, aug_pow_cont_5474057_1228515)) + in + let aug_pow_then_5474154_1228703 _ = + (_5474060_1228521 ((1::Int), zero_pb_5474158_1228720)) + in + let _1228762 :: Int = (bool2bit ((0::Int) == _5474047_1228499)) in + (([aug_pow_else_5474024_1228457, aug_pow_then_5474154_1228703] !! _1228762) eta_tup_pb_5474192_1228771) + in + let _5474215_1228821 (_1228824 :: (Int , ((Int , ([Int] -> a)) -> a))) = + (_5474215_1228823 _1228824) + in + let aug_pow_cont_5474212_1228815 ((_5474218_1228848@(_5474220_1228850, _5474228_1228877)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let comp_tup_pb__5474226_1228865 ((_5474229_1228900@(_5474231_1228902, _5474240_1228929)):: (Int , ([Int] -> a))) = + let _5474240_1228927 (_1228930 :: [Int]) = + (_5474240_1228929 _1228930) + in + let inner_cont_5474237_1228917 ((_5474248_1228963@[_5474249_1228964, _5474255_1228976]):: [Int]) = + let _1228950 :: Int = (_5474220_1228850 * _5474231_1228902) in + let _1228969 :: Int = (_1228950 + _5474249_1228964) in + (_5474240_1228927 [_1228969, _5474255_1228976]) + in + let _1228907 :: Int = (_5474077_1228549 * _5474231_1228902) in + (_5474228_1228877 (_1228907, inner_cont_5474237_1228917)) + in + let _1228855 :: Int = (_5474077_1228549 * _5474220_1228850) in + (_5474215_1228821 (_1228855, comp_tup_pb__5474226_1228865)) + in + let aug_pow_else_5474013_1228396 _ = + let _1228805 :: Int = ((-1::Int) + _5474204_1228798) in + (aug_f_5474023_1228437 (_1228805, aug_pow_cont_5474212_1228815)) + in + let aug_pow_then_5474264_1228993 _ = + (_5474215_1228821 ((1::Int), zero_pb_5474158_1228720)) + in + let _1229011 :: Int = (bool2bit ((0::Int) == _5474204_1228798)) in + (([aug_pow_else_5474013_1228396, aug_pow_then_5474264_1228993] !! _1229011) eta_tup_pb_5474273_1229021) +-- external +f_diffed ((__5474282_1229058@(((__5474284_1229060@[_5474285_1229061, _5474286_1229068]):: [Int]), ret_5474337_1229130)):: ([Int] , ((Int , [Int]) -> a))) = + let ret_5474337_1229128 (_1229131 :: (Int , [Int])) = + (ret_5474337_1229130 _1229131) + in + let ret_cont_5474294_1229081 ((__5474306_1229101@(r_5474350_1229140, pb_5474308_1229103)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let pb_ret_cont_5474323_1229119 (__1229141 :: [Int]) = + (ret_5474337_1229128 (r_5474350_1229140, __1229141)) + in + (pb_5474308_1229103 ((1::Int), pb_ret_cont_5474323_1229119)) + in + (f_deriv_5474001_1228345 ((__5474284_1229060 !! (0::Int)), (__5474284_1229060 !! (1::Int)), ret_cont_5474294_1229081)) +-- external +thorin_main ((__5474458_1229272@(mem_5474471_1229285, _, _, return_5474460_1229276)):: (unit , Int , (IORef (IORef Int)) , ((unit , Int) -> a))) = + let return_5474460_1229270 (_1229277 :: (unit , Int)) = + (return_5474460_1229276 _1229277) + in + let ret_cont_5474429_1229229 ((__5474438_1229246@(r_5474505_1229311, pb_5474440_1229248)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let pb_ret_cont_5474448_1229261 ((__5474524_1229341@[pr_a_5474546_1229361, pr_b_5474525_1229342]):: [Int]) = + let _1229318 :: Int = ((10000::Int) * r_5474505_1229311) in + let _1229368 :: Int = ((100::Int) * pr_a_5474546_1229361) in + let _1229373 :: Int = (pr_b_5474525_1229342 + _1229368) in + let _1229378 :: Int = (_1229318 + _1229373) in + (return_5474460_1229270 (mem_5474471_1229285, _1229378)) + in + (pb_5474440_1229248 ((1::Int), pb_ret_cont_5474448_1229261)) + in + (f_deriv_5474001_1228345 ((42::Int), (3::Int), ret_cont_5474429_1229229)) diff --git a/lit/backend/ad/pow_ad_preopt.thorin b/lit/backend/ad/pow_ad_preopt.thorin new file mode 100644 index 0000000000..778e68d718 --- /dev/null +++ b/lit/backend/ad/pow_ad_preopt.thorin @@ -0,0 +1,226 @@ +// RUN: rm -f %t.hs ; \ +// RUN: %thorin -d backend %s --backend ml --output - + +.import core; +.import mem; + +// .lam internal_diff_core_wrap_add_5378834 [.Nat] → Π «2; .Idx 4294967296» → [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = { + .lam internal_diff_core_wrap_add_5378834 [m_5378909: .Nat] → Π «2; .Idx 4294967296» → [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = { + .con __5378927 __5378944::[i_5378954: .Idx 4294967296, pb_ret_5378946: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + pb_ret_5378946 ‹2; i_5378954› + }; + .lam __5378884 __5378911::[_5378915: .Idx 4294967296, _5378919: .Idx 4294967296] → [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = { + .let _5378922: .Idx 4294967296 = %core.wrap.add 4294967296 m_5378909 __5378911; + (_5378922, __5378927) + }; + __5378884 + }; +// __5378879 +// }; +// .lam internal_diff_core_wrap_mul_5379044 [.Nat] → Π «2; .Idx 4294967296» → [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = { + .lam internal_diff_core_wrap_mul_5379044 [m_5379120: .Nat] → Π «2; .Idx 4294967296» → [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = { + .lam __5379094 __5379122::[_5379126: .Idx 4294967296, _5379130: .Idx 4294967296] → [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = { + .con __5379138 __5379147::[i_5379162: .Idx 4294967296, pb_ret_5379149: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _5379167: .Idx 4294967296 = %core.wrap.mul 4294967296 m_5379120 (_5379130, i_5379162); + .let _5379177: .Idx 4294967296 = %core.wrap.mul 4294967296 m_5379120 (_5379126, i_5379162); + pb_ret_5379149 (_5379167, _5379177) + }; + .let _5379133: .Idx 4294967296 = %core.wrap.mul 4294967296 m_5379120 __5379122; + (_5379133, __5379138) + }; + __5379094 + }; +// __5379089 +// }; +.con id_pb_5379243 _5379244::[s_5379249: «2; .Idx 4294967296», _5379246: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _5379246 s_5379249 +}; +.con extract_pb_5379240 _5379253::[s_5379255: .Idx 4294967296, _5379259: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + id_pb_5379243 ((s_5379255, 0:(.Idx 4294967296)), _5379259) +}; +.con zero_pb_5379336 _5379337::[.Idx 4294967296, _5379339: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _5379339 ‹2; 0:(.Idx 4294967296)› +}; +.con zero_pb_5379403 _5379404::[.Cn .Idx 4294967296, _5379406: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _5379406 ‹2; 0:(.Idx 4294967296)› +}; +.con zero_pb_5379441 _5379442::[.Idx 4294967296, _5379444: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _5379444 ‹2; 0:(.Idx 4294967296)› +}; +// .lam internal_diff_core_icmp_xyglE_5379505 [«2; .Idx 4294967296»] → [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx 4294967296»]] = { + .lam internal_diff_core_icmp_xyglE_5379505 __5379561::[_5379565: .Idx 4294967296, _5379569: .Idx 4294967296] → [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx 4294967296»]] = { + .con __5379577 __5379586::[.Idx 2, pb_ret_5379588: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + pb_ret_5379588 ‹2; 0:(.Idx 4294967296)› + }; + .let _5379572: .Idx 2 = %core.icmp.xyglE 4294967296 __5379561; + (_5379572, __5379577) + }; +// __5379544 +// }; +.con tup_pb_5379621 _5379622::[[], tup_ret_cont_5379624: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_ret_cont_5379624 ‹2; 0:(.Idx 4294967296)› +}; +.con extract_pb_5379708 _5379709::[s_5379711: .Idx 4294967296, _5379714: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + id_pb_5379243 ((0:(.Idx 4294967296), s_5379711), _5379714) +}; +.con tup_pb_5379702 _5379703::[tup_s_5379705::[_5379706: .Idx 4294967296, _5379717: .Idx 4294967296], tup_ret_cont_5379720: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con inner_cont_5379707 _5379721::[_5379722: .Idx 4294967296, _5379730: .Idx 4294967296] @(1:(.Idx 2)) = { + .con inner_cont_5379718 _5379723::[_5379724: .Idx 4294967296, _5379731: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5379729: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379722, _5379724); + .let _5379736: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379730, _5379731); + tup_ret_cont_5379720 (_5379729, _5379736) + }; + extract_pb_5379708 (tup_s_5379705#1:(.Idx 2), inner_cont_5379718) + }; + zero_pb_5379336 (tup_s_5379705#0:(.Idx 2), inner_cont_5379707) +}; +.con zero_pb_5379756 _5379757::[.Cn .Idx 4294967296, _5379759: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _5379759 ‹2; 0:(.Idx 4294967296)› +}; +.con f_deriv_5378732 _5379200::[arg_5379202::[_5379203: .Idx 4294967296, _5379628: .Idx 4294967296], _5379635: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con aug_f_5378771 _5378974::[_5378976::[_5378978: .Idx 4294967296, _5378987: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]], _5379350: .Cn [[.Idx 4294967296, .Cn .Idx 4294967296], .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con aug_pow_cont_5378985 _5379204::[_5379206: .Idx 4294967296, _5379270: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con tup_pb_5379234 _5379262::[tup_s_5379264::[_5379265: .Idx 4294967296, _5379271: .Idx 4294967296], tup_ret_cont_5379276: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con inner_cont_5379268 _5379293::[_5379294: .Idx 4294967296, _5379302: .Idx 4294967296] @(1:(.Idx 2)) = { + .con inner_cont_5379272 _5379295::[_5379296: .Idx 4294967296, _5379303: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5379301: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379294, _5379296); + .let _5379308: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379302, _5379303); + tup_ret_cont_5379276 (_5379301, _5379308) + }; + _5379270 (tup_s_5379264#1:(.Idx 2), inner_cont_5379272) + }; + extract_pb_5379240 (tup_s_5379264#0:(.Idx 2), inner_cont_5379268) + }; + .let _5379208: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = internal_diff_core_wrap_mul_5379044 0 (arg_5379202#0:(.Idx 2), _5379206); + .con comp_tup_pb__5379213 _5379216::[_5379218: .Idx 4294967296, _5379317: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_5379224 [_5379315: «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_pb_5379234 (_5379315, _5379317) + }; + _5379208#1:(.Idx 2) (_5379218, comp_tup_pb__cont_5379224) + }; + _5378976#1:(.Idx 2) (_5379208#0:(.Idx 2), comp_tup_pb__5379213) + }; + .con extract_pb_5379348 _5379351::[s_5379353: .Idx 4294967296, _5379357: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + // _5379350 ((s_5379353, %autodiff.zero .Cn .Idx 4294967296), _5379357) + _5379350 ((s_5379353, .bot:(.Cn .Idx 4294967296)), _5379357) + }; + .con tup_pb_5379333 _5379343::[tup_s_5379345::[_5379346: .Idx 4294967296, _5379360: .Idx 4294967296], tup_ret_cont_5379363: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con inner_cont_5379347 _5379364::[_5379365: .Idx 4294967296, _5379373: .Idx 4294967296] @(1:(.Idx 2)) = { + .con inner_cont_5379361 _5379366::[_5379367: .Idx 4294967296, _5379374: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5379372: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379365, _5379367); + .let _5379379: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379373, _5379374); + tup_ret_cont_5379363 (_5379372, _5379379) + }; + extract_pb_5379348 (tup_s_5379345#1:(.Idx 2), inner_cont_5379361) + }; + zero_pb_5379336 (tup_s_5379345#0:(.Idx 2), inner_cont_5379347) + }; + .let _5378980: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = internal_diff_core_wrap_add_5378834 0 (4294967295:(.Idx 4294967296), _5378976#0:(.Idx 2)); + .con comp_tup_pb__5379326 _5379329::[_5379331: .Idx 4294967296, _5379388: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_5379332 [_5379386: «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_pb_5379333 (_5379386, _5379388) + }; + _5378980#1:(.Idx 2) (_5379331, comp_tup_pb__cont_5379332) + }; + .con tup_pb_5379325 _5379393::[tup_s_5379395::[_5379397: .Idx 4294967296, _5379409: .Cn .Idx 4294967296], tup_ret_cont_5379412: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con inner_cont_5379398 _5379413::[_5379414: .Idx 4294967296, _5379422: .Idx 4294967296] @(1:(.Idx 2)) = { + .con inner_cont_5379410 _5379415::[_5379416: .Idx 4294967296, _5379423: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5379421: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379414, _5379416); + .let _5379428: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379422, _5379423); + tup_ret_cont_5379412 (_5379421, _5379428) + }; + zero_pb_5379403 (tup_s_5379395#1:(.Idx 2), inner_cont_5379410) + }; + comp_tup_pb__5379326 (tup_s_5379395#0:(.Idx 2), inner_cont_5379398) + }; + .con aug_pow_else_5378772 [[[], .Cn [[], .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + aug_f_5378771 ((_5378980#0:(.Idx 2), aug_pow_cont_5378985), tup_pb_5379325) + }; + .con aug_pow_then_5379439 [[[], .Cn [[], .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + _5378976#1:(.Idx 2) (1:(.Idx 4294967296), zero_pb_5379441) + }; + .let _5379617: [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx 4294967296»]] = internal_diff_core_icmp_xyglE_5379505 (0:(.Idx 4294967296), _5378976#0:(.Idx 2)); + (aug_pow_else_5378772, aug_pow_then_5379439)#(_5379617#0:(.Idx 2)) ((), tup_pb_5379621) + }; + .con aug_pow_cont_5379633 _5379636::[_5379638: .Idx 4294967296, _5379657: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con tup_pb_5379650 _5379651::[tup_s_5379653::[_5379654: .Idx 4294967296, _5379658: .Idx 4294967296], tup_ret_cont_5379661: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con inner_cont_5379655 _5379662::[_5379663: .Idx 4294967296, _5379671: .Idx 4294967296] @(1:(.Idx 2)) = { + .con inner_cont_5379659 _5379664::[_5379665: .Idx 4294967296, _5379672: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5379670: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379663, _5379665); + .let _5379677: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379671, _5379672); + tup_ret_cont_5379661 (_5379670, _5379677) + }; + _5379657 (tup_s_5379653#1:(.Idx 2), inner_cont_5379659) + }; + extract_pb_5379240 (tup_s_5379653#0:(.Idx 2), inner_cont_5379655) + }; + .let _5379640: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = internal_diff_core_wrap_mul_5379044 0 (arg_5379202#0:(.Idx 2), _5379638); + .con comp_tup_pb__5379643 _5379646::[_5379648: .Idx 4294967296, _5379686: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_5379649 [_5379684: «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_pb_5379650 (_5379684, _5379686) + }; + _5379640#1:(.Idx 2) (_5379648, comp_tup_pb__cont_5379649) + }; + _5379635 (_5379640#0:(.Idx 2), comp_tup_pb__5379643) + }; + .let _5379630: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = internal_diff_core_wrap_add_5378834 0 (4294967295:(.Idx 4294967296), arg_5379202#1:(.Idx 2)); + .con comp_tup_pb__5379695 _5379698::[_5379700: .Idx 4294967296, _5379745: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_5379701 [_5379743: «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_pb_5379702 (_5379743, _5379745) + }; + _5379630#1:(.Idx 2) (_5379700, comp_tup_pb__cont_5379701) + }; + .con tup_pb_5379694 _5379750::[tup_s_5379752::[_5379754: .Idx 4294967296, _5379762: .Cn .Idx 4294967296], tup_ret_cont_5379765: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con inner_cont_5379755 _5379766::[_5379767: .Idx 4294967296, _5379775: .Idx 4294967296] @(1:(.Idx 2)) = { + .con inner_cont_5379763 _5379768::[_5379769: .Idx 4294967296, _5379776: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _5379774: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379767, _5379769); + .let _5379781: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5379775, _5379776); + tup_ret_cont_5379765 (_5379774, _5379781) + }; + zero_pb_5379756 (tup_s_5379752#1:(.Idx 2), inner_cont_5379763) + }; + comp_tup_pb__5379695 (tup_s_5379752#0:(.Idx 2), inner_cont_5379755) + }; + .con aug_pow_else_5378747 [[[], .Cn [[], .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + aug_f_5378771 ((_5379630#0:(.Idx 2), aug_pow_cont_5379633), tup_pb_5379694) + }; + .con aug_pow_then_5379790 [[[], .Cn [[], .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + _5379635 (1:(.Idx 4294967296), zero_pb_5379441) + }; + // .let _5379794: [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx 4294967296»]] = internal_diff_core_icmp_xyglE_5379505 (0:(.Idx 4294967296), arg_5379202#1:(.Idx 2)); + .let _5379794: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), arg_5379202#1:(.Idx 2)); + (aug_pow_else_5378747, aug_pow_then_5379790)#_5379794 ((), tup_pb_5379621) + // (aug_pow_else_5378747, aug_pow_then_5379790)#(_5379794#0:(.Idx 2)) ((), tup_pb_5379621) + // .let idx : .Idx 2 = _5379794#0:(.Idx 2); + // ((aug_pow_else_5378747, aug_pow_then_5379790)#idx) ((), tup_pb_5379621) +}; +.con .extern f_diffed __5379802::[__5379804: «2; .Idx 4294967296», ret_5379854: .Cn [.Idx 4294967296, «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con ret_cont_5379812 __5379824::[r_5379865: .Idx 4294967296, pb_5379826: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_5379841 [__5379866: «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + ret_5379854 (r_5379865, __5379866) + }; + pb_5379826 (1:(.Idx 4294967296), pb_ret_cont_5379841) + }; + f_deriv_5378732 (__5379804, ret_cont_5379812) +}; +.con .extern main __5381527::[mem_5381538: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_5381529: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con ret_cont_5381499 __5381508::[r_5381571: .Idx 4294967296, pb_5381510: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_5381518 __5381590::[pr_a_5381612: .Idx 4294967296, pr_b_5381591: .Idx 4294967296] @(0:(.Idx 2)) = { + .let _5381578: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_5381571); + .let _5381619: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_5381612); + .let _5381624: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_5381591, _5381619); + .let _5381629: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_5381578, _5381624); + return_5381529 (mem_5381538, _5381629) + }; + pb_5381510 (1:(.Idx 4294967296), pb_ret_cont_5381518) + }; + f_deriv_5378732 ((42:(.Idx 4294967296), 3:(.Idx 4294967296)), ret_cont_5381499) +}; + +.lam .extern _compile [] -> Pipeline = { + %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) + // (%compile.debug_phase 1) + // (%compile.debug_phase 2) + // (%compile.debug_phase 3) +}; diff --git a/lit/backend/ad/pow_ad_preopt_fix.ml b/lit/backend/ad/pow_ad_preopt_fix.ml new file mode 100644 index 0000000000..3fa793a8e9 --- /dev/null +++ b/lit/backend/ad/pow_ad_preopt_fix.ml @@ -0,0 +1,199 @@ + +let bool2bit x = if x then 1 else 0 +(* handle uninitialized values *) +(* let rec magic () : 'a = magic () *) +let unpack m = match m with + | Some x -> x + | None -> failwith "expected Some, got None" +let get_0_of_2 (x, _) = x (* fst *) +let get_1_of_2 (_, x) = x (* snd *) +let get_0_of_3 (x, _, _) = x +let get_1_of_3 (_, x, _) = x +let get_2_of_3 (_, _, x) = x +let rec magic arg : 'a = magic arg +[@@@warning "-partial-match"] + + +let rec __5378927_1236713 (((i_5378954_1236743, pb_ret_5378946_1236732) as __5378944_1236730): (int * ((int list) -> 'a))) = + (pb_ret_5378946_1236732 (List.init 2 (fun _ -> i_5378954_1236743))) +let rec internal_diff_core_wrap_add_5378834_1236637 (__1236685 : int) = + let rec __5378884_1236658 (([_1236696; _1236700] as __5378911_1236692): (int list)) = + let _1236703: int = (_1236696 + _1236700) in + (_1236703, __5378927_1236713) + in + __5378884_1236658 +let rec internal_diff_core_wrap_mul_5379044_1236824 (__1236865 : int) = + let rec __5379094_1236842 (([_1236877; _1236881] as __5379122_1236873): (int list)) = + let rec __5379138_1236894 (((i_5379162_1236934, pb_ret_5379149_1236911) as __5379147_1236909): (int * ((int list) -> 'a))) = + let _1236939: int = (_1236881 * i_5379162_1236934) in + let _1236958: int = (_1236877 * i_5379162_1236934) in + (pb_ret_5379149_1236911 [_1236939; _1236958]) + in + let _1236884: int = (_1236877 * _1236881) in + (_1236884, __5379138_1236894) + in + __5379094_1236842 +let rec id_pb_5379243_1237120 (((s_5379249_1237131, _5379246_1237128) as _5379244_1237126): ((int list) * ((int list) -> 'a))) = + (_5379246_1237128 s_5379249_1237131) +let rec extract_pb_5379240_1237105 (((s_5379255_1237154, _5379259_1237163) as _5379253_1237152): (int * ((int list) -> 'a))) = + (id_pb_5379243_1237120 ([s_5379255_1237154; (0:int)], _5379259_1237163)) +let rec zero_pb_5379336_1237457 (((_, _5379339_1237474) as _5379337_1237472): (int * ((int list) -> 'a))) = + (_5379339_1237474 (List.init 2 (fun _ -> (0:int)))) +let rec zero_pb_5379403_1237784 (((_, _5379406_1237792) as _5379404_1237790): ((int -> 'a) * ((int list) -> 'a))) = + (_5379406_1237792 (List.init 2 (fun _ -> (0:int)))) +let rec zero_pb_5379441_1237947 (((_, _5379444_1237965) as _5379442_1237963): (int * ((int list) -> 'a))) = + (_5379444_1237965 (List.init 2 (fun _ -> (0:int)))) +let rec __5379577_1236512 (((_, pb_ret_5379588_1236533) as __5379586_1236531): (int * ((int list) -> 'a))) = + (pb_ret_5379588_1236533 (List.init 2 (fun _ -> (0:int)))) +let rec internal_diff_core_icmp_xyglE_5379505_1236469 (([_1236495; _1236499] as __5379561_1236491): (int list)) = + let _1236502: int = (bool2bit (_1236495 = _1236499)) in + (_1236502, __5379577_1236512) +let rec tup_pb_5379621_1237988 (((_, tup_ret_cont_5379624_1237997) as _5379622_1237995): (unit * ((int list) -> 'a))) = + (tup_ret_cont_5379624_1237997 (List.init 2 (fun _ -> (0:int)))) +let rec extract_pb_5379708_1238494 (((s_5379711_1238520, _5379714_1238529) as _5379709_1238518): (int * ((int list) -> 'a))) = + (id_pb_5379243_1237120 ([(0:int); s_5379711_1238520], _5379714_1238529)) +let rec tup_pb_5379702_1238435 ((((([_5379706_1238469; _5379717_1238547] as tup_s_5379705_1238468): (int list)), tup_ret_cont_5379720_1238569) as _5379703_1238466): ((int list) * ((int list) -> 'a))) = + let rec inner_cont_5379707_1238479 (([_5379722_1238592; _5379730_1238625] as _5379721_1238591): (int list)) = + let rec inner_cont_5379718_1238557 (([_5379724_1238606; _5379731_1238632] as _5379723_1238605): (int list)) = + let _1238611: int = (_5379722_1238592 + _5379724_1238606) in + let _1238637: int = (_5379730_1238625 + _5379731_1238632) in + (tup_ret_cont_5379720_1238569 [_1238611; _1238637]) + in + (extract_pb_5379708_1238494 (List.nth tup_s_5379705_1238468 (1:int), inner_cont_5379718_1238557)) + in + (zero_pb_5379336_1237457 (List.nth tup_s_5379705_1238468 (0:int), inner_cont_5379707_1238479)) +let rec zero_pb_5379756_1238717 (((_, _5379759_1238734) as _5379757_1238732): ((int -> 'a) * ((int list) -> 'a))) = + (_5379759_1238734 (List.init 2 (fun _ -> (0:int)))) +let rec f_deriv_5378732_1236202 ((((([_5379203_1236972; _5379628_1236295] as arg_5379202_1236294): (int list)), _5379635_1238051) as _5379200_1236292): ((int list) * ((int * ((int * ((int list) -> 'a)) -> 'a)) -> 'a))) = + let rec aug_f_5378771_1236401 ((((((_5378978_1236552, _5378987_1236777) as _5378976_1236550): (int * ((int * ((int * ((int list) -> 'a)) -> 'a)) -> 'a))), _5379350_1237540) as _5378974_1236548): ((int * ((int * ((int * ((int list) -> 'a)) -> 'a)) -> 'a)) * (((int * (int -> 'a)) * ((int list) -> 'a)) -> 'a))) = + let rec aug_pow_cont_5378985_1236770 (((_5379206_1236987, _5379270_1237218) as _5379204_1236985): (int * ((int * ((int list) -> 'a)) -> 'a))) = + let rec tup_pb_5379234_1237087 ((((([_5379265_1237196; _5379271_1237234] as tup_s_5379264_1237195): (int list)), tup_ret_cont_5379276_1237255) as _5379262_1237193): ((int list) * ((int list) -> 'a))) = + let rec inner_cont_5379268_1237206 (([_5379294_1237284; _5379302_1237317] as _5379293_1237283): (int list)) = + let rec inner_cont_5379272_1237243 (([_5379296_1237298; _5379303_1237324] as _5379295_1237297): (int list)) = + let _1237303: int = (_5379294_1237284 + _5379296_1237298) in + let _1237329: int = (_5379302_1237317 + _5379303_1237324) in + (tup_ret_cont_5379276_1237255 [_1237303; _1237329]) + in + (_5379270_1237218 (List.nth tup_s_5379264_1237195 (1:int), inner_cont_5379272_1237243)) + in + (extract_pb_5379240_1237105 (List.nth tup_s_5379264_1237195 (0:int), inner_cont_5379268_1237206)) + in + let _1236989: (int * ((int * ((int list) -> 'a)) -> 'a)) = ((internal_diff_core_wrap_mul_5379044_1236824 0) [List.nth arg_5379202_1236294 (0:int); _5379206_1236987]) in + let rec comp_tup_pb__5379213_1237000 (((_5379218_1237032, _5379317_1237347) as _5379216_1237030): (int * ((int list) -> 'a))) = + let rec comp_tup_pb__cont_5379224_1237045 (__1237339 : (int list)) = + (tup_pb_5379234_1237087 (__1237339, _5379317_1237347)) + in + (get_1_of_2 _1236989 (_5379218_1237032, comp_tup_pb__cont_5379224_1237045)) + in + (get_1_of_2 _5378976_1236550 (get_0_of_2 _1236989, comp_tup_pb__5379213_1237000)) + in + let rec extract_pb_5379348_1237533 (((s_5379353_1237561, _5379357_1237575) as _5379351_1237559): (int * ((int list) -> 'a))) = + (_5379350_1237540 ((s_5379353_1237561, magic), _5379357_1237575)) + in + let rec tup_pb_5379333_1237441 ((((([_5379346_1237506; _5379360_1237593] as tup_s_5379345_1237505): (int list)), tup_ret_cont_5379363_1237615) as _5379343_1237503): ((int list) * ((int list) -> 'a))) = + let rec inner_cont_5379347_1237516 (([_5379365_1237639; _5379373_1237672] as _5379364_1237638): (int list)) = + let rec inner_cont_5379361_1237603 (([_5379367_1237653; _5379374_1237679] as _5379366_1237652): (int list)) = + let _1237658: int = (_5379365_1237639 + _5379367_1237653) in + let _1237684: int = (_5379373_1237672 + _5379374_1237679) in + (tup_ret_cont_5379363_1237615 [_1237658; _1237684]) + in + (extract_pb_5379348_1237533 (List.nth tup_s_5379345_1237505 (1:int), inner_cont_5379361_1237603)) + in + (zero_pb_5379336_1237457 (List.nth tup_s_5379345_1237505 (0:int), inner_cont_5379347_1237516)) + in + let _1236758: (int * ((int * ((int list) -> 'a)) -> 'a)) = ((internal_diff_core_wrap_add_5378834_1236637 0) [(-1:int); get_0_of_2 _5378976_1236550]) in + let rec comp_tup_pb__5379326_1237381 (((_5379331_1237414, _5379388_1237702) as _5379329_1237412): (int * ((int list) -> 'a))) = + let rec comp_tup_pb__cont_5379332_1237424 (__1237694 : (int list)) = + (tup_pb_5379333_1237441 (__1237694, _5379388_1237702)) + in + (get_1_of_2 _1236758 (_5379331_1237414, comp_tup_pb__cont_5379332_1237424)) + in + let rec tup_pb_5379325_1237364 ((((((_5379397_1237738, _5379409_1237810) as tup_s_5379395_1237736): (int * (int -> 'a))), tup_ret_cont_5379412_1237832) as _5379393_1237734): ((int * (int -> 'a)) * ((int list) -> 'a))) = + let rec inner_cont_5379398_1237748 (([_5379414_1237856; _5379422_1237889] as _5379413_1237855): (int list)) = + let rec inner_cont_5379410_1237820 (([_5379416_1237870; _5379423_1237896] as _5379415_1237869): (int list)) = + let _1237875: int = (_5379414_1237856 + _5379416_1237870) in + let _1237901: int = (_5379422_1237889 + _5379423_1237896) in + (tup_ret_cont_5379412_1237832 [_1237875; _1237901]) + in + (zero_pb_5379403_1237784 (get_1_of_2 tup_s_5379395_1237736, inner_cont_5379410_1237820)) + in + (comp_tup_pb__5379326_1237381 (get_0_of_2 tup_s_5379395_1237736, inner_cont_5379398_1237748)) + in + let rec aug_pow_else_5378772_1236571 _ = + (aug_f_5378771_1236401 ((get_0_of_2 _1236758, aug_pow_cont_5378985_1236770), tup_pb_5379325_1237364)) + in + let rec aug_pow_then_5379439_1237919 _ = + (get_1_of_2 _5378976_1236550 ((1:int), zero_pb_5379441_1237947)) + in + let _1236554: (int * ((int * ((int list) -> 'a)) -> 'a)) = (internal_diff_core_icmp_xyglE_5379505_1236469 [(0:int); get_0_of_2 _5378976_1236550]) in + (List.nth [aug_pow_else_5378772_1236571; aug_pow_then_5379439_1237919] (get_0_of_2 _1236554) ((), tup_pb_5379621_1237988)) + in + let rec aug_pow_cont_5379633_1238044 (((_5379638_1238086, _5379657_1238217) as _5379636_1238084): (int * ((int * ((int list) -> 'a)) -> 'a))) = + let rec tup_pb_5379650_1238160 ((((([_5379654_1238195; _5379658_1238233] as tup_s_5379653_1238194): (int list)), tup_ret_cont_5379661_1238255) as _5379651_1238192): ((int list) * ((int list) -> 'a))) = + let rec inner_cont_5379655_1238205 (([_5379663_1238279; _5379671_1238312] as _5379662_1238278): (int list)) = + let rec inner_cont_5379659_1238243 (([_5379665_1238293; _5379672_1238319] as _5379664_1238292): (int list)) = + let _1238298: int = (_5379663_1238279 + _5379665_1238293) in + let _1238324: int = (_5379671_1238312 + _5379672_1238319) in + (tup_ret_cont_5379661_1238255 [_1238298; _1238324]) + in + (_5379657_1238217 (List.nth tup_s_5379653_1238194 (1:int), inner_cont_5379659_1238243)) + in + (extract_pb_5379240_1237105 (List.nth tup_s_5379653_1238194 (0:int), inner_cont_5379655_1238205)) + in + let _1238088: (int * ((int * ((int list) -> 'a)) -> 'a)) = ((internal_diff_core_wrap_mul_5379044_1236824 0) [List.nth arg_5379202_1236294 (0:int); _5379638_1238086]) in + let rec comp_tup_pb__5379643_1238100 (((_5379648_1238133, _5379686_1238342) as _5379646_1238131): (int * ((int list) -> 'a))) = + let rec comp_tup_pb__cont_5379649_1238143 (__1238334 : (int list)) = + (tup_pb_5379650_1238160 (__1238334, _5379686_1238342)) + in + (get_1_of_2 _1238088 (_5379648_1238133, comp_tup_pb__cont_5379649_1238143)) + in + (_5379635_1238051 (get_0_of_2 _1238088, comp_tup_pb__5379643_1238100)) + in + let _1238032: (int * ((int * ((int list) -> 'a)) -> 'a)) = ((internal_diff_core_wrap_add_5378834_1236637 0) [(-1:int); List.nth arg_5379202_1236294 (1:int)]) in + let rec comp_tup_pb__5379695_1238376 (((_5379700_1238409, _5379745_1238655) as _5379698_1238407): (int * ((int list) -> 'a))) = + let rec comp_tup_pb__cont_5379701_1238419 (__1238647 : (int list)) = + (tup_pb_5379702_1238435 (__1238647, _5379745_1238655)) + in + (get_1_of_2 _1238032 (_5379700_1238409, comp_tup_pb__cont_5379701_1238419)) + in + let rec tup_pb_5379694_1238359 ((((((_5379754_1238691, _5379762_1238752) as tup_s_5379752_1238689): (int * (int -> 'a))), tup_ret_cont_5379765_1238774) as _5379750_1238687): ((int * (int -> 'a)) * ((int list) -> 'a))) = + let rec inner_cont_5379755_1238701 (([_5379767_1238798; _5379775_1238831] as _5379766_1238797): (int list)) = + let rec inner_cont_5379763_1238762 (([_5379769_1238812; _5379776_1238838] as _5379768_1238811): (int list)) = + let _1238817: int = (_5379767_1238798 + _5379769_1238812) in + let _1238843: int = (_5379775_1238831 + _5379776_1238838) in + (tup_ret_cont_5379765_1238774 [_1238817; _1238843]) + in + (zero_pb_5379756_1238717 (get_1_of_2 tup_s_5379752_1238689, inner_cont_5379763_1238762)) + in + (comp_tup_pb__5379695_1238376 (get_0_of_2 tup_s_5379752_1238689, inner_cont_5379755_1238701)) + in + let rec aug_pow_else_5378747_1236318 _ = + (aug_f_5378771_1236401 ((get_0_of_2 _1238032, aug_pow_cont_5379633_1238044), tup_pb_5379694_1238359)) + in + let rec aug_pow_then_5379790_1238861 _ = + (_5379635_1238051 ((1:int), zero_pb_5379441_1237947)) + in + let _1236300: int = (bool2bit ((0:int) = List.nth arg_5379202_1236294 (1:int))) in + (List.nth [aug_pow_else_5378747_1236318; aug_pow_then_5379790_1238861] _1236300 ((), tup_pb_5379621_1237988)) +(* external *) +let rec f_diffed (((__5379804_1238883, ret_5379854_1238947) as __5379802_1238881): ((int list) * ((int * (int list)) -> 'a))) = + let rec ret_cont_5379812_1238896 (((r_5379865_1238958, pb_5379826_1238918) as __5379824_1238916): (int * ((int * ((int list) -> 'a)) -> 'a))) = + let rec pb_ret_cont_5379841_1238940 (__1238959 : (int list)) = + (ret_5379854_1238947 (r_5379865_1238958, __1238959)) + in + (pb_5379826_1238918 ((1:int), pb_ret_cont_5379841_1238940)) + in + (f_deriv_5378732_1236202 (__5379804_1238883, ret_cont_5379812_1238896)) +(* external *) +let rec thorin_main (((mem_5381538_1239112, _, _, return_5381529_1239105) as __5381527_1239101): (unit * int * ((int option ref) option ref) * ((unit * int) -> 'a))) = + let rec ret_cont_5381499_1239059 (((r_5381571_1239143, pb_5381510_1239076) as __5381508_1239074): (int * ((int * ((int list) -> 'a)) -> 'a))) = + let rec pb_ret_cont_5381518_1239094 (([pr_a_5381612_1239193; pr_b_5381591_1239174] as __5381590_1239173): (int list)) = + let _1239150: int = ((10000:int) * r_5381571_1239143) in + let _1239200: int = ((100:int) * pr_a_5381612_1239193) in + let _1239205: int = (pr_b_5381591_1239174 + _1239200) in + let _1239210: int = (_1239150 + _1239205) in + (return_5381529_1239105 (mem_5381538_1239112, _1239210)) + in + (pb_5381510_1239076 ((1:int), pb_ret_cont_5381518_1239094)) + in + (f_deriv_5378732_1236202 ([(42:int); (3:int)], ret_cont_5381499_1239059)) diff --git a/lit/backend/ad/pow_ad_preopt_fixed.hs b/lit/backend/ad/pow_ad_preopt_fixed.hs new file mode 100644 index 0000000000..dcfad93662 --- /dev/null +++ b/lit/backend/ad/pow_ad_preopt_fixed.hs @@ -0,0 +1,198 @@ + +{-# LANGUAGE ScopedTypeVariables #-} +{-# OPTIONS_GHC -Wno-incomplete-patterns #-} +module Preopt where + +import Data.IORef +bool2bit x = if x then 1 else 0 +get_0_of_2 (x, _) = x +get_1_of_2 (_, x) = x +get_0_of_3 (x, _, _) = x +get_1_of_3 (_, x, _) = x +get_2_of_3 (_, _, x) = x +magic a = magic a + + +__5378927_1243805 ((__5378944_1243822@(i_5378954_1243835, pb_ret_5378946_1243824)):: (Int , ([Int] -> a))) = + (pb_ret_5378946_1243824 (replicate 2 i_5378954_1243835)) +internal_diff_core_wrap_add_5378834_1243729 (__1243777 :: Integer) = + let __5378884_1243750 ((__5378911_1243784@[_1243788, _1243792]):: [Int]) = + let _1243795 :: Int = (_1243788 + _1243792) in + (_1243795, __5378927_1243805) + in + __5378884_1243750 +internal_diff_core_wrap_mul_5379044_1243916 (__1243957 :: Integer) = + let __5379094_1243934 ((__5379122_1243965@[_1243969, _1243973]):: [Int]) = + let __5379138_1243986 ((__5379147_1244001@(i_5379162_1244026, pb_ret_5379149_1244003)):: (Int , ([Int] -> a))) = + let _1244031 :: Int = (_1243973 * i_5379162_1244026) in + let _1244050 :: Int = (_1243969 * i_5379162_1244026) in + (pb_ret_5379149_1244003 [_1244031, _1244050]) + in + let _1243976 :: Int = (_1243969 * _1243973) in + (_1243976, __5379138_1243986) + in + __5379094_1243934 +id_pb_5379243_1244212 ((_5379244_1244218@(s_5379249_1244223, _5379246_1244220)):: ([Int] , ([Int] -> a))) = + (_5379246_1244220 s_5379249_1244223) +extract_pb_5379240_1244197 ((_5379253_1244244@(s_5379255_1244246, _5379259_1244255)):: (Int , ([Int] -> a))) = + (id_pb_5379243_1244212 ([s_5379255_1244246, (0::Int)], _5379259_1244255)) +zero_pb_5379336_1244549 ((_5379337_1244564@(_, _5379339_1244566)):: (Int , ([Int] -> a))) = + (_5379339_1244566 (replicate 2 (0::Int))) +zero_pb_5379403_1244876 ((_5379404_1244882@(_, _5379406_1244884)):: ((Int -> a) , ([Int] -> a))) = + (_5379406_1244884 (replicate 2 (0::Int))) +zero_pb_5379441_1245039 ((_5379442_1245055@(_, _5379444_1245057)):: (Int , ([Int] -> a))) = + (_5379444_1245057 (replicate 2 (0::Int))) +__5379577_1243606 ((__5379586_1243625@(_, pb_ret_5379588_1243627)):: (Int , ([Int] -> a))) = + (pb_ret_5379588_1243627 (replicate 2 (0::Int))) +internal_diff_core_icmp_xyglE_5379505_1243563 ((__5379561_1243585@[_1243589, _1243593]):: [Int]) = + let _1243596 :: Int = (bool2bit (_1243589 == _1243593)) in + (_1243596, __5379577_1243606) +tup_pb_5379621_1245080 ((_5379622_1245087@(_, tup_ret_cont_5379624_1245089)):: (unit , ([Int] -> a))) = + (tup_ret_cont_5379624_1245089 (replicate 2 (0::Int))) +extract_pb_5379708_1245586 ((_5379709_1245610@(s_5379711_1245612, _5379714_1245621)):: (Int , ([Int] -> a))) = + (id_pb_5379243_1244212 ([(0::Int), s_5379711_1245612], _5379714_1245621)) +tup_pb_5379702_1245527 ((_5379703_1245558@(((tup_s_5379705_1245560@[_5379706_1245561, _5379717_1245639]):: [Int]), tup_ret_cont_5379720_1245661)):: ([Int] , ([Int] -> a))) = + let inner_cont_5379707_1245571 ((_5379721_1245683@[_5379722_1245684, _5379730_1245717]):: [Int]) = + let inner_cont_5379718_1245649 ((_5379723_1245697@[_5379724_1245698, _5379731_1245724]):: [Int]) = + let _1245703 :: Int = (_5379722_1245684 + _5379724_1245698) in + let _1245729 :: Int = (_5379730_1245717 + _5379731_1245724) in + (tup_ret_cont_5379720_1245661 [_1245703, _1245729]) + in + (extract_pb_5379708_1245586 (tup_s_5379705_1245560 !! (1::Int), inner_cont_5379718_1245649)) + in + (zero_pb_5379336_1244549 (tup_s_5379705_1245560 !! (0::Int), inner_cont_5379707_1245571)) +zero_pb_5379756_1245809 ((_5379757_1245824@(_, _5379759_1245826)):: ((Int -> a) , ([Int] -> a))) = + (_5379759_1245826 (replicate 2 (0::Int))) +f_deriv_5378732_1243296 ((_5379200_1243386@(((arg_5379202_1243388@[_5379203_1244064, _5379628_1243389]):: [Int]), _5379635_1245143)):: ([Int] , ((Int , ((Int , ([Int] -> a)) -> a)) -> a))) = + let aug_f_5378771_1243495 ((_5378974_1243642@(((_5378976_1243644@(_5378978_1243646, _5378987_1243869)):: (Int , ((Int , ((Int , ([Int] -> a)) -> a)) -> a))), _5379350_1244632)):: ((Int , ((Int , ((Int , ([Int] -> a)) -> a)) -> a)) , (((Int , (Int -> a)) , ([Int] -> a)) -> a))) = + let aug_pow_cont_5378985_1243862 ((_5379204_1244077@(_5379206_1244079, _5379270_1244310)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let tup_pb_5379234_1244179 ((_5379262_1244285@(((tup_s_5379264_1244287@[_5379265_1244288, _5379271_1244326]):: [Int]), tup_ret_cont_5379276_1244347)):: ([Int] , ([Int] -> a))) = + let inner_cont_5379268_1244298 ((_5379293_1244375@[_5379294_1244376, _5379302_1244409]):: [Int]) = + let inner_cont_5379272_1244335 ((_5379295_1244389@[_5379296_1244390, _5379303_1244416]):: [Int]) = + let _1244395 :: Int = (_5379294_1244376 + _5379296_1244390) in + let _1244421 :: Int = (_5379302_1244409 + _5379303_1244416) in + (tup_ret_cont_5379276_1244347 [_1244395, _1244421]) + in + (_5379270_1244310 (tup_s_5379264_1244287 !! (1::Int), inner_cont_5379272_1244335)) + in + (extract_pb_5379240_1244197 (tup_s_5379264_1244287 !! (0::Int), inner_cont_5379268_1244298)) + in + let _1244081 :: (Int , ((Int , ([Int] -> a)) -> a)) = ((internal_diff_core_wrap_mul_5379044_1243916 0) [arg_5379202_1243388 !! (0::Int), _5379206_1244079]) in + let comp_tup_pb__5379213_1244092 ((_5379216_1244122@(_5379218_1244124, _5379317_1244439)):: (Int , ([Int] -> a))) = + let comp_tup_pb__cont_5379224_1244137 (__1244431 :: [Int]) = + (tup_pb_5379234_1244179 (__1244431, _5379317_1244439)) + in + ((get_1_of_2 _1244081) (_5379218_1244124, comp_tup_pb__cont_5379224_1244137)) + in + ((get_1_of_2 _5378976_1243644) ((get_0_of_2 _1244081), comp_tup_pb__5379213_1244092)) + in + let extract_pb_5379348_1244625 ((_5379351_1244651@(s_5379353_1244653, _5379357_1244667)):: (Int , ([Int] -> a))) = + (_5379350_1244632 ((s_5379353_1244653, magic), _5379357_1244667)) + in + let tup_pb_5379333_1244533 ((_5379343_1244595@(((tup_s_5379345_1244597@[_5379346_1244598, _5379360_1244685]):: [Int]), tup_ret_cont_5379363_1244707)):: ([Int] , ([Int] -> a))) = + let inner_cont_5379347_1244608 ((_5379364_1244730@[_5379365_1244731, _5379373_1244764]):: [Int]) = + let inner_cont_5379361_1244695 ((_5379366_1244744@[_5379367_1244745, _5379374_1244771]):: [Int]) = + let _1244750 :: Int = (_5379365_1244731 + _5379367_1244745) in + let _1244776 :: Int = (_5379373_1244764 + _5379374_1244771) in + (tup_ret_cont_5379363_1244707 [_1244750, _1244776]) + in + (extract_pb_5379348_1244625 (tup_s_5379345_1244597 !! (1::Int), inner_cont_5379361_1244695)) + in + (zero_pb_5379336_1244549 (tup_s_5379345_1244597 !! (0::Int), inner_cont_5379347_1244608)) + in + let _1243850 :: (Int , ((Int , ([Int] -> a)) -> a)) = ((internal_diff_core_wrap_add_5378834_1243729 0) [(-1::Int), (get_0_of_2 _5378976_1243644)]) in + let comp_tup_pb__5379326_1244473 ((_5379329_1244504@(_5379331_1244506, _5379388_1244794)):: (Int , ([Int] -> a))) = + let comp_tup_pb__cont_5379332_1244516 (__1244786 :: [Int]) = + (tup_pb_5379333_1244533 (__1244786, _5379388_1244794)) + in + ((get_1_of_2 _1243850) (_5379331_1244506, comp_tup_pb__cont_5379332_1244516)) + in + let tup_pb_5379325_1244456 ((_5379393_1244826@(((tup_s_5379395_1244828@(_5379397_1244830, _5379409_1244902)):: (Int , (Int -> a))), tup_ret_cont_5379412_1244924)):: ((Int , (Int -> a)) , ([Int] -> a))) = + let inner_cont_5379398_1244840 ((_5379413_1244947@[_5379414_1244948, _5379422_1244981]):: [Int]) = + let inner_cont_5379410_1244912 ((_5379415_1244961@[_5379416_1244962, _5379423_1244988]):: [Int]) = + let _1244967 :: Int = (_5379414_1244948 + _5379416_1244962) in + let _1244993 :: Int = (_5379422_1244981 + _5379423_1244988) in + (tup_ret_cont_5379412_1244924 [_1244967, _1244993]) + in + (zero_pb_5379403_1244876 ((get_1_of_2 tup_s_5379395_1244828), inner_cont_5379410_1244912)) + in + (comp_tup_pb__5379326_1244473 ((get_0_of_2 tup_s_5379395_1244828), inner_cont_5379398_1244840)) + in + let aug_pow_else_5378772_1243665 _ = + (aug_f_5378771_1243495 (((get_0_of_2 _1243850), aug_pow_cont_5378985_1243862), tup_pb_5379325_1244456)) + in + let aug_pow_then_5379439_1245011 _ = + ((get_1_of_2 _5378976_1243644) ((1::Int), zero_pb_5379441_1245039)) + in + let _1243648 :: (Int , ((Int , ([Int] -> a)) -> a)) = (internal_diff_core_icmp_xyglE_5379505_1243563 [(0::Int), (get_0_of_2 _5378976_1243644)]) in + (([aug_pow_else_5378772_1243665, aug_pow_then_5379439_1245011] !! (get_0_of_2 _1243648)) ((), tup_pb_5379621_1245080)) + in + let aug_pow_cont_5379633_1245136 ((_5379636_1245176@(_5379638_1245178, _5379657_1245309)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let tup_pb_5379650_1245252 ((_5379651_1245284@(((tup_s_5379653_1245286@[_5379654_1245287, _5379658_1245325]):: [Int]), tup_ret_cont_5379661_1245347)):: ([Int] , ([Int] -> a))) = + let inner_cont_5379655_1245297 ((_5379662_1245370@[_5379663_1245371, _5379671_1245404]):: [Int]) = + let inner_cont_5379659_1245335 ((_5379664_1245384@[_5379665_1245385, _5379672_1245411]):: [Int]) = + let _1245390 :: Int = (_5379663_1245371 + _5379665_1245385) in + let _1245416 :: Int = (_5379671_1245404 + _5379672_1245411) in + (tup_ret_cont_5379661_1245347 [_1245390, _1245416]) + in + (_5379657_1245309 (tup_s_5379653_1245286 !! (1::Int), inner_cont_5379659_1245335)) + in + (extract_pb_5379240_1244197 (tup_s_5379653_1245286 !! (0::Int), inner_cont_5379655_1245297)) + in + let _1245180 :: (Int , ((Int , ([Int] -> a)) -> a)) = ((internal_diff_core_wrap_mul_5379044_1243916 0) [arg_5379202_1243388 !! (0::Int), _5379638_1245178]) in + let comp_tup_pb__5379643_1245192 ((_5379646_1245223@(_5379648_1245225, _5379686_1245434)):: (Int , ([Int] -> a))) = + let comp_tup_pb__cont_5379649_1245235 (__1245426 :: [Int]) = + (tup_pb_5379650_1245252 (__1245426, _5379686_1245434)) + in + ((get_1_of_2 _1245180) (_5379648_1245225, comp_tup_pb__cont_5379649_1245235)) + in + (_5379635_1245143 ((get_0_of_2 _1245180), comp_tup_pb__5379643_1245192)) + in + let _1245124 :: (Int , ((Int , ([Int] -> a)) -> a)) = ((internal_diff_core_wrap_add_5378834_1243729 0) [(-1::Int), arg_5379202_1243388 !! (1::Int)]) in + let comp_tup_pb__5379695_1245468 ((_5379698_1245499@(_5379700_1245501, _5379745_1245747)):: (Int , ([Int] -> a))) = + let comp_tup_pb__cont_5379701_1245511 (__1245739 :: [Int]) = + (tup_pb_5379702_1245527 (__1245739, _5379745_1245747)) + in + ((get_1_of_2 _1245124) (_5379700_1245501, comp_tup_pb__cont_5379701_1245511)) + in + let tup_pb_5379694_1245451 ((_5379750_1245779@(((tup_s_5379752_1245781@(_5379754_1245783, _5379762_1245844)):: (Int , (Int -> a))), tup_ret_cont_5379765_1245866)):: ((Int , (Int -> a)) , ([Int] -> a))) = + let inner_cont_5379755_1245793 ((_5379766_1245889@[_5379767_1245890, _5379775_1245923]):: [Int]) = + let inner_cont_5379763_1245854 ((_5379768_1245903@[_5379769_1245904, _5379776_1245930]):: [Int]) = + let _1245909 :: Int = (_5379767_1245890 + _5379769_1245904) in + let _1245935 :: Int = (_5379775_1245923 + _5379776_1245930) in + (tup_ret_cont_5379765_1245866 [_1245909, _1245935]) + in + (zero_pb_5379756_1245809 ((get_1_of_2 tup_s_5379752_1245781), inner_cont_5379763_1245854)) + in + (comp_tup_pb__5379695_1245468 ((get_0_of_2 tup_s_5379752_1245781), inner_cont_5379755_1245793)) + in + let aug_pow_else_5378747_1243412 _ = + (aug_f_5378771_1243495 (((get_0_of_2 _1245124), aug_pow_cont_5379633_1245136), tup_pb_5379694_1245451)) + in + let aug_pow_then_5379790_1245953 _ = + (_5379635_1245143 ((1::Int), zero_pb_5379441_1245039)) + in + let _1243394 :: Int = (bool2bit ((0::Int) == arg_5379202_1243388 !! (1::Int))) in + (([aug_pow_else_5378747_1243412, aug_pow_then_5379790_1245953] !! _1243394) ((), tup_pb_5379621_1245080)) +-- external +f_diffed ((__5379802_1245973@(__5379804_1245975, ret_5379854_1246039)):: ([Int] , ((Int , [Int]) -> a))) = + let ret_cont_5379812_1245988 ((__5379824_1246008@(r_5379865_1246050, pb_5379826_1246010)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let pb_ret_cont_5379841_1246032 (__1246051 :: [Int]) = + (ret_5379854_1246039 (r_5379865_1246050, __1246051)) + in + (pb_5379826_1246010 ((1::Int), pb_ret_cont_5379841_1246032)) + in + (f_deriv_5378732_1243296 (__5379804_1245975, ret_cont_5379812_1245988)) +-- external +thorin_main ((__5381527_1246193@(mem_5381538_1246204, _, _, return_5381529_1246197)):: (unit , Int , (IORef (IORef Int)) , ((unit , Int) -> a))) = + let ret_cont_5381499_1246151 ((__5381508_1246166@(r_5381571_1246235, pb_5381510_1246168)):: (Int , ((Int , ([Int] -> a)) -> a))) = + let pb_ret_cont_5381518_1246186 ((__5381590_1246265@[pr_a_5381612_1246285, pr_b_5381591_1246266]):: [Int]) = + let _1246242 :: Int = ((10000::Int) * r_5381571_1246235) in + let _1246292 :: Int = ((100::Int) * pr_a_5381612_1246285) in + let _1246297 :: Int = (pr_b_5381591_1246266 + _1246292) in + let _1246302 :: Int = (_1246242 + _1246297) in + (return_5381529_1246197 (mem_5381538_1246204, _1246302)) + in + (pb_5381510_1246168 ((1::Int), pb_ret_cont_5381518_1246186)) + in + (f_deriv_5378732_1243296 ([(42::Int), (3::Int)], ret_cont_5381499_1246151)) diff --git a/lit/backend/ad/timing_hs/.devcontainer/.ghci b/lit/backend/ad/timing_hs/.devcontainer/.ghci new file mode 100644 index 0000000000..ce42ab8d9a --- /dev/null +++ b/lit/backend/ad/timing_hs/.devcontainer/.ghci @@ -0,0 +1,34 @@ +:set prompt "\ESC[94m\STX \ESC[m\STX" +:set prompt-cont "\ESC[1;32mλ| \ESC[m" +:set +t +:set +m +:set +s + +:set editor emacs + +:set -Wall +:set -ferror-spans +:set -freverse-errors +:set -fprint-expanded-synonyms +:set -fprint-explicit-foralls +:set -fprint-explicit-kinds +:set -ignore-package pretty-simple -package pretty-simple +-- :set -fobject-code + +:seti -XFlexibleContexts +:seti -XFlexibleInstances +:seti -XOverloadedStrings +:seti -XGADTSyntax +:seti -XGeneralizedNewtypeDeriving +:seti -XInstanceSigs +:seti -XLambdaCase +:seti -XPartialTypeSignatures +:seti -XScopedTypeVariables +:seti -XPolyKinds +:seti -XDataKinds +:seti -XTypeApplications +:seti -XTypeApplications + +:def hlint const . return $ ":! hlint \"src\"" +:def hoogle \s -> return $ ":! hoogle --count=15 \"" ++ s ++ "\"" +:def package \ m -> return $ ":! ghc-pkg --simple-output find-module " ++ m \ No newline at end of file diff --git a/lit/backend/ad/timing_hs/.devcontainer/Dockerfile b/lit/backend/ad/timing_hs/.devcontainer/Dockerfile new file mode 100644 index 0000000000..e4c5788ec6 --- /dev/null +++ b/lit/backend/ad/timing_hs/.devcontainer/Dockerfile @@ -0,0 +1,98 @@ +FROM debian as base + +ARG USERNAME=vscode +ARG GHC_VERSION=9.0.2 +ARG STACK_VERSION=2.7.5 +ARG STACK_RESOLVER=lts-19.16 +ARG CABAL_VERSION=3.4.1.0 +ARG HLS_VERSION=1.7.0.0 +ARG LLVM_VERSION=12 + +ENV USERNAME=${USERNAME} \ + USER_UID=2001 \ + USER_GID=2001 \ + DEBIAN_FRONTEND=noninteractive \ + GHC_VERSION=${GHC_VERSION} \ + STACK_RESOLVER=${STACK_RESOLVER} \ + STACK_VERSION=${STACK_VERSION} \ + CABAL_VERSION=${CABAL_VERSION} \ + HLS_VERSION=${HLS_VERSION} \ + LLVM_VERSION=${LLVM_VERSION} + +RUN ulimit -n 8192 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends apt-utils bash build-essential ca-certificates curl gcc git gnupg libffi-dev libffi7 libgmp-dev libgmp-dev libgmp10 libicu-dev libncurses-dev libncurses5 libnuma1 libnuma-dev libtinfo5 lsb-release make procps software-properties-common sudo wget xz-utils z3 zlib1g-dev + +RUN wget -O /tmp/llvm.sh https://apt.llvm.org/llvm.sh && chmod +x /tmp/llvm.sh && /tmp/llvm.sh ${LLVM_VERSION} && rm /tmp/llvm.sh + +RUN groupadd --gid $USER_GID $USERNAME && \ + useradd -ms /bin/bash -K MAIL_DIR=/dev/null --uid $USER_UID --gid $USER_GID -m $USERNAME && \ + echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME && \ + chmod 0440 /etc/sudoers.d/$USERNAME + +USER ${USER_UID}:${USER_GID} +WORKDIR /home/${USERNAME} +ENV PATH="/home/${USERNAME}/.local/bin:/home/${USERNAME}/.cabal/bin:/home/${USERNAME}/.ghcup/bin:$PATH" + +RUN echo "export PATH=$PATH" >> /home/$USERNAME/.profile + +ENV BOOTSTRAP_HASKELL_NONINTERACTIVE=yes \ + BOOTSTRAP_HASKELL_NO_UPGRADE=yes + +FROM base as tooling + +RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh + +# Set the GHC version. +RUN ghcup install ghc ${GHC_VERSION} && ghcup set ghc ${GHC_VERSION} + +# Install cabal-iinstall +RUN ghcup install cabal ${CABAL_VERSION} && ghcup set cabal ${CABAL_VERSION} + +# Update Cabal. +RUN cabal update && cabal new-install cabal-install + +# Configure cabal +RUN cabal user-config update -f && \ + sed -i 's/-- ghc-options:/ghc-options: -haddock/g' ~/.cabal/config + +# Install stack +RUN ghcup install stack ${STACK_VERSION} && ghcup set stack ${STACK_VERSION} + +# Set system-ghc, install-ghc and resolver for stack. +RUN ((stack ghc -- --version 2>/dev/null) || true) && \ + # Set global defaults for stack. + stack config --system-ghc set system-ghc true --global && \ + stack config --system-ghc set install-ghc false --global && \ + stack config --system-ghc set resolver $STACK_RESOLVER + +# Set global custom defaults for stack. +RUN printf "ghc-options:\n \"\$everything\": -haddock\n" >> /home/${USERNAME}/.stack/config.yaml + +# Install hls +RUN ghcup install hls ${HLS_VERSION} && ghcup set hls ${HLS_VERSION} + +FROM tooling as packages + +# Install global packages. +# Versions are pinned, since we don't want to accidentally break anything (by always installing latest). +RUN cabal install --haddock-hoogle \ + fsnotify-0.3.0.1 \ + haskell-dap-0.0.15.0 \ + ghci-dap-0.0.17.0 \ + haskell-debug-adapter-0.0.35.0 \ + hlint-3.3.6 \ + apply-refact-0.9.3.0 \ + retrie-1.1.0.0 \ + hoogle-5.0.18.3 \ + ormolu-0.3.1.0 + +FROM packages as hoogle + +# Generate hoogle db +RUN hoogle generate && stack hoogle + +ENV DEBIAN_FRONTEND=dialog + +ENTRYPOINT ["/bin/bash"] diff --git a/lit/backend/ad/timing_hs/.devcontainer/devcontainer.json b/lit/backend/ad/timing_hs/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..54af78f088 --- /dev/null +++ b/lit/backend/ad/timing_hs/.devcontainer/devcontainer.json @@ -0,0 +1,91 @@ +{ + "name": "DevContainer for Haskell (GHC, Stack, Cabal, HIE, LSP, DAP, etc.)", + "remoteUser": "vscode", + "runArgs": [], + "build": { + "args": { + "USERNAME": "vscode", + "GHC_VERSION": "9.0.2", + "STACK_VERSION": "2.7.5", + "STACK_RESOLVER": "lts-19.16", + "CABAL_VERSION": "3.6.2.0", + "HLS_VERSION": "1.7.0.0", + "LLVM_VERSION": "12" + }, + "context": "..", + "dockerfile": "Dockerfile" + }, + "extensions": [ + "haskell.haskell", + "phoityne.phoityne-vscode", + "eriksik2.vscode-ghci", + "jcanero.hoogle-vscode" + ], + "settings": { + "files.exclude": { + "**/*.olean": true, + "**/.DS_Store": true, + "**/.git": true, + "**/.hg": true, + "**/.svn": true, + "**/CVS": true + }, + "haskell.checkProject": true, + "haskell.formattingProvider": "ormolu", + "haskell.indentationRules.enabled": true, + "haskell.liquidOn": false, + "haskell.manageHLS": "GHCup", + "haskell.maxCompletions": 40, + "haskell.openDocumentationInHackage": false, + "haskell.openSourceInHackage": false, + "haskell.plugin.alternateNumberFormat.globalOn": true, + "haskell.plugin.callHierarchy.globalOn": true, + "haskell.plugin.changeTypeSignature.globalOn": true, + "haskell.plugin.class.globalOn": true, + "haskell.plugin.eval.config.diff": true, + "haskell.plugin.eval.config.exception": true, + "haskell.plugin.eval.globalOn": true, + "haskell.plugin.ghcide-code-actions-bindings.globalOn": true, + "haskell.plugin.ghcide-code-actions-fill-holes.globalOn": true, + "haskell.plugin.ghcide-code-actions-imports-exports.globalOn": true, + "haskell.plugin.ghcide-code-actions-type-signatures.globalOn": true, + "haskell.plugin.ghcide-completions.config.autoExtendOn": true, + "haskell.plugin.ghcide-completions.config.snippetsOn": true, + "haskell.plugin.ghcide-completions.globalOn": true, + "haskell.plugin.ghcide-hover-and-symbols.hoverOn": true, + "haskell.plugin.ghcide-hover-and-symbols.symbolsOn": true, + "haskell.plugin.ghcide-type-lenses.config.mode": "always", + "haskell.plugin.ghcide-type-lenses.globalOn": true, + "haskell.plugin.haddockComments.globalOn": true, + "haskell.plugin.hlint.codeActionsOn": true, + "haskell.plugin.hlint.config.flags": [], + "haskell.plugin.hlint.diagnosticsOn": true, + "haskell.plugin.importLens.codeActionsOn": true, + "haskell.plugin.importLens.codeLensOn": true, + "haskell.plugin.moduleName.globalOn": true, + "haskell.plugin.pragmas.codeActionsOn": true, + "haskell.plugin.pragmas.completionOn": true, + "haskell.plugin.qualifyImportedNames.globalOn": true, + "haskell.plugin.refineImports.codeActionsOn": true, + "haskell.plugin.refineImports.codeLensOn": true, + "haskell.plugin.refineImports.globalOn": true, + "haskell.plugin.rename.config.crossModule": true, + "haskell.plugin.rename.globalOn": true, + "haskell.plugin.retrie.globalOn": true, + "haskell.plugin.splice.globalOn": true, + "haskell.plugin.tactic.config.max_use_ctor_actions": 5, + "haskell.plugin.tactics.codeActionsOn": true, + "haskell.plugin.tactics.codeLensOn": true, + "haskell.plugin.tactics.config.auto_gas": 4, + "haskell.plugin.tactics.config.hole_severity": "hint", + "haskell.plugin.tactics.config.max_use_ctor_actions": 5, + "haskell.plugin.tactics.config.proofstate_styling": true, + "haskell.plugin.tactics.config.timeout_duration": 5, + "haskell.plugin.tactics.globalOn": true, + "haskell.plugin.tactics.hoverOn": true, + "haskell.trace.client": "error", + "haskell.trace.server": "off", + "haskell.upgradeGHCup": true, + "hoogle-vscode.useCabalDependencies": true + } +} \ No newline at end of file diff --git a/lit/backend/ad/timing_hs/.vscode/tasks.json b/lit/backend/ad/timing_hs/.vscode/tasks.json new file mode 100644 index 0000000000..c7efda6e91 --- /dev/null +++ b/lit/backend/ad/timing_hs/.vscode/tasks.json @@ -0,0 +1,50 @@ + +{ + // Automatically created by phoityne-vscode extension. + + "version": "2.0.0", + "presentation": { + "reveal": "always", + "panel": "new" + }, + "tasks": [ + { + // F7 + "group": { + "kind": "build", + "isDefault": true + }, + "label": "haskell build", + "type": "shell", + //"command": "cabal configure && cabal build" + "command": "stack build" + }, + { + // F6 + "group": "build", + "type": "shell", + "label": "haskell clean & build", + //"command": "cabal clean && cabal configure && cabal build" + "command": "stack clean && stack build" + //"command": "stack clean ; stack build" // for powershell + }, + { + // F8 + "group": { + "kind": "test", + "isDefault": true + }, + "type": "shell", + "label": "haskell test", + //"command": "cabal test" + "command": "stack test" + }, + { + // F6 + "isBackground": true, + "type": "shell", + "label": "haskell watch", + "command": "stack build --test --no-run-tests --file-watch" + } + ] +} diff --git a/lit/backend/ad/timing_hs/Opt.hs b/lit/backend/ad/timing_hs/Opt.hs new file mode 120000 index 0000000000..fd89a734c4 --- /dev/null +++ b/lit/backend/ad/timing_hs/Opt.hs @@ -0,0 +1 @@ +../pow_ad_fix.hs \ No newline at end of file diff --git a/lit/backend/ad/timing_hs/Preopt.hs b/lit/backend/ad/timing_hs/Preopt.hs new file mode 120000 index 0000000000..0d218ff6ac --- /dev/null +++ b/lit/backend/ad/timing_hs/Preopt.hs @@ -0,0 +1 @@ +../pow_ad_preopt_fixed.hs \ No newline at end of file diff --git a/lit/backend/ad/timing_hs/Result.txt b/lit/backend/ad/timing_hs/Result.txt new file mode 100644 index 0000000000..0f55ab5cb0 --- /dev/null +++ b/lit/backend/ad/timing_hs/Result.txt @@ -0,0 +1,11 @@ +Deepseq: +CPU time: 0.51s +CPU time: 0.86s + +All sum: +CPU time: 0.61s +CPU time: 1.04s + +Zero grad sum: +CPU time: 0.36s +CPU time: 0.58s diff --git a/lit/backend/ad/timing_hs/run.sh b/lit/backend/ad/timing_hs/run.sh new file mode 100755 index 0000000000..7c1e6a7d46 --- /dev/null +++ b/lit/backend/ad/timing_hs/run.sh @@ -0,0 +1,8 @@ +ghc --make test.hs -o test.out +ghc -O3 --make test.hs -o test_O3.out +echo "Running test.out" +./test.out +echo "Running test_O3.out" +./test_O3.out +# rm -f test *.hi *.o +rm -f *.hi *.o diff --git a/lit/backend/ad/timing_hs/test.hs b/lit/backend/ad/timing_hs/test.hs new file mode 100644 index 0000000000..2edd0d6170 --- /dev/null +++ b/lit/backend/ad/timing_hs/test.hs @@ -0,0 +1,122 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE ViewPatterns #-} +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# HLINT ignore "Use camelCase" #-} + +import Control.DeepSeq +import Opt +import Preopt +import System.CPUTime +import System.TimeIt +import Control.Monad.IO.Class (MonadIO(liftIO)) +import Text.Printf + +-- time (def "" -> name) f x = do +-- let start_time = get_time () +-- let y = f x +-- let end_time = get_time () +-- let time = end_time - start_time +-- print (name, time) +-- return y + +pow_manual :: (Int, Int) -> Int +pow_manual (a, 0) = 1 +pow_manual (a, b) = a * pow_manual (a, b - 1) + +-- f_diffed_hs :: (Int, Int) -> (Int, (Int, Int)) +-- f_diffed_hs (a, b) = (a ^ b, (b * a ^ (b - 1), 0)) + +tests = + [ ((i * 37 + 12) `mod` 10000, (i `mod` 100) + 1) + | i <- [1 .. 100000] + ] + +timeItNamed :: MonadIO m => String -> m a -> m a +timeItNamed name ioa = do + (t, a) <- timeItT ioa + liftIO $ printf ("%10s: %6.4fs\n") name t + return a + +test tests name f = + -- do + -- start <- getCPUTime + -- let !r = foo inputList + -- end <- getCPUTime + -- let diff = end - start in + -- print "Execution time: " diff + -- -- return (end - start) + Main.timeItNamed name $ + ( -- let !r = (map f tests) in + -- let !r = sum (map (\t -> let !(a,(b,x)) = f t in a+b+x) tests) in + -- let !r = sum (map (\t -> let !(a,(b,x)) = f t in x) tests) in + let r = (map (\t -> f t) tests) + in r `deepseq` (return ()) + -- print r + ) + +wrap f (a, b) = + let (r, [da, db]) = f ([a, b], id) + in (r, (da, db)) + +pow_full_pe :: (Int, Int) -> (Int, (Int, Int)) +pow_full_pe (a, b) = (pow_manual (a, b), (b * pow_manual (a, b - 1), 0)) + +zero_pb :: Int -> (Int, Int) +zero_pb = \_ -> (0, 0) + +pair_sum :: (Int, Int) -> (Int, Int) -> (Int, Int) +pair_sum (a, b) (c, d) = (a + c, b + d) + +app_pb f (a, a_pb) = let (r, r_pb) = f a in (r, \s -> a_pb (r_pb s)) + +tup_pb (a, a_pb) (b, b_pb) = ((a, b), \(s1, s2) -> pair_sum (a_pb s1) (b_pb s2)) + +mul_diffed :: (Int, Int) -> (Int, Int -> (Int, Int)) +mul_diffed (a, b) = (a * b, \s -> (b * s, a * s)) + +sub_diffed :: (Int, Int) -> (Int, Int -> (Int, Int)) +sub_diffed (a, b) = (a - b, \s -> (s, -s)) + +const_diffed :: Int -> (Int, Int -> (Int, Int)) +const_diffed c = (c, zero_pb) + +pow_hs_r :: (Int, Int) -> (Int, Int -> (Int, Int)) +pow_hs_r (a, 0) = const_diffed 1 +pow_hs_r (a, b) = + let a' = (a, \s -> (s, 0)) in + let b' = (b, \s -> (0, s)) in + let bo' = tup_pb b' (const_diffed 1) in + let r1' = app_pb sub_diffed bo' in + let t1' = tup_pb a' r1' in + let r2' = app_pb pow_hs_r t1' in + let t2' = tup_pb a' r2' in + app_pb mul_diffed t2' + +pow_hs :: (Int, Int) -> (Int, (Int, Int)) +pow_hs arg = let (r, r_pb) = pow_hs_r arg in (r, r_pb 1) + +pow_pe_r :: (Int, Int) -> (Int, Int -> (Int, Int)) +pow_pe_r (a, 0) = const_diffed 1 +pow_pe_r (a, b) = + let (r, r_pb) = pow_pe_r (a, b - 1) in + ( + a * r, + \s -> + -- let (da, db) = r_pb s in + -- (r+a*da, 0) + let (da, db) = r_pb (s*a) in + (s*r+da, db) + ) + +pow_pe :: (Int, Int) -> (Int, (Int, Int)) +pow_pe arg = let (r, r_pb) = pow_pe_r arg in (r, r_pb 1) + +main = do + test tests "PreOpt" (wrap Preopt.f_diffed) + test tests "Opt" (wrap Opt.f_diffed) + test tests "Manual" pow_hs + test tests "PE" pow_pe + test tests "FullPE" pow_full_pe + +-- print (wrap Opt.f_diffed (42, 2)) diff --git a/lit/backend/ad/timing_ml/Makefile b/lit/backend/ad/timing_ml/Makefile new file mode 100644 index 0000000000..b12167d5ab --- /dev/null +++ b/lit/backend/ad/timing_ml/Makefile @@ -0,0 +1,23 @@ +all: compile run cleanup + +FILES=preopt.ml opt.ml test.ml + + +test.out: + ocamlc -o test.out ${FILES} +test_opt.out: + ocamlopt -o test_opt.out ${FILES} +test_opt3.out: + ocamlopt -O3 -o test_opt3.out ${FILES} +compile: test.out test_opt.out test_opt3.out + +run: test.out test_opt.out test_opt3.out + ./test.out + ./test_opt.out + ./test_opt3.out + +cleanup: + rm -f *.cmo *.cmi *.out *.o *.cmx + + + diff --git a/lit/backend/ad/timing_ml/Result.txt b/lit/backend/ad/timing_ml/Result.txt new file mode 100644 index 0000000000..82c3056283 --- /dev/null +++ b/lit/backend/ad/timing_ml/Result.txt @@ -0,0 +1,9 @@ +./test.out +Execution time PreOpt: 2.510529s +Execution time Opt: 0.800442s +./test_opt.out +Execution time PreOpt: 0.271631s +Execution time Opt: 0.072939s +./test_opt3.out +Execution time PreOpt: 0.262393s +Execution time Opt: 0.071822s diff --git a/lit/backend/ad/timing_ml/opt.ml b/lit/backend/ad/timing_ml/opt.ml new file mode 120000 index 0000000000..64176ab978 --- /dev/null +++ b/lit/backend/ad/timing_ml/opt.ml @@ -0,0 +1 @@ +../pow_ad.thorin.ml \ No newline at end of file diff --git a/lit/backend/ad/timing_ml/preopt.ml b/lit/backend/ad/timing_ml/preopt.ml new file mode 120000 index 0000000000..ce21d28118 --- /dev/null +++ b/lit/backend/ad/timing_ml/preopt.ml @@ -0,0 +1 @@ +../pow_ad_preopt_fix.ml \ No newline at end of file diff --git a/lit/backend/ad/timing_ml/test.ml b/lit/backend/ad/timing_ml/test.ml new file mode 100644 index 0000000000..7854885b3f --- /dev/null +++ b/lit/backend/ad/timing_ml/test.ml @@ -0,0 +1,132 @@ + +let time ?(name="") f x = + let t = Sys.time() in + let fx = f x in + Printf.printf "Execution time %10s: %fs\n" name (Sys.time() -. t); + fx + + +let auto_tests = + List.init 100000 (fun i -> ((i*37+12) mod 10000, (i mod 100) + 1)) + + +let test tests s f = + (* let r = time ~name:s (fun _ -> List.iter (fun t -> ignore (f t)) tests) () in *) + let r = time ~name:s (fun _ -> List.map f tests) () in + (* ignore r *) + let _,oc = Filename.open_temp_file "tmp" "txt" in + List.iter (fun (r,(da,db)) -> Printf.fprintf oc "%d %d %d\n" r da db) r; + close_out oc; + () + +let[@warning "-partial-match"] wrap f (a,b) = + let (r,[da;db]) = f ([a;b], Fun.id) in (r,(da,db)) + +let rec pow_manual (a,b) = + if b = 0 then 1 else a * pow_manual (a,b-1) + +let pow_ml_full_pe (a,b) = ( + pow_manual (a,b), + (b*pow_manual (a,b-1), 0) +) + +let zero_pb = fun _ -> (0,0) +let pair_sum (da,db) (da',db') = (da+da', db+db') +let app_pb f (a, a_pb) = + let r, r_pb = f a in + (r, fun s -> a_pb (r_pb s)) +let tup_pb (a,a_pb) (b,b_pb) = (a,b), fun (s1,s2) -> pair_sum (a_pb s1) (b_pb s2) +let mul_diffed (a,b) = (a*b, fun s -> (s*b, s*a)) +let sub_diffed (a,b) = (a-b, fun s -> (s, -s)) +let const_diffed c = (c, zero_pb) +(* let mul_diffed (a',b') = + let t' = tup_pb a' b' in + app_pb mul_diffed t' *) + + +let rec pow_ml_r (a,b) = + match b with + | 0 -> const_diffed 1 + | _ -> + (* + let r1 = b-1 + let r2 = pow (a,r1) + let r3 = a * r2 + + + let bo = (b,1) + let r1 = sub b,1 + let t1 = (a,r1) + let r2 = pow t1 + let t2 = (a,r2) + let r3 = mul t2 + *) + let a' = (a, fun s -> (s,0)) in + let b' = (b, fun s -> (0,s)) in + let bo' = tup_pb b' (const_diffed 1) in + let r1' = app_pb sub_diffed bo' in + let t1' = tup_pb a' r1' in + let r2' = app_pb pow_ml_r t1' in + let t2' = tup_pb a' r2' in + app_pb mul_diffed t2' + + (* let (r,pb) = pow_ml (a,b-1) in *) +(* +let rec pow_ml (a,b) = + match b with + | 0 -> (1, fun _ -> (0,0)) + | _ -> + let a' = (a, fun _ -> (1,0)) in + let b' = (b, fun _ -> (0,1)) in + let bo' = sub_diff (b, 1) in + let r' = app_pb pow_ml *) + (* let (r,pb) = pow_ml (a,b-1) in *) + + +let rec pow_ml_pe_r (a,b) = + match b with + | 0 -> const_diffed 1 + | _ -> + let r,pb = pow_ml_pe_r (a,b-1) in + ( + a*r, + fun s -> + (* let (da,db) = pb s in + (r+a*da,0) *) + let (da,db) = pb (s*a) in + (s*r+da,db) + ) + +let pow_ml arg = + let (r,pb) = pow_ml_r arg in + (r, pb 1) + +let pow_ml_pe arg = + let (r,pb) = pow_ml_pe_r arg in + (r, pb 1) + +(* let () = + let (r,(da,db)) = pow_ml (42, 3) in + Printf.printf "r: %d, da: %d, db: %d\n" r da db; + let (r,(da,db)) = pow_ml_pe (42, 3) in + Printf.printf "r: %d, da: %d, db: %d\n" r da db *) +(* let () = + let (r,(da,db)) = pow (42, 3) in + Printf.printf "r: %d, da: %d, db: %d\n" r da db; + let (r,(da,db)) = pow_ml (42, 3) in + Printf.printf "r: %d, da: %d, db: %d\n" r da db; + let (r,(da,db)) = pow_ml_pe (42, 3) in + Printf.printf "r: %d, da: %d, db: %d\n" r da db *) + + + +let pow = wrap Opt.f_diffed +let pow_preopt = wrap Preopt.f_diffed + +let () = + test auto_tests "PreOpt" pow_preopt; + test auto_tests "Opt" pow; + test auto_tests "Manual" pow_ml; + test auto_tests "PE" pow_ml_pe; + test auto_tests "FullPE" pow_ml_full_pe + diff --git a/lit/backend/ad/timing_rs/.gitignore b/lit/backend/ad/timing_rs/.gitignore new file mode 100644 index 0000000000..e58354c0dc --- /dev/null +++ b/lit/backend/ad/timing_rs/.gitignore @@ -0,0 +1,3 @@ +./**/target/ +Cargo.lock +Result.txt diff --git a/lit/backend/ad/timing_rs/test2/Cargo.toml b/lit/backend/ad/timing_rs/test2/Cargo.toml new file mode 100644 index 0000000000..5ece822863 --- /dev/null +++ b/lit/backend/ad/timing_rs/test2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/lit/backend/ad/timing_rs/test2/src/main.rs b/lit/backend/ad/timing_rs/test2/src/main.rs new file mode 100644 index 0000000000..65cf45f35e --- /dev/null +++ b/lit/backend/ad/timing_rs/test2/src/main.rs @@ -0,0 +1,47 @@ +fn add_tuple(n: i32, ab: (i32, i32)) -> i32 { + ab.0 + ab.1 +} +fn add_tuple2((ab @ (a, b)): (i32, i32)) -> i32 { + a + ab.1 +} +fn add_list([a, b]: [i32; 2]) -> i32 { + a + b +} +fn sum_list(n: i32, xs: &[i32]) -> i32 { + if n == 0 { + 0 + } else { + add_list([xs[0], sum_list(n - 1, &xs[1..])]) + } +} +// fn sum_list2(n: i32, xs: [i32; n]) -> i32 { +// 42 << 2 +// } + +fn bool2bit(b: bool) -> i32 { + if b { + 1 + } else { + 0 + } +} + +fn fortyTwo() -> [i32; 5] { + [42; 5] +} + +fn cps(a: i32, ret: Box T>) -> T { + ret(a) +} + +fn add_tuple3((ab @ (a, b)): (i32, Box i32>)) -> i32 { + b(a) +} + +// fn f_1172768(((af@(a, ret)): (i32 , Box T>))) -> T { +// ret a +// } + +fn main() { + println!("Hello, world!"); +} diff --git a/lit/backend/ad/timing_rs/test3/Cargo.toml b/lit/backend/ad/timing_rs/test3/Cargo.toml new file mode 100644 index 0000000000..a108408cce --- /dev/null +++ b/lit/backend/ad/timing_rs/test3/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test3" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/lit/backend/ad/timing_rs/test3/src/main.rs b/lit/backend/ad/timing_rs/test3/src/main.rs new file mode 100644 index 0000000000..2e6056a785 --- /dev/null +++ b/lit/backend/ad/timing_rs/test3/src/main.rs @@ -0,0 +1,73 @@ +#![allow(arithmetic_overflow)] +fn bool2bit(b: bool) -> i32 { + if b { + 1 + } else { + 0 + } +} + + +fn f_1172768(((_1172809@(_1172811, _1172833)) : (i32 , Box T>))) -> T { + let _1172831 = Box::new(move |(_1172834 : i32)| { + (_1172833 _1172834) + }); + + let pow_cont_1172826 = Box::new(move |(__1172859 : i32)| { + let _1172866 : i32 = ((42:i32) * __1172859); + (_1172831 _1172866) + }); + + let pow_else_1172790 = Box::new(move |_| { + let _1172818 : i32 = ((-1:i32) + _1172811); + (f_1172768 (_1172818, pow_cont_1172826)) + }); + + let pow_then_1172877 = Box::new(move |_| { + (_1172831 (1:i32)) + }); + + let _1172904 : i32 = (bool2bit ((0:i32) == _1172811)); + (([pow_else_1172790, pow_then_1172877][_1172904]) ()) +} + +// external +fn thorin_main(((__1172931@(mem_1172950, _, _, return_1172935)): (() , i32 , &(&(i32)) , Box T>))) -> T { + let return_1172930 = Box::new(move |(_1172936 : (() , i32))| { + (return_1172935 _1172936) + }); + + let ret_cont_1172921 = Box::new(move |(r_1172954 : i32)| { + (return_1172930 (mem_1172950, r_1172954)) + }); + + (f_1172768 ((2:i32), ret_cont_1172921)) +} + +// external +fn pow(((__1173017@(((__1173019@[a_1173020, b_1173024]): [i32;2]), ret_1173047)): ([i32;2] , Box T>))) -> T { + let ret_1173045 = Box::new(move |(_1173048 : i32)| { + (ret_1173047 _1173048) + }); + + let pow_cont_1173036 = Box::new(move |(__1173055 : i32)| { + let _1173060 : i32 = ((__1173019[(0:i32)]) * __1173055); + (ret_1173045 _1173060) + }); + + let pow_else_1173002 = Box::new(move |_| { + let _1173031 : i32 = ((-1:i32) + (__1173019[(1:i32)])); + (pow ([(__1173019[(0:i32)]), _1173031], pow_cont_1173036)) + }); + + let pow_then_1173067 = Box::new(move |_| { + (ret_1173045 (1:i32)) + }); + + let _1173081 : i32 = (bool2bit ((0:i32) == (__1173019[(1:i32)]))); + (([pow_else_1173002, pow_then_1173067][_1173081]) ()) +} + +fn main() { + println!("Hello, world!"); +} diff --git a/lit/backend/ad/timing_rs/test_dyn/Cargo.toml b/lit/backend/ad/timing_rs/test_dyn/Cargo.toml new file mode 100644 index 0000000000..5ad12e2c5f --- /dev/null +++ b/lit/backend/ad/timing_rs/test_dyn/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "timing_rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[profile.dev] +overflow-checks = false diff --git a/lit/backend/ad/timing_rs/test_dyn/src/main.rs b/lit/backend/ad/timing_rs/test_dyn/src/main.rs new file mode 100644 index 0000000000..3066b11d05 --- /dev/null +++ b/lit/backend/ad/timing_rs/test_dyn/src/main.rs @@ -0,0 +1,126 @@ +#![allow(arithmetic_overflow)] +#![feature(bench_black_box)] + +fn pow_manual(a: i32, b: i32) -> i32 { + if b == 0 { + 1 + } else { + a * pow_manual(a, b - 1) + } +} + +fn pow_full_pe(a: i32, b: i32) -> (i32, (i32, i32)) { + (pow_manual(a, b), (a * pow_manual(a, b - 1), 0)) +} + +fn pow_pe_r(a: i32, b: i32) -> (i32, Box (i32, i32)>) { + if b == 0 { + (1, Box::new(|s| (0, 0))) + } else { + let (r, r_pb) = pow_pe_r(a, b - 1); + ( + a * r, + Box::new(move |s| { + let (da, db) = r_pb(s * a); + (s * r + da, db) + }), + ) + } +} + +fn pow_pe(a: i32, b: i32) -> (i32, (i32, i32)) { + let (r, r_pb) = pow_pe_r(a, b); + (r, r_pb(1)) +} + +// start + +fn zero_pb(s: i32) -> (i32, i32) { + (0, 0) +} +fn fst_pb(s: i32) -> (i32, i32) { + (s, 0) +} +fn snd_pb(s: i32) -> (i32, i32) { + (0, s) +} +fn pair_sum((p @ (a, b)): (i32, i32), (c, d): (i32, i32)) -> (i32, i32) { + (a + c, b + d) +} +fn app_pb( + f: Box (i32, Box (i32, i32)>)>, + (a, a_pb): ((i32, i32), Box (i32, i32)>), +) -> (i32, Box (i32, i32)>) { + let (r, r_pb) = f(a); + (r, Box::new(move |s| a_pb(r_pb(s)))) +} +fn tup_pb( + (a, a_pb): (i32, Box (i32, i32)>), + (b, b_pb): (i32, Box (i32, i32)>), +) -> ((i32, i32), Box (i32, i32)>) { + ( + (a, b), + Box::new(move |(sa, sb)| pair_sum(a_pb(sa), b_pb(sb))), + ) +} +fn mul_diff((a, b): (i32, i32)) -> (i32, Box (i32, i32)>) { + (a * b, Box::new(move |s| (b * s, a * s))) +} +fn sub_diff((a, b): (i32, i32)) -> (i32, Box (i32, i32)>) { + (a - b, Box::new(move |s| (s, -s))) +} +fn const_diff(c: i32) -> (i32, Box (i32, i32)>) { + (c, Box::new(zero_pb)) +} +fn pow_rs_r((a, b): (i32, i32)) -> (i32, Box (i32, i32)>) { + if b == 0 { + const_diff(1) + } else { + // Type annotation necessary + let a_diff: (i32, Box (i32, i32)>) = (a, Box::new(fst_pb)); + // needed because of ownership of a_diff in tup_pb => TODO: handle correctly + let a_diff2: (i32, Box (i32, i32)>) = (a, Box::new(fst_pb)); + let b_diff: (i32, Box (i32, i32)>) = (b, Box::new(snd_pb)); + let bo_diff = tup_pb(b_diff, const_diff(1)); + let r1_diff = app_pb(Box::new(sub_diff), bo_diff); + let t1_diff = tup_pb(a_diff, r1_diff); + let r2_diff = app_pb(Box::new(pow_rs_r), t1_diff); + let t2_diff = tup_pb(a_diff2, r2_diff); + app_pb(Box::new(mul_diff), t2_diff) + // const_diff(1) + } +} +// end + +fn pow_rs(a: i32, b: i32) -> (i32, (i32, i32)) { + // (0, (0, 0)) + let (r, r_pb) = pow_rs_r((a, b)); + (r, r_pb(1)) +} + +fn main() { + let tests = (0..100000) + .map(|i| ((i * 37 + 12) % 10000, (i % 100) + 1)) + .collect::>(); + + let start = std::time::Instant::now(); + for (a, b) in tests.iter() { + let (_r, (_da, _db)) = std::hint::black_box(pow_rs(*a, *b)); + } + let time = start.elapsed().as_secs_f64(); + println!("{:10}: {}s", "Rust", time); + + let start = std::time::Instant::now(); + for (a, b) in tests.iter() { + let (_r, (_da, _db)) = std::hint::black_box(pow_pe(*a, *b)); + } + let time = start.elapsed().as_secs_f64(); + println!("{:10}: {}s", "PE", time); + + let start = std::time::Instant::now(); + for (a, b) in tests.iter() { + let (_r, (_da, _db)) = std::hint::black_box(pow_full_pe(*a, *b)); + } + let time = start.elapsed().as_secs_f64(); + println!("{:10}: {}s", "Full PE", time); +} diff --git a/lit/backend/ad/timing_rs/test_gen/Cargo.toml b/lit/backend/ad/timing_rs/test_gen/Cargo.toml new file mode 100644 index 0000000000..be93cc9ae1 --- /dev/null +++ b/lit/backend/ad/timing_rs/test_gen/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "test_gen" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/lit/backend/ad/timing_rs/test_gen/src/main.rs b/lit/backend/ad/timing_rs/test_gen/src/main.rs new file mode 100644 index 0000000000..272ea7f39e --- /dev/null +++ b/lit/backend/ad/timing_rs/test_gen/src/main.rs @@ -0,0 +1,198 @@ +#![allow(arithmetic_overflow)] +#![feature(bench_black_box)] +#![feature(trait_alias)] + +fn zero_pb(s: i32) -> (i32, i32) { + (0, 0) +} +fn fst_pb(s: i32) -> (i32, i32) { + (s, 0) +} +fn snd_pb(s: i32) -> (i32, i32) { + (0, s) +} +fn pair_sum((a, b): (i32, i32), (c, d): (i32, i32)) -> (i32, i32) { + (a + c, b + d) +} + +// Pullbacks + +fn app_pb( + f: impl Fn((i32, i32)) -> (i32, Box (i32, i32)>), + // f: Box (i32, impl Fn(i32) -> (i32, i32))>, + (a, a_pb): ((i32, i32), impl Fn((i32, i32)) -> (i32, i32) + 'static), +) -> (i32, impl Fn(i32) -> (i32, i32)) { + let (r, r_pb) = f(a); + (r, move |s| a_pb(r_pb(s))) +} +fn tup_pb( + (a, a_pb): (i32, impl Fn(i32) -> (i32, i32)), + (b, b_pb): (i32, impl Fn(i32) -> (i32, i32)), +) -> ((i32, i32), impl Fn((i32, i32)) -> (i32, i32)) { + ((a, b), (move |(sa, sb)| pair_sum(a_pb(sa), b_pb(sb)))) +} +fn mul_diff((a, b): (i32, i32)) -> (i32, Box (i32, i32)>) { + (a * b, Box::new(move |s| (b * s, a * s))) +} +fn sub_diff((a, b): (i32, i32)) -> (i32, Box (i32, i32)>) { + (a - b, Box::new(move |s| (s, -s))) +} +fn const_diff(c: i32) -> (i32, impl Fn(i32) -> (i32, i32)) { + (c, (zero_pb)) +} +fn pow_rs_r((a, b): (i32, i32)) -> (i32, Box (i32, i32)>) { + if b == 0 { + // Box::new(const_diff(1)) + (1, Box::new(zero_pb)) + } else { + // Type annotation necessary + let a_diff = (a, (fst_pb)); + // needed because of ownership of a_diff in tup_pb => TODO: handle correctly + let a_diff2 = (a, (fst_pb)); + let b_diff = (b, (snd_pb)); + let bo_diff = tup_pb(b_diff, const_diff(1)); + let r1_diff = app_pb((sub_diff), bo_diff); + let t1_diff = tup_pb(a_diff, r1_diff); + let r2_diff = app_pb((pow_rs_r), t1_diff); + let t2_diff = tup_pb(a_diff2, r2_diff); + let (r, r_pb) = (app_pb((mul_diff), (t2_diff))); + (r, Box::new(r_pb)) + // const_diff(1) + } +} + +fn pow_rs(a: i32, b: i32) -> (i32, (i32, i32)) { + // (0, (0, 0)) + let (r, r_pb) = pow_rs_r((a, b)); + (r, r_pb(1)) +} + +// PE Version + +// trait PB = Fn(i32) -> (i32, i32); + +// fn pow_pe_r(a: i32, b: i32) -> (i32, impl PB) { +// // (0, |s| (0, 0)) +// if b == 0 { +// (1, |s| (0, 0)) +// } else { +// let (r, pow_pb) = pow_pe_r(a, b - 1); +// // (r, r_pb) +// let r_pb = move |s| { +// let (da, db) = pow_pb(s * a); +// (s * r + da, db) +// }; +// (a * r, r_pb) +// // (a * r, move |s| { +// // let (da, db) = r_pb(s * a); +// // (s * r + da, db) +// // }) +// } +// } + +// trait PB { +// fn apply(&self, s: i32) -> (i32, i32); +// } + +// struct Const(); + +// impl PB for Const { +// fn apply(&self, s: i32) -> (i32, i32) { +// (0, 0) +// } +// } + +// struct Pow(i32, i32, i32, impl PB); + +// impl PB for Pow { +// fn apply(&self, s: i32) -> (i32, i32) { +// let a = self.0; +// let b = self.1; +// let r = self.2; +// let pow_pb = &self.3; +// let (da, db) = pow_pb(s * a); +// (s * r + da, db) +// } +// } + +// fn pow_pe_r(a: i32, b: i32) -> (i32, impl PB) { +// // (0, |s| (0, 0)) +// if b == 0 { +// (1, Const()) +// } else { +// let (r, pow_pb) = pow_pe_r(a, b - 1); +// (a * r, Pow(a, b, r, pow_pb)) +// } +// } + +// trait PB { +// fn apply(&self, s: i32) -> (i32, i32); +// } + +// fn pow_pe(a: i32, b: i32) -> (i32, (i32, i32)) { +// let (r, r_pb) = pow_pe_r(a, b); +// (r, r_pb(1)) +// } + +// enum to store pow_pe_r return pb +enum PowPB { + Const, + Closure(i32, i32, i32, Box), +} + +fn pow_pe_r(a: i32, b: i32) -> (i32, PowPB) { + if b == 0 { + // (1, Box::new(|s| (0, 0))) + (1, PowPB::Const) + } else { + let (r, r_pb) = pow_pe_r(a, b - 1); + ( + a * r, + PowPB::Closure(a, b, r, Box::new(r_pb)), // Box::new(move |s| { + // let (da, db) = r_pb(s * a); + // (s * r + da, db) + // }), + ) + } +} + +fn eval_pow_pb(pb: PowPB, s: i32) -> (i32, i32) { + match pb { + PowPB::Const => (0, 0), + PowPB::Closure(a, b, r, r_pb) => { + let (da, db) = eval_pow_pb(*r_pb, s * a); + (s * r + da, db) + } + } +} + +fn pow_pe(a: i32, b: i32) -> (i32, (i32, i32)) { + let (r, r_pb) = pow_pe_r(a, b); + (r, eval_pow_pb(r_pb, 1)) +} + +// enum PowPB2 (i32, i32)> { +// Const, +// Closure(F), +// } + +fn main() { + println!("Hello, world!"); + let tests = (0..100000) + .map(|i| ((i * 37 + 12) % 10000, (i % 100) + 1)) + .collect::>(); + + let start = std::time::Instant::now(); + for (a, b) in tests.iter() { + let (_r, (_da, _db)) = std::hint::black_box(pow_rs(*a, *b)); + } + let time = start.elapsed().as_secs_f64(); + println!("{:10}: {}s", "Rust", time); + + let start = std::time::Instant::now(); + for (a, b) in tests.iter() { + let (_r, (_da, _db)) = std::hint::black_box(pow_pe(*a, *b)); + } + let time = start.elapsed().as_secs_f64(); + println!("{:10}: {}s", "PE", time); +} diff --git a/lit/backend/ad/timing_thorin/ReadMe.md b/lit/backend/ad/timing_thorin/ReadMe.md new file mode 100644 index 0000000000..5faf24015e --- /dev/null +++ b/lit/backend/ad/timing_thorin/ReadMe.md @@ -0,0 +1,77 @@ +- [Link](https://docs.google.com/spreadsheets/d/1oIMw4am_GX5CpX_h4Yvx1G7gr6ZFzOh2OVj2wWkMYw8/edit#gid=0) +- PreOpt: Diffed Thorin Code (directly after ad pass) + - For Thorin: manual inline annotation switched off +- Opt: Thorin Code right before codegen +- Manual: Mostly modular (without extract) ad approach +- PartialEval: Conceivable partial evaluation (see below) +- FullEval: Fully evaluated ad approach (known result) + +## Manual +``` +zero* = λ s. (0,0) +pair_sum (da, db) (da', db') = (da + da', db + db') +app' f' (a, a*) = + let r, r* = f' a in + (r, λ s. a* (r* s)) +tup' (a, a*) (b, b*) = + ((a, b), λ s. pair_sum (a* s) (b* s)) +mul' (a,b) = + (a*b, λ s. (s * b, s * a)) +sub' (a,b) = + (a-b, λ s. (s, -s)) +const' c = (c, zero*) +pow (a,b) = + if b=0 then const' 1 else + let a' = (a, λ s. (s, 0)) in + let b' = (b, λ s. (0, s)) in + let t0' = tup' b' (const' 1) in + let r1' = app' sub' t0' in + let t1' = tup' a' r1' in + let r2' = app' pow t1' in + let t2' = tup' a' r2' in + app' mul' t2' +``` + +The code is the augmented code for +``` +let r1 = b-1 +let r2 = pow (a,r1) +let r3 = a*r2 +``` + +## PartialEval +``` +pow (a,b) = + if b=0 then const' 1 else + let r,pow* = pow (a,b-1) in + ( + a*r, + λ s. + let da,db = pow* (s*a) in + (s*r + da, db) + ) +``` + +Reasoning: +``` +a* = λ s. (s, 0) +b* = λ s. (0, s) +t₀* = λ s₀₁. (0, s₀) +r₁* = λ s. t₀* (sub* s) + = λ s. (0, s) +t₁* = λ s₀₁. (s₀, s₁) = id +r₂* = λ s. t₁* (pow* s) + = λ s. pow* s = pow* +t₂* = λ s₀₁. (s₀, 0) + pow* (s₁) +r₃* = λ s. t₂* (mul* s) + = λ s. t₂* (s * r₂, s * a) + = λ s. + let da,db = pow* (s*a) in + (s*r₂ + da, db) +``` + + +## FullEval +``` +pow (a,b) = (a^b, (b*a^(b-1), 0)) +``` diff --git a/lit/backend/ad/timing_thorin/Result.txt b/lit/backend/ad/timing_thorin/Result.txt new file mode 100644 index 0000000000..a2f2b2d9d7 --- /dev/null +++ b/lit/backend/ad/timing_thorin/Result.txt @@ -0,0 +1,28 @@ +Running test.out +real 0.139260 +Running test_O3.out +real 0.134650 + +Running test.out +real 0.134111 +Running test_O3.out +real 0.135552 + + + +Simulated Pre Opt ( + only const, tup, app => inlining (no inner cont) +) + +Running test.out + Opt: real 0.136726 + Manual: real 0.343095 + PE: real 0.136663 + Full PE: real 0.018098 +C Full PE: real 0.022386 +Running test_O3.out + Opt: real 0.143705 + Manual: real 0.267097 + PE: real 0.133919 + Full PE: real 0.001315 +C Full PE: real 0.000000 diff --git a/lit/backend/ad/timing_thorin/pow_pe.thorin.custom b/lit/backend/ad/timing_thorin/pow_pe.thorin.custom new file mode 100644 index 0000000000..452c62616f --- /dev/null +++ b/lit/backend/ad/timing_thorin/pow_pe.thorin.custom @@ -0,0 +1,202 @@ + +.import core; +.import autodiff; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con .extern pow [[a:I32, b:I32], ret: .Cn [I32]] = { + .con pow_then [] = ret (1:I32); + + .con pow_cont [v:I32] = { + .let m = %core.wrap.mul _32 0 (a,v); + ret m + }; + .con pow_else [] = { + .let b_1 = %core.wrap.sub _32 0 (b,1:I32); + pow ((a,b_1),pow_cont) + }; + + .let cmp = %core.icmp.e _32 (b,0:I32); + ((pow_else, pow_then)#cmp) () +}; + +.con .extern pow_full_pe [[a:I32, b:I32], ret: .Cn [I32, [I32, I32]]] = { + pow ((a,b), .cn [r:I32] = { + .let b_1 = %core.wrap.sub _32 0 (b,1:I32); + pow ((a,b_1), .cn [r2:I32] = { + .let da = %core.wrap.mul _32 0 (a,r2); + ret (r, (da, 0:I32)) + }) + }) +}; + + + +.con zero_pb ![I32, ret: .Cn [I32, I32]] = { + ret (0:I32, 0:I32) +}; + +.con fst_pb ![s:I32, ret: .Cn [I32, I32]] = { + ret (s, 0:I32) +}; + +.con snd_pb ![s:I32, ret: .Cn [I32, I32]] = { + ret (0:I32, s) +}; + +.con pair_sum ![ + [[a:I32, b:I32], + [c:I32, d:I32]], + ret: .Cn [I32, I32] +] = { + .let s1 = %core.wrap.add _32 0 (a,c); + .let s2 = %core.wrap.add _32 0 (b,d); + ret (s1, s2) +}; + +.con app_pb ![ + f : .Cn [[I32, I32], .Cn [I32, .Cn [I32, .Cn[I32, I32]]]], + [a:[I32, I32], a_pb: .Cn[[I32, I32], .Cn [I32, I32]]], + ret: .Cn [I32, .Cn [I32, .Cn [I32, I32]]] +] = { + f (a, .cn ![r:I32, r_pb: .Cn [I32, .Cn [I32, I32]]] = { + .con pb ![s:I32, pb_ret: .Cn [I32,I32]] = { + r_pb (s, .cn ![d:[I32,I32]] = { + a_pb (d, pb_ret) + }) + }; + ret (r, pb) + }) +}; + +.con tup_pb ![ + [a:I32, a_pb: .Cn [I32, .Cn [I32, I32]]], + [b:I32, b_pb: .Cn [I32, .Cn [I32, I32]]], + ret: .Cn [[I32, I32], .Cn [[I32,I32], .Cn [I32, I32]]] +] = { + ret ((a,b),.cn ![[s1:I32,s2:I32], pb_ret: .Cn [I32, I32]] = { + a_pb (s1, .cn ![d1:[I32,I32]] = { + b_pb (s2, .cn ![d2:[I32,I32]] = { + pair_sum ((d1,d2), pb_ret) + }) + }) + }) +}; + +.con mul_diff ![ + [a:I32, b:I32], + ret: .Cn [I32, .Cn [I32, .Cn [I32, I32]]] +] = { + .let m = %core.wrap.mul _32 0 (a,b); + ret (m, .cn ![s:I32, pb_ret:.Cn[I32,I32]] = { + .let da = %core.wrap.mul _32 0 (b,s); + .let db = %core.wrap.mul _32 0 (a,s); + pb_ret (da, db) + }) +}; + +.con sub_diff ![ + [a:I32, b:I32], + ret: .Cn [I32, .Cn [I32, .Cn [I32, I32]]] +] = { + .let m = %core.wrap.sub _32 0 (a,b); + ret (m, .cn ![s:I32, pb_ret:.Cn[I32,I32]] = { + .let da = s; + .let db = %core.wrap.sub _32 0 (0:I32,s); + pb_ret (da, db) + }) +}; + +.con const_diff ![ + c:I32, + ret: .Cn [I32, .Cn [I32, .Cn [I32, I32]]] +] = { + ret (c, zero_pb ) +}; + +.con pow_thorin_r [[a:I32, b:I32], ret: .Cn [I32, .Cn [I32, .Cn [I32, I32]]]] = { + .con pow_then ![] = const_diff (1:I32, ret); + + .con pow_cont ![r:I32, pb:.Cn[I32, .Cn[I32, I32]]] = { + .let m = %core.wrap.mul _32 0 (a,r); + ret (m, .cn ![s:I32, pb_ret:.Cn[I32,I32]] = { + pb (s, .cn![da:I32, db:I32] = { + .let da = %core.wrap.mul _32 0 (a,da); + .let ra = %core.wrap.add _32 0 (r,da); + pb_ret (ra, 0:I32) + }) + // .let da = %core.wrap.mul _32 0 (a,s); + // .let db = %core.wrap.mul _32 0 (r,s); + // pb_ret (da, db) + }) + }; + .con pow_else ![] = { + .let a_d = (a, fst_pb); + .let b_d = (b, snd_pb); + + const_diff (1:I32, .cn ![one_d: [I32, .Cn[I32, .Cn[I32,I32]]]] = { + tup_pb (b_d, one_d, .cn ![bo_d:[[I32,I32], .Cn[[I32,I32],.Cn[I32,I32]]]] = { + app_pb(sub_diff, bo_d, .cn ![r1_d: [I32, .Cn[I32, .Cn[I32,I32]]]] = { + tup_pb (a_d, r1_d, .cn ![t1_d: [[I32,I32], .Cn[[I32,I32],.Cn[I32,I32]]]] = { + app_pb (pow_thorin_r, t1_d, .cn ![r2_d: [I32, .Cn[I32, .Cn[I32,I32]]]] = { + tup_pb (a_d, r2_d, .cn ![t2_d: [[I32,I32], .Cn[[I32,I32],.Cn[I32,I32]]]] = { + app_pb (mul_diff, t2_d, pow_cont) + }) + }) + }) + }) + }) + }) + }; + + .let cmp = %core.icmp.e _32 (b,0:I32); + ((pow_else, pow_then)#cmp) () +}; + + + +.con pow_pe_r [[a:I32, b:I32], ret: .Cn [I32, .Cn [I32, .Cn [I32, I32]]]] = { + // const_diff (1:I32, ret) + .con pow_then [] = const_diff (1:I32, ret); + + .con pow_cont [r:I32, pb:.Cn[I32, .Cn[I32, I32]]] = { + .let m = %core.wrap.mul _32 0 (a,r); + ret (m, .cn [s:I32, pb_ret:.Cn[I32,I32]] = { + pb (s, .cn[da:I32, db:I32] = { + .let da = %core.wrap.mul _32 0 (a,da); + .let ra = %core.wrap.add _32 0 (r,da); + pb_ret (ra, 0:I32) + }) + // .let da = %core.wrap.mul _32 0 (a,s); + // .let db = %core.wrap.mul _32 0 (r,s); + // pb_ret (da, db) + }) + }; + .con pow_else [] = { + .let b_1 = %core.wrap.sub _32 0 (b,1:I32); + pow_pe_r ((a,b_1),pow_cont) + }; + + .let cmp = %core.icmp.e _32 (b,0:I32); + ((pow_else, pow_then)#cmp) () +}; + +// .con .extern pow_pe [[a:I32, b:I32], ret: .Cn [I32, [I32, I32]]] = { +.con .extern pow_pe [[a:I32, b:I32], ret: .Cn [I32, I32, I32]] = { + pow_pe_r ((a,b), .cn [r:I32, pb:.Cn[I32, .Cn[I32, I32]]] = { + pb (1:I32, .cn [da:I32, db:I32] = { + // ret (r, (da, db)) + ret (r, da, db) + }) + }) +}; + +.con .extern pow_thorin [[a:I32, b:I32], ret: .Cn [I32, I32, I32]] = { + pow_thorin_r ((a,b), .cn [r:I32, pb:.Cn[I32, .Cn[I32, I32]]] = { + pb (1:I32, .cn [da:I32, db:I32] = { + ret (r, da, db) + }) + }) +}; diff --git a/lit/backend/ad/timing_thorin/run.sh b/lit/backend/ad/timing_thorin/run.sh new file mode 100755 index 0000000000..9b3452250e --- /dev/null +++ b/lit/backend/ad/timing_thorin/run.sh @@ -0,0 +1,9 @@ +clang pow_pe.ll pow.ll test.c -o test.out -Wno-override-module +clang -O3 pow_pe.ll pow.ll test.c -o test_O3.out -Wno-override-module +# clang pow.ll test.c -o test.out -Wno-override-module +# clang -O3 pow.ll test.c -o test_O3.out -Wno-override-module + +echo "Running test.out" +./test.out +echo "Running test_O3.out" +./test_O3.out diff --git a/lit/backend/ad/timing_thorin/test.c b/lit/backend/ad/timing_thorin/test.c new file mode 100644 index 0000000000..b63fefd745 --- /dev/null +++ b/lit/backend/ad/timing_thorin/test.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +void* time() { + struct timeval* tv = (struct timeval*)malloc(sizeof(*tv)); + gettimeofday(tv, NULL); + return (void*)tv; +} + +static float tdiff(struct timeval* start, struct timeval* end) { + return (end->tv_sec - start->tv_sec) + 1e-6 * (end->tv_usec - start->tv_usec); +} + +void print_time_diff(void* tv1, void* tv2) { + printf("real\t%0.6f \n", tdiff((struct timeval*)tv1, (struct timeval*)tv2)); +} + + + + + +struct int_triple { + int a; + int b; + int c; +}; + +struct int_pair { + int a; + int b; +}; + +struct ret_tuple { + int a; + struct int_pair b; +}; + +struct int_triple f_diffed_reshape(int a, int b); +struct ret_tuple pow_full_pe_reshape(int a, int b); +struct int_triple pow_pe_reshape(int a, int b); +struct int_triple pow_thorin_reshape(int a, int b); + +int pow_manual(int a, int b) { + if (b == 0) { + return 1; + } + return a*pow_manual(a, b-1); +} + +struct ret_tuple pow_c_full_pe(int a, int b) { + return (struct ret_tuple){pow_manual(a, b), + {b*pow_manual(a, b-1), 0}}; +} + + + + + + + +int main() { + struct int_pair *tests = (struct int_pair *)malloc(100000*sizeof(*tests)); + for (int i = 0; i < 100000; i++) { + tests[i].a = (i*37+12)%10000; + tests[i].b = (i % 100)+1; + } + + // struct int_triple res = f_diffed_reshape(42, 2); + // printf("%d %d %d \n", res.a, res.b, res.c); + + void* start = time(); + for (int i = 0; i < 100000; i++) { + struct int_triple res = f_diffed_reshape(tests[i].a, tests[i].b); + } + void* end = time(); + printf("%10s", "Opt: "); + print_time_diff(start, end); + + start = time(); + for (int i = 0; i < 100000; i++) { + struct int_triple res = pow_thorin_reshape(tests[i].a, tests[i].b); + } + end = time(); + printf("%10s", "Manual: "); + print_time_diff(start, end); + + start = time(); + for (int i = 0; i < 100000; i++) { + struct int_triple res = pow_pe_reshape(tests[i].a, tests[i].b); + } + end = time(); + printf("%10s", "PE: "); + print_time_diff(start, end); + + start = time(); + for (int i = 0; i < 100000; i++) { + struct ret_tuple res = pow_full_pe_reshape(tests[i].a, tests[i].b); + } + end = time(); + printf("%10s", "FullPE: "); + print_time_diff(start, end); + + + // C versions + + + start = time(); + for (int i = 0; i < 100000; i++) { + struct ret_tuple res = pow_c_full_pe(tests[i].a, tests[i].b); + } + end = time(); + printf("%10s", "C FullPE: "); + print_time_diff(start, end); + + return 0; +} diff --git a/lit/backend/pow.thorin b/lit/backend/pow.thorin new file mode 100644 index 0000000000..fc877bb6de --- /dev/null +++ b/lit/backend/pow.thorin @@ -0,0 +1,82 @@ +// RUN: %thorin -d backend %s --backend ml --output %s.ml +// RUN: ocaml %s_test.ml +// RUN: rm -f %s.ml + + + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +/// if b<=0: +/// 1 +/// else +/// a*pow(a,b-1) +/// +/// pow(a,b,ret): +/// ((pow_else,pow_then)#cmp) () +/// then(): +/// ret 1 +/// else(): +/// pow(a,b-1,cont) +/// cont(v): +/// ret (a*v) +/// +.con .extern pow ((a b: I32), ret: .Cn I32) = { + .con pow_then [] = ret (1:I32); + + .con pow_cont [v:I32] = { + .let m = %core.wrap.mul _32 0 (a,v); + ret m + }; + .con pow_else [] = { + .let b_1 = %core.wrap.sub _32 0 (b,1:I32); + pow ((a,b_1),pow_cont) + }; + .let cmp = %core.icmp.e _32 (b,0:I32); + ((pow_else, pow_then)#cmp) () +}; + +.con f ((a b: I32), ret: .Cn I32) = { + .con pow_then [] = ret (1:I32); + + .con pow_cont [v:I32] = { + .let m = %core.wrap.mul _32 0 (a,v); + ret m + }; + .con pow_else [] = { + .let b_1 = %core.wrap.sub _32 0 (b,1:I32); + f ((a,b_1),pow_cont) + }; + .let cmp = %core.icmp.e _32 (b,0:I32); + ((pow_else, pow_then)#cmp) () +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + .con ret_cont r::[I32] = return (mem, r); + + .let c = (42:I32, 2:I32); + f (c,ret_cont) +}; + + +// 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: _{{[0-9_]+}} _{{[0-9_]+}} + +// CHECK-DAG: .con pow_then_{{[0-9_]+}} [] {{(@.*)?}}= { +// CHECK-DAG: _{{[0-9_]+}} 1:(.Idx 4294967296) + +// CHECK-DAG: .con pow_cont_{{[0-9_]+}} _{{[0-9_]+}}: .Idx 4294967296 {{(@.*)?}}= { +// CHECK-DAG: .let _{{[0-9_]+}}: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (42:(.Idx 4294967296), _{{[0-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: 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: (pow_else_{{[0-9_]+}}, pow_then_{{[0-9_]+}})#_{{[0-9_]+}} () + diff --git a/lit/backend/pow.thorin_test.ml b/lit/backend/pow.thorin_test.ml new file mode 100644 index 0000000000..5dc7c90bc4 --- /dev/null +++ b/lit/backend/pow.thorin_test.ml @@ -0,0 +1,23 @@ +#use "pow.thorin.ml";; + +let pow_ds (a,b) = pow ([a;b], Fun.id) + +(* let test a b = pow ([a;b], fun r -> Printf.printf "%d ^ %d = %d (expected %d)\n" a b r (int_of_float (float_of_int a ** float_of_int b))) *) +let test ?(verbose=false) a b = + let r = pow_ds (a,b) in + let expected = int_of_float (float_of_int a ** float_of_int b) in + (if verbose then + Printf.printf "%d ^ %d = %d (%s)\n" a b r (if r = expected then "OK" else "ERROR") + else + ()) + ; + r = expected + +let tests = [ + (42,2); + (42,3) +] + +let _ = List.iter (fun (a,b) -> + assert (test ~verbose:true a b) + ) tests diff --git a/lit/clos/largeArr.thorin b/lit/clos/largeArr.thorin new file mode 100644 index 0000000000..3b7cd12df7 --- /dev/null +++ b/lit/clos/largeArr.thorin @@ -0,0 +1,15 @@ +// RUN: rm -f %t.ll ; \ +// RUN: timeout 10 %thorin -d clos %s --output-ll %t.ll --output-thorin - + +.import mem; + +.let i32 = .Idx 4294967296; +.let size = 100000000:.Nat; + +.con .extern main [mem: %mem.M, argc: i32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0:.Nat)», 0:.Nat), return : .Cn [%mem.M, i32]] = { + .let (alloc_mem, arr) = %mem.alloc (<>, 0) (mem); + .let lea = %mem.lea (size, , 0) (arr, 0:(.Idx size)); + .let (load_mem, val) = %mem.load (i32, 0) (alloc_mem, lea); + + return ( load_mem, 1:i32 ) +}; diff --git a/lit/clos/lib.c b/lit/clos/lib.c index f74b4c419a..a65f3f8713 100644 --- a/lit/clos/lib.c +++ b/lit/clos/lib.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include // #include void print_i32(int32_t i) { printf("%" PRId32 "\n", i); } @@ -8,6 +10,27 @@ void print_i32(int32_t i) { printf("%" PRId32 "\n", i); } void println_i32(int32_t i) { printf("%" PRId32 "\n", i); } void newline() { printf("\n"); } +// void printInteger(int i) { printf("%d, ", i); } +// void printIntegerNL(int i) { printf("%d\n", i); } +// void printNL() { printf("\n"); } +void printInteger(int i) {} +void printIntegerNL(int i) {} +void printNL() {} + // long jmpbuf_size(){ // return _JBLEN; // for clos::sjlj // } + +void* time() { + struct timeval* tv = (struct timeval*)malloc(sizeof(*tv)); + gettimeofday(tv, NULL); + return (void*)tv; +} + +static float tdiff(struct timeval* start, struct timeval* end) { + return (end->tv_sec - start->tv_sec) + 1e-6 * (end->tv_usec - start->tv_usec); +} + +void print_time_diff(void* tv1, void* tv2) { + printf("real\t%0.6f \n", tdiff((struct timeval*)tv1, (struct timeval*)tv2)); +} diff --git a/lit/clos/loopDiff.thorin b/lit/clos/loopDiff.thorin index c599870ce7..4c481fdc41 100644 --- a/lit/clos/loopDiff.thorin +++ b/lit/clos/loopDiff.thorin @@ -3,19 +3,21 @@ .import mem; .import core; -.import direct; .let i32 = .Idx 4294967296; .let i8 = .Idx 256; +.let void_ptr = %mem.Ptr («⊤:.Nat; []», 0); .con printInteger [mem: %mem.M, val: i32, return : .Cn [%mem.M]]; .con printNL [mem: %mem.M, return : .Cn [%mem.M]]; +.con time [mem: %mem.M, return : .Cn [%mem.M, void_ptr]]; +.con print_time_diff [mem: %mem.M, t1: void_ptr, t2: void_ptr, return : .Cn [%mem.M]]; .let size = 100:.Nat; +// .let size = 100000:.Nat; +.let arr_size = ⊤:.Nat; .con printArr [mem: %mem.M, arr : %mem.Ptr (<>, 0:.Nat), return : .Cn [%mem.M]] = { - .let arr_size = ⊤:.Nat; - .con loop_body [mem: %mem.M, i : i32, continue : .Cn %mem.M] = { .let lea = %mem.lea (arr_size, , 0) (arr, i); .let (load_mem, val) = %mem.load (i32, 0) (mem, lea); @@ -44,8 +46,6 @@ }; .con init [mem: %mem.M, arr : %mem.Ptr (<>, 0:.Nat), offset : i32, return : .Cn [%mem.M]] = { - .let arr_size = ⊤:.Nat; - .con loop_body [mem: %mem.M, i : i32, continue : .Cn %mem.M] = { .let lea = %mem.lea (arr_size, , 0) (arr, i); .let add = %core.wrap.add 4294967296 0 (offset, i); @@ -72,7 +72,6 @@ .con const [mem: %mem.M, arr : %mem.Ptr (<>, 0:.Nat), constValue : i32, return : .Cn [%mem.M]] = { - .let arr_size = ⊤:.Nat; .con loop_body [mem: %mem.M, i : i32, continue : .Cn %mem.M] = { .let lea = %mem.lea (arr_size, , 0) (arr, i); @@ -101,8 +100,6 @@ .con outer [mem: %mem.M, x : i32, return : .Cn [%mem.M]] = { - .let arr_size = ⊤:.Nat; - .let (alloc_mem_a, a_arr) = %mem.alloc (<>, 0) (mem); .let (alloc_mem_b, b_arr) = %mem.alloc (<>, 0) (alloc_mem_a); .let (alloc_mem_c, c_arr) = %mem.alloc (<>, 0) (alloc_mem_b); @@ -116,7 +113,7 @@ }; .let pb_type = .Cn [%mem.M, .Cn [%mem.M]]; - .let (alloc_pb_mem, pb_ptr) = %mem.malloc (pb_type, 0) (alloc_mem_cd, 32); + .let (alloc_pb_mem, pb_ptr) = %mem.malloc (pb_type, 0) (alloc_mem_cd, 32); // besser slot .let pb_arr = %core.bitcast ( %mem.Ptr («⊤:.Nat; pb_type», 0), @@ -192,23 +189,39 @@ printArr(mem, ad_arr, print_bd) }; - .con loop_head [mem: %mem.M, i : i32] = { - .con exit [mem: %mem.M] = { - .let (backward_pass_mem, backward_pass) = %mem.load (pb_type, 0) (mem, lea_pb); - backward_pass (backward_pass_mem, print_ad) - }; - .con yield [mem: %mem.M] = { - loop_head( mem, %core.wrap.add 4294967296 0 (i, 1:i32) ) + .con time_start_cont [mem:%mem.M, start_time:void_ptr] = { + .con timer [mem:%mem.M] = { + .con time_end_cont [mem:%mem.M, end_time:void_ptr] = { + print_time_diff (mem, start_time, end_time, print_ad) + }; + time (mem, time_end_cont) + // print_ad(mem) }; - .con enter [mem: %mem.M] = { - loop_body ( mem, i, yield ) + .con loop_head [mem: %mem.M, i : i32] = { + .con exit [mem: %mem.M] = { + .let (backward_pass_mem, backward_pass) = %mem.load (pb_type, 0) (mem, lea_pb); + backward_pass (backward_pass_mem, timer) + }; + + .con yield [mem: %mem.M] = { + // loop_head( mem, %core.wrap.add (0, 4294967296) (i, 1:i32) ) + loop_head( mem, %core.wrap.add 4294967296 0 (i, 1:i32) ) + }; + + .con enter [mem: %mem.M] = { + loop_body ( mem, i, yield ) + }; + + .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (i32, .Nat) size); + .let target = (exit, enter)#condition; + target ( mem ) + // .con yield [mem: %mem.M] = { + // loop_head( mem, %core.wrap.add 4294967296 0 (i, 1:i32) ) }; - .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (i32, .Nat) size); - .let target = (exit, enter)#condition; - target ( mem ) + loop_head ( mem, 0:i32 ) }; .con init_a [mem: %mem.M] = { @@ -217,7 +230,7 @@ .con init_ad [mem: %mem.M] = { .con init_bd [mem: %mem.M] = { .con init_cd [mem: %mem.M] = { - loop_head ( mem, 0:i32 ) + time (mem, time_start_cont) }; const(mem, cd_arr, 1:i32, init_cd) diff --git a/lit/clos/loopDiff2.thorin b/lit/clos/loopDiff2.thorin index e67d4fb37b..5cda81bff6 100644 --- a/lit/clos/loopDiff2.thorin +++ b/lit/clos/loopDiff2.thorin @@ -3,13 +3,16 @@ .import mem; .import core; -.import direct; -.let i32 = .Idx 4294967296; +.let _32 = 4294967296; +.let i32 = .Idx _32; .let i8 = .Idx 256; +.let void_ptr = %mem.Ptr («⊤:.Nat; []», 0); .con printInteger [mem: %mem.M, val: i32, return : .Cn [%mem.M]]; .con printNL [mem: %mem.M, return : .Cn [%mem.M]]; +.con time [mem: %mem.M, return : .Cn [%mem.M, void_ptr]]; +.con print_time_diff [mem: %mem.M, t1: void_ptr, t2: void_ptr, return : .Cn [%mem.M]]; .let size = 100000:.Nat; @@ -190,38 +193,53 @@ printArr(mem, ad_arr, print_bd) }; - .con backward_loop_head [mem: %mem.M, i : i32] = { - .con yield [mem: %mem.M] = { - backward_loop_head( mem, %core.wrap.add 4294967296 0 (i, 1:i32) ) - }; - .con enter [mem: %mem.M] = { - .let lea_pb = %mem.lea (⊤:.Nat, <⊤:.Nat; pb_type>, 0) (pb_arr, i); - .let (backward_pass_mem, backward_pass) = %mem.load (pb_type, 0) (mem, lea_pb); - backward_pass ( backward_pass_mem, 1:i32, yield ) - }; - .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (i32, .Nat) size); - .let target = (print_ad, enter)#condition; - target ( mem ) - }; + .con time_start_cont [mem:%mem.M, start_time:void_ptr] = { - .con loop_head [mem: %mem.M, i : i32] = { - .con exit [mem: %mem.M] = { - backward_loop_head(mem, 0:i32) + .con timer [mem:%mem.M] = { + .con time_end_cont [mem:%mem.M, end_time:void_ptr] = { + print_time_diff (mem, start_time, end_time, print_ad) + }; + time (mem, time_end_cont) + // print_ad(mem) }; - .con yield [mem: %mem.M] = { - loop_head( mem, %core.wrap.add 4294967296 0 (i, 1:i32) ) - }; + .con backward_loop_head [mem: %mem.M, i : i32] = { + .con yield [mem: %mem.M] = { + backward_loop_head( mem, %core.wrap.add 4294967296 0 (i, 1:i32) ) + }; - .con enter [mem: %mem.M] = { - loop_body ( mem, i, yield ) + .con enter [mem: %mem.M] = { + .let lea_pb = %mem.lea (⊤:.Nat, <⊤:.Nat; pb_type>, 0) (pb_arr, i); + .let (backward_pass_mem, backward_pass) = %mem.load (pb_type, 0) (mem, lea_pb); + backward_pass ( backward_pass_mem, 1:i32, yield ) + }; + + .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (i32, .Nat) size); + .let target = (timer, enter)#condition; + target ( mem ) }; - .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (i32, .Nat) size); - .let target = (exit, enter)#condition; - target ( mem ) + + .con loop_head [mem: %mem.M, i : i32] = { + .con exit [mem: %mem.M] = { + backward_loop_head(mem, 0:i32) + }; + + .con yield [mem: %mem.M] = { + loop_head( mem, %core.wrap.add _32 0 (i, 1:i32) ) + }; + + .con enter [mem: %mem.M] = { + loop_body ( mem, i, yield ) + }; + + .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (i32, .Nat) size); + .let target = (exit, enter)#condition; + target ( mem ) + }; + loop_head ( mem, 0:i32 ) }; .con init_a [mem: %mem.M] = { @@ -230,7 +248,8 @@ .con init_ad [mem: %mem.M] = { .con init_bd [mem: %mem.M] = { .con init_cd [mem: %mem.M] = { - loop_head ( mem, 0:i32 ) + time (mem, time_start_cont) + // loop_head ( mem, 0:i32 ) }; const(mem, cd_arr, 1:i32, init_cd) diff --git a/lit/clos/no_mem_lazy.thorin b/lit/clos/no_mem_lazy.thorin new file mode 100644 index 0000000000..418cd68725 --- /dev/null +++ b/lit/clos/no_mem_lazy.thorin @@ -0,0 +1,22 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + +.import core; +.import mem; + +.let I32 = .Idx 4294967296; + +.con f [a:I32, ret: .Cn [I32]] = { + .let b = %core.wrap.mul 4294967296:.Nat 0:.Nat (a, a); + ret b +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + .con ret_cont [r:I32] = { + .con ret_cont2 [r2:I32] = { + return (mem, r2) + }; + f (r, ret_cont2) + }; + f (42:I32,ret_cont) +}; diff --git a/lit/clos/pow_ad_eval_simpl.thorin.disabled b/lit/clos/pow_ad_eval_simpl.thorin.disabled new file mode 100644 index 0000000000..3e69746797 --- /dev/null +++ b/lit/clos/pow_ad_eval_simpl.thorin.disabled @@ -0,0 +1,65 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + + +/* +*/ + +.import core; +.import mem; +.con zero_pb_745910_661133 _745912_661141::[.Idx 4294967296, _745914_661143: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _745914_661139 [_661144: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745914_661143 _661144 + }; + _745914_661139 ‹2; 0:(.Idx 4294967296)› +}; +.con tup_pb_745946_661190 _745948_661198::[[], _745950_661200: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _745950_661196 [_661201: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745950_661200 _661201 + }; + _745950_661196 ‹2; 0:(.Idx 4294967296)› +}; +.con aug_f_745675_660796 _660883::[_660885: .Idx 4294967296, _660909: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con aug_pow_cont_745734_660902 _745753_660946::[_745755_660948: .Idx 4294967296, _745773_660977: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con comp_tup_pb__745765_660965 _745778_661000::[_745780_661002: .Idx 4294967296, _745799_661037: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _745799_661035 [_661038: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745799_661037 _661038 + }; + .con comp_tup_pb__cont_cont_cont_745796_661025 _745840_661079::[_745841_661080: .Idx 4294967296, _745847_661092: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _661066: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_745755_660948, _745780_661002); + .let _661085: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661066, _745841_661080); + _745799_661035 (_661085, _745847_661092) + }; + .let _661009: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745780_661002); + _745773_660977 (_661009, comp_tup_pb__cont_cont_cont_745796_661025) + }; + .let _660955: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745755_660948); + _660909 (_660955, comp_tup_pb__745765_660965) + }; + .con aug_pow_else_745690_660849 [.Cn [[], .Cn «2; .Idx 4294967296»]]@(0:(.Idx 2)) = { + .let _660892: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _660885); + aug_f_745675_660796 (_660892, aug_pow_cont_745734_660902) + }; + .con aug_pow_then_745900_661112[.Cn [[], .Cn «2; .Idx 4294967296»]]@(0:(.Idx 2)) = { + _660909 (1:(.Idx 4294967296), zero_pb_745910_661133) + }; + .let _661176: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _660885); + (aug_pow_else_745690_660849, aug_pow_then_745900_661112)#_661176 tup_pb_745946_661190 + // aug_pow_then_745900_661112 tup_pb_745946_661190 +}; +.con .extern main __746011_661274::[mem_746034_661291: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_746015_661278: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_746015_661272[_661279: [%mem.M, .Idx 4294967296]]@(0:(.Idx 2)) = { + return_746015_661278 _661279 + }; + .con ret_cont_745972_661223 __745982_661247::[r_746066_661318: .Idx 4294967296, pb_745984_661249: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_746000_661266 __746083_661349::[pr_a_746103_661369: .Idx 4294967296, pr_b_746084_661350: .Idx 4294967296] @(0:(.Idx 2)) = { + .let _661325: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_746066_661318); + .let _661376: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_746103_661369); + .let _661381: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_746084_661350, _661376); + .let _661386: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661325, _661381); + return_746015_661272 (mem_746034_661291, _661386) + }; + pb_745984_661249 (1:(.Idx 4294967296), pb_ret_cont_746000_661266) + }; + aug_f_745675_660796 (3:(.Idx 4294967296), ret_cont_745972_661223) +}; diff --git a/lit/clos/pow_ad_eval_simpl2.thorin.disabled b/lit/clos/pow_ad_eval_simpl2.thorin.disabled new file mode 100644 index 0000000000..4417c68b36 --- /dev/null +++ b/lit/clos/pow_ad_eval_simpl2.thorin.disabled @@ -0,0 +1,65 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + + +/* +*/ + +.import core; +.import mem; +.con zero_pb_745910_661133 _745912_661141::[.Idx 4294967296, _745914_661143: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _745914_661139 [_661144: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745914_661143 _661144 + }; + _745914_661139 ‹2; 0:(.Idx 4294967296)› +}; +.con tup_pb_745946_661190 _745948_661198::[_745950_661200: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _745950_661196 [_661201: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745950_661200 _661201 + }; + _745950_661196 ‹2; 0:(.Idx 4294967296)› +}; +.con aug_f_745675_660796 _660883::[_660885: .Idx 4294967296, _660909: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con aug_pow_cont_745734_660902 _745753_660946::[_745755_660948: .Idx 4294967296, _745773_660977: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con comp_tup_pb__745765_660965 _745778_661000::[_745780_661002: .Idx 4294967296, _745799_661037: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con _745799_661035 [_661038: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745799_661037 _661038 + }; + .con comp_tup_pb__cont_cont_cont_745796_661025 _745840_661079::[_745841_661080: .Idx 4294967296, _745847_661092: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _661066: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_745755_660948, _745780_661002); + .let _661085: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661066, _745841_661080); + _745799_661035 (_661085, _745847_661092) + }; + .let _661009: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745780_661002); + _745773_660977 (_661009, comp_tup_pb__cont_cont_cont_745796_661025) + }; + .let _660955: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745755_660948); + _660909 (_660955, comp_tup_pb__745765_660965) + }; + .con aug_pow_else_745690_660849 [.Cn [.Cn «2; .Idx 4294967296»]]@(0:(.Idx 2)) = { + .let _660892: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _660885); + aug_f_745675_660796 (_660892, aug_pow_cont_745734_660902) + }; + .con aug_pow_then_745900_661112[.Cn [.Cn «2; .Idx 4294967296»]]@(0:(.Idx 2)) = { + _660909 (1:(.Idx 4294967296), zero_pb_745910_661133) + }; + .let _661176: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _660885); + (aug_pow_else_745690_660849, aug_pow_then_745900_661112)#_661176 tup_pb_745946_661190 + // aug_pow_then_745900_661112 tup_pb_745946_661190 +}; +.con .extern main __746011_661274::[mem_746034_661291: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_746015_661278: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_746015_661272[_661279: [%mem.M, .Idx 4294967296]]@(0:(.Idx 2)) = { + return_746015_661278 _661279 + }; + .con ret_cont_745972_661223 __745982_661247::[r_746066_661318: .Idx 4294967296, pb_745984_661249: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_746000_661266 __746083_661349::[pr_a_746103_661369: .Idx 4294967296, pr_b_746084_661350: .Idx 4294967296] @(0:(.Idx 2)) = { + .let _661325: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_746066_661318); + .let _661376: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_746103_661369); + .let _661381: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_746084_661350, _661376); + .let _661386: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661325, _661381); + return_746015_661272 (mem_746034_661291, _661386) + }; + pb_745984_661249 (1:(.Idx 4294967296), pb_ret_cont_746000_661266) + }; + aug_f_745675_660796 (3:(.Idx 4294967296), ret_cont_745972_661223) +}; diff --git a/lit/clos/pow_ad_eval_simpl2_mem.thorin b/lit/clos/pow_ad_eval_simpl2_mem.thorin new file mode 100644 index 0000000000..dbd67e3428 --- /dev/null +++ b/lit/clos/pow_ad_eval_simpl2_mem.thorin @@ -0,0 +1,66 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + + +/* +expects failure -- but the error message could be improved +*/ + +.import core; +.import mem; +.con zero_pb_745910_661133 _745912_661141::[mem:%mem.M, .Idx 4294967296, _745914_661143: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745914_661139 _661144::[mem:%mem.M,_661144_2: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745914_661143 _661144 + }; + _745914_661139 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con tup_pb_745946_661190 _745948_661198::[mem:%mem.M,_745950_661200: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745950_661196 [mem:%mem.M,_661201: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745950_661200 (mem,_661201) + }; + _745950_661196 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con aug_f_745675_660796 _660883::[mem:%mem.M,_660885: .Idx 4294967296, _660909: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]]] @(0:(.Idx 2)) = { + .con aug_pow_cont_745734_660902 _745753_660946::[mem:%mem.M,_745755_660948: .Idx 4294967296, _745773_660977: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con comp_tup_pb__745765_660965 _745778_661000::[mem:%mem.M,_745780_661002: .Idx 4294967296, _745799_661037: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745799_661035 [mem:%mem.M,_661038: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745799_661037 (mem,_661038) + }; + .con comp_tup_pb__cont_cont_cont_745796_661025 _745840_661079::[mem:%mem.M,[_745841_661080: .Idx 4294967296, _745847_661092: .Idx 4294967296]] @(1:(.Idx 2)) = { + .let _661066: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_745755_660948, _745780_661002); + .let _661085: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661066, _745841_661080); + _745799_661035 (mem,(_661085, _745847_661092)) + }; + .let _661009: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745780_661002); + _745773_660977 (mem,_661009, comp_tup_pb__cont_cont_cont_745796_661025) + }; + .let _660955: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745755_660948); + _660909 (mem,_660955, comp_tup_pb__745765_660965) + }; + .con aug_pow_else_745690_660849 [mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + .let _660892: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _660885); + aug_f_745675_660796 (mem,_660892, aug_pow_cont_745734_660902) + }; + .con aug_pow_then_745900_661112[mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + _660909 (mem,1:(.Idx 4294967296), zero_pb_745910_661133) + }; + .let _661176: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _660885); + (aug_pow_else_745690_660849, aug_pow_then_745900_661112)#_661176 (mem,tup_pb_745946_661190) + // aug_pow_then_745900_661112 tup_pb_745946_661190 +}; +.con .extern main __746011_661274::[mem: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_746015_661278: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_746015_661272[_661279: [%mem.M, .Idx 4294967296]]@(0:(.Idx 2)) = { + return_746015_661278 _661279 + }; + .con ret_cont_745972_661223 __745982_661247::[mem:%mem.M,r_746066_661318: .Idx 4294967296, pb_745984_661249: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con pb_ret_cont_746000_661266 __746083_661349::[mem:%mem.M,[pr_a_746103_661369: .Idx 4294967296, pr_b_746084_661350: .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _661325: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_746066_661318); + .let _661376: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_746103_661369); + .let _661381: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_746084_661350, _661376); + .let _661386: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661325, _661381); + return_746015_661272 (mem, _661386) + }; + pb_745984_661249 (mem,1:(.Idx 4294967296), pb_ret_cont_746000_661266) + }; + aug_f_745675_660796 (mem,3:(.Idx 4294967296), ret_cont_745972_661223) +}; diff --git a/lit/clos/pow_ad_eval_simpl2_mem2.thorin b/lit/clos/pow_ad_eval_simpl2_mem2.thorin new file mode 100644 index 0000000000..de1c432aab --- /dev/null +++ b/lit/clos/pow_ad_eval_simpl2_mem2.thorin @@ -0,0 +1,65 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + + +/* +*/ + +.import core; +.import mem; +.con zero_pb_745910_661133 _745912_661141::[mem:%mem.M, .Idx 4294967296, _745914_661143: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745914_661139 _661144::[mem:%mem.M,_661144_2: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745914_661143 _661144 + }; + _745914_661139 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con tup_pb_745946_661190 _745948_661198::[mem:%mem.M,_745950_661200: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745950_661196 [mem:%mem.M,_661201: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745950_661200 (mem,_661201) + }; + _745950_661196 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con aug_f_745675_660796 _660883::[mem:%mem.M,_660885: .Idx 4294967296, _660909: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]]] @(0:(.Idx 2)) = { + .con aug_pow_cont_745734_660902 _745753_660946::[mem:%mem.M,_745755_660948: .Idx 4294967296, _745773_660977: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con comp_tup_pb__745765_660965 _745778_661000::[mem:%mem.M,_745780_661002: .Idx 4294967296, _745799_661037: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745799_661035 [mem:%mem.M,_661038: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745799_661037 (mem,_661038) + }; + .con comp_tup_pb__cont_cont_cont_745796_661025 _745840_661079::[mem:%mem.M,[_745841_661080: .Idx 4294967296, _745847_661092: .Idx 4294967296]] @(1:(.Idx 2)) = { + .let _661066: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_745755_660948, _745780_661002); + .let _661085: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661066, _745841_661080); + _745799_661035 (mem,(_661085, _745847_661092)) + }; + .let _661009: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745780_661002); + _745773_660977 (mem,_661009, comp_tup_pb__cont_cont_cont_745796_661025) + }; + .let _660955: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745755_660948); + _660909 (mem,_660955, comp_tup_pb__745765_660965) + }; + .con aug_pow_else_745690_660849 [mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + .let _660892: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _660885); + aug_f_745675_660796 (mem,_660892, aug_pow_cont_745734_660902) + }; + .con aug_pow_then_745900_661112[mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + _660909 (mem,1:(.Idx 4294967296), zero_pb_745910_661133) + }; + .let _661176: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _660885); + (aug_pow_else_745690_660849, aug_pow_then_745900_661112)#_661176 (mem,tup_pb_745946_661190) + // aug_pow_then_745900_661112 tup_pb_745946_661190 +}; +.con .extern main __746011_661274::[mem: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_746015_661278: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_746015_661272[_661279: [%mem.M, .Idx 4294967296]]@(0:(.Idx 2)) = { + return_746015_661278 _661279 + }; + .con ret_cont_745972_661223 __745982_661247::[mem:%mem.M,r_746066_661318: .Idx 4294967296, pb_745984_661249: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con pb_ret_cont_746000_661266 __746083_661349::[mem:%mem.M,[pr_a_746103_661369: .Idx 4294967296, pr_b_746084_661350: .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _661325: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_746066_661318); + .let _661376: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_746103_661369); + .let _661381: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_746084_661350, _661376); + .let _661386: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661325, _661381); + return_746015_661272 (mem, _661386) + }; + pb_745984_661249 (mem,1:(.Idx 4294967296), pb_ret_cont_746000_661266) + }; + aug_f_745675_660796 (mem,3:(.Idx 4294967296), ret_cont_745972_661223) +}; diff --git a/lit/clos/pow_ad_eval_simpl2_mem_fixed.thorin b/lit/clos/pow_ad_eval_simpl2_mem_fixed.thorin new file mode 100644 index 0000000000..54d1198edc --- /dev/null +++ b/lit/clos/pow_ad_eval_simpl2_mem_fixed.thorin @@ -0,0 +1,73 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - +// RUN: clang %S/lib.c %t.ll -o %t -Wno-override-module +// TODO: execute + +/* +*/ + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con zero_pb_745910_661133 _745912_661141::[mem:%mem.M, .Idx 4294967296, _745914_661143: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745914_661139 _661144::[mem:%mem.M,_661144_2: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745914_661143 _661144 + }; + _745914_661139 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con tup_pb_745946_661190 _745948_661198::[mem:%mem.M,_745950_661200: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745950_661196 [mem:%mem.M,_661201: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745950_661200 (mem,_661201) + }; + _745950_661196 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con aug_f_745675_660796 _660883::[mem:%mem.M,_660885: .Idx 4294967296, _660909: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]]] @(0:(.Idx 2)) = { + .con aug_pow_cont_745734_660902 _745753_660946::[mem:%mem.M,_745755_660948: .Idx 4294967296, _745773_660977: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con comp_tup_pb__745765_660965 _745778_661000::[mem:%mem.M,_745780_661002: .Idx 4294967296, _745799_661037: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745799_661035 [mem:%mem.M,_661038: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745799_661037 (mem,_661038) + }; + .con comp_tup_pb__cont_cont_cont_745796_661025 _745840_661079::[mem:%mem.M,[_745841_661080: .Idx 4294967296, _745847_661092: .Idx 4294967296]] @(1:(.Idx 2)) = { + .let _661066: .Idx 4294967296 = %core.wrap.mul _32 0 (_745755_660948, _745780_661002); + .let _661085: .Idx 4294967296 = %core.wrap.add _32 0 (_661066, _745841_661080); + _745799_661035 (mem,(_661085, _745847_661092)) + }; + .let _661009: .Idx 4294967296 = %core.wrap.mul _32 0 (4:(.Idx 4294967296), _745780_661002); + _745773_660977 (mem,_661009, comp_tup_pb__cont_cont_cont_745796_661025) + }; + .let _660955: .Idx 4294967296 = %core.wrap.mul _32 0 (4:(.Idx 4294967296), _745755_660948); + _660909 (mem,_660955, comp_tup_pb__745765_660965) + // _660909 (mem,_660955, zero_pb_745910_661133) + // works + // _660909 (mem,1:(.Idx 4294967296), zero_pb_745910_661133) + }; + .con aug_pow_else_745690_660849 [mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + .let _660892: .Idx 4294967296 = %core.wrap.add _32 0 (4294967295:(.Idx 4294967296), _660885); + aug_f_745675_660796 (mem,_660892, aug_pow_cont_745734_660902) + }; + .con aug_pow_then_745900_661112[mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + _660909 (mem,1:(.Idx 4294967296), zero_pb_745910_661133) + }; + .let _661176: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _660885); + (aug_pow_else_745690_660849, aug_pow_then_745900_661112)#_661176 (mem,tup_pb_745946_661190) + // aug_pow_then_745900_661112 tup_pb_745946_661190 +}; +.con .extern main __746011_661274::[mem_746034_661291: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_746015_661278: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_746015_661272[_661279: [%mem.M, .Idx 4294967296]]@(0:(.Idx 2)) = { + return_746015_661278 _661279 + }; + .con ret_cont_745972_661223 __745982_661247::[mem:%mem.M,r_746066_661318: .Idx 4294967296, pb_745984_661249: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con pb_ret_cont_746000_661266 __746083_661349::[mem:%mem.M,[pr_a_746103_661369: .Idx 4294967296, pr_b_746084_661350: .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _661325: .Idx 4294967296 = %core.wrap.mul _32 0 (10000:(.Idx 4294967296), r_746066_661318); + .let _661376: .Idx 4294967296 = %core.wrap.mul _32 0 (100:(.Idx 4294967296), pr_a_746103_661369); + .let _661381: .Idx 4294967296 = %core.wrap.add _32 0 (pr_b_746084_661350, _661376); + .let _661386: .Idx 4294967296 = %core.wrap.add _32 0 (_661325, _661381); + return_746015_661272 (mem_746034_661291, _661386) + }; + pb_745984_661249 (mem,1:(.Idx 4294967296), pb_ret_cont_746000_661266) + }; + aug_f_745675_660796 (mem_746034_661291,3:(.Idx 4294967296), ret_cont_745972_661223) +}; diff --git a/lit/clos/pow_ad_eval_simpl2_mem_simpl.thorin b/lit/clos/pow_ad_eval_simpl2_mem_simpl.thorin new file mode 100644 index 0000000000..959ad14a45 --- /dev/null +++ b/lit/clos/pow_ad_eval_simpl2_mem_simpl.thorin @@ -0,0 +1,79 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + + +/* +*/ + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con zero_pb_745910_661133 _745912_661141::[mem:%mem.M, .Idx 4294967296, _745914_661143: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745914_661139 _661144::[mem:%mem.M,_661144_2: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745914_661143 _661144 + }; + _745914_661139 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con tup_pb_745946_661190 _745948_661198::[mem:%mem.M,_745950_661200: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + .con _745950_661196 [mem:%mem.M,_661201: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + _745950_661200 (mem,_661201) + }; + _745950_661196 (mem,‹2; 0:(.Idx 4294967296)›) +}; +.con aug_f_745675_660796 _660883::[mem:%mem.M,_660885: .Idx 4294967296, _660909: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]]] @(0:(.Idx 2)) = { + // .con aug_pow_cont_745734_660902 _745753_660946::[mem:%mem.M,_745755_660948: .Idx 4294967296, _745773_660977: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con comp_tup_pb__745765_660965 _745778_661000::[mem:%mem.M,_745780_661002: .Idx 4294967296, _745799_661037: .Cn [%mem.M,«2; .Idx 4294967296»]] @(1:(.Idx 2)) = { + _745799_661037 (mem,(_745780_661002,_745780_661002)) + }; + // _745773_660977 (mem, _745755_660948, comp_tup_pb__745765_660965) + // }; + _660909 (mem, _660885, comp_tup_pb__745765_660965) + + // .con top [%mem.M,.Idx 4294967296, ret: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] = { + // ret (mem, _660885, aug_pow_cont_745734_660902) + // }; + + // .con _745799_661035 [mem:%mem.M,_661038: «2; .Idx 4294967296»]@(0:(.Idx 2)) = { + // _745799_661037 (mem,_661038) + // }; + // .con comp_tup_pb__cont_cont_cont_745796_661025 _745840_661079::[mem:%mem.M,[_745841_661080: .Idx 4294967296, _745847_661092: .Idx 4294967296]] @(1:(.Idx 2)) = { + // .let _661066: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_745755_660948, _745780_661002); + // .let _661085: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_661066, _745841_661080); + // _745799_661035 (mem,(_661085, _745847_661092)) + // }; + // .let _661009: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745780_661002); + // _745773_660977 (mem,_661009, comp_tup_pb__cont_cont_cont_745796_661025) + // }; + // .let _660955: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _745755_660948); + // _660909 (mem,_660955, comp_tup_pb__745765_660965) + // }; + // .con aug_pow_else_745690_660849 [mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + // .let _660892: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _660885); + // aug_f_745675_660796 (_660892, aug_pow_cont_745734_660902) + // }; + // .con aug_pow_then_745900_661112[mem:%mem.M,.Cn [%mem.M,.Cn [%mem.M,«2; .Idx 4294967296»]]]@(0:(.Idx 2)) = { + // _660909 (1:(.Idx 4294967296), zero_pb_745910_661133) + // }; + // .let _661176: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _660885); + // (aug_pow_else_745690_660849, aug_pow_then_745900_661112)#_661176 tup_pb_745946_661190 + // aug_pow_then_745900_661112 tup_pb_745946_661190 +}; +.con .extern main __746011_661274::[mem_746034_661291: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_746015_661278: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con return_746015_661272[_661279: [%mem.M, .Idx 4294967296]]@(0:(.Idx 2)) = { + return_746015_661278 _661279 + }; + .con ret_cont_745972_661223 __745982_661247::[mem:%mem.M,r_746066_661318: .Idx 4294967296, pb_745984_661249: .Cn [%mem.M,.Idx 4294967296, .Cn [%mem.M,«2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con pb_ret_cont_746000_661266 __746083_661349::[mem:%mem.M,[pr_a_746103_661369: .Idx 4294967296, pr_b_746084_661350: .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _661325: .Idx 4294967296 = %core.wrap.mul _32 0 (10000:(.Idx 4294967296), r_746066_661318); + .let _661376: .Idx 4294967296 = %core.wrap.mul _32 0 (100:(.Idx 4294967296), pr_a_746103_661369); + .let _661381: .Idx 4294967296 = %core.wrap.add _32 0 (pr_b_746084_661350, _661376); + .let _661386: .Idx 4294967296 = %core.wrap.add _32 0 (_661325, _661381); + return_746015_661272 (mem_746034_661291, _661386) + }; + pb_745984_661249 (mem,1:(.Idx 4294967296), pb_ret_cont_746000_661266) + }; + aug_f_745675_660796 (mem_746034_661291,3:(.Idx 4294967296), ret_cont_745972_661223) +}; diff --git a/lit/clos/recursiveLoop.thorin b/lit/clos/recursiveLoop.thorin new file mode 100644 index 0000000000..21f7046b04 --- /dev/null +++ b/lit/clos/recursiveLoop.thorin @@ -0,0 +1,64 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + +.import mem; +.import core; +.import direct; + +.let _32 = 4294967296; +.let I32 = .Idx _32; +.let i8 = .Idx 256; +.let pb_type = .Cn [%mem.M, .Cn [%mem.M]]; + +.con printInteger [mem: %mem.M, val: I32, return : .Cn [%mem.M]]; +.con printIntegerNL [mem: %mem.M, val: I32, return : .Cn [%mem.M]]; +.con printNL [mem: %mem.M, return : .Cn [%mem.M]]; + +.let size = 10:.Nat; + +.con recursive [mem: %mem.M, i : I32, last_pullback: pb_type, return: .Cn [%mem.M]] = { + .con exit [mem: %mem.M] = { + last_pullback ( mem, return ) + }; + + .con loop_body [mem: %mem.M] = { + .con pb [mem: %mem.M, return: .Cn [%mem.M]] = { + .con next [mem: %mem.M] = { + last_pullback (mem, return) + }; + + printIntegerNL( mem, i , next ) + }; + + .con next [mem: %mem.M] = { + recursive( mem, %core.wrap.add _32 0 (i, 1:I32), pb, return ) + }; + + printIntegerNL( mem, i , next ) + }; + + .let condition = %core.icmp.ul 4294967296 (i, %core.bitcast (I32, .Nat) size); + .let target = (exit, loop_body)#condition; + target ( mem ) +}; + +.con end [mem: %mem.M, return : .Cn [%mem.M]] = { + return (mem) +}; + +.con outer [mem: %mem.M, x : I32, return : .Cn [%mem.M]] = { + recursive ( mem, 0:I32, end, return ) +}; + +.con .extern main [mem: %mem.M, argc: I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0:.Nat)», 0:.Nat), return : .Cn [%mem.M, I32]] = { + .con callback (mem: %mem.M) = { + + .con callback2 (mem: %mem.M) = { + return (mem, 1:I32) + }; + + recursive (mem, 3:I32, end, callback2) + }; + + outer(mem, 1:I32, callback) +}; diff --git a/lit/clos/return_higher_order3.thorin.disabled b/lit/clos/return_higher_order3.thorin.disabled new file mode 100644 index 0000000000..1aeec99597 --- /dev/null +++ b/lit/clos/return_higher_order3.thorin.disabled @@ -0,0 +1,28 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + +/* +TODO: investigate and open error +thorin: /dialects/clos/phase/clos_conv.cpp:64: const thorin::Def* thorin::clos::clos_pack_dbg(const thorin::Def*, const thorin::Def*, const thorin::Def*, const thorin::Def*): Assertion `pi && env->type() == pi->dom(Clos_Env_Param)' failed. +*/ + +.import mem; +.import core; +.import direct; + +.let i32 = .Idx 4294967296; +.let i8 = .Idx 256; +.let pb_type = .Cn [%mem.M]; + +.con .extern main [mem: %mem.M, argc: i32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0:.Nat)», 0:.Nat), return : .Cn [%mem.M, i32]] = { + .con callback (mem: %mem.M) = { + return (mem, 1:i32) + }; + + .let (alloc_pb_mem, pb_ptr) = %mem.malloc (pb_type, 0) (mem, 1); + + .let store_return_mem = %mem.store (pb_type, 0) (alloc_pb_mem, pb_ptr, callback); + + .let (load_clos_mem, load_clos) = %mem.load (pb_type, 0) (store_return_mem, pb_ptr); + load_clos(load_clos_mem) +}; diff --git a/lit/clos/return_higher_order4.thorin b/lit/clos/return_higher_order4.thorin new file mode 100644 index 0000000000..770b5b044f --- /dev/null +++ b/lit/clos/return_higher_order4.thorin @@ -0,0 +1,28 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + +/* +TODO: investigate and open error +thorin: /dialects/clos/phase/clos_conv.cpp:64: const thorin::Def* thorin::clos::clos_pack_dbg(const thorin::Def*, const thorin::Def*, const thorin::Def*, const thorin::Def*): Assertion `pi && env->type() == pi->dom(Clos_Env_Param)' failed. +*/ + +.import mem; +.import core; +.import direct; + +.let i32 = .Idx 4294967296; +.let i8 = .Idx 256; +.let pb_type = .Cn [%mem.M, .Cn [%mem.M, i32]]; + +.con .extern main [mem: %mem.M, argc: i32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0:.Nat)», 0:.Nat), return : .Cn [%mem.M, i32]] = { + .con callback [mem: %mem.M, return : .Cn [%mem.M, i32]] = { + return (mem, 1:i32) + }; + + .let (alloc_pb_mem, pb_ptr) = %mem.malloc (pb_type, 0) (mem, 1); + + .let store_return_mem = %mem.store (pb_type, 0) (alloc_pb_mem, pb_ptr, callback); + + .let (load_clos_mem, load_clos) = %mem.load (pb_type, 0) (store_return_mem, pb_ptr); + load_clos(load_clos_mem, return) +}; diff --git a/lit/clos/return_higher_order5.thorin.disabled b/lit/clos/return_higher_order5.thorin.disabled new file mode 100644 index 0000000000..389a1f2de3 --- /dev/null +++ b/lit/clos/return_higher_order5.thorin.disabled @@ -0,0 +1,28 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d clos %s --output-ll %t.ll -o - + +/* +TODO: investigate and open error +thorin: /dialects/clos/phase/clos_conv.cpp:64: const thorin::Def* thorin::clos::clos_pack_dbg(const thorin::Def*, const thorin::Def*, const thorin::Def*, const thorin::Def*): Assertion `pi && env->type() == pi->dom(Clos_Env_Param)' failed. +*/ + +.import mem; +.import core; +.import direct; + +.let i32 = .Idx 4294967296; +.let i8 = .Idx 256; +.let pb_type = .Cn [%mem.M, .Cn [%mem.M, i32]]; + +.con .extern main [mem: %mem.M, argc: i32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0:.Nat)», 0:.Nat), return : .Cn [%mem.M, i32]] = { + .con callback [mem: %mem.M, return2 : .Cn [%mem.M, i32]] = { + return (mem, 1:i32) + }; + + .let (alloc_pb_mem, pb_ptr) = %mem.malloc (pb_type, 0) (mem, 1); + + .let store_return_mem = %mem.store (pb_type, 0) (alloc_pb_mem, pb_ptr, callback); + + .let (load_clos_mem, load_clos) = %mem.load (pb_type, 0) (store_return_mem, pb_ptr); + load_clos(load_clos_mem, return) +}; diff --git a/lit/clos/using_c_function.thorin b/lit/clos/using_c_function.thorin index 8f42cbd7fa..7d36e31eec 100644 --- a/lit/clos/using_c_function.thorin +++ b/lit/clos/using_c_function.thorin @@ -1,6 +1,13 @@ // RUN: rm -f %t.ll ; \ // RUN: %thorin -d clos %s --output-ll %t.ll -o - + +// build a linked list/stack/for loop +// in a for loop +// first the integers are printed ascending +// then the stack is called and should print them descending +// the functions are stored and loaded in between each iteration + .import mem; .import core; .import direct; diff --git a/lit/compile/default.thorin b/lit/compile/default.thorin index b33b2fbd87..7a4b61866c 100644 --- a/lit/compile/default.thorin +++ b/lit/compile/default.thorin @@ -17,7 +17,7 @@ }; .lam .extern _compile [] -> Pipeline = { - default_pipeline + default_core_pipeline }; // CHECK-DAG: .con return diff --git a/lit/compile/id.thorin b/lit/compile/id.thorin index ebf234bb65..11783111a4 100644 --- a/lit/compile/id.thorin +++ b/lit/compile/id.thorin @@ -14,6 +14,7 @@ .lam .extern _compile [] -> Pipeline = { %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) // (%compile.debug_phase 1) (%compile.debug_phase 2) // (%compile.debug_phase 3) diff --git a/lit/compile/opt.thorin b/lit/compile/opt.thorin index 1bdeb69581..7f9d74ba38 100644 --- a/lit/compile/opt.thorin +++ b/lit/compile/opt.thorin @@ -18,6 +18,7 @@ .lam .extern _compile [] -> Pipeline = { %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) optimization_phase }; diff --git a/lit/compile/ret_wrap.thorin b/lit/compile/ret_wrap.thorin index e2f25b98e4..71c8f40b50 100644 --- a/lit/compile/ret_wrap.thorin +++ b/lit/compile/ret_wrap.thorin @@ -18,6 +18,7 @@ .lam .extern _compile [] -> Pipeline = { %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) (%compile.passes_to_phase 1 %compile.ret_wrap_pass) }; diff --git a/lit/compile/two_phase.thorin b/lit/compile/two_phase.thorin index b65f0a2148..a940c1c9f7 100644 --- a/lit/compile/two_phase.thorin +++ b/lit/compile/two_phase.thorin @@ -18,6 +18,7 @@ .lam .extern _compile [] -> Pipeline = { %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) (%compile.passes_to_phase 1 %compile.ret_wrap_pass) (%compile.passes_to_phase 1 %compile.ret_wrap_pass) }; diff --git a/lit/compile/unused.thorin b/lit/compile/unused.thorin new file mode 100644 index 0000000000..df51caec00 --- /dev/null +++ b/lit/compile/unused.thorin @@ -0,0 +1,20 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - | FileCheck %s + +.import mem; +.import compile; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return : .Cn [%mem.M, I32]] = { + return (mem, 42:I32) +}; + +.lam .extern _unused_compile [] -> Pipeline = { + %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) +}; + +// CHECK-DAG: return{{.*}}42 diff --git a/lit/core/normalize_and_tree.thorin b/lit/core/normalize_and_tree.thorin index dfec5c839f..6a98c1308f 100644 --- a/lit/core/normalize_and_tree.thorin +++ b/lit/core/normalize_and_tree.thorin @@ -14,9 +14,9 @@ %core.bit2.and_ 2 (.tt, .ff)))) }; -// CHECK-DAG: .con .extern and_lit _[[retId:[0-9_]+]]: .Cn .Idx 2 = { +// CHECK-DAG: .con .extern and_lit _[[retId:[0-9_]+]]: .Cn .Idx 2 {{(@.*)?}}= { // CHECK-DAG: _[[etaId:[0-9_]+]] 0:(.Idx 2) -// CHECK-DAG: .con _[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 2 = { +// CHECK-DAG: .con _[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 2 {{(@.*)?}}= { // CHECK-DAG: _[[retId]] _[[etaVar]] diff --git a/lit/core/normalize_and_tt.thorin b/lit/core/normalize_and_tt.thorin index ed863e21f5..8587550d08 100644 --- a/lit/core/normalize_and_tt.thorin +++ b/lit/core/normalize_and_tt.thorin @@ -7,8 +7,8 @@ return (%core.bit2.and_ 2 (i, .tt)) }; -// CHECK-DAG: and_tt _{{[0-9_]+}}::[i_[[valId_tt:[0-9_]+]]: .Idx 2, return_[[retId_tt:[0-9_]+]]: .Cn .Idx 2] = { +// CHECK-DAG: and_tt _{{[0-9_]+}}::[i_[[valId_tt:[0-9_]+]]: .Idx 2, return_[[retId_tt:[0-9_]+]]: .Cn .Idx 2] {{(@.*)?}}= { // CHECK-DAG: return_[[etaId_tt:[0-9_]+]] i_[[valId_tt]] -// CHECK-DAG: return_[[etaId_tt]] _[[etaVar_tt:[0-9_]+]]: .Idx 2 = { +// CHECK-DAG: return_[[etaId_tt]] _[[etaVar_tt:[0-9_]+]]: .Idx 2 {{(@.*)?}}= { // CHECK-DAG: return_[[retId_tt]] _[[etaVar_tt]] diff --git a/lit/core/normalize_and_tt_tt.thorin b/lit/core/normalize_and_tt_tt.thorin index a9414083e2..d48bef4caf 100644 --- a/lit/core/normalize_and_tt_tt.thorin +++ b/lit/core/normalize_and_tt_tt.thorin @@ -7,8 +7,8 @@ return (%core.bit2.and_ 2 (.tt, .tt)) }; -// CHECK-DAG: .con .extern and_lit_tt_tt _[[retId:[0-9_]+]]: .Cn .Idx 2 = { +// CHECK-DAG: .con .extern and_lit_tt_tt _[[retId:[0-9_]+]]: .Cn .Idx 2 {{(@.*)?}}= { // CHECK-DAG: _[[etaId:[0-9_]+]] 1:(.Idx 2) -// CHECK-DAG: .con _[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 2 = { +// CHECK-DAG: .con _[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 2 {{(@.*)?}}= { // CHECK-DAG: _[[retId]] _[[etaVar]] diff --git a/lit/core/normalize_bitcast.thorin b/lit/core/normalize_bitcast.thorin index beb1cd3072..4f9a4602a8 100644 --- a/lit/core/normalize_bitcast.thorin +++ b/lit/core/normalize_bitcast.thorin @@ -8,9 +8,9 @@ return (%core.bitcast (.Idx 4294967296, .Nat) (%core.bitcast (.Nat, %mem.Ptr (.Idx 256, 0)) i)) }; -// CHECK-DAG: bitcast_bitcast _{{[0-9_]+}}::[i_[[valId:[0-9_]+]]: %mem.Ptr (.Idx 256, 0), return_[[retId:[0-9_]+]]: .Cn .Idx 4294967296] = { +// CHECK-DAG: bitcast_bitcast _{{[0-9_]+}}::[i_[[valId:[0-9_]+]]: %mem.Ptr (.Idx 256, 0), return_[[retId:[0-9_]+]]: .Cn .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: .let _[[castedId:[0-9_]+]]: .Idx 4294967296 = %core.bitcast (.Idx 4294967296, %mem.Ptr (.Idx 256, 0)) i_[[valId]]; // CHECK-DAG: return_[[etaId:[0-9_]+]] _[[castedId]] -// CHECK-DAG: return_[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 4294967296 = { +// CHECK-DAG: return_[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 4294967296 {{(@.*)?}}= { // CHECK-DAG: return_[[retId]] _[[etaVar]] diff --git a/lit/core/normalize_icmp.thorin b/lit/core/normalize_icmp.thorin index a2d62bee11..b31ced4f7d 100644 --- a/lit/core/normalize_icmp.thorin +++ b/lit/core/normalize_icmp.thorin @@ -12,8 +12,8 @@ (.tt, .ff))) }; -// CHECK-DAG: icmp_lit _[[retId:[0-9_]+]]: .Cn .Idx 2 = { +// CHECK-DAG: icmp_lit _[[retId:[0-9_]+]]: .Cn .Idx 2 {{(@.*)?}}= { // CHECK-DAG: _[[etaId:[0-9_]+]] 1:(.Idx 2) -// CHECK-DAG: _[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 2 = { +// CHECK-DAG: _[[etaId]] _[[etaVar:[0-9_]+]]: .Idx 2 {{(@.*)?}}= { // CHECK-DAG: _[[retId]] _[[etaVar]] diff --git a/lit/core/pow.thorin b/lit/core/pow.thorin index 19270b4ba9..f6e2484812 100644 --- a/lit/core/pow.thorin +++ b/lit/core/pow.thorin @@ -44,18 +44,18 @@ }; -// 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_]+}}::[_{{[0-9_]+}}: .Idx 4294967296, _{{[0-9_]+}}: .Cn .Idx 4294967296] {{(@.*)?}}= { +// CHECK-DAG: .con _{{[0-9_]+}} _{{[0-9_]+}}: .Idx 4294967296 {{(@.*)?}}= { // CHECK-DAG: _{{[0-9_]+}} _{{[0-9_]+}} -// CHECK-DAG: .con pow_then_{{[0-9_]+}} [] = { +// CHECK-DAG: .con pow_then_{{[0-9_]+}} [] {{(@.*)?}}= { // CHECK-DAG: _{{[0-9_]+}} 1:(.Idx 4294967296) -// CHECK-DAG: .con pow_cont_{{[0-9_]+}} __{{[0-9_]+}}: .Idx 4294967296 = { +// CHECK-DAG: .con pow_cont_{{[0-9_]+}} _{{[0-9_]+}}: .Idx 4294967296 {{(@.*)?}}= { // CHECK-DAG: .let _{{[0-9_]+}}: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (42:(.Idx 4294967296), _{{[0-9_]+}}); // CHECK-DAG: _{{[0-9_]+}} _{{[0-9_]+}} -// CHECK-DAG: .con pow_else_{{[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: f_{{[0-9_]+}} (_{{[0-9_]+}}, pow_cont_{{[0-9_]+}}) diff --git a/lit/core/ret_add.thorin b/lit/core/ret_add.thorin index e05107165e..cc4592336f 100644 --- a/lit/core/ret_add.thorin +++ b/lit/core/ret_add.thorin @@ -25,7 +25,7 @@ atoi (argv_load_a#.ff, argv_load_a#.tt, atoi_cont_a) }; -// CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .Idx 4294967296, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .Idx 4294967296, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: atoi_cont_a_[[aContId:[0-9_]+]] _{{[0-9_]+}}::[mem_{{[0-9]+}}: %mem.M, a_[[aId:[0-9_]+]]: .Idx 4294967296] diff --git a/lit/core/ret_and.thorin b/lit/core/ret_and.thorin index 74cbf3d808..976f0aa40b 100644 --- a/lit/core/ret_and.thorin +++ b/lit/core/ret_and.thorin @@ -25,7 +25,7 @@ atoi (argv_load_a#.ff, argv_load_a#.tt, atoi_cont_a) }; -// CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .Idx 4294967296, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .Idx 4294967296, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: atoi_cont_a_[[aContId:[0-9_]+]] _{{[0-9_]+}}::[mem_{{[0-9]+}}: %mem.M, a_[[aId:[0-9_]+]]: .Idx 4294967296] diff --git a/lit/core/ret_lshr.thorin b/lit/core/ret_lshr.thorin index 3016e6e21f..75a4a24679 100644 --- a/lit/core/ret_lshr.thorin +++ b/lit/core/ret_lshr.thorin @@ -25,7 +25,7 @@ atoi (argv_load_a#.ff, argv_load_a#.tt, atoi_cont_a) }; -// CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .Idx 4294967296, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .Idx 4294967296, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: atoi_cont_a_[[aContId:[0-9_]+]] _{{[0-9_]+}}::[mem_{{[0-9]+}}: %mem.M, a_[[aId:[0-9_]+]]: .Idx 4294967296] diff --git a/lit/demo/const.thorin b/lit/demo/const.thorin index 20edfab06b..136d282772 100644 --- a/lit/demo/const.thorin +++ b/lit/demo/const.thorin @@ -14,8 +14,8 @@ ret_cont c }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId:[_0-9]*]] (mem_[[memId]], 42:(.Idx 4294967296)) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/direct/2out_2.thorin.disabled b/lit/direct/2out_2.thorin.disabled index 46c884e046..48c8c0fc5c 100644 --- a/lit/direct/2out_2.thorin.disabled +++ b/lit/direct/2out_2.thorin.disabled @@ -10,38 +10,6 @@ old var access .import core; .import direct; .import mem; -.lam .extern internal_diff_core_icmp_xYgLE __661202: .Nat → .Cn [«2; (.Idx __661202)», .Cn [(.Idx 2), .Cn [(.Idx 2), .Cn «2; (.Idx __661202)»]]] = { - .con cmp_pb_661307 __661318::[(.Idx 2), pb_ret_661320: .Cn «2; (.Idx __661202)»] = { - pb_ret_661320 ‹2; 0:(.Idx __661202)› - }; - .con inner_cmp_661249 __661263::[__661282::[_661286: (.Idx __661202), _661290: (.Idx __661202)], ret_661265: .Cn [(.Idx 2), .Cn [(.Idx 2), .Cn «2; (.Idx __661202)»]]] = { - .let _661293: (.Idx 2) = %core.icmp.xYgLE __661202 __661282; - ret_661265 (_661293, cmp_pb_661307) - }; - inner_cmp_661249 -}; -.lam .extern internal_diff_core_wrap_add __661416::[_661507: .Nat, w_661417: .Nat] → .Cn [«2; (.Idx w_661417)», .Cn [(.Idx w_661417), .Cn [(.Idx w_661417), .Cn «2; (.Idx w_661417)»]]] = { - .con add_pb_661520 __661529::[s_661539: (.Idx w_661417), pb_ret_661531: .Cn «2; (.Idx w_661417)»] = { - pb_ret_661531 ‹2; s_661539› - }; - .con inner_add_deriv_cps_661466 __661475::[__661495::[_661499: (.Idx w_661417), _661503: (.Idx w_661417)], ret_661477: .Cn [(.Idx w_661417), .Cn [(.Idx w_661417), .Cn «2; (.Idx w_661417)»]]] = { - .let _661510: (.Idx w_661417) = %core.wrap.add __661416 __661495; - ret_661477 (_661510, add_pb_661520) - }; - inner_add_deriv_cps_661466 -}; -.lam .extern internal_diff_core_wrap_mul __661617::[_661702: .Nat, w_661618: .Nat] → .Cn [«2; (.Idx w_661618)», .Cn [(.Idx w_661618), .Cn [(.Idx w_661618), .Cn «2; (.Idx w_661618)»]]] = { - .con inner_mul_deriv_cps_661661 __661670::[__661690::[_661694: (.Idx w_661618), _661698: (.Idx w_661618)], ret_661672: .Cn [(.Idx w_661618), .Cn [(.Idx w_661618), .Cn «2; (.Idx w_661618)»]]] = { - .con mul_pb_661715 __661724::[s_661739: (.Idx w_661618), pb_ret_661726: .Cn «2; (.Idx w_661618)»] = { - .let _661751: (.Idx w_661618) = %core.wrap.mul __661617 (__661690#1:(.Idx 2), s_661739); - .let _661761: (.Idx w_661618) = %core.wrap.mul __661617 (__661690#0:(.Idx 2), s_661739); - pb_ret_661726 (_661751, _661761) - }; - .let _661705: (.Idx w_661618) = %core.wrap.mul __661617 __661690; - ret_661672 (_661705, mul_pb_661715) - }; - inner_mul_deriv_cps_661661 -}; .lam Uf_661956 _661974: (.Idx 4294967296) → ★ = { (.Idx 4294967296) }; diff --git a/lit/direct/ad_mem.thorin b/lit/direct/ad_mem.thorin new file mode 100644 index 0000000000..86e55b88e5 --- /dev/null +++ b/lit/direct/ad_mem.thorin @@ -0,0 +1,102 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d direct %s -o - | FileCheck %s + +.import core; +.import direct; +.import mem; +.lam Uf_690595 _690612: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_690659 _690676: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_690710 _690711::[__690716::[_690720: .Idx 4294967296, _690724: .Idx 4294967296], ret_690713: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_690728 __690729::[s_690734: .Idx 4294967296, pb_ret_690731: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _690746: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#1:(.Idx 2), s_690734); + .let _690752: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#0:(.Idx 2), s_690734); + pb_ret_690731 (_690746, _690752) + }; + .let _690727: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __690716; + ret_690713 (_690727, mul_pb_690728) +}; +.lam Uf_691251 _691268: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_691294 _691295::[__691299::[_691303: .Idx 4294967296, _691307: .Idx 4294967296], ret_691297: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_691311 __691312::[s_691317: .Idx 4294967296, pb_ret_691314: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _691322: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#1:(.Idx 2), s_691317); + .let _691328: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#0:(.Idx 2), s_691317); + pb_ret_691314 (_691322, _691328) + }; + .let _691310: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __691299; + ret_691297 (_691310, mul_pb_691311) +}; +.lam Uf_691363 _691380: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691406 _691407::[.Idx 4294967296, _691409: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691409 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691429 _691446: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con extract_pb_691470 _691471::[s_691476: .Idx 4294967296, _691473: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691473 (⊥:%mem.M, s_691476) +}; +.lam Uf_691899 _691916: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691934 _691935::[.Idx 4294967296, _691937: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691937 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691949 _691966: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_692052 _692069: %mem.M → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_692087 _692088::[%mem.M, _692090: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _692090 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.con .extern main __690558::[mem_690876: %mem.M, argc_691342: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_690562: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _691344: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_691251) eta_inner_mul_deriv_cps_691294 (42:(.Idx 4294967296), argc_691342); + // ^ + .con comp_tup_pb__691250 _691347::[_691349: .Idx 4294967296, _691358: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691356 _691420::[_691421: .Idx 4294967296, _691480: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691422: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691363) zero_pb_691406 _691421; + // ^ + .let _691481: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691429) extract_pb_691470 _691480; + // ^ + .let _691488: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691422#1:(.Idx 2), _691481#1:(.Idx 2)); + _691358 (⊤:%mem.M, _691488) + }; + _691344#1:(.Idx 2) (_691349, comp_tup_pb__cont_691356) + }; + .let _690877: [%mem.M, %mem.Ptr («100; .Idx 4294967296», 0)] = %mem.alloc («100; .Idx 4294967296», 0) mem_690876; + .let _pullback_alloc_690882: [%mem.M, %mem.Ptr («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0)] = %mem.malloc («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0) (_690877#0:(.Idx 2), 800); + .let pullback_lea_691249: %mem.Ptr (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) = %mem.lea (100, ‹100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]›, 0) (_pullback_alloc_690882#1:(.Idx 2), 1:(.Idx 100)); + .let _691499: %mem.M = %mem.store (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (_pullback_alloc_690882#0:(.Idx 2), pullback_lea_691249, comp_tup_pb__691250); + .let _691865: %mem.Ptr (.Idx 4294967296, 0) = %mem.lea (100, ‹100; .Idx 4294967296›, 0) (_690877#1:(.Idx 2), 1:(.Idx 100)); + .let _691874: %mem.M = %mem.store (.Idx 4294967296, 0) (_691499, _691865, _691344#0:(.Idx 2)); + .let aug_load_691882: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_691874, _691865); + .let pullback_load_692016: [%mem.M, .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]] = %mem.load (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (aug_load_691882#0:(.Idx 2), pullback_lea_691249); + .con comp_tup_pb__690636 _691889::[_691891: .Idx 4294967296, _691894: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691892 _691940::[_691941: .Idx 4294967296, _692020: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691942: [%mem.M, .Idx 4294967296] = (⊤:%mem.M, 42:(.Idx 4294967296)); + .let _692021: [%mem.M, .Idx 4294967296] = (⊤:%mem.M, 42:(.Idx 4294967296)); + .let _692028: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691942#1:(.Idx 2), _692021#1:(.Idx 2)); + _691894 (⊤:%mem.M, _692028) + }; + .let _691886: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_690659) eta_inner_mul_deriv_cps_690710 (100:(.Idx 4294967296), aug_load_691882#1:(.Idx 2)); + // ^ + _691886#1:(.Idx 2) (_691891, comp_tup_pb__cont_691892) + }; + .let _692035: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_690595) comp_tup_pb__690636 1:(.Idx 4294967296); + // ^ + .let _692095: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (%mem.M, Uf_692052) zero_pb_692087 pullback_load_692016#0:(.Idx 2); + // ^ + .let _692102: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_692035#1:(.Idx 2), _692095#1:(.Idx 2)); + return_690562 (⊤:%mem.M, _692102) +}; + +// CHECK-DAG: return{{.*}}84 diff --git a/lit/direct/ad_mem.thorin.disabled b/lit/direct/ad_mem.thorin.disabled new file mode 100644 index 0000000000..8e56c454c5 --- /dev/null +++ b/lit/direct/ad_mem.thorin.disabled @@ -0,0 +1,107 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d direct %s -o - | FileCheck %s + +.import core; +.import direct; +.import mem; +.lam Uf_690595 _690612: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_690659 _690676: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_690710 _690711::[__690716::[_690720: .Idx 4294967296, _690724: .Idx 4294967296], ret_690713: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_690728 __690729::[s_690734: .Idx 4294967296, pb_ret_690731: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _690746: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#1:(.Idx 2), s_690734); + .let _690752: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#0:(.Idx 2), s_690734); + pb_ret_690731 (_690746, _690752) + }; + .let _690727: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __690716; + ret_690713 (_690727, mul_pb_690728) +}; +.lam Uf_691251 _691268: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_691294 _691295::[__691299::[_691303: .Idx 4294967296, _691307: .Idx 4294967296], ret_691297: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_691311 __691312::[s_691317: .Idx 4294967296, pb_ret_691314: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _691322: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#1:(.Idx 2), s_691317); + .let _691328: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#0:(.Idx 2), s_691317); + pb_ret_691314 (_691322, _691328) + }; + .let _691310: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __691299; + ret_691297 (_691310, mul_pb_691311) +}; +.lam Uf_691363 _691380: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691406 _691407::[.Idx 4294967296, _691409: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691409 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691429 _691446: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con extract_pb_691470 _691471::[s_691476: .Idx 4294967296, _691473: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691473 (⊥:%mem.M, s_691476) +}; +.lam Uf_691899 _691916: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691934 _691935::[.Idx 4294967296, _691937: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691937 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691949 _691966: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_692052 _692069: %mem.M → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_692087 _692088::[%mem.M, _692090: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _692090 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.con .extern main __690558::[mem_690876: %mem.M, argc_691342: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_690562: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _691344: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_691251) eta_inner_mul_deriv_cps_691294 (42:(.Idx 4294967296), argc_691342); + // ^ + .con comp_tup_pb__691250 _691347::[_691349: .Idx 4294967296, _691358: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691356 _691420::[_691421: .Idx 4294967296, _691480: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691422: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691363) zero_pb_691406 _691421; + // ^ + .let _691481: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691429) extract_pb_691470 _691480; + // ^ + .let _691488: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691422#1:(.Idx 2), _691481#1:(.Idx 2)); + _691358 (⊤:%mem.M, _691488) + }; + _691344#1:(.Idx 2) (_691349, comp_tup_pb__cont_691356) + }; + .let _690877: [%mem.M, %mem.Ptr («100; .Idx 4294967296», 0)] = %mem.alloc («100; .Idx 4294967296», 0) mem_690876; + .let _pullback_alloc_690882: [%mem.M, %mem.Ptr («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0)] = %mem.malloc («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0) (_690877#0:(.Idx 2), 800); + .let pullback_lea_691249: %mem.Ptr (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) = %mem.lea (100, ‹100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]›, 0) (_pullback_alloc_690882#1:(.Idx 2), 1:(.Idx 100)); + .let _691499: %mem.M = %mem.store (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (_pullback_alloc_690882#0:(.Idx 2), pullback_lea_691249, comp_tup_pb__691250); + .let _691865: %mem.Ptr (.Idx 4294967296, 0) = %mem.lea (100, ‹100; .Idx 4294967296›, 0) (_690877#1:(.Idx 2), 1:(.Idx 100)); + .let _691874: %mem.M = %mem.store (.Idx 4294967296, 0) (_691499, _691865, _691344#0:(.Idx 2)); + .let aug_load_691882: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_691874, _691865); + .let pullback_load_692016: [%mem.M, .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]] = %mem.load (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (aug_load_691882#0:(.Idx 2), pullback_lea_691249); + .con comp_tup_pb__690636 _691889::[_691891: .Idx 4294967296, _691894: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691892 _691940::[_691941: .Idx 4294967296, _692020: .Idx 4294967296] @(1:(.Idx 2)) = { + // .let _691942: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691899) zero_pb_691934 _691941; + // ^ + .let _691942: [%mem.M, .Idx 4294967296] = (⊤:%mem.M, 42:(.Idx 4294967296)); + // .let _692021: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691949) pullback_load_692016#1:(.Idx 2) _692020; + // ^ + .let _692021: [%mem.M, .Idx 4294967296] = (⊤:%mem.M, 42:(.Idx 4294967296)); + .let _692028: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691942#1:(.Idx 2), _692021#1:(.Idx 2)); + _691894 (⊤:%mem.M, _692028) + }; + // comp_tup_pb__cont_691892 (42:(.Idx 4294967296), 42:(.Idx 4294967296)) + .let _691886: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_690659) eta_inner_mul_deriv_cps_690710 (100:(.Idx 4294967296), aug_load_691882#1:(.Idx 2)); + // ^ + _691886#1:(.Idx 2) (_691891, comp_tup_pb__cont_691892) + }; + // .let _692035: [%mem.M, .Idx 4294967296] = (⊤:%mem.M,42:(.Idx 4294967296)); + .let _692035: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_690595) comp_tup_pb__690636 1:(.Idx 4294967296); + // ^ + // .let _692095: [%mem.M, .Idx 4294967296] = (pullback_load_692016#0:(.Idx 2), 43:(.Idx 4294967296)); + .let _692095: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (%mem.M, Uf_692052) zero_pb_692087 pullback_load_692016#0:(.Idx 2); + // ^ + .let _692102: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_692035#1:(.Idx 2), _692095#1:(.Idx 2)); + return_690562 (⊤:%mem.M, _692102) +}; diff --git a/lit/direct/ad_mem2.thorin b/lit/direct/ad_mem2.thorin new file mode 100644 index 0000000000..7bd9743997 --- /dev/null +++ b/lit/direct/ad_mem2.thorin @@ -0,0 +1,104 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d direct %s -o - | FileCheck %s + +.import core; +.import direct; +.import mem; +.lam Uf_690595 _690612: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_690659 _690676: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_690710 _690711::[__690716::[_690720: .Idx 4294967296, _690724: .Idx 4294967296], ret_690713: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_690728 __690729::[s_690734: .Idx 4294967296, pb_ret_690731: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _690746: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#1:(.Idx 2), s_690734); + .let _690752: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#0:(.Idx 2), s_690734); + pb_ret_690731 (_690746, _690752) + }; + .let _690727: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __690716; + ret_690713 (_690727, mul_pb_690728) +}; +.lam Uf_691251 _691268: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_691294 _691295::[__691299::[_691303: .Idx 4294967296, _691307: .Idx 4294967296], ret_691297: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_691311 __691312::[s_691317: .Idx 4294967296, pb_ret_691314: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _691322: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#1:(.Idx 2), s_691317); + .let _691328: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#0:(.Idx 2), s_691317); + pb_ret_691314 (_691322, _691328) + }; + .let _691310: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __691299; + ret_691297 (_691310, mul_pb_691311) +}; +.lam Uf_691363 _691380: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691406 _691407::[.Idx 4294967296, _691409: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691409 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691429 _691446: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con extract_pb_691470 _691471::[s_691476: .Idx 4294967296, _691473: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691473 (⊥:%mem.M, s_691476) +}; +.lam Uf_691899 _691916: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691934 _691935::[.Idx 4294967296, _691937: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691937 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691949 _691966: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_692052 _692069: %mem.M → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_692087 _692088::[%mem.M, _692090: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _692090 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.con .extern main __690558::[mem_690876: %mem.M, argc_691342: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_690562: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _691344: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_691251) eta_inner_mul_deriv_cps_691294 (42:(.Idx 4294967296), argc_691342); + // ^ + .con comp_tup_pb__691250 _691347::[_691349: .Idx 4294967296, _691358: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691356 _691420::[_691421: .Idx 4294967296, _691480: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691422: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691363) zero_pb_691406 _691421; + // ^ + .let _691481: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691429) extract_pb_691470 _691480; + // ^ + .let _691488: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691422#1:(.Idx 2), _691481#1:(.Idx 2)); + _691358 (⊤:%mem.M, _691488) + }; + _691344#1:(.Idx 2) (_691349, comp_tup_pb__cont_691356) + }; + .let _690877: [%mem.M, %mem.Ptr («100; .Idx 4294967296», 0)] = %mem.alloc («100; .Idx 4294967296», 0) mem_690876; + .let _pullback_alloc_690882: [%mem.M, %mem.Ptr («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0)] = %mem.malloc («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0) (_690877#0:(.Idx 2), 800); + .let pullback_lea_691249: %mem.Ptr (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) = %mem.lea (100, ‹100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]›, 0) (_pullback_alloc_690882#1:(.Idx 2), 1:(.Idx 100)); + .let _691499: %mem.M = %mem.store (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (_pullback_alloc_690882#0:(.Idx 2), pullback_lea_691249, comp_tup_pb__691250); + .let _691865: %mem.Ptr (.Idx 4294967296, 0) = %mem.lea (100, ‹100; .Idx 4294967296›, 0) (_690877#1:(.Idx 2), 1:(.Idx 100)); + .let _691874: %mem.M = %mem.store (.Idx 4294967296, 0) (_691499, _691865, _691344#0:(.Idx 2)); + .let aug_load_691882: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_691874, _691865); + .let pullback_load_692016: [%mem.M, .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]] = %mem.load (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (aug_load_691882#0:(.Idx 2), pullback_lea_691249); + .con comp_tup_pb__690636 _691889::[_691891: .Idx 4294967296, _691894: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691892 _691940::[_691941: .Idx 4294967296, _692020: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691942: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691899) zero_pb_691934 _691941; + // ^ + .let _692021: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691949) pullback_load_692016#1:(.Idx 2) _692020; + // ^ + .let _692028: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691942#1:(.Idx 2), _692021#1:(.Idx 2)); + _691894 (⊤:%mem.M, _692028) + }; + .let _691886: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_690659) eta_inner_mul_deriv_cps_690710 (100:(.Idx 4294967296), aug_load_691882#1:(.Idx 2)); + // ^ + _691886#1:(.Idx 2) (_691891, comp_tup_pb__cont_691892) + }; + .let _692035: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_690595) comp_tup_pb__690636 1:(.Idx 4294967296); + // ^ + .let _692095: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (%mem.M, Uf_692052) zero_pb_692087 pullback_load_692016#0:(.Idx 2); + // ^ + .let _692102: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_692035#1:(.Idx 2), _692095#1:(.Idx 2)); + return_690562 (⊤:%mem.M, _692102) +}; + +// CHECK-DAG: return{{.*}}84 diff --git a/lit/direct/ad_mem_eval.thorin.disabled b/lit/direct/ad_mem_eval.thorin.disabled new file mode 100644 index 0000000000..32e19a5370 --- /dev/null +++ b/lit/direct/ad_mem_eval.thorin.disabled @@ -0,0 +1,26 @@ +.import core; +.import direct; +.import mem; +.con comp_tup_pb__691250_320895 _691347_321743::[_691349_321745: .Idx 4294967296, _691358_321768: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con _691358_321766 [_321769: [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + _691358_321768 _321769 + }; + .con comp_tup_pb__cont_691356_321759 _691420_321787::[.Idx 4294967296, _691480_321788: .Idx 4294967296] @(1:(.Idx 2)) = { + _691358_321766 (⊤:%mem.M, _691480_321788) + }; + _321726 (_691349_321745, comp_tup_pb__cont_691356_321759) +}; +.con comp_tup_pb__cont_691892_cont_cont_321850 _321954::[%mem.M, _321956: .Idx 4294967296] @(1:(.Idx 2)) = { + return_690562_322234 (⊤:%mem.M, _321956) +}; +.con .extern main __690558_320477::[mem_690876_320481: %mem.M, argc_691342_321701: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_690562_321471: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .let _320484: [%mem.M, %mem.Ptr («100; .Idx 4294967296», 0)] = %mem.malloc («100; .Idx 4294967296», 0) (mem_690876_320481, 400); + .let _320493: [%mem.M, %mem.Ptr («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0)] = %mem.malloc («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0) (_320484#0:(.Idx 2), 800); + .let _320879: %mem.Ptr (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) = %mem.lea (100, ‹100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]›, 0) (_320493#1:(.Idx 2), 1:(.Idx 100)); + .let _321799: %mem.M = %mem.store (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (_320493#0:(.Idx 2), _320879, comp_tup_pb__691250_320895); + .let _321809: %mem.Ptr (.Idx 4294967296, 0) = %mem.lea (100, ‹100; .Idx 4294967296›, 0) (_320484#1:(.Idx 2), 1:(.Idx 100)); + .let _321816: %mem.M = %mem.store (.Idx 4294967296, 0) (_321799, _321809, _321428); + .let _321824: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_321816, _321809); + .let _321834: [%mem.M, .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]] = %mem.load (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (_321824#0:(.Idx 2), _320879); + _321834#1:(.Idx 2) (100:(.Idx 4294967296), comp_tup_pb__cont_691892_cont_cont_321850) +}; diff --git a/lit/direct/ad_mem_print_error.thorin.disabled b/lit/direct/ad_mem_print_error.thorin.disabled new file mode 100644 index 0000000000..152317efc5 --- /dev/null +++ b/lit/direct/ad_mem_print_error.thorin.disabled @@ -0,0 +1,143 @@ +.import core; +.import direct; +.import mem; +.lam .extern internal_diff_core_icmp_XygLe __689499: .Nat → .Cn [«2; .Idx __689422», .Cn [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx __689422»]]] = { + .con cmp_pb_689606 __689620::[.Idx 2, pb_ret_689622: .Cn «2; .Idx __689499»] @(1:(.Idx 2)) = { + pb_ret_689622 ‹2; 0:(.Idx __689499)› + }; + .con inner_cmp_689546 __689563::[__689582::[_689586: .Idx __689499, _689590: .Idx __689499], ret_689565: .Cn [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx __689499»]]] @(1:(.Idx 2)) = { + .let _689593: .Idx 2 = %core.icmp.XygLe __689499 __689582; + ret_689565 (_689593, cmp_pb_689606) + }; + inner_cmp_689546 +}; +.lam .extern internal_diff_core_icmp_xYgLE __689713: .Nat → .Cn [«2; .Idx __689655», .Cn [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx __689655»]]] = { + .con cmp_pb_689792 __689798::[.Idx 2, pb_ret_689800: .Cn «2; .Idx __689713»] @(1:(.Idx 2)) = { + pb_ret_689800 ‹2; 0:(.Idx __689713)› + }; + .con inner_cmp_689751 __689757::[__689776::[_689780: .Idx __689713, _689784: .Idx __689713], ret_689759: .Cn [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx __689713»]]] @(1:(.Idx 2)) = { + .let _689787: .Idx 2 = %core.icmp.xYgLE __689713 __689776; + ret_689759 (_689787, cmp_pb_689792) + }; + inner_cmp_689751 +}; +.lam .extern internal_diff_core_icmp_xyglE __689888: .Nat → .Cn [«2; .Idx __689830», .Cn [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx __689830»]]] = { + .con cmp_pb_689970 __689979::[.Idx 2, pb_ret_689981: .Cn «2; .Idx __689888»] @(1:(.Idx 2)) = { + pb_ret_689981 ‹2; 0:(.Idx __689888)› + }; + .con inner_cmp_689926 __689935::[__689954::[_689958: .Idx __689888, _689962: .Idx __689888], ret_689937: .Cn [.Idx 2, .Cn [.Idx 2, .Cn «2; .Idx __689888»]]] @(1:(.Idx 2)) = { + .let _689965: .Idx 2 = %core.icmp.xyglE __689888 __689954; + ret_689937 (_689965, cmp_pb_689970) + }; + inner_cmp_689926 +}; +.lam .extern internal_diff_core_wrap_add __690082::[_690173: .Nat, w_690083: .Nat] → .Cn [«2; .Idx w_690015», .Cn [.Idx w_690015, .Cn [.Idx w_690015, .Cn «2; .Idx w_690015»]]] = { + .con add_pb_690186 __690195::[s_690205: .Idx w_690083, pb_ret_690197: .Cn «2; .Idx w_690083»] @(1:(.Idx 2)) = { + pb_ret_690197 ‹2; s_690205› + }; + .con inner_add_deriv_cps_690132 __690141::[__690161::[_690165: .Idx w_690083, _690169: .Idx w_690083], ret_690143: .Cn [.Idx w_690083, .Cn [.Idx w_690083, .Cn «2; .Idx w_690083»]]] @(1:(.Idx 2)) = { + .let _690176: .Idx w_690083 = %core.wrap.add __690082 __690161; + ret_690143 (_690176, add_pb_690186) + }; + inner_add_deriv_cps_690132 +}; +.lam .extern internal_diff_core_wrap_mul __690292::[_690377: .Nat, w_690293: .Nat] → .Cn [«2; .Idx w_690231», .Cn [.Idx w_690231, .Cn [.Idx w_690231, .Cn «2; .Idx w_690231»]]] = { + .con inner_mul_deriv_cps_690336 __690345::[__690365::[_690369: .Idx w_690293, _690373: .Idx w_690293], ret_690347: .Cn [.Idx w_690293, .Cn [.Idx w_690293, .Cn «2; .Idx w_690293»]]] @(1:(.Idx 2)) = { + .con mul_pb_690390 __690399::[s_690414: .Idx w_690293, pb_ret_690401: .Cn «2; .Idx w_690293»] @(1:(.Idx 2)) = { + .let _690426: .Idx w_690293 = %core.wrap.mul __690292 (__690365#1:(.Idx 2), s_690414); + .let _690436: .Idx w_690293 = %core.wrap.mul __690292 (__690365#0:(.Idx 2), s_690414); + pb_ret_690401 (_690426, _690436) + }; + .let _690380: .Idx w_690293 = %core.wrap.mul __690292 __690365; + ret_690347 (_690380, mul_pb_690390) + }; + inner_mul_deriv_cps_690336 +}; +.lam Uf_690595 _690612: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_690659 _690676: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_690710 _690711::[__690716::[_690720: .Idx 4294967296, _690724: .Idx 4294967296], ret_690713: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_690728 __690729::[s_690734: .Idx 4294967296, pb_ret_690731: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _690746: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#1:(.Idx 2), s_690734); + .let _690752: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__690716#0:(.Idx 2), s_690734); + pb_ret_690731 (_690746, _690752) + }; + .let _690727: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __690716; + ret_690713 (_690727, mul_pb_690728) +}; +.lam Uf_691251 _691268: «2; .Idx 4294967296» → ★ = { + [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] +}; +.con eta_inner_mul_deriv_cps_691294 _691295::[__691299::[_691303: .Idx 4294967296, _691307: .Idx 4294967296], ret_691297: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]]] @(0:(.Idx 2)) = { + .con mul_pb_691311 __691312::[s_691317: .Idx 4294967296, pb_ret_691314: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .let _691322: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#1:(.Idx 2), s_691317); + .let _691328: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (__691299#0:(.Idx 2), s_691317); + pb_ret_691314 (_691322, _691328) + }; + .let _691310: .Idx 4294967296 = %core.wrap.mul 4294967296 0 __691299; + ret_691297 (_691310, mul_pb_691311) +}; +.lam Uf_691363 _691380: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691406 _691407::[.Idx 4294967296, _691409: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691409 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691429 _691446: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con extract_pb_691470 _691471::[s_691476: .Idx 4294967296, _691473: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691473 (⊥:%mem.M, s_691476) +}; +.lam Uf_691899 _691916: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_691934 _691935::[.Idx 4294967296, _691937: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _691937 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.lam Uf_691949 _691966: .Idx 4294967296 → ★ = { + [%mem.M, .Idx 4294967296] +}; +.lam Uf_692052 _692069: %mem.M → ★ = { + [%mem.M, .Idx 4294967296] +}; +.con zero_pb_692087 _692088::[%mem.M, _692090: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + _692090 (⊥:%mem.M, 0:(.Idx 4294967296)) +}; +.con .extern main __690558::[mem_690876: %mem.M, argc_691342: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_690562: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con comp_tup_pb__691250 _691347::[_691349: .Idx 4294967296, _691358: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691356 _691420::[_691421: .Idx 4294967296, _691480: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691422: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691363) zero_pb_691406 _691421; + .let _691481: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691429) extract_pb_691470 _691480; + .let _691488: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691422#1:(.Idx 2), _691481#1:(.Idx 2)); + _691358 (⊤:%mem.M, _691488) + }; + .let _691344: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_691251) eta_inner_mul_deriv_cps_691294 (42:(.Idx 4294967296), argc_691342); + _691344#1:(.Idx 2) (_691349, comp_tup_pb__cont_691356) + }; + .con comp_tup_pb__690636 _691889::[_691891: .Idx 4294967296, _691894: .Cn [%mem.M, .Idx 4294967296]] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_691892 _691940::[_691941: .Idx 4294967296, _692020: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _691942: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691899) zero_pb_691934 _691941; + .let _690877: [%mem.M, %mem.Ptr («100; .Idx 4294967296», 0)] = %mem.alloc («100; .Idx 4294967296», 0) mem_690876; + .let _pullback_alloc_690882: [%mem.M, %mem.Ptr («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0)] = %mem.malloc («100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]», 0) (_690877#0:(.Idx 2), 800); + .let pullback_lea_691249: %mem.Ptr (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) = %mem.lea (100, ‹100; .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]›, 0) (_pullback_alloc_690882#1:(.Idx 2), 1:(.Idx 100)); + .let _691499: %mem.M = %mem.store (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (_pullback_alloc_690882#0:(.Idx 2), pullback_lea_691249, comp_tup_pb__691250); + .let _691865: %mem.Ptr (.Idx 4294967296, 0) = %mem.lea (100, ‹100; .Idx 4294967296›, 0) (_690877#1:(.Idx 2), 1:(.Idx 100)); + .let _691874: %mem.M = %mem.store (.Idx 4294967296, 0) (_691499, _691865, _691344#0:(.Idx 2)); + .let aug_load_691882: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_691874, _691865); + .let pullback_load_692016: [%mem.M, .Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]]] = %mem.load (.Cn [.Idx 4294967296, .Cn [%mem.M, .Idx 4294967296]], 0) (aug_load_691882#0:(.Idx 2), pullback_lea_691249); + .let _692021: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_691949) pullback_load_692016#1:(.Idx 2) _692020; + .let _692028: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_691942#1:(.Idx 2), _692021#1:(.Idx 2)); + _691894 (⊤:%mem.M, _692028) + }; + .let _691886: [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] = %direct.cps2ds_dep («2; .Idx 4294967296», Uf_690659) eta_inner_mul_deriv_cps_690710 (100:(.Idx 4294967296), aug_load_691882#1:(.Idx 2)); + _691886#1:(.Idx 2) (_691891, comp_tup_pb__cont_691892) + }; + .let _692035: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (.Idx 4294967296, Uf_690595) comp_tup_pb__690636 1:(.Idx 4294967296); + .let _692095: [%mem.M, .Idx 4294967296] = %direct.cps2ds_dep (%mem.M, Uf_692052) zero_pb_692087 pullback_load_692016#0:(.Idx 2); + .let _692102: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_692035#1:(.Idx 2), _692095#1:(.Idx 2)); + return_690562 (⊤:%mem.M, _692102) +}; diff --git a/lit/direct/ds2cps_ax_cps2ds_twice.thorin b/lit/direct/ds2cps_ax_cps2ds_twice.thorin new file mode 100644 index 0000000000..1a9d7f1870 --- /dev/null +++ b/lit/direct/ds2cps_ax_cps2ds_twice.thorin @@ -0,0 +1,25 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d direct %s --output-ll %t.ll -o - | FileCheck %s + +.import direct; +.import mem; +.import core; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con f ![a:I32, return: .Cn I32] = { + .let b = %core.wrap.add _32 0 (2:I32, a); + return b +}; + + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return : .Cn [%mem.M, I32]] = { + .let g = %direct.cps2ds (I32,I32) f; + .let c1 = g (38:I32); + .let h = %direct.cps2ds (I32,I32) f; + .let c2 = h (c1); + return (mem, c2) +}; + +// CHECK-DAG: return{{.*}}42 diff --git a/lit/direct/ds2cps_ax_cps2ds_twice_diff.thorin b/lit/direct/ds2cps_ax_cps2ds_twice_diff.thorin new file mode 100644 index 0000000000..27708b5e36 --- /dev/null +++ b/lit/direct/ds2cps_ax_cps2ds_twice_diff.thorin @@ -0,0 +1,29 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d direct %s --output-ll %t.ll -o - | FileCheck %s + +.import direct; +.import mem; +.import core; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con f [a:I32, return: .Cn I32] = { + .let b = %core.wrap.add _32 0 (2:I32, a); + return b +}; + +.con f2 [a:I32, return: .Cn I32] = { + .let b = %core.wrap.add _32 0 (30:I32, a); + return b +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return : .Cn [%mem.M, I32]] = { + .let g = %direct.cps2ds (I32,I32) f; + .let c1 = g (10:I32); + .let h = %direct.cps2ds (I32,I32) f2; + .let c2 = h (c1); + return (mem, c2) +}; + +// CHECK-DAG: return{{.*}}42 diff --git a/lit/main_loop.thorin b/lit/main_loop.thorin index ce49d62425..c7f991bce6 100644 --- a/lit/main_loop.thorin +++ b/lit/main_loop.thorin @@ -20,20 +20,20 @@ loop (mem, 0:(.Idx 4294967296), 0:(.Idx 4294967296)) }; -// CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: loop_[[loopId:[0-9_]+]] (mem_[[memId]], 0:(.Idx 4294967296), 0:(.Idx 4294967296)) -// CHECK-DAG: .con return_[[returnEtaId:[0-9_]+]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: .con return_[[returnEtaId:[0-9_]+]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] -// CHECK-DAG: .con loop_[[loopId]] _{{[0-9_]+}}::[mem_[[loopMemId:[0-9_]+]]: %mem.M, i_[[iterId:[0-9_]+]]: .Idx 4294967296, acc_[[accId:[0-9_]+]]: .Idx 4294967296] = { +// CHECK-DAG: .con loop_[[loopId]] _{{[0-9_]+}}::[mem_[[loopMemId:[0-9_]+]]: %mem.M, i_[[iterId:[0-9_]+]]: .Idx 4294967296, acc_[[accId:[0-9_]+]]: .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: _[[condId:[0-9_]+]]: .Idx 2 = %core.icmp.XygLe 4294967296 (i_[[iterId]], argc_[[argcId]]); // CHECK-DAG: (_[[exitId:[0-9_]+]], body_[[bodyId:[0-9_]+]])#_[[condId]] mem_[[loopMemId]] -// CHECK-DAG: .con _[[exitId]] m_[[mExitVarId:[0-9_]+]]: %mem.M = { -// CHECK-DAG: return_[[returnEtaId]] (m_[[mExitVarId]], acc_[[accId]]) +// CHECK-DAG: .con _[[exitId]] [[mExitVarId:[0-9m_]+]]: %mem.M {{(@.*)?}}= { +// CHECK-DAG: return_[[returnEtaId]] ([[mExitVarId]], acc_[[accId]]) -// CHECK-DAG: .con body_[[bodyId]] m_[[mBodyVarId:[0-9_]+]]: %mem.M = { +// CHECK-DAG: .con body_[[bodyId]] [[mBodyVarId:[0-9m_]+]]: %mem.M {{(@.*)?}}= { // CHECK-DAG: _[[addIterId:[0-9_]+]]: .Idx 4294967296 = %core.wrap.add 4294967296 0 (1:(.Idx 4294967296), i_[[iterId]]); // CHECK-DAG: _[[addAccId:[0-9_]+]]: .Idx 4294967296 = %core.wrap.add 4294967296 0 (acc_[[accId]], i_[[iterId]]); -// CHECK-DAG: loop_[[loopId]] (m_[[mBodyVarId]], _[[addIterId]], _[[addAccId]]) +// CHECK-DAG: loop_[[loopId]] ([[mBodyVarId]], _[[addIterId]], _[[addAccId]]) diff --git a/lit/mem/ad_pow_no_mem.thorin b/lit/mem/ad_pow_no_mem.thorin new file mode 100644 index 0000000000..fca4b59009 --- /dev/null +++ b/lit/mem/ad_pow_no_mem.thorin @@ -0,0 +1,64 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin -d mem -d clos %s --output-ll %t.ll -o - + +.import clos; +.import core; +.import mem; +.con zero_pb_792997 _792998::[.Idx 4294967296, _793000: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _793000 ‹2; 0:(.Idx 4294967296)› +}; +.con tup_pb_793028 [_793029: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _793029 ‹2; 0:(.Idx 4294967296)› +}; +.con tup_pb_793027 [_793031: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_pb_793028 _793031 +}; +.con tup_pb_793026 _793033::[_793035: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + tup_pb_793027 _793035 +}; +.con aug_f_792792 _792829::[_792831: .Idx 4294967296, _792843: .Cn [.Idx 4294967296, .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]], _792972: .Cn [.Idx 4294967296, .Cn .Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con aug_pow_cont_792841 _792864::[_792866: .Idx 4294967296, _792884: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con comp_tup_pb__792876 _792889::[_792891: .Idx 4294967296, _792909: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + .con comp_tup_pb__cont_cont_cont_792907 _792949::[_792950: .Idx 4294967296, _792956: .Idx 4294967296] @(1:(.Idx 2)) = { + .let _792948: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (_792866, _792891); + .let _792955: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_792948, _792950); + _792909 (_792955, _792956) + }; + .let _792898: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _792891); + _792884 (_792898, comp_tup_pb__cont_cont_cont_792907) + }; + .let _792873: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (4:(.Idx 4294967296), _792866); + _792843 (_792873, comp_tup_pb__792876) + }; + .con _792970 _792973:: [.Idx 4294967296, .Cn .Idx 4294967296, .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _792972 _792973 + }; + .con tup_pb_792969 _792975::[_792977: .Idx 4294967296, .Cn .Idx 4294967296, _792980: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _792970 (_792977, ⊥:.Cn .Idx 4294967296, _792980) + }; + .con aug_pow_else_792809 [.Cn .Cn «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + .let _792838: .Idx 4294967296 = %core.wrap.add 4294967296 0 (4294967295:(.Idx 4294967296), _792831); + aug_f_792792 (_792838, aug_pow_cont_792841, tup_pb_792969) + }; + .con aug_pow_then_792987 [.Cn .Cn «2; .Idx 4294967296»] @(0:(.Idx 2)) = { + _792843 (1:(.Idx 4294967296), zero_pb_792997) + }; + .let _793024: .Idx 2 = %core.icmp.xyglE 4294967296 (0:(.Idx 4294967296), _792831); + (aug_pow_else_792809, aug_pow_then_792987)#_793024 tup_pb_793026 +}; +.con tup_pb_793210 _793211::[_793217: .Idx 4294967296, .Cn .Idx 4294967296, _793213: .Cn «2; .Idx 4294967296»] @(1:(.Idx 2)) = { + _793213 (0:(.Idx 4294967296), _793217) +}; +.con .extern main __793094::[mem_793115: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_793098: .Cn [%mem.M, .Idx 4294967296]] @(0:(.Idx 2)) = { + .con ret_cont_793055 __793065::[r_793151: .Idx 4294967296, pb_793067: .Cn [.Idx 4294967296, .Cn «2; .Idx 4294967296»]] @(0:(.Idx 2)) = { + .con pb_ret_cont_793084 __793168::[pr_a_793188: .Idx 4294967296, pr_b_793169: .Idx 4294967296] @(0:(.Idx 2)) = { + .let _793158: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (10000:(.Idx 4294967296), r_793151); + .let _793195: .Idx 4294967296 = %core.wrap.mul 4294967296 0 (100:(.Idx 4294967296), pr_a_793188); + .let _793200: .Idx 4294967296 = %core.wrap.add 4294967296 0 (pr_b_793169, _793195); + .let _793205: .Idx 4294967296 = %core.wrap.add 4294967296 0 (_793158, _793200); + return_793098 (mem_793115, _793205) + }; + pb_793067 (1:(.Idx 4294967296), pb_ret_cont_793084) + }; + aug_f_792792 (3:(.Idx 4294967296), ret_cont_793055, tup_pb_793210) +}; diff --git a/lit/mem/add_top_mem.thorin b/lit/mem/add_top_mem.thorin new file mode 100644 index 0000000000..2eed98460b --- /dev/null +++ b/lit/mem/add_top_mem.thorin @@ -0,0 +1,26 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - + +// TODO: add filecheck + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con .extern f [mem: %mem.M, a: I32, ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + f (⊤:%mem.M, argc,return) +}; + +.lam .extern _compile [] -> Pipeline = { + %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) + // optimization_phase + (%compile.single_pass_phase %mem.add_mem_pass) +}; diff --git a/lit/mem/add_top_mem2.thorin b/lit/mem/add_top_mem2.thorin new file mode 100644 index 0000000000..0123793c40 --- /dev/null +++ b/lit/mem/add_top_mem2.thorin @@ -0,0 +1,34 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - + +// TODO: add filecheck + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con .extern f [mem: %mem.M, a: I32, ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern g [a: I32, ret: .Cn [I32]] = { + ret a +}; + +.con .extern h [a: I32, ret: .Cn [%mem.M, I32]] = { + ret (⊤:%mem.M,a) +}; + + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + f (⊤:%mem.M, argc,return) +}; + +.lam .extern _compile [] -> Pipeline = { + %compile.pipe + (%compile.single_pass_phase %compile.internal_cleanup_pass) + // optimization_phase + (%compile.single_pass_phase %mem.add_mem_pass) +}; diff --git a/lit/mem/alloc_load_store.thorin b/lit/mem/alloc_load_store.thorin index 7f3a417b04..9391968050 100644 --- a/lit/mem/alloc_load_store.thorin +++ b/lit/mem/alloc_load_store.thorin @@ -17,7 +17,7 @@ return (free, load#1:(.Idx 2)) }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: _[[appAllocId:[0-9_]+]]: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.malloc (.Idx 4294967296, 0) (mem_[[mainMemId]], 4); // CHECK-DAG: _[[appStoreId:[0-9_]+]]: %mem.M = %mem.store (.Idx 4294967296, 0) (_[[appAllocId]]#0:(.Idx 2), _[[appAllocId]]#1:(.Idx 2), argc_[[argcId]]); // CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_[[appStoreId]], _[[appAllocId]]#1:(.Idx 2)); @@ -25,5 +25,5 @@ // CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (_[[appFreeId]], _[[appLoadId]]#1:(.Idx 2)) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/mem/arg_style.thorin b/lit/mem/arg_style.thorin new file mode 100644 index 0000000000..042f8cec36 --- /dev/null +++ b/lit/mem/arg_style.thorin @@ -0,0 +1,84 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - + +// TODO: add filecheck + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; +.let Tas = (I32, 0); + +// We want the functions to be extern. +// Functions with argstyle might stay until code gen and can not be inlined in general. +// Therefore, we need to handle them explicitely. +// As such functions prevent code gen, we want to ignore the extern flag. + +.con .extern f1 [mem: %mem.M, a: I32, ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern f2 [[mem: %mem.M, a: I32], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern g1 [mem: %mem.M, a: I32, b:I32, ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con .extern g2 [[mem: %mem.M, a: I32, b:I32], ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con .extern g3 [[mem: %mem.M, [a: I32, b:I32]], ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con .extern g4 [mem: %mem.M, [a: I32, b:I32], ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con .extern h1 [mem: %mem.M, a: I32, x:%mem.Ptr (I32, 0), ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern h2 [mem: %mem.M, [a: I32, x:%mem.Ptr (I32, 0)], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern h3 [[mem: %mem.M, a: I32, x:%mem.Ptr (I32, 0)], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern h4 [[mem: %mem.M, [a: I32, x:%mem.Ptr (I32, 0)]], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern e1 [mem: %mem.M, a: I32, [], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern e2 [mem: %mem.M, [a: I32, []], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern e3 [[mem: %mem.M, [a: I32, []]], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + + .let (mem2,p) = %mem.alloc Tas mem; + // .let mem3 = %mem.store Tas (mem2, p, argc); + + // .con .extern cont_f1 [mem:%mem.M, v:I32] = { + // f1 () + // }; + return (mem2, argc) + +}; diff --git a/lit/mem/arg_style_no_extern.thorin b/lit/mem/arg_style_no_extern.thorin new file mode 100644 index 0000000000..a5a9392368 --- /dev/null +++ b/lit/mem/arg_style_no_extern.thorin @@ -0,0 +1,176 @@ +// RUN: rm -f %t.ll +// RUN: cpp %s -o %t_pre.thorin -D "TYPE='g'" -D "NUMBER=3" -P -C -nostdinc +// RUN: %thorin -d mem %t_pre.thorin --output-ll %t.ll -o - + +// TODO: add filecheck + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; +.let Tas = (I32, 0); + +.con f1 [mem: %mem.M, a: I32, ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con f2 [[mem: %mem.M, a: I32], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con g1 [mem: %mem.M, a: I32, b:I32, ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con g2 [[mem: %mem.M, a: I32, b:I32], ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con g3 [[mem: %mem.M, [a: I32, b:I32]], ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con g4 [mem: %mem.M, [a: I32, b:I32], ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (a,b); + ret (mem,c) +}; + +.con h1 [mem: %mem.M, a: I32, x:%mem.Ptr (I32, 0), ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con h2 [mem: %mem.M, [a: I32, x:%mem.Ptr (I32, 0)], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con h3 [[mem: %mem.M, a: I32, x:%mem.Ptr (I32, 0)], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con h4 [[mem: %mem.M, [a: I32, x:%mem.Ptr (I32, 0)]], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con e1 [mem: %mem.M, a: I32, [], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con e2 [mem: %mem.M, [a: I32, []], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +.con e3 [[mem: %mem.M, [a: I32, []]], ret: .Cn [%mem.M, I32]] = { + ret (mem,a) +}; + +// .con i1 [[], ret: .Cn [%mem.M, I32]] = { +// ret (mem,42:I32) +// }; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + + .let a = argc; + .let (mem2,p) = %mem.alloc Tas mem; + + .con cont [mem:%mem.M, v:I32] = { + .let a = v; + .let cont = return; + .let mem2 = mem; + + #if 0 + // f1 (mem, v, return) + // f2 ((mem, v), return) + // g3 ((mem, (a,a)), return) + // g2 ((mem, a,a), return) + // g4 (mem2, (a,a), cont) + // e1 (mem2, a, (), cont) + // e2 (mem2, (a, ()), cont) + // e3 ((mem2, (a, ())), cont) + #endif + #if TYPE == 'f' + #if NUMBER == 1 + f1 (mem, v, return) + #elif NUMBER == 2 + f2 ((mem, v), return) + #endif + #elif TYPE == 'g' + #if NUMBER == 1 + g1 (mem, a, a, return) + #elif NUMBER == 2 + g2 ((mem, a,a), return) + #elif NUMBER == 3 + g3 ((mem, (a,a)), return) + #elif NUMBER == 4 + g4 (mem2, (a,a), cont) + #endif + #elif TYPE == 'h' + #if NUMBER == 1 + h1 (mem, a, p, return) + #elif NUMBER == 2 + h2 (mem, (a, p), return) + #elif NUMBER == 3 + h3 ((mem, a, p), return) + #elif NUMBER == 4 + h4 ((mem, (a, p)), return) + #endif + #elif TYPE == 'e' + #if NUMBER == 1 + e1 (mem2, a, (), cont) + #elif NUMBER == 2 + e2 (mem2, (a, ()), cont) + #elif NUMBER == 3 + e3 ((mem2, (a, ())), cont) + #endif + #endif + }; + + #if 0 + // f1 (mem2, argc, cont) + // f2 ((mem2, argc), cont) + // g3 ((mem2, (a,a)), cont) + // g2 ((mem2, a,a), cont) + // g4 (mem2, (a,a), cont) + // e1 (mem2, a, (), cont) + // e2 (mem2, (a, ()), cont) + // e3 ((mem2, (a, ())), cont) + #endif + #if TYPE == 'f' + #if NUMBER == 1 + f1 (mem, v, return) + #elif NUMBER == 2 + f2 ((mem, v), return) + #endif + #elif TYPE == 'g' + #if NUMBER == 1 + g1 (mem, a, a, return) + #elif NUMBER == 2 + g2 ((mem, a,a), return) + #elif NUMBER == 3 + g3 ((mem, (a,a)), return) + #elif NUMBER == 4 + g4 (mem2, (a,a), cont) + #endif + #elif TYPE == 'h' + #if NUMBER == 1 + h1 (mem, a, p, return) + #elif NUMBER == 2 + h2 (mem, (a, p), return) + #elif NUMBER == 3 + h3 ((mem, a, p), return) + #elif NUMBER == 4 + h4 ((mem, (a, p)), return) + #endif + #elif TYPE == 'e' + #if NUMBER == 1 + e1 (mem2, a, (), cont) + #elif NUMBER == 2 + e2 (mem2, (a, ()), cont) + #elif NUMBER == 3 + e3 ((mem2, (a, ())), cont) + #endif + #endif +}; diff --git a/lit/mem/malloc_load_store.thorin b/lit/mem/malloc_load_store.thorin index bcdbd8ef93..b3512ebb35 100644 --- a/lit/mem/malloc_load_store.thorin +++ b/lit/mem/malloc_load_store.thorin @@ -17,7 +17,7 @@ return (free, load#1:(.Idx 2)) }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: _[[appMallocId:[0-9_]+]]: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.malloc (.Idx 4294967296, 0) (mem_[[mainMemId]], 4); // CHECK-DAG: _[[appStoreId:[0-9_]+]]: %mem.M = %mem.store (.Idx 4294967296, 0) (_[[appMallocId]]#0:(.Idx 2), _[[appMallocId]]#1:(.Idx 2), argc_[[argcId]]); // CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_[[appStoreId]], _[[appMallocId]]#1:(.Idx 2)); @@ -25,5 +25,5 @@ // CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (_[[appFreeId]], _[[appLoadId]]#1:(.Idx 2)) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/mem/mslot_load_store.thorin b/lit/mem/mslot_load_store.thorin index 5878e8c42b..80bce6317f 100644 --- a/lit/mem/mslot_load_store.thorin +++ b/lit/mem/mslot_load_store.thorin @@ -16,11 +16,11 @@ return load }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: _[[appMSlotId:[0-9_]+]]: [%mem.M, %mem.Ptr (.Idx 4294967296, 0)] = %mem.mslot (.Idx 4294967296, 0) (mem_[[mainMemId]], 4, 0); // CHECK-DAG: _[[appStoreId:[0-9_]+]]: %mem.M = %mem.store (.Idx 4294967296, 0) (_[[appMSlotId]]#0:(.Idx 2), _[[appMSlotId]]#1:(.Idx 2), argc_[[argcId]]); // CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = %mem.load (.Idx 4294967296, 0) (_[[appStoreId]], _[[appMSlotId]]#1:(.Idx 2)); // CHECK-DAG: return_[[returnEtaId:[0-9_]+]] _[[appLoadId]] -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/mem/no_mem.thorin b/lit/mem/no_mem.thorin new file mode 100644 index 0000000000..7be5de60ba --- /dev/null +++ b/lit/mem/no_mem.thorin @@ -0,0 +1,26 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - | FileCheck %s + +.import core; +.import mem; + +.let I32 = .Idx 4294967296; + +.con f ![a:I32, ret: .Cn [I32]] = { + .let b = %core.wrap.mul 4294967296:.Nat 0:.Nat (a, a); + ret b +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + + .con ret_cont [r:I32] = { + .con ret_cont2 [r2:I32] = { + return (mem, r2) + }; + f (r, ret_cont2) + }; + + f (42:I32,ret_cont) +}; + +// CHECK-DAG: return{{.*}}3111696 diff --git a/lit/mem/no_mem_lazy.thorin b/lit/mem/no_mem_lazy.thorin new file mode 100644 index 0000000000..aa4eb6f13b --- /dev/null +++ b/lit/mem/no_mem_lazy.thorin @@ -0,0 +1,24 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - + +.import core; +.import mem; + +.let I32 = .Idx 4294967296; + +.con f [a:I32, ret: .Cn [I32]] = { + .let b = %core.wrap.mul 4294967296:.Nat 0:.Nat (a, a); + ret b +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + + .con ret_cont [r:I32] = { + .con ret_cont2 [r2:I32] = { + return (mem, r2) + }; + f (r, ret_cont2) + }; + + f (42:I32,ret_cont) +}; diff --git a/lit/mem/slot_load_store.thorin b/lit/mem/slot_load_store.thorin index f0700b836c..e8ac06cd3b 100644 --- a/lit/mem/slot_load_store.thorin +++ b/lit/mem/slot_load_store.thorin @@ -16,8 +16,8 @@ return load }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .Idx 256», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (mem_[[mainMemId]], argc_[[argcId]]) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/mem/two_fun_mem.thorin b/lit/mem/two_fun_mem.thorin new file mode 100644 index 0000000000..2c3a59c036 --- /dev/null +++ b/lit/mem/two_fun_mem.thorin @@ -0,0 +1,46 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - +// RUN: clang %t.ll -o %t -Wno-override-module +// RUN: %t; test $? -eq 5 +// RUN: %t 1; test $? -eq 7 +// RUN: %t 1 2; test $? -eq 9 + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; +.let Tas = (I32, 0); + +.con f [mem: %mem.M, p: %mem.Ptr (I32, 0), ret: .Cn [%mem.M, I32]] = { + .let (mem2, v) = %mem.load Tas (mem, p); + + .con g1 [mem: %mem.M, ret: .Cn [%mem.M, I32]] = { + .let b = %core.wrap.add _32 0 (v, 1:I32); + ret (mem2, b) + }; + + .con g2 [mem: %mem.M, ret: .Cn [%mem.M, I32]] = { + .let c = %core.wrap.add _32 0 (v, 2:I32); + ret (mem2, c) + }; + + .con cont1 [mem:%mem.M, a:I32] = { + .con cont2 [mem:%mem.M, b:I32] = { + .let c = %core.wrap.add _32 0 (a, b); + ret (mem, c) + }; + g2 (mem2, cont2) + }; + g1 (mem2, cont1) +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + + .let (mem2,p) = %mem.alloc Tas mem; + .let mem3 = %mem.store Tas (mem2, p, argc); + + f (mem3, p, return) +}; + +// TODO: check for 1+x, 2+x, a+b diff --git a/lit/mem/two_fun_no_mem.thorin b/lit/mem/two_fun_no_mem.thorin new file mode 100644 index 0000000000..2f7f0c3bbf --- /dev/null +++ b/lit/mem/two_fun_no_mem.thorin @@ -0,0 +1,46 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - +// RUN: clang %t.ll -o %t -Wno-override-module +// RUN: %t; test $? -eq 5 +// RUN: %t 1; test $? -eq 7 +// RUN: %t 1 2; test $? -eq 9 + +.import core; +.import mem; + +.let _32 = 4294967296; +.let I32 = .Idx _32; +.let Tas = (I32, 0); + +.con f [mem: %mem.M, p: %mem.Ptr (I32, 0), ret: .Cn [%mem.M, I32]] = { + .let (mem2, v) = %mem.load Tas (mem, p); + + .con g1 [ret: .Cn I32] = { + .let b = %core.wrap.add _32 0 (v, 1:I32); + ret b + }; + + .con g2 [ret: .Cn I32] = { + .let c = %core.wrap.add _32 0 (v, 2:I32); + ret c + }; + + .con cont1 [a:I32] = { + .con cont2 [b:I32] = { + .let c = %core.wrap.add _32 0 (a, b); + ret (mem2, c) + }; + g2 cont2 + }; + g1 cont1 +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0:.Nat), 0:.Nat), return : .Cn [%mem.M, I32]] = { + + .let (mem2,p) = %mem.alloc Tas mem; + .let mem3 = %mem.store Tas (mem2, p, argc); + + f (mem3, p, return) +}; + +// TODO: check for 1+x, 2+x, a+b diff --git a/lit/opt/default.thorin b/lit/opt/default.thorin new file mode 100644 index 0000000000..a0ff182020 --- /dev/null +++ b/lit/opt/default.thorin @@ -0,0 +1,21 @@ +// RUN: rm -f %t.ll ; \ +// RUN: %thorin %s --output-ll %t.ll -o - | FileCheck %s + +.import mem; +.import core; +.import compile; +.import opt; + +.let _32 = 4294967296; +.let I32 = .Idx _32; + +.con f [mem : %mem.M, a : I32, return : .Cn [%mem.M, I32]] = { + return (mem, a) +}; + +.con .extern main [mem : %mem.M, argc : I32, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return : .Cn [%mem.M, I32]] = { + f (mem, 42:I32, return) +}; + +// CHECK-DAG: .con return +// CHECK-DAG: return{{.*}}42 diff --git a/lit/parse_output_parse.thorin b/lit/parse_output_parse.thorin.disabled similarity index 87% rename from lit/parse_output_parse.thorin rename to lit/parse_output_parse.thorin.disabled index ec74dc0845..28139dc9bc 100644 --- a/lit/parse_output_parse.thorin +++ b/lit/parse_output_parse.thorin.disabled @@ -5,6 +5,11 @@ // RUN: %t 1 2 3 ; test $? -eq 4 // RUN: %t a b c d e f ; test $? -eq 7 +/* +https://github.com/AnyDSL/thorin2/issues/114 +*/ + + .import mem; .con .extern main [mem : %mem.M, argc : .Idx 4294967296, argv : %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return : .Cn [%mem.M, .Idx 4294967296]] = { @@ -14,8 +19,8 @@ single_arg_parse_test mem }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (mem_[[memId]], argc_[[argcId]]) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/refly/debug.thorin b/lit/refly/debug.thorin index d3cb30fba6..9a91c32700 100644 --- a/lit/refly/debug.thorin +++ b/lit/refly/debug.thorin @@ -10,8 +10,8 @@ return (mem, c) }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId:[_0-9]*]] (mem_[[memId]], 42:(.Idx 4294967296)) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/refly/debug_perm.thorin b/lit/refly/debug_perm.thorin index e869dab886..5dcdb6ae20 100644 --- a/lit/refly/debug_perm.thorin +++ b/lit/refly/debug_perm.thorin @@ -10,8 +10,8 @@ return (mem, c) }; -// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[memId:[_0-9]*]]: %mem.M, .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId:[_0-9]*]] (mem_[[memId]], 42:(.Idx 4294967296)) -// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/ret_argc.thorin b/lit/ret_argc.thorin index 419b08bdeb..6e43407146 100644 --- a/lit/ret_argc.thorin +++ b/lit/ret_argc.thorin @@ -11,8 +11,8 @@ .let i32 = .Idx 4294967296; .con .extern main(mem: %mem.M, argc: i32, argv: %mem.Ptr (%mem.Ptr (i8, 0), 0), return: .Cn [%mem.M, i32]) = return (mem, argc); -// CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] = { +// CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .Idx 4294967296, %mem.Ptr (%mem.Ptr (.Idx 256, 0), 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .Idx 4294967296]] {{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (mem_[[memId]], argc_[[argcId]]) -// CHECK-DAG: .con return_[[returnEtaId:[0-9_]+]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] = { +// CHECK-DAG: .con return_[[returnEtaId:[0-9_]+]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .Idx 4294967296] {{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/thorin/analyses/deptree.cpp b/thorin/analyses/deptree.cpp index fb0538a9c3..a86c71602c 100644 --- a/thorin/analyses/deptree.cpp +++ b/thorin/analyses/deptree.cpp @@ -28,11 +28,11 @@ VarSet DepTree::run(Def* nom) { auto n = nom2node_[var->nom()].get(); if (!n) { world().ELOG("var {} used before nom {} discovered, old var still around?", var, var->nom()); - world().ELOG("var {} : {}", var, var->type()); + world().ELOG("var {} : {} [{}]", var, var->type(), var->node_name()); world().ELOG("var nom {} : {}", var->nom(), var->nom()->type()); } assert(n && "Old var still around?"); - + // if (n) parent = n->depth() > parent->depth() ? n : parent; } if (nom->is_external() && parent != root_.get()) { diff --git a/thorin/analyses/domfrontier.h b/thorin/analyses/domfrontier.h index e47de35da9..1dfba6c667 100644 --- a/thorin/analyses/domfrontier.h +++ b/thorin/analyses/domfrontier.h @@ -12,7 +12,7 @@ namespace thorin { template class DomFrontierBase { public: - DomFrontierBase(const DomFrontierBase&) = delete; + DomFrontierBase(const DomFrontierBase&) = delete; DomFrontierBase& operator=(DomFrontierBase) = delete; explicit DomFrontierBase(const CFG& cfg) diff --git a/thorin/analyses/domtree.h b/thorin/analyses/domtree.h index 9364be44b3..d3ecf87eed 100644 --- a/thorin/analyses/domtree.h +++ b/thorin/analyses/domtree.h @@ -11,7 +11,7 @@ namespace thorin { template class DomTreeBase { public: - DomTreeBase(const DomTreeBase&) = delete; + DomTreeBase(const DomTreeBase&) = delete; DomTreeBase& operator=(DomTreeBase) = delete; explicit DomTreeBase(const CFG& cfg) diff --git a/thorin/def.cpp b/thorin/def.cpp index 48ca70dfc8..33c7875bcf 100644 --- a/thorin/def.cpp +++ b/thorin/def.cpp @@ -269,7 +269,7 @@ void Def::set_debug_name(std::string_view n) const { 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); + dbg_ = w.tuple({name, dbg_->proj(1), dbg_->proj(2)}); } } #endif @@ -333,6 +333,25 @@ void Def::unset_type() { } bool Def::is_set() const { + // auto all_set = std::ranges::all_of(ops(), [](auto op) { return op != nullptr; }); + // assert((!isa_structural() || all_set) && "structurals must be always set"); + + // if (all_set) return true; + // if (!(std::ranges::all_of(ops(), [](auto op) { return op == nullptr; }))) { + // world().ELOG("{} {}", this->unique_name(), this->name()); + // if (auto lam = isa()) { + // world().ELOG(" {}", lam->filter()); + // world().ELOG(" {}", lam->body()); + // } + // assert(false && "some operands are set, others aren't"); + // } + + // assert(std::ranges::all_of(ops(), [](auto op) { return op == nullptr; }) && "some operands are set, others + // aren't"); return false; + // } + + // bool Def::is_unfinished() const { + // return std::ranges::any_of(ops(), [](auto op) { return op == nullptr; }); if (num_ops() == 0) return true; bool result = ops().back(); assert((!result || std::ranges::all_of(ops().skip_back(), [](auto op) { return op; })) && diff --git a/thorin/dialects.h b/thorin/dialects.h index 9e2411767b..d9a6eaf947 100644 --- a/thorin/dialects.h +++ b/thorin/dialects.h @@ -24,7 +24,6 @@ struct DialectInfo { const char* plugin_name; /// Callback for registering the dialects' callbacks for the pipeline extension points. - void (*add_passes)(PipelineBuilder& builder); void (*register_passes)(Passes& passes); /// Callback for registering the mapping from backend names to emission functions in the given \a backends map. @@ -59,9 +58,6 @@ class Dialect { void* handle() { return handle_.get(); } /// Registers callbacks in the \a builder that extend the exposed PassMan's. - void add_passes(PipelineBuilder& builder) const { - if (info_.add_passes) info_.add_passes(builder); - } void register_passes(Passes& passes) const { if (info_.register_passes) info_.register_passes(passes); } diff --git a/thorin/dump.cpp b/thorin/dump.cpp index 2d1f2d889d..879251cfd4 100644 --- a/thorin/dump.cpp +++ b/thorin/dump.cpp @@ -257,7 +257,7 @@ void Dumper::dump(Lam* lam) { auto ptrn = [&](auto&) { dump_ptrn(lam->var(), lam->type()->dom()); }; if (lam->type()->is_cn()) { - tab.println(os, ".con {}{} {} = {{", external(lam), id(lam), ptrn); + tab.println(os, ".con {}{} {} @({}) = {{", external(lam), id(lam), ptrn, lam->filter()); } else { tab.println(os, ".lam {}{} {} → {} = {{", external(lam), id(lam), ptrn, lam->type()->codom()); } diff --git a/thorin/error.cpp b/thorin/error.cpp index 3952cf4197..2e790455b2 100644 --- a/thorin/error.cpp +++ b/thorin/error.cpp @@ -28,8 +28,8 @@ void ErrorHandler::index_out_of_range(const Def* arity, nat_t index, const Def* void ErrorHandler::ill_typed_app(const Def* callee, const Def* arg, const Def* dbg) { Debug d(dbg ? dbg : arg->dbg()); - err(d.loc, "cannot pass argument '{}' of type '{}' to '{}' of domain '{}'", arg, arg->type(), callee, - callee->type()->as()->dom()); + err(d.loc, "cannot pass argument \n '{}' of type \n '{}' to \n '{}' of domain \n '{}'", arg, arg->type(), + callee, callee->type()->as()->dom()); } } // namespace thorin diff --git a/thorin/pass/optimize.cpp b/thorin/pass/optimize.cpp index 55fff1dde8..b330dae725 100644 --- a/thorin/pass/optimize.cpp +++ b/thorin/pass/optimize.cpp @@ -1,5 +1,7 @@ #include "thorin/pass/optimize.h" +#include + #include "thorin/dialects.h" #include "thorin/pass/fp/beta_red.h" @@ -16,8 +18,8 @@ namespace thorin { /// See optimize.h for magic numbers -void optimize(World& world, Passes& passes, PipelineBuilder& builder) { - auto compilation_functions = {"_compile"}; +void optimize(World& world, Passes& passes, std::vector& dialects) { + auto compilation_functions = {"_compile", "_default_compile", "_core_compile", "_fallback_compile"}; const Def* compilation = nullptr; for (auto compilation_function : compilation_functions) { if (auto compilation_ = world.lookup(compilation_function)) { @@ -25,60 +27,49 @@ void optimize(World& world, Passes& passes, PipelineBuilder& builder) { compilation_->make_internal(); } } - // TODO: reenable when default compilation is available - if (compilation) { - assert(compilation && "no compilation function found"); - - // We found a compilation directive in the file and use it to build the compilation pipeline. - // The general idea is that passes and phases are exposed as axioms. - // Each pass/phase axiom is associated with a handler function operating on the PipelineBuilder in the - // passes map. This registering is analogous to the normalizers (`code -> code`) but only operated using - // side effects that change the pipeline. - world.DLOG("compilation using {} : {}", compilation, compilation->type()); - - // We can not directly access compile axioms here. - // But the compile dialect has not the necessary communication pipeline. - // Therefore, we register the handlers and let the compile dialect call them. - - PipelineBuilder pipe_builder; - // TODO: remove indirections of pipeline builder. Just add passes and phases directly to the pipeline. - - auto pipeline = compilation->as()->body(); - auto [ax, phases] = collect_args(pipeline); - - // handle pipeline like all other pass axioms - auto pipeline_axiom = ax->as(); - auto pipeline_flags = pipeline_axiom->flags(); - assert(passes.contains(pipeline_flags)); - passes[pipeline_flags](world, pipe_builder, pipeline); - - Pipeline pipe(world); - world.DLOG("Building pipeline"); - pipe_builder.buildPipeline(pipe); - - pipe.run(); - return; + // make all functions `[] -> Pipeline` internal + std::vector make_internal; + 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 (!compilation) { compilation = lam; } + make_internal.push_back(def); + } + } } - - // TODO: remove together with the old compilation pipeline - builder.extend_opt_phase(0, [](thorin::PassMan& man) { man.add(); }); - builder.extend_opt_phase(1, [](thorin::PassMan& man) { man.add(); }); - builder.extend_opt_phase(2, [](thorin::PassMan& man) { man.add(); }); - - // main phase - builder.add_opt(Opt_Phase); - builder.extend_opt_phase(200, [](thorin::PassMan& man) { man.add(); }); - // codegen prep phase - builder.extend_opt_phase( - Codegen_Prep_Phase, [](thorin::PassMan& man) { man.add(); }, Pass_Internal_Priority); - - Pipeline pipe(world); - - // auto passes = builder.passes(); - // for (auto p : passes) pipe.add(builder.opt_phase(p, world)); - builder.buildPipeline(pipe); - - pipe.run(); + for (auto def : make_internal) { def->make_internal(); } + assert(compilation && "no compilation function found"); + + // We found a compilation directive in the file and use it to build the compilation pipeline. + // The general idea is that passes and phases are exposed as axioms. + // Each pass/phase axiom is associated with a handler function operating on the PipelineBuilder in the + // passes map. This registering is analogous to the normalizers (`code -> code`) but only operated using + // side effects that change the pipeline. + world.DLOG("compilation using {} : {}", compilation, compilation->type()); + + // We can not directly access compile axioms here. + // But the compile dialect has not the necessary communication pipeline. + // Therefore, we register the handlers and let the compile dialect call them. + + PipelineBuilder pipe_builder(world); + // TODO: remove indirections of pipeline builder. Just add passes and phases directly to the pipeline. + for (auto& dialect : dialects) { pipe_builder.register_dialect(dialect); } + + auto pipeline = compilation->as()->body(); + auto [ax, phases] = collect_args(pipeline); + + // handle pipeline like all other pass axioms + auto pipeline_axiom = ax->as(); + auto pipeline_flags = pipeline_axiom->flags(); + assert(passes.contains(pipeline_flags)); + world.DLOG("Building pipeline"); + passes[pipeline_flags](world, pipe_builder, pipeline); + + world.DLOG("Executing pipeline"); + pipe_builder.run_pipeline(); + + return; } } // namespace thorin diff --git a/thorin/pass/optimize.h b/thorin/pass/optimize.h index 43373a722b..886601bdfe 100644 --- a/thorin/pass/optimize.h +++ b/thorin/pass/optimize.h @@ -6,19 +6,15 @@ namespace thorin { -static constexpr int Pass_Internal_Priority = 50; -static constexpr int Pass_Default_Priority = 100; -static constexpr int Opt_Phase = 100; -static constexpr int Codegen_Prep_Phase = 300; - class World; class PipelineBuilder; class Def; +class Dialect; using DefVec = std::vector; // `axiom ↦ (pipeline part) × (axiom application) → ()` // The function should inspect application to construct the pass/phase and add it to the pipeline. using Passes = absl::flat_hash_map>; -void optimize(World&, Passes&, PipelineBuilder&); +void optimize(World&, Passes&, std::vector&); } // namespace thorin diff --git a/thorin/pass/pass.cpp b/thorin/pass/pass.cpp index 00093a66c0..fdf45f49de 100644 --- a/thorin/pass/pass.cpp +++ b/thorin/pass/pass.cpp @@ -47,7 +47,7 @@ void PassMan::run() { world().debug_dump(); for (auto&& pass : passes_) pass->prepare(); - + auto externals = std::vector(world().externals().begin(), world().externals().end()); for (const auto& [_, nom] : externals) { analyzed(nom); @@ -55,6 +55,7 @@ void PassMan::run() { } while (!curr_state().stack.empty()) { + for (auto&& pass : passes_) world().ILOG(" + {}", pass->name()); push_state(); curr_nom_ = pop(curr_state().stack); world().VLOG("=== state {}: {} ===", states_.size() - 1, curr_nom_); diff --git a/thorin/pass/pipelinebuilder.cpp b/thorin/pass/pipelinebuilder.cpp index 30d3fbb2ce..58e75b9fa1 100644 --- a/thorin/pass/pipelinebuilder.cpp +++ b/thorin/pass/pipelinebuilder.cpp @@ -1,19 +1,23 @@ #include "thorin/pass/pipelinebuilder.h" -#include +// #include -#include +// #include +// #include #include "thorin/def.h" +#include "thorin/dialects.h" #include "thorin/lattice.h" #include "thorin/pass/fp/beta_red.h" #include "thorin/pass/fp/eta_exp.h" #include "thorin/pass/fp/eta_red.h" #include "thorin/pass/fp/tail_rec_elim.h" +#include "thorin/pass/pass.h" #include "thorin/pass/rw/partial_eval.h" #include "thorin/pass/rw/ret_wrap.h" #include "thorin/pass/rw/scalarize.h" +#include "thorin/phase/phase.h" #include "dialects/mem/passes/fp/copy_prop.h" #include "dialects/mem/passes/fp/ssa_constr.h" @@ -22,97 +26,27 @@ namespace thorin { -void PipelineBuilder::remember_pass_instance(Pass* p, const Def* def) { pass_instances_[def] = p; } -Pass* PipelineBuilder::get_pass_instance(const Def* def) { return pass_instances_[def]; } - -int PipelineBuilder::last_phase() { - auto phase_ids = phases(); - auto max_phase_id = std::max_element(phase_ids.begin(), phase_ids.end()); - auto max_phase = max_phase_id == phase_ids.end() ? 0 : *max_phase_id; - return max_phase; -} - -void PipelineBuilder::append_phase_end(PhaseBuilder phase, int priority) { - append_phase(last_phase() + 1, phase, priority); -} -void PipelineBuilder::append_pass_in_end(PassBuilder pass, int priority) { - extend_opt_phase(last_phase(), pass, priority); -} -void PipelineBuilder::append_pass_after_end(PassBuilder pass, int priority) { - extend_opt_phase(last_phase() + 1, pass, priority); -} - -void PipelineBuilder::extend_opt_phase(PassBuilder&& extension) { extend_opt_phase(Opt_Phase, extension); } - -void PipelineBuilder::extend_codegen_prep_phase(PassBuilder&& extension) { - extend_opt_phase(Codegen_Prep_Phase, extension); -} - -void PipelineBuilder::append_phase(int i, PhaseBuilder extension, int priority) { - if (!phase_extensions_.contains(i)) { phase_extensions_[i] = PhaseList(); } - phase_extensions_[i].push_back({priority, extension}); -} - -void PipelineBuilder::extend_opt_phase(int i, PassBuilder extension, int priority) { - // adds extension to the i-th optimization phase - // if the ith phase does not exist, it is created - if (!pass_extensions_.contains(i)) { pass_extensions_[i] = std::vector(); } - pass_extensions_[i].push_back({priority, extension}); -} - -void PipelineBuilder::add_opt(int i) { - extend_opt_phase( - i, - [](thorin::PassMan& man) { - man.add(); - man.add(); - auto er = man.add(); - auto ee = man.add(er); - man.add(ee); - man.add(er); - }, - Pass_Internal_Priority); // elevated priority +void PipelineBuilder::remember_pass_instance(Pass* p, const Def* def) { + def->world().DLOG("associating {} with {}", def->gid(), p); + pass_instances_[def] = p; } +Pass* PipelineBuilder::get_pass_instance(const Def* def) { return pass_instances_[def]; } -std::vector PipelineBuilder::passes() { - std::vector keys; - for (auto iter = pass_extensions_.begin(); iter != pass_extensions_.end(); iter++) { keys.push_back(iter->first); } - std::ranges::stable_sort(keys); - return keys; +void PipelineBuilder::begin_pass_phase() { man = std::make_unique(world_); } +void PipelineBuilder::end_pass_phase() { + std::unique_ptr&& pass_man_ref = std::move(man); + pipe->add(std::move(pass_man_ref)); + man = nullptr; } -std::vector PipelineBuilder::phases() { - std::vector keys; - for (auto iter = pass_extensions_.begin(); iter != pass_extensions_.end(); iter++) { keys.push_back(iter->first); } - for (auto iter = phase_extensions_.begin(); iter != phase_extensions_.end(); iter++) { - keys.push_back(iter->first); +void PipelineBuilder::register_dialect(Dialect& dialect) { dialects_.push_back(&dialect); } +bool PipelineBuilder::is_registered_dialect(std::string name) { + for (auto& dialect : dialects_) { + if (dialect->name() == name) { return true; } } - std::ranges::stable_sort(keys); - // erase duplicates to avoid duplicating phases - keys.erase(std::unique(keys.begin(), keys.end()), keys.end()); - return keys; -} - -std::unique_ptr PipelineBuilder::opt_phase(int i, World& world) { - auto man = std::make_unique(world); - - std::stable_sort(pass_extensions_[i].begin(), pass_extensions_[i].end(), passCmp()); - - for (const auto& ext : pass_extensions_[i]) { ext.second(*man); } - - return man; -} - -void PipelineBuilder::buildPipeline(Pipeline& pipeline) { - for (auto i : phases()) { buildPipelinePart(i, pipeline); } + return false; } -void PipelineBuilder::buildPipelinePart(int i, Pipeline& pipeline) { - if (pass_extensions_.contains(i)) { pipeline.add(opt_phase(i, pipeline.world())); } - if (phase_extensions_.contains(i)) { - std::stable_sort(phase_extensions_[i].begin(), phase_extensions_[i].end(), phaseCmp()); - for (const auto& ext : phase_extensions_[i]) { ext.second(pipeline); } - } -} +void PipelineBuilder::run_pipeline() { pipe->run(); } } // namespace thorin diff --git a/thorin/pass/pipelinebuilder.h b/thorin/pass/pipelinebuilder.h index 9fbf3a82d7..ca82cd1034 100644 --- a/thorin/pass/pipelinebuilder.h +++ b/thorin/pass/pipelinebuilder.h @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include "thorin/world.h" #include "thorin/pass/optimize.h" #include "thorin/pass/pass.h" @@ -9,66 +8,45 @@ namespace thorin { -using PassBuilder = std::function; -using PhaseBuilder = std::function; -using PrioPassBuilder = std::pair; -using PrioPhaseBuilder = std::pair; -using PassList = std::vector; -using PhaseList = std::vector; -using PassInstanceMap = absl::btree_map>; - -struct passCmp { - constexpr bool operator()(PrioPassBuilder const& a, PrioPassBuilder const& b) const noexcept { - return a.first < b.first; - } -}; - -struct phaseCmp { - constexpr bool operator()(PrioPhaseBuilder const& a, PrioPhaseBuilder const& b) const noexcept { - return a.first < b.first; - } -}; +using PassInstanceMap = absl::btree_map>; class PipelineBuilder { public: - explicit PipelineBuilder() {} - - int last_phase(); + PipelineBuilder(World& world) + : pipe(std::make_unique(world)) + , world_(world) {} // Adds a pass and remembers it associated with the given def. template void add_pass(const Def* def, Args&&... args) { - append_pass_in_end([&, def, ... args = std::forward(args)](PassMan& man) { - auto pass = (Pass*)man.add

(args...); - remember_pass_instance(pass, def); - }); + auto pass = (Pass*)man->add

(std::forward(args)...); + remember_pass_instance(pass, def); + } + // TODO: add remembered entry + template + void add_phase(Args&&... args) { + assert(!man && "cannot add phase while in pass phase"); + pipe->add

(std::forward(args)...); } + void begin_pass_phase(); + void end_pass_phase(); + void remember_pass_instance(Pass* p, const Def*); Pass* get_pass_instance(const Def*); - void append_phase_end(PhaseBuilder, int priority = Pass_Default_Priority); - void append_pass_in_end(PassBuilder, int priority = Pass_Default_Priority); - void append_pass_after_end(PassBuilder, int priority = Pass_Default_Priority); + void register_dialect(Dialect& d); + bool is_registered_dialect(std::string name); - void append_phase(int i, PhaseBuilder, int priority = Pass_Default_Priority); - void extend_opt_phase(int i, PassBuilder, int priority = Pass_Default_Priority); - void extend_opt_phase(PassBuilder&&); - void add_opt(int i); - void extend_codegen_prep_phase(PassBuilder&&); - - std::unique_ptr opt_phase(int i, World& world); - void buildPipeline(Pipeline& pipeline); - void buildPipelinePart(int i, Pipeline& pipeline); - void add_opt(PassMan man); - - std::vector passes(); - std::vector phases(); + void run_pipeline(); private: - std::map pass_extensions_; - std::map phase_extensions_; + std::set registered_dialects_; + std::vector dialects_; PassInstanceMap pass_instances_; + std::unique_ptr man; + std::unique_ptr pipe; + World& world_; }; template @@ -79,10 +57,21 @@ void register_pass(Passes& passes, CArgs&&... args) { }; } + +template +void register_phase(Passes& passes, CArgs&&... args) { + passes[flags_t(Axiom::Base)] = [... args = std::forward(args)](World&, PipelineBuilder& builder, + const Def*) { + builder.add_phase

(args...); + }; +} + template void register_pass_with_arg(Passes& passes) { - passes[flags_t(Axiom::Base)] = [](World&, PipelineBuilder& builder, const Def* app) { + passes[flags_t(Axiom::Base)] = [](World& world, PipelineBuilder& builder, const Def* app) { auto pass_arg = (Q*)(builder.get_pass_instance(app->as()->arg())); + world.DLOG("register using arg: {} of type {} for gid {}", pass_arg, typeid(Q).name(), + app->as()->arg()->gid()); builder.add_pass

(app, pass_arg); }; } diff --git a/thorin/pass/rw/lam_spec.cpp b/thorin/pass/rw/lam_spec.cpp index d995cf8f58..9000eb4732 100644 --- a/thorin/pass/rw/lam_spec.cpp +++ b/thorin/pass/rw/lam_spec.cpp @@ -36,8 +36,12 @@ const Def* LamSpec::rewrite(const Def* def) { auto [app, old_lam] = isa_apped_nom_lam(def); if (!isa_workable(old_lam)) return def; + Scope scope(old_lam); + // Skip recursion to avoid infinite inlining. + if (scope.free_defs().contains(old_lam)) return def; + DefVec new_doms, new_vars, new_args; - auto skip = old_lam->ret_var() ? (is_top_level(old_lam) ? 1 : 0) : 0; + auto skip = old_lam->ret_var() && is_top_level(old_lam); auto old_doms = old_lam->doms(); for (auto dom : old_doms.skip_back(skip)) { diff --git a/thorin/world.cpp b/thorin/world.cpp index 0a164f89ed..453d60bd0f 100644 --- a/thorin/world.cpp +++ b/thorin/world.cpp @@ -182,6 +182,7 @@ const Def* World::tuple_str(std::string_view s, const Def* dbg) { } const Def* World::extract(const Def* d, const Def* index, const Def* dbg) { + assert(d); if (index->isa()) { auto n = index->num_ops(); DefArray idx(n, [&](size_t i) { return index->op(i); }); @@ -233,6 +234,7 @@ const Def* World::extract(const Def* d, const Def* index, const Def* dbg) { else elem_t = extract(tuple(type->as()->ops(), dbg), index, dbg); + assert(d); return unify(2, elem_t, d, index, dbg); } @@ -240,7 +242,15 @@ const Def* World::insert(const Def* d, const Def* index, const Def* val, const D auto type = d->unfold_type(); auto size = Idx::size(index->type()); - if (err() && !checker().equiv(type->arity(), size, dbg)) err()->index_out_of_range(type->arity(), index, dbg); + if (err()) { + if (!checker().equiv(type->arity(), size, dbg)) err()->index_out_of_range(type->arity(), index, dbg); + + // The value type does not match the type in the tuple at position index. + if (auto index_lit = isa_lit(index)) { + auto target_type = type->proj(*index_lit); + if (!checker().assignable(target_type, val, dbg)) err()->expected_type(target_type, dbg); + } + } 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