MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
conv.cpp
Go to the documentation of this file.
2
3#include "mim/plug/cps/cps.h"
4
5namespace mim::plug::cps {
6
7/// A term-level, direct-style function that we can and want to convert.
8/// Type-level and higher-order functions stay in direct style.
9static bool convertible(Lam* lam) {
10 if (!lam->is_set() || lam->is_external() || lam->is_annex() || Lam::isa_cn(lam)) return false;
11 auto codom = lam->codom();
12 return !codom->isa<Type>() && !codom->isa<Pi>();
13}
14
15const Def* Conv::map(const Def* old_def, const Def* new_def) {
16 auto& old2new = new_def->free_vars().has_intersection(scoped_) ? old2news_.back() : old2news_.front();
17 return old2new[old_def] = new_def;
18}
19
20const Def* Conv::rewrite_mut_Lam(Lam* old_lam) {
21 if (!is_bootstrapping() && convertible(old_lam)) return convert(old_lam);
22
23 auto new_lam = new_world().mut_lam(rewrite(old_lam->type())->as<Pi>());
24 map(old_lam, new_lam);
25 if (!old_lam->is_set()) return new_lam;
26
27 auto scope = Scope(*this, !is_bootstrapping() && Lam::isa_cn(old_lam));
28 auto new_filter = rewrite(old_lam->filter());
29 auto new_body = wire(scope.base(), rewrite(old_lam->body()));
30 return new_lam->set(new_filter, new_body);
31}
32
33const Def* Conv::convert(Lam* old_lam) {
34 auto& w = new_world();
35 auto old_pi = old_lam->type();
36 auto new_dom = rewrite(old_pi->dom());
37
38 Lam* new_lam;
39 if (auto old_var = old_pi->has_var()) {
40 // dependent codom: bind it against a fresh mutable Sigma [a: A, Cn B[old_var → a]]
41 auto sigma = w.mut_sigma(2);
42 sigma->var();
43 scoped_ = w.vars().insert(scoped_, sigma->has_var());
44 push();
45 map(old_var, sigma->var(2, 0));
46 auto new_codom = rewrite(old_pi->codom());
47 pop();
48 sigma->set(0, new_dom);
49 sigma->set(1, w.cn(new_codom));
50 new_lam = w.mut_con(sigma);
51 } else {
52 new_lam = w.mut_fun(new_dom, rewrite(old_pi->codom()));
53 }
54 new_lam->set(old_lam->dbg())->debug_suffix("_cps");
55
56 auto [param, ret] = new_lam->vars<2>();
57 map(old_lam->var(), param);
58 auto wrapper = map(old_lam, op_cps2ds_dep(new_lam));
59
60 DLOG("convert {}: {} ↝ {}: {}", old_lam, old_pi, new_lam, new_lam->type());
61
62 auto scope = Scope(*this, true);
63 auto new_filter = rewrite(old_lam->filter());
64 auto tail = w.app(ret, rewrite(old_lam->body()));
65 new_lam->set(new_filter, wire(scope.base(), tail));
66
67 return wrapper;
68}
69
70const Def* Conv::rewrite_imm_App(const App* old_app) {
71 auto new_arg = rewrite(old_app->arg());
72 auto new_callee = rewrite(old_app->callee());
73
74 if (liftable_)
75 if (auto wrapped = Axm::isa<cps2ds_dep>(new_callee)) return lift(wrapped->arg(), new_arg, old_app);
76
77 return new_world().app(new_callee, new_arg);
78}
79
80const Def* Conv::lift(const Def* k, const Def* new_arg, const App* old_app) {
81 auto& w = new_world();
82 auto cont = w.mut_con(rewrite(old_app->type()))->set_filter(false);
83 auto res = cont->var();
84 cont->set(w.append_suffix(k->sym(), "_cont"));
85 scoped_ = w.vars().insert(scoped_, cont->has_var());
86 pending_.emplace_back(k, new_arg, cont);
87
88 DLOG("lift {} ↝ {} ({}, {})", old_app, k, new_arg, cont);
89
90 return res;
91}
92
93const Def* Conv::wire(size_t base, const Def* body) {
94 auto& w = new_world();
95 while (pending_.size() > base) {
96 auto [callee, arg, cont] = pending_.back();
97 pending_.pop_back();
98 cont->set_body(body);
99 body = w.app(callee, w.tuple({arg, cont}));
100 }
101 return body;
102}
103
104} // namespace mim::plug::cps
const Def * callee() const
Definition lam.h:276
const Def * arg() const
Definition lam.h:285
static auto isa(const Def *def)
Definition axm.h:107
Base class for all Defs.
Definition def.h:261
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:308
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:441
const Def * debug_suffix(std::string) const
Definition def.cpp:544
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
bool is_external() const noexcept
Definition def.h:500
auto vars(F f) noexcept
Definition def.h:441
Sym sym() const
Definition def.h:558
Vars free_vars() const
Global set of free Vars: extends local_vars() by transitively following mutables as well.
Definition def.cpp:347
Dbg dbg() const
Definition def.h:556
bool is_annex() const noexcept
Definition def.h:504
A function.
Definition lam.h:110
const Def * filter() const
Definition lam.h:122
static const Lam * isa_cn(const Def *d)
Definition lam.h:141
Lam * set(Filter filter, const Def *body)
Definition lam.cpp:29
const Pi * type() const
Definition lam.h:130
const Def * body() const
Definition lam.h:123
const Def * codom() const
Definition lam.h:132
A dependent function type.
Definition lam.h:14
World & new_world()
Create new Defs into this.
Definition phase.h:368
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
Definition phase.h:356
virtual void push()
Definition rewrite.h:38
virtual void pop()
Definition rewrite.h:39
std::deque< Def2Def > old2news_
Definition rewrite.h:99
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:56
bool has_intersection(Set other) const noexcept
Is ?.
Definition sets.h:272
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:205
Lam * mut_lam(const Pi *pi)
Definition world.h:388
const Def * rewrite_mut_Lam(Lam *) final
Definition conv.cpp:20
const Def * rewrite_imm_App(const App *) final
Definition conv.cpp:70
const Def * map(const Def *, const Def *) final
Definition conv.cpp:15
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:94
The CPS Plugin
Definition cps.h:8
const Def * op_cps2ds_dep(const Def *k)
Definition cps.h:16
static bool convertible(Lam *lam)
A term-level, direct-style function that we can and want to convert.
Definition conv.cpp:9