Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
ssa_constr.cpp
Go to the documentation of this file.
2
4
6
7namespace thorin::plug::mem {
8
9namespace {
10Ref get_sloxy_type(const Proxy* sloxy) { return force<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
17void SSAConstr::enter() { lam2sloxy2val_[curr_mut()].clear(); }
18
20 if (proxy->tag() == Traxy) {
21 world().DLOG("traxy '{}'", proxy);
22 for (size_t i = 1, e = proxy->num_ops(); i != e; i += 2)
23 set_val(curr_mut(), as_proxy(proxy->op(i), Sloxy), proxy->op(i + 1));
24 return proxy->op(0);
25 }
26
27 return proxy;
28}
29
31 if (auto slot = match<mem::slot>(def)) {
32 auto [mem, id] = slot->args<2>();
33 auto [_, ptr] = slot->projs<2>();
34 auto sloxy = proxy(ptr->type(), {curr_mut(), id}, Sloxy)->set(slot->dbg());
35 world().DLOG("sloxy: '{}'", sloxy);
36 if (!keep_.contains(sloxy)) {
37 set_val(curr_mut(), sloxy, world().bot(get_sloxy_type(sloxy)));
38 data(curr_mut()).writable.emplace(sloxy);
39 return world().tuple({mem, sloxy});
40 }
41 } else if (auto load = match<mem::load>(def)) {
42 auto [mem, ptr] = load->args<2>();
43 if (auto sloxy = isa_proxy(ptr, Sloxy)) return world().tuple({mem, get_val(curr_mut(), sloxy)});
44 } else if (auto store = match<mem::store>(def)) {
45 auto [mem, ptr, val] = store->args<3>();
46 if (auto sloxy = isa_proxy(ptr, Sloxy)) {
47 if (data(curr_mut()).writable.contains(sloxy)) {
48 set_val(curr_mut(), sloxy, val);
49 return op_remem(mem)->set(store->dbg());
50 }
51 }
52 } else if (auto [app, mem_lam] = isa_apped_mut_lam(def); isa_workable(mem_lam)) {
53 return mem2phi(app, mem_lam);
54 } else {
55 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
56 if (auto lam = def->op(i)->isa_mut<Lam>(); isa_workable(lam)) {
57 if (mem2phi_.contains(lam)) return def->refine(i, eta_exp_->proxy(lam));
58 }
59 }
60 }
61
62 return def;
63}
64
65Ref SSAConstr::get_val(Lam* lam, const Proxy* sloxy) {
66 auto& sloxy2val = lam2sloxy2val_[lam];
67 if (auto i = sloxy2val.find(sloxy); i != sloxy2val.end()) {
68 auto val = i->second;
69 world().DLOG("get_val found: '{}': '{}': '{}'", sloxy, val, lam);
70 return val;
71 } else if (lam->is_external()) {
72 world().DLOG("cannot install phi for '{}' in '{}'", sloxy, lam);
73 return sloxy;
74 } else if (auto pred = data(lam).pred) {
75 world().DLOG("get_val recurse: '{}': '{}' -> '{}'", sloxy, pred, lam);
76 return get_val(pred, sloxy);
77 } else {
78 auto phixy = proxy(get_sloxy_type(sloxy), {sloxy, lam}, Phixy)->set(sloxy->dbg());
79 phixy->debug_prefix("_phi_");
80 world().DLOG("get_val phixy: '{}' '{}'", sloxy, lam);
81 return set_val(lam, sloxy, phixy);
82 }
83}
84
85Ref SSAConstr::set_val(Lam* lam, const Proxy* sloxy, Ref val) {
86 world().DLOG("set_val: '{}': '{}': '{}'", sloxy, val, lam);
87 return lam2sloxy2val_[lam][sloxy] = val;
88}
89
90Ref SSAConstr::mem2phi(const App* app, Lam* mem_lam) {
91 auto&& sloxys = lam2sloxys_[mem_lam];
92 if (sloxys.empty()) return app;
93
94 DefVec types, phis;
95 for (auto i = sloxys.begin(), e = sloxys.end(); i != e;) {
96 auto sloxy = *i;
97 if (keep_.contains(sloxy)) {
98 i = sloxys.erase(i);
99 } else {
100 phis.emplace_back(sloxy);
101 types.emplace_back(get_sloxy_type(sloxy));
102 ++i;
103 }
104 }
105
106 size_t num_phis = phis.size();
107 if (num_phis == 0) return app;
108
109 auto&& [phi_lam, old_phis] = mem2phi_[mem_lam];
110 if (phi_lam == nullptr || old_phis != phis) {
111 old_phis = phis;
112 phi_lam = world().mut_lam(merge_sigma(mem_lam->dom(), types), mem_lam->codom())->set(mem_lam->dbg());
113 eta_exp_->new2old(phi_lam, mem_lam);
114 world().DLOG("new phi_lam '{}'", phi_lam);
115
116 auto num_mem_vars = mem_lam->num_vars();
117 DefVec traxy_ops(2 * num_phis + 1);
118 traxy_ops[0] = phi_lam->var();
119 for (size_t i = 0; auto sloxy : sloxys) {
120 traxy_ops[2 * i + 1] = sloxy;
121 traxy_ops[2 * i + 2] = phi_lam->var(num_mem_vars + i);
122 ++i;
123 }
124 auto traxy = proxy(phi_lam->var()->type(), traxy_ops, Traxy);
125
126 auto new_vars = DefVec(num_mem_vars, [&](size_t i) { return traxy->proj(i); });
127 phi_lam->set(mem_lam->reduce(world().tuple(mem_lam->dom(), new_vars)));
128 } else {
129 world().DLOG("reuse phi_lam '{}'", phi_lam);
130 }
131
132 world().DLOG("mem_lam => phi_lam: '{}': '{}' => '{}': '{}'", mem_lam, mem_lam->type()->dom(), phi_lam,
133 phi_lam->dom());
134 auto sloxy = sloxys.begin();
135 auto args = DefVec(num_phis, [&](auto) { return get_val(curr_mut(), *sloxy++); });
136 return world().app(phi_lam, merge_tuple(app->arg(), args));
137}
138
140 if (proxy->tag() == Sloxy) {
141 auto sloxy_lam = proxy->op(0)->as_mut<Lam>();
142
143 if (keep_.emplace(proxy).second) {
144 world().DLOG("keep: '{}'; pointer needed", proxy);
145 return undo_enter(sloxy_lam);
146 }
147 }
148
149 assert(proxy->tag() == Phixy);
150 auto [sloxy, mem_lam] = split_phixy(proxy);
151 if (lam2sloxys_[mem_lam].emplace(sloxy).second) {
152 world().DLOG("phi needed: phixy '{}' for sloxy '{}' for mem_lam '{}'", proxy, sloxy, mem_lam);
153 return undo_visit(mem_lam);
154 }
155
156 return No_Undo;
157}
158
160 for (size_t i = 0, e = def->num_ops(); i != e; ++i) {
161 if (auto succ_lam = isa_workable(def->op(i)->isa_mut<Lam>())) {
162 auto& succ_info = data(succ_lam);
163
164 // TODO this is a bit scruffy - maybe we can do better
165 if (Lam::isa_basicblock(succ_lam) && succ_lam != curr_mut())
166 for (auto writable = data(curr_mut()).writable; auto&& w : writable) succ_info.writable.insert(w);
167
168 if (!isa_callee(def, i)) {
169 if (succ_info.pred) {
170 world().DLOG("several preds in non-callee position; wait for EtaExp");
171 succ_info.pred = nullptr;
172 } else {
173 world().DLOG("'{}' -> '{}'", curr_mut(), succ_lam);
174 succ_info.pred = curr_mut();
175 }
176 }
177 }
178 }
179
180 return No_Undo;
181}
182
183} // namespace thorin::plug::mem
const Def * refine(size_t i, const Def *new_op) const
Definition def.cpp:226
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == -1_n) or std::array (otherwise).
Definition def.h:369
bool is_external() const
Definition def.h:433
const Def * op(size_t i) const
Definition def.h:269
size_t num_ops() const
Definition def.h:270
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
Dbg dbg() const
Definition def.h:468
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Definition def.h:457
Def * set(size_t i, const Def *def)
Successively set from left to right.
Definition def.cpp:254
const Proxy * proxy(Lam *lam)
Definition eta_exp.h:21
void new2old(Lam *new_lam, Lam *old_lam)
Definition eta_exp.h:22
undo_t undo_visit(Def *mut) const
Retrieves the point to backtrack to just before mut was seen the very first time.
Definition pass.h:273
undo_t undo_enter(Def *mut) const
Retrieves the point to backtrack to just before rewriting mut's body.
Definition pass.h:280
A function.
Definition lam.h:97
static const Lam * isa_basicblock(Ref d)
Definition lam.h:133
Lam * set(Filter filter, const Def *body)
Definition lam.h:159
const Proxy * isa_proxy(Ref def, u32 tag=0)
Check whether given def is a Proxy whose Proxy::pass matches this Pass's IPass::index.
Definition pass.h:77
World & world()
Definition pass.h:296
const Proxy * as_proxy(Ref def, u32 tag=0)
Definition pass.h:82
const Proxy * proxy(Ref type, Defs ops, u32 tag=0)
Definition pass.h:75
u32 tag() const
Definition def.h:775
M * curr_mut() const
Definition pass.h:232
Helper class to retrieve Infer::arg if present.
Definition def.h:87
Ref app(Ref callee, Ref arg)
Definition world.cpp:183
Ref tuple(Defs ops)
Definition world.cpp:226
Lam * mut_lam(const Pi *pi)
Definition world.h:263
Ref rewrite(const Proxy *) override
void enter() override
Invoked just before Pass::rewriteing PassMan::curr_mut's body.
undo_t analyze(const Proxy *) override
@ Proxy
Definition def.h:41
The mem Plugin
Definition mem.h:11
Ref op_remem(Ref mem)
Definition mem.h:128
static constexpr undo_t No_Undo
Definition pass.h:15
const Def * merge_tuple(const Def *def, Defs defs)
Definition tuple.cpp:99
size_t undo_t
Definition pass.h:14
const Def * merge_sigma(const Def *def, Defs defs)
Definition tuple.cpp:94
const App * isa_callee(const Def *def, size_t i)
Definition lam.h:231
Vector< const Def * > DefVec
Definition def.h:63
std::pair< const App *, Lam * > isa_apped_mut_lam(const Def *def)
Definition lam.h:239
Lam * isa_workable(Lam *lam)
These are Lams that are neither nullptr, nor Lam::is_external, nor Lam::is_unset.
Definition lam.h:234