MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
lower_typed_clos.cpp
Go to the documentation of this file.
2
3#include <functional>
4
5#include "mim/check.h"
6
7namespace mim::plug::clos {
8
9namespace {
10const Def* insert_ret(const Def* def, const Def* ret) {
11 auto new_ops = DefVec(def->num_projs() + 1, [&](auto i) { return (i == def->num_projs()) ? ret : def->proj(i); });
12 auto& w = def->world();
13 return def->is_intro() ? w.tuple(new_ops) : w.sigma(new_ops);
14}
15} // namespace
16
18 // TODO put into c'tor - doesn't work right now, because world becomes invalid
19 dummy_ret_ = world().bot(world().cn(world().annex<mem::M>()));
20
21 for (auto mut : world().copy_externals())
22 rewrite(mut);
23 while (!worklist_.empty()) {
24 auto [lvm, lcm, lam] = worklist_.front();
25 worklist_.pop();
26 lcm_ = lcm;
27 lvm_ = lvm;
28 world().DLOG("in {} (lvm={}, lcm={})", lam, lvm_, lcm_);
29 if (lam->is_set()) {
30 auto new_f = rewrite(lam->filter());
31 auto new_b = rewrite(lam->body());
32 lam->unset()->set({new_f, new_b});
33 }
34 }
35
36 for (auto lam : new_externals_)
37 lam->make_external();
38}
39
40Lam* LowerTypedClos::make_stub(Lam* lam, enum Mode mode, bool adjust_bb_type) {
41 assert(lam && "make_stub: not a lam");
42 if (auto i = old2new_.find(lam); i != old2new_.end() && i->second->isa_mut<Lam>()) return i->second->as_mut<Lam>();
43 auto& w = world();
44 auto new_dom = w.sigma(DefVec(lam->num_doms(), [&](auto i) -> const Def* {
45 auto new_dom = rewrite(lam->dom(i));
46 if (i == Clos_Env_Param) {
47 if (mode == Unbox)
48 return env_type();
49 else if (mode == Box)
50 return world().call<mem::Ptr0>(new_dom);
51 }
52 return new_dom;
53 }));
54 if (Lam::isa_basicblock(lam) && adjust_bb_type) new_dom = insert_ret(new_dom, dummy_ret_->type());
55 auto new_type = w.cn(new_dom);
56 auto new_lam = lam->stub(new_type);
57 w.DLOG("stub {} ~> {}", lam, new_lam);
58 if (lam->is_set()) new_lam->set(lam->filter(), lam->body());
59 if (lam->is_external()) {
60 lam->make_internal();
61 new_externals_.emplace_back(new_lam);
62 }
63 auto lcm = mem::mem_var(new_lam);
64 // TODO I guess, this is not correct: check mode?
65 auto env = new_lam->num_vars() < 2 ? new_lam->var() : new_lam->var(Clos_Env_Param);
66 if (mode == Box) {
67 auto env_mem = w.call<mem::load>(Defs{lcm, env});
68 lcm = w.extract(env_mem, 0_u64)->set("mem");
69 env = w.extract(env_mem, 1_u64)->set("closure_env");
70 } else if (mode == Unbox) {
71 env = w.call<core::bitcast>(lam->dom(Clos_Env_Param), env)->set("unboxed_env");
72 }
73 auto new_args = w.tuple(DefVec(lam->num_doms(), [&](auto i) {
74 return (i == Clos_Env_Param) ? env : (lam->var(i) == mem::mem_var(lam)) ? lcm : new_lam->var(i);
75 }));
76 assert(new_args->num_projs() == lam->num_doms());
77 assert(lam->num_doms() <= new_lam->num_doms());
78 map(lam->var(), new_args);
79 worklist_.emplace(mem::mem_var(lam), lcm, new_lam);
80 return map(lam, new_lam)->as<Lam>();
81}
82
83const Def* LowerTypedClos::rewrite(const Def* def) {
84 switch (def->node()) {
85 case Node::Bot:
86 case Node::Top:
87 case Node::Type:
88 case Node::Univ:
89 case Node::Nat: return def;
90 default: break;
91 }
92
93 auto& w = world();
94
95 if (auto i = old2new_.find(def); i != old2new_.end()) return i->second;
96 if (auto var = def->isa<Var>();
97 var && var->mut()->isa_mut<Lam>()) // TODO put this conditions inside the assert below
98 assert(false && "Lam vars should appear in a map!");
99
100 auto new_type = rewrite(def->type());
101
102 if (auto ct = isa_clos_type(def)) {
103 auto pi = rewrite(ct->op(1))->as<Pi>();
104 if (Pi::isa_basicblock(pi)) pi = w.cn(insert_ret(pi->dom(), dummy_ret_->type()));
105 auto env_type = rewrite(ct->op(2));
106 return map(def, w.sigma({pi, env_type}));
107 } else if (auto proj = def->isa<Extract>()) {
108 auto tuple = proj->tuple();
109 auto idx = Lit::isa(proj->index());
110 if (isa_clos_type(tuple->type())) {
111 assert(idx && idx <= 2 && "unknown proj from closure tuple");
112 if (*idx == 0)
113 return map(def, env_type());
114 else
115 return map(def, rewrite(tuple)->proj(*idx - 1));
116 } else if (auto var = tuple->isa<Var>(); var && isa_clos_type(var->mut())) {
117 assert(false && "proj fst type form closure type");
118 }
119 }
120
121 if (auto c = isa_clos_lit(def)) {
122 auto env = rewrite(c.env());
123 auto mode = (env->type()->isa<Idx>() || Axm::isa<mem::Ptr>(env->type())) ? Unbox : Box;
124 const Def* fn = make_stub(c.fnc_as_lam(), mode, true);
125 if (env->type() == w.sigma()) {
126 // Optimize empty env
127 env = w.bot(env_type());
128 } else if (!mode) {
129 auto mem_ptr = (c.get() == attr::esc) ? mem::op_alloc(env->type(), lcm_) : mem::op_slot(env->type(), lcm_);
130 auto mem = w.extract(mem_ptr, 0_u64);
131 auto env_ptr = mem_ptr->proj(1_u64); //, w.dbg(fn->sym() + "_env"));
132 lcm_ = w.call<mem::store>(Defs{mem, env_ptr, env});
133 map(lvm_, lcm_);
134 env = env_ptr;
135 }
136 fn = w.call<core::bitcast>(new_type->op(0), fn);
137 env = w.call<core::bitcast>(new_type->op(1), env);
138 return map(def, w.tuple({fn, env}));
139 } else if (auto lam = def->isa_mut<Lam>()) {
140 return make_stub(lam, No_Env, false);
141 } else if (auto mut = def->isa_mut()) {
142 assert(!isa_clos_type(mut));
143 auto new_mut = mut->stub(new_type);
144 map(mut, new_mut);
145 for (size_t i = 0; i < mut->num_ops(); i++)
146 if (mut->op(i)) new_mut->set(i, rewrite(mut->op(i)));
147 if (!def->isa_mut<Global>() && Checker::alpha<Checker::Check>(mut, new_mut)) return map(mut, mut);
148 if (auto imm = new_mut->immutabilize()) return map(mut, imm);
149 return new_mut;
150 } else if (def->isa<Axm>()) {
151 return def;
152 } else {
153 auto new_ops = DefVec(def->num_ops(), [&](auto i) { return rewrite(def->op(i)); });
154
155 if (auto app = def->isa<App>()) {
156 // Add dummy retcont to first-class BB
157 if (auto p = app->callee()->isa<Extract>();
158 p && isa_clos_type(p->tuple()->type()) && Pi::isa_basicblock(app->callee_type()))
159 new_ops[1] = insert_ret(new_ops[1], dummy_ret_);
160 }
161
162 auto new_def = def->rebuild(new_type, new_ops);
163
164 // We may need to update the mem token after all ops have been rewritten:
165 // F (m, a1, ..., (env, f):pct)
166 // ~>
167 // let [m', env_ptr] = :alloc T m'
168 // let m'' = :store env_ptr env
169 // F (m, a1', ..., (env_ptr, f'))
170 // ~>
171 // let ...
172 // F (m'', a1', ..., (env_ptr, f'))
173 for (size_t i = 0; i < new_def->num_ops(); i++)
174 if (new_def->op(i)->type() == w.annex<mem::M>()) new_def = new_def->refine(i, lcm_);
175
176 if (new_type == w.annex<mem::M>()) { // :store
177 lcm_ = new_def;
178 lvm_ = def;
179 } else if (new_type->isa<Sigma>()) { // :alloc, :slot, ...
180 for (size_t i = 0; i < new_type->num_ops(); i++) {
181 if (new_type->op(i) == w.annex<mem::M>()) {
182 lcm_ = w.extract(new_def, i);
183 lvm_ = w.extract(def, i);
184 break;
185 }
186 }
187 }
188
189 return map(def, new_def);
190 }
191}
192
193} // namespace mim::plug::clos
static auto isa(const Def *def)
Definition axm.h:107
static bool alpha(const Def *d1, const Def *d2)
Definition check.h:96
Base class for all Defs.
Definition def.h:216
bool is_set() const
Yields true if empty or the last op is set.
Definition def.cpp:276
void make_internal()
Definition def.cpp:541
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:394
bool is_external() const
Definition def.h:429
A function.
Definition lam.h:107
const Def * filter() const
Definition lam.h:119
const Def * dom() const
Definition lam.h:128
static const Lam * isa_basicblock(const Def *d)
Definition lam.h:139
Lam * stub(const Def *type)
Definition lam.h:181
const Def * body() const
Definition lam.h:120
static std::optional< T > isa(const Def *def)
Definition def.h:773
World & world()
Definition phase.h:27
static const Pi * isa_basicblock(const Def *d)
Is this a continuation (Pi::isa_cn) that is not Pi::isa_returning?
Definition lam.h:48
const Def * bot(const Def *type)
Definition world.h:455
void start() override
Actual entry.
The clos Plugin
Definition clos.h:7
ClosLit isa_clos_lit(const Def *def, bool fn_isa_lam=true)
Tries to match a closure literal.
Definition clos.cpp:65
static constexpr size_t Clos_Env_Param
Describes where the environment is placed in the argument list.
Definition clos.h:107
const Sigma * isa_clos_type(const Def *def)
Definition clos.cpp:112
The mem Plugin
Definition mem.h:11
const Def * op_slot(const Def *type, const Def *mem)
Definition mem.h:144
const Def * mem_var(Lam *lam)
Returns the memory argument of a function if it has one.
Definition mem.h:38
const Def * op_alloc(const Def *type, const Def *mem)
Definition mem.h:136
The tuple Plugin
View< const Def * > Defs
Definition def.h:51
Vector< const Def * > DefVec
Definition def.h:52
@ Nat
Definition def.h:89
@ Pi
Definition def.h:89
@ Univ
Definition def.h:89
@ Bot
Definition def.h:89
@ Lam
Definition def.h:89
@ Global
Definition def.h:89
@ Var
Definition def.h:89
@ Axm
Definition def.h:89
@ Sigma
Definition def.h:89
@ Extract
Definition def.h:89
@ Type
Definition def.h:89
@ Top
Definition def.h:89
@ App
Definition def.h:89