MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
ssa.cpp
Go to the documentation of this file.
2
3#include <mim/pass/eta_exp.h>
4
5#include "mim/plug/mem/mem.h"
6
7namespace mim::plug::mem::pass {
8
9namespace {
10const Def* get_sloxy_type(const Proxy* sloxy) { return Axm::as<mem::Ptr>(sloxy->type())->arg(0); }
11
12std::tuple<const Proxy*, Lam*> split_phixy(const Proxy* phixy) {
13 return {phixy->op(0)->as<Proxy>(), phixy->op(1)->as_mut<Lam>()};
14}
15} // namespace
16
19 eta_exp_ = man->find<EtaExp>();
20}
21
22void SSA::enter() { lam2sloxy2val_[curr_mut()].clear(); }
23
24const Def* SSA::rewrite(const Proxy* proxy) {
25 if (proxy->tag() == Traxy) {
26 DLOG("traxy '{}'", proxy);
27 for (size_t i = 1, e = proxy->num_ops(); i != e; i += 2)
28 set_val(curr_mut(), as_proxy(proxy->op(i), Sloxy), proxy->op(i + 1));
29 return proxy->op(0);
30 }
31
32 return proxy;
33}
34
35const Def* SSA::rewrite(const Def* def) {
36 if (auto slot = Axm::isa<mem::slot>(def)) {
37 auto [mem, id] = slot->args<2>();
38 auto [_, ptr] = slot->projs<2>();
39 auto sloxy = proxy(ptr->type(), {curr_mut(), id}, Sloxy)->set(slot->dbg());
40 DLOG("sloxy: '{}'", sloxy);
41 if (!keep_.contains(sloxy)) {
42 set_val(curr_mut(), sloxy, world().bot(get_sloxy_type(sloxy)));
43 data(curr_mut()).writable.emplace(sloxy);
44 return world().tuple({mem, sloxy});
45 }
46 } else if (auto load = Axm::isa<mem::load>(def)) {
47 auto [mem, ptr] = load->args<2>();
48 if (auto sloxy = isa_proxy(ptr, Sloxy)) return world().tuple({mem, get_val(curr_mut(), sloxy)});
49 } else if (auto store = Axm::isa<mem::store>(def)) {
50 auto [mem, ptr, val] = store->args<3>();
51 if (auto sloxy = isa_proxy(ptr, Sloxy)) {
52 if (data(curr_mut()).writable.contains(sloxy)) {
53 set_val(curr_mut(), sloxy, val);
54 return op_remem(mem)->set(store->dbg());
55 }
56 }
57 } else if (auto [app, mem_lam] = isa_apped_mut_lam(def); isa_workable(mem_lam)) {
58 return mem2phi(app, mem_lam);
59 } else {
60 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
61 if (auto lam = def->op(i)->isa_mut<Lam>(); isa_workable(lam)) {
62 if (mem2phi_.contains(lam)) return def->refine(i, eta_exp_->proxy(lam));
63 }
64 }
65 }
66
67 return def;
68}
69
70const Def* SSA::get_val(Lam* lam, const Proxy* sloxy) {
71 auto& sloxy2val = lam2sloxy2val_[lam];
72 if (auto i = sloxy2val.find(sloxy); i != sloxy2val.end()) {
73 auto val = i->second;
74 DLOG("get_val found: '{}': '{}': '{}'", sloxy, val, lam);
75 return val;
76 } else if (lam->is_external()) {
77 DLOG("cannot install phi for '{}' in '{}'", sloxy, lam);
78 return sloxy;
79 } else if (auto pred = data(lam).pred) {
80 DLOG("get_val recurse: '{}': '{}' -> '{}'", sloxy, pred, lam);
81 return get_val(pred, sloxy);
82 } else {
83 auto phixy = proxy(get_sloxy_type(sloxy), {sloxy, lam}, Phixy)->set(sloxy->dbg());
84 phixy->debug_prefix("_phi_");
85 DLOG("get_val phixy: '{}' '{}'", sloxy, lam);
86 return set_val(lam, sloxy, phixy);
87 }
88}
89
90const Def* SSA::set_val(Lam* lam, const Proxy* sloxy, const Def* val) {
91 DLOG("set_val: '{}': '{}': '{}'", sloxy, val, lam);
92 return lam2sloxy2val_[lam][sloxy] = val;
93}
94
95const Def* SSA::mem2phi(const App* app, Lam* mem_lam) {
96 auto&& sloxys = lam2sloxys_[mem_lam];
97 if (sloxys.empty()) return app;
98
99 DefVec types, phis;
100 for (auto i = sloxys.begin(), e = sloxys.end(); i != e;) {
101 auto sloxy = *i;
102 if (keep_.contains(sloxy)) {
103 i = sloxys.erase(i);
104 } else {
105 phis.emplace_back(sloxy);
106 types.emplace_back(get_sloxy_type(sloxy));
107 ++i;
108 }
109 }
110
111 size_t num_phis = phis.size();
112 if (num_phis == 0) return app;
113
114 auto&& [phi_lam, old_phis] = mem2phi_[mem_lam];
115 if (phi_lam == nullptr || old_phis != phis) {
116 old_phis = phis;
117 phi_lam = world().mut_lam(merge_sigma(mem_lam->dom(), types), mem_lam->codom())->set(mem_lam->dbg());
118 eta_exp_->new2old(phi_lam, mem_lam);
119 DLOG("new phi_lam '{}'", phi_lam);
120
121 auto num_mem_vars = mem_lam->num_vars();
122 DefVec traxy_ops(2 * num_phis + 1);
123 traxy_ops[0] = phi_lam->var();
124 for (size_t i = 0; auto sloxy : sloxys) {
125 traxy_ops[2 * i + 1] = sloxy;
126 traxy_ops[2 * i + 2] = phi_lam->var(num_mem_vars + i);
127 ++i;
128 }
129 auto traxy = proxy(phi_lam->var()->type(), traxy_ops, Traxy);
130
131 auto new_vars = DefVec(num_mem_vars, [&](size_t i) { return traxy->proj(i); });
132 phi_lam->set(mem_lam->reduce(world().tuple(mem_lam->dom(), new_vars)));
133 } else {
134 DLOG("reuse phi_lam '{}'", phi_lam);
135 }
136
137 DLOG("mem_lam => phi_lam: '{}': '{}' => '{}': '{}'", mem_lam, mem_lam->type()->dom(), phi_lam, phi_lam->dom());
138 auto sloxy = sloxys.begin();
139 auto args = DefVec(num_phis, [&](auto) { return get_val(curr_mut(), *sloxy++); });
140 return world().app(phi_lam, merge_tuple(app->arg(), args));
141}
142
144 if (proxy->tag() == Sloxy) {
145 auto sloxy_lam = proxy->op(0)->as_mut<Lam>();
146
147 if (keep_.emplace(proxy).second) {
148 DLOG("keep: '{}'; pointer needed", proxy);
149 return undo_enter(sloxy_lam);
150 }
151 }
152
153 assert(proxy->tag() == Phixy);
154 auto [sloxy, mem_lam] = split_phixy(proxy);
155 if (lam2sloxys_[mem_lam].emplace(sloxy).second) {
156 DLOG("phi needed: phixy '{}' for sloxy '{}' for mem_lam '{}'", proxy, sloxy, mem_lam);
157 return undo_visit(mem_lam);
158 }
159
160 return No_Undo;
161}
162
164 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
165 if (auto succ_lam = isa_workable(def->op(i)->isa_mut<Lam>())) {
166 auto& succ_info = data(succ_lam);
167
168 // TODO this is a bit scruffy - maybe we can do better
169 if (Lam::isa_basicblock(succ_lam) && succ_lam != curr_mut())
170 for (auto writable = data(curr_mut()).writable; auto&& w : writable)
171 succ_info.writable.insert(w);
172
173 if (!isa_callee(def, i)) {
174 if (succ_info.pred) {
175 DLOG("several preds in non-callee position; wait for EtaExp");
176 succ_info.pred = nullptr;
177 } else {
178 DLOG("'{}' -> '{}'", curr_mut(), succ_lam);
179 succ_info.pred = curr_mut();
180 }
181 }
182 }
183 }
184
185 return No_Undo;
186}
187
188} // namespace mim::plug::mem::pass
static auto isa(const Def *def)
Definition axm.h:107
static auto as(const Def *def)
Definition axm.h:129
Base class for all Defs.
Definition def.h:251
Def * set(size_t i, const Def *)
Successively set from left to right.
Definition def.cpp:266
const Def * refine(size_t i, const Def *new_op) const
Definition def.cpp:232
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:482
const Def * op(size_t i) const noexcept
Definition def.h:308
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:429
bool is_external() const noexcept
Definition def.h:464
Dbg dbg() const
Definition def.h:502
constexpr size_t num_ops() const noexcept
Definition def.h:309
Performs η-expansion: f -> λx.f x, if f is a Lam with more than one user and does not appear in calle...
Definition eta_exp.h:13
undo_t undo_visit(Def *mut) const
Definition pass.h:360
undo_t undo_enter(Def *mut) const
Definition pass.h:367
A function.
Definition lam.h:111
Lam * set(Filter filter, const Def *body)
Definition lam.cpp:29
static const Lam * isa_basicblock(const Def *d)
Definition lam.h:143
const Proxy * proxy(const Def *type, Defs ops, u32 tag=0)
Definition pass.h:141
virtual void init(PassMan *)
Definition pass.cpp:30
PassMan & man()
Definition pass.h:97
friend class PassMan
Definition pass.h:166
const Proxy * isa_proxy(const Def *def, u32 tag=0)
Check whether given def is a Proxy whose Proxy::pass matches this Pass's IPass::index.
Definition pass.h:143
const Proxy * as_proxy(const Def *def, u32 tag=0)
Definition pass.h:148
Lam * curr_mut() const
Definition pass.h:307
World & world()
Definition pass.h:64
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:196
const Def * tuple(Defs ops)
Definition world.cpp:288
Lam * mut_lam(const Pi *pi)
Definition world.h:297
const Def * rewrite(const Proxy *) override
Definition ssa.cpp:24
void init(PassMan *) final
Definition ssa.cpp:17
undo_t analyze(const Proxy *) override
Definition ssa.cpp:143
void enter() override
Invoked just before Pass::rewriteing PassMan::curr_mut's body.
Definition ssa.cpp:22
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:95
The mem Plugin
Definition mem.h:11
const Def * op_remem(const Def *mem)
Definition mem.h:128
Vector< const Def * > DefVec
Definition def.h:77
std::pair< const App *, Lam * > isa_apped_mut_lam(const Def *def)
Definition lam.h:354
const Def * merge_sigma(const Def *def, Defs defs)
Definition tuple.cpp:136
Lam * isa_workable(Lam *lam)
These are Lams that are neither nullptr, nor Lam::is_external, nor Lam::is_unset.
Definition lam.h:349
const App * isa_callee(const Def *def, size_t i)
Definition lam.h:346
size_t undo_t
Definition pass.h:21
static constexpr undo_t No_Undo
Definition pass.h:22
const Def * merge_tuple(const Def *def, Defs defs)
Definition tuple.cpp:141
@ Lam
Definition def.h:114
@ App
Definition def.h:114
@ Proxy
Definition def.h:114