MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
sym_expr_opt.cpp
Go to the documentation of this file.
2
3#include <absl/container/fixed_array.h>
4
5namespace mim {
6
7Def* SymExprOpt::Analysis::rewrite_mut(Def* mut) {
8 map(mut, mut);
9
10 if (auto var = mut->has_var()) {
11 map(var, var);
12
13 if (mut->isa<Lam>())
14 for (auto var : mut->tvars()) {
15 map(var, var);
16 lattice_[var] = var;
17 }
18 }
19
20 for (auto d : mut->deps())
21 rewrite(d);
22
23 return mut;
24}
25
26const Def* SymExprOpt::Analysis::propagate(const Def* top, const Def* def) {
27 auto [i, ins] = lattice_.emplace(top, def);
28 if (ins) {
29 todo_ = true;
30 DLOG("propagate: {} → {}", top, def);
31 return def;
32 }
33
34 auto cur = i->second;
35 if (!cur || def->isa<Bot>() || cur == def || cur == top || cur->isa<Proxy>()) return cur;
36
37 todo_ = true;
38 DLOG("cannot propagate {}, trying GVN", top);
39 if (cur->isa<Bot>()) return i->second = def;
40 return i->second = nullptr; // we reached top for propagate; nullptr marks this to bundle for GVN
41}
42
43static nat_t get_index(const Def* def) { return Lit::as(def->as<Extract>()->index()); }
44
45const Def* SymExprOpt::Analysis::rewrite_imm_App(const App* app) {
46 if (auto lam = app->callee()->isa_mut<Lam>(); isa_optimizable(lam)) {
47 auto n = app->num_targs();
48 auto abstr_args = absl::FixedArray<const Def*>(n);
49 auto abstr_vars = absl::FixedArray<const Def*>(n);
50
51 // propagate
52 for (size_t i = 0; i != n; ++i) {
53 auto abstr = rewrite(app->targ(i));
54 abstr_vars[i] = propagate(lam->tvar(i), abstr);
55 abstr_args[i] = abstr;
56 }
57
58 // GVN bundle: All things marked as top (nullptr) by propagate are now treated as one entity by bundling them
59 // into one proxy
60 for (size_t i = 0; i != n; ++i) {
61 if (abstr_vars[i]) continue;
62
63 auto vars = DefVec();
64 auto vi = lam->tvar(i);
65 auto ai = abstr_args[i];
66 vars.emplace_back(vi);
67
68 for (size_t j = i + 1; j != n; ++j) {
69 auto vj = lam->tvar(j);
70 if (abstr_vars[j] || abstr_args[j] != ai) continue;
71 vars.emplace_back(vj);
72 }
73
74 if (vars.size() == 1) {
75 lattice_[vi] = abstr_vars[i] = vi; // top
76 } else {
77 auto proxy = world().proxy(vi->type(), vars, 0, 0);
78
79 for (auto p : proxy->ops()) {
80 auto j = get_index(p);
81 auto vj = lam->tvar(j);
82 if (abstr_vars[j] || abstr_args[j] != ai) continue;
83 lattice_[vj] = abstr_vars[j] = proxy;
84 }
85
86 DLOG("bundle: {}", proxy);
87 }
88 }
89
90 // GVN split: We have to prove that all incoming args for all vars in a bundle are the same value.
91 // Otherwise we have to refine the bundle by splitting off contradictions.
92 // E.g.: Say we started with `{a, b, c, d, e}` as a single bundle for all tvars of `lam`.
93 // Now, we see `lam (x, y, x, y, z)`. Then we have to build:
94 // a -> {a, c}
95 // b -> {b, d}
96 // c -> {a, c}
97 // d -> {b, d}
98 // e -> e (top)
99 for (size_t i = 0; i != n; ++i) {
100 if (auto proxy = abstr_vars[i]->isa<Proxy>()) {
101 auto num = proxy->num_ops();
102 auto vars = DefVec();
103 auto ai = abstr_args[i];
104
105 for (auto p : proxy->ops()) {
106 auto j = get_index(p);
107 auto vj = lam->tvar(j);
108 if (p == vj) {
109 if (ai == abstr_args[j]) vars.emplace_back(vj);
110 }
111 }
112
113 auto new_num = vars.size();
114 if (new_num == 1) {
115 todo_ = true;
116 auto vi = lam->tvar(i);
117 lattice_[vi] = abstr_vars[i] = vi;
118 DLOG("single: {}", vi);
119 } else if (new_num != num) {
120 todo_ = true;
121 auto new_proxy = world().proxy(ai->type(), vars, 0, 0);
122 DLOG("split: {}", new_proxy);
123
124 for (auto p : new_proxy->ops()) {
125 auto j = get_index(p);
126 auto vj = lam->tvar(j);
127 if (p == vj) lattice_[vj] = abstr_vars[j] = new_proxy;
128 }
129 }
130 // if new_num == num: do nothing
131 }
132 }
133
134 // set new abstract var
135 auto abstr_var = world().tuple(abstr_vars);
136 map(lam->var(), abstr_var);
137 lattice_[lam->var()] = abstr_var;
138
139 if (!lookup(lam))
140 for (auto d : lam->deps())
141 rewrite(d);
142
143 return world().app(lam, abstr_args);
144 }
145
146 return Rewriter::rewrite_imm_App(app);
147}
148
149static bool keep(const Def* old_var, const Def* abstr) {
150 if (old_var == abstr) return true; // top
151 auto proxy = abstr->isa<Proxy>();
152 return proxy && proxy->op(0) == old_var; // first in GVN bundle?
153}
154
155const Def* SymExprOpt::rewrite_imm_App(const App* old_app) {
156 if (auto old_lam = old_app->callee()->isa_mut<Lam>()) {
157 if (auto l = lattice(old_lam->var()); l && l != old_lam->var()) {
158 todo_ = true;
159
160 size_t num_old = old_lam->num_tvars();
161 Lam* new_lam;
162 if (auto i = lam2lam_.find(old_lam); i != lam2lam_.end())
163 new_lam = i->second;
164 else {
165 // build new dom
166 auto new_doms = DefVec();
167 for (size_t i = 0; i != num_old; ++i) {
168 auto old_var = old_lam->var(num_old, i);
169 auto abstr = lattice(old_var);
170 if (keep(old_var, abstr)) new_doms.emplace_back(rewrite(old_lam->dom(num_old, i)));
171 }
172
173 // build new lam
174 size_t num_new = new_doms.size();
175 auto new_vars = absl::FixedArray<const Def*>(num_old);
176 new_lam = new_world().mut_lam(new_doms, rewrite(old_lam->codom()))->set(old_lam->dbg());
177 lam2lam_[old_lam] = new_lam;
178
179 // build new var
180 for (size_t i = 0, j = 0; i != num_old; ++i) {
181 auto old_var = old_lam->var(num_old, i);
182 auto abstr = lattice(old_var);
183
184 if (keep(old_var, abstr)) {
185 auto v = new_lam->var(num_new, j++);
186 new_vars[i] = v;
187 if (abstr != old_var) map(abstr, v); // GVN bundle
188 } else {
189 new_vars[i] = rewrite(abstr); // SCCP propagate
190 }
191 }
192
193 map(old_lam->var(), new_vars);
194 new_lam->set(rewrite(old_lam->filter()), rewrite(old_lam->body()));
195 }
196
197 // build new app
198 size_t num_new = new_lam->num_vars();
199 auto new_args = absl::FixedArray<const Def*>(num_new);
200 for (size_t i = 0, j = 0; i != num_old; ++i) {
201 auto old_var = old_lam->var(num_old, i);
202 auto abstr = lattice(old_var);
203 if (keep(old_var, abstr)) new_args[j++] = rewrite(old_app->targ(i));
204 }
205
206 return map(old_app, new_world().app(new_lam, new_args));
207 }
208 }
209
210 return Rewriter::rewrite_imm_App(old_app);
211}
212
213} // namespace mim
const Def * callee() const
Definition lam.h:276
Base class for all Defs.
Definition def.h:251
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:486
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
nat_t num_vars() noexcept
Definition def.h:429
Extracts from a Sigma or Array-typed Extract::tuple the element at position Extract::index.
Definition tuple.h:206
const Def * index() const
Definition tuple.h:217
A function.
Definition lam.h:110
Lam * set(Filter filter, const Def *body)
Definition lam.cpp:29
static T as(const Def *def)
Definition def.h:832
bool todo_
Set to true to indicate that you want to rerun all Phasees in your current fixed-point PhaseMan.
Definition phase.h:57
World & new_world()
Create new Defs into this.
Definition phase.h:146
World & world()=delete
Hides both and forbids direct access.
virtual const Def * map(const Def *old_def, const Def *new_def)
Definition rewrite.h:59
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:27
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
Definition rewrite.h:69
const Def * rewrite_imm_App(const App *) final
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:201
const Def * tuple(Defs ops)
Definition world.cpp:293
const Proxy * proxy(const Def *type, Defs ops, u32 index, u32 tag)
Definition world.h:258
Lam * mut_lam(const Pi *pi)
Definition world.h:322
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:95
Definition ast.h:14
u64 nat_t
Definition types.h:44
static bool keep(const Def *old_var, const Def *abstr)
Vector< const Def * > DefVec
Definition def.h:77
static nat_t get_index(const Def *def)
Lam * isa_optimizable(Lam *lam)
These are Lams that are.
Definition lam.h:352
TExt< false > Bot
Definition lattice.h:171
@ Lam
Definition def.h:114
@ App
Definition def.h:114
@ Proxy
Definition def.h:114