Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
clos_conv_prep.cpp
Go to the documentation of this file.
2
4
6
7namespace thorin::plug::clos {
8
9namespace {
10// FIXME: these guys do not work if another pass rewrites curr_mut()'s body
11bool isa_cnt(const App* body, Ref def, size_t i) {
12 return Pi::isa_returning(body->callee_type()) && body->arg() == def && i == def->num_ops() - 1;
13}
14
15Ref isa_br(const App* body, Ref 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, Ref 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(Ref def) {
27 if (auto [var, lam] = ca_isa_var<Lam>(def); var && lam && var == lam->ret_var()) return lam;
28 return nullptr;
29}
30
31} // namespace
32
34 if (eta_exp_) lam = eta_exp_->new2old(lam);
35 return lam2fscope_[lam];
36}
37
40 lam2fscope_[curr_mut()] = curr_mut();
41 world().DLOG("scope {} -> {}", curr_mut(), curr_mut());
42 scope_ = std::make_unique<Scope>(curr_mut());
43 for (auto def : scope_->bound()) {
44 assert(def);
45 if (auto bb_lam = Lam::isa_mut_basicblock(def)) {
46 world().DLOG("scope {} -> {}", bb_lam, curr_mut());
47 lam2fscope_[bb_lam] = curr_mut();
48 }
49 }
50 }
51
52 auto body = curr_mut()->body()->isa<App>();
53 // Skip if the mutable is already wrapped or the body is undefined/no continuation.
54 ignore_ = !(body && Pi::isa_cn(body->callee_type())) || wrapper_.contains(curr_mut());
55}
56
57const App* ClosConvPrep::rewrite_arg(const App* app) {
58 auto& w = world();
59 auto arg = app->arg();
60
61 if (arg->isa<Var>()) return app;
62
63 for (auto i = 0u; i < arg->num_projs(); i++) {
64 auto op = arg->proj(i);
65
66 auto refine = [&](Ref new_op) {
67 Ref args;
68 if (arg == op)
69 args = new_op;
70 else
71 args = arg->refine(i, new_op);
72 return app->refine(1, args)->as<App>();
73 };
74
75 if (auto lam = isa_retvar(op); lam && from_outer_scope(lam)) {
76 w.DLOG("found return var from enclosing scope: {}", op);
77 return refine(eta_wrap(op, attr::freeBB)->set("free_ret"));
78 }
79 if (auto bb_lam = Lam::isa_mut_basicblock(op); bb_lam && from_outer_scope(bb_lam)) {
80 w.DLOG("found BB from enclosing scope {}", op);
81 return refine(w.call(attr::freeBB, op));
82 }
83 if (isa_cnt(app, arg, i)) {
84 if (match<attr>(attr::ret, op) || isa_retvar(op)) {
85 return app;
86 } else if (auto contlam = op->isa_mut<Lam>()) {
87 return refine(w.call(attr::ret, contlam));
88 } else {
89 auto wrapper = eta_wrap(op, attr::ret)->set("eta_cont");
90 w.DLOG("eta expanded return cont: {} -> {}", op, wrapper);
91 return refine(wrapper);
92 }
93 }
94
95 if (!isa_callee_br(app, arg, i)) {
96 if (auto bb_lam = Lam::isa_mut_basicblock(op)) {
97 w.DLOG("found firstclass use of BB: {}", bb_lam);
98 return refine(w.call(attr::fstclassBB, bb_lam));
99 }
100 // TODO: If EtaRed eta-reduces branches, we have to wrap them again!
101 if (isa_retvar(op)) {
102 w.DLOG("found firstclass use of return var: {}", op);
103 return refine(eta_wrap(op, attr::fstclassBB)->set("fstclass_ret"));
104 }
105 }
106 }
107
108 return app;
109}
110
112 auto& w = world();
113 if (Pi::isa_cn(app->callee_type())) {
114 if (auto br = app->callee()->isa<Extract>()) {
115 auto branches = br->tuple();
116 // Eta-Expand branches
117 if (branches->isa<Tuple>() && branches->type()->isa<Arr>()) {
118 for (size_t i = 0, e = branches->num_ops(); i != e; ++i) {
119 if (!branches->op(i)->isa_mut<Lam>()) {
120 auto wrapper = eta_wrap(branches->op(i), attr::bot)->set("eta_br");
121 w.DLOG("eta wrap branch: {} -> {}", branches->op(i), wrapper);
122 branches = branches->refine(i, wrapper);
123 }
124 }
125 return app->refine(0, app->callee()->refine(0, branches))->as<App>();
126 }
127 }
128 }
129
130 return app;
131}
132
134 if (ignore_ || match<attr>(def)) return def;
135
136 if (auto app = def->isa<App>()) {
137 app = rewrite_arg(app);
138 app = rewrite_callee(app);
139 return app;
140 }
141
142 return def;
143}
144
145} // namespace thorin::plug::clos
const Def * callee() const
Definition lam.h:206
const Pi * callee_type() const
Definition lam.h:208
const Def * arg() const
Definition lam.h:215
A (possibly paramterized) Array.
Definition tuple.h:50
const Def * refine(size_t i, const Def *new_op) const
Definition def.cpp:226
size_t num_ops() const
Definition def.h:270
const Def * type() const
Yields the raw type of this Def, i.e. maybe nullptr.
Definition def.h:248
T * isa_mut() const
If this is *mut*able, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:449
Def * set(size_t i, const Def *def)
Successively set from left to right.
Definition def.cpp:254
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
Definition def.cpp:531
void new2old(Lam *new_lam, Lam *old_lam)
Definition eta_exp.h:22
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:118
A function.
Definition lam.h:97
Ref body() const
Definition lam.h:108
static Lam * isa_mut_basicblock(Ref d)
Only for mutables.
Definition lam.h:136
World & world()
Definition pass.h:296
static const Pi * isa_returning(Ref d)
Is this a continuation (Pi::isa_cn) which has a Pi::ret_pi?
Definition lam.h:52
static const Pi * isa_cn(Ref d)
Is this a continuation - i.e. is the Pi::codom thorin::Bottom?
Definition lam.h:50
Helper class to retrieve Infer::arg if present.
Definition def.h:87
Data constructor for a Sigma.
Definition tuple.h:39
const App * rewrite_callee(const App *app)
void enter() override
Invoked just before Pass::rewriteing PassMan::curr_mut's body.
const App * rewrite_arg(const App *app)
@ Extract
Definition def.h:41
@ Tuple
Definition def.h:41
The clos Plugin
Definition clos.h:7
const App * isa_callee(const Def *def, size_t i)
Definition lam.h:231