MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
clos_conv_prep.cpp
Go to the documentation of this file.
2
3#include <mim/nest.h>
4
6
8
9namespace {
10
11bool isa_cnt(const App* body, const Def* def, size_t i) {
12 return Pi::isa_returning(body->callee_type()) && body->arg() == def && i == def->num_ops() - 1;
13}
14
15const Def* isa_br(const App* body, const Def* def) {
16 if (!Pi::isa_cn(body->callee_type())) return nullptr;
17 auto proj = body->callee()->isa<Extract>();
18 return (proj && proj->tuple() == def && proj->tuple()->isa<Tuple>()) ? proj->tuple() : nullptr;
19}
20
21bool isa_callee_br(const App* body, const Def* def, size_t i) {
22 if (!Pi::isa_cn(body->callee_type())) return false;
23 return isa_callee(def, i) || isa_br(body, def);
24}
25
26Lam* isa_retvar(const Def* def) {
27 if (auto [var, lam] = isa_var_proj<Lam>(def); var && lam && var == lam->ret_var()) return lam;
28 return nullptr;
29}
30
31} // namespace
32
34 if (analyzed_) return false;
35 analyzed_ = true;
36
37 // Collect all returning Lams and assign each basicblock Lam in their Nest to them.
38 DefSet done;
39 auto visit = [&](auto&& visit, const Def* def) -> void {
40 if (!done.emplace(def).second) return;
41
42 if (auto lam = def->isa_mut<Lam>(); lam && Pi::isa_returning(lam)) {
43 lam2fscope_[lam] = lam;
44 DLOG("scope {} -> {}", lam, lam);
45 auto nest = Nest(lam);
46 for (auto mut : nest.muts())
47 if (auto bb_lam = Lam::isa_mut_basicblock(mut)) {
48 DLOG("scope {} -> {}", bb_lam, lam);
49 lam2fscope_[bb_lam] = lam;
50 }
51 }
52
53 if (auto mut = def->isa_mut()) {
54 if (mut->is_set())
55 for (auto op : mut->deps())
56 visit(visit, op);
57 } else {
58 for (auto op : def->deps())
59 visit(visit, op);
60 }
61 };
62 for (auto def : old_world().roots())
63 visit(visit, def);
64
65 return false;
66}
67
68const Def* ClosConvPrep::eta_wrap(const Def* old_op, attr a) {
69 auto [entry, inserted] = old2wrapper_.emplace(old_op, nullptr);
70 auto& wrapper = entry->second;
71 if (inserted) {
72 auto& w = new_world();
73 wrapper = w.mut_lam(rewrite(old_op->type())->as<Pi>());
74 wrapper->app(false, rewrite(old_op), wrapper->var());
75 }
76 return new_world().call(a, wrapper);
77}
78
79const Def* ClosConvPrep::rewrite_arg(const App* app, const Def* old_op) {
80 auto arg = app->arg();
81 auto i = 0u;
82 for (; i < arg->num_projs(); i++)
83 if (arg->proj(i) == old_op) break;
84
85 if (auto lam = isa_retvar(old_op); lam && from_outer_scope(lam)) {
86 DLOG("found return var from enclosing scope: {}", old_op);
87 return eta_wrap(old_op, attr::free_bb)->set("free_ret");
88 }
89 if (auto bb_lam = Lam::isa_mut_basicblock(old_op); bb_lam && from_outer_scope(bb_lam)) {
90 DLOG("found BB from enclosing scope {}", old_op);
91 return new_world().call(attr::free_bb, rewrite(old_op));
92 }
93 if (isa_cnt(app, arg, i)) {
94 if (Axm::isa<attr>(attr::returning, old_op) || isa_retvar(old_op)) {
95 return rewrite(old_op);
96 } else if (auto contlam = old_op->isa_mut<Lam>()) {
97 return new_world().call(attr::returning, rewrite(contlam));
98 } else {
99 auto wrapper = eta_wrap(old_op, attr::returning)->set("eta_cont");
100 DLOG("eta expanded return cont: {} -> {}", old_op, wrapper);
101 return wrapper;
102 }
103 }
104
105 if (!isa_callee_br(app, arg, i)) {
106 if (auto bb_lam = Lam::isa_mut_basicblock(old_op)) {
107 DLOG("found firstclass use of BB: {}", bb_lam);
108 return new_world().call(attr::fstclass_bb, rewrite(bb_lam));
109 }
110 // @note This relies on branches staying in `Extract`-of-`Tuple` form; if eta-reduction were to collapse
111 // a branch back into a bare continuation, it would have to be re-wrapped here.
112 if (isa_retvar(old_op)) {
113 DLOG("found firstclass use of return var: {}", old_op);
114 return eta_wrap(old_op, attr::fstclass_bb)->set("fstclass_ret");
115 }
116 }
117
118 return rewrite(old_op);
119}
120
121const Def* ClosConvPrep::rewrite_callee_op(const Def* old_op) {
122 if (!old_op->isa_mut<Lam>()) {
123 auto wrapper = eta_wrap(old_op, attr::bottom)->set("eta_br");
124 DLOG("eta wrap branch: {} -> {}", old_op, wrapper);
125 return wrapper;
126 }
127 return rewrite(old_op);
128}
129
131 if (is_bootstrapping() || Axm::isa<attr>(app)) return RWPhase::rewrite_imm_App(app);
132
133 // Skip if the surrounding mutable is no Lam with a continuation call as body.
134 auto mut = curr_mut() ? curr_mut()->isa_mut<Lam>() : nullptr;
135 auto body = mut && mut->is_set() ? mut->body()->isa<App>() : nullptr;
136 if (!body || !Pi::isa_cn(body->callee_type())) return RWPhase::rewrite_imm_App(app);
137
138 auto& w = new_world();
139
140 // Eta-expand branches in callee position.
141 const Def* new_callee = nullptr;
142 if (Pi::isa_cn(app->callee_type())) {
143 if (auto br = app->callee()->isa<Extract>()) {
144 auto branches = br->tuple();
145 if (branches->isa<Tuple>() && branches->type()->isa<Arr>()) {
146 auto new_ops
147 = DefVec(branches->num_ops(), [&](size_t i) { return rewrite_callee_op(branches->op(i)); });
148 new_callee = w.extract(w.tuple(new_ops), rewrite(br->index()));
149 }
150 }
151 }
152 if (!new_callee) new_callee = rewrite(app->callee());
153
154 // Wrap the argument's projections.
155 const Def* new_arg;
156 auto arg = app->arg();
157 if (arg->isa<Var>()) {
158 new_arg = rewrite(arg);
159 } else {
160 auto new_args = DefVec(arg->num_projs(), [&](size_t i) { return rewrite_arg(app, arg->proj(i)); });
161 new_arg = arg->num_projs() == 1 ? new_args[0] : w.tuple(new_args);
162 }
163
164 return w.app(new_callee, new_arg);
165}
166
167} // namespace mim::plug::clos::phase
const Pi * callee_type() const
Definition lam.h:278
const Def * callee() const
Definition lam.h:276
const Def * arg() const
Definition lam.h:285
A (possibly paramterized) Array.
Definition tuple.h:121
static auto isa(const Def *def)
Definition axm.h:107
Base class for all Defs.
Definition def.h:261
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:276
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:527
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:441
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
Definition def.cpp:491
nat_t num_projs() const
Yields Def::arity(), if it is a Lit, or 1 otherwise.
Definition def.cpp:628
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:210
A function.
Definition lam.h:110
static Lam * isa_mut_basicblock(const Def *d)
Only for mutables.
Definition lam.h:145
Builds a nesting tree for all mutables/binders.
Definition nest.h:30
A dependent function type.
Definition lam.h:14
static const Pi * isa_cn(const Def *d)
Is this a continuation - i.e. is the Pi::codom mim::Bottom?
Definition lam.h:47
static const Pi * isa_returning(const Def *d)
Is this a continuation (Pi::isa_cn) which has a Pi::ret_pi?
Definition lam.h:49
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
World & old_world()
Get old Defs from here.
Definition phase.h:367
D * curr_mut() const
Definition rewrite.h:89
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:56
Data constructor for a Sigma.
Definition tuple.h:70
A variable introduced by a binder (mutable).
Definition def.h:756
const Def * call(const Def *callee, T &&arg, Args &&... args)
Definition world.h:641
const Def * rewrite_imm_App(const App *) final
bool analyze() final
Fills lam2fscope_: assigns each basicblock Lam to its enclosing returning Lam.
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:94
std::tuple< const Extract *, N * > isa_var_proj(const Def *def)
If def is a projection var#i of the Var of some mutable of type N, returns (projection,...
Definition clos.h:72
Vector< const Def * > DefVec
Definition def.h:79
GIDSet< const Def * > DefSet
Definition def.h:76
const App * isa_callee(const Def *def, size_t i)
Definition lam.h:345
@ Lam
Definition def.h:109
@ Extract
Definition def.h:109
@ App
Definition def.h:109
@ Tuple
Definition def.h:109