3#include <absl/container/fixed_array.h>
7Def* SymExprOpt::Analysis::rewrite_mut(
Def* mut) {
10 if (
auto var = mut->has_var()) {
14 for (
auto var : mut->tvars()) {
20 for (
auto d : mut->deps())
26const Def* SymExprOpt::Analysis::propagate(
const Def* top,
const Def* def) {
27 auto [i, ins] = lattice_.emplace(top, def);
30 DLOG(
"propagate: {} → {}", top, def);
35 if (!cur || def->isa<
Bot>() || cur == def || cur == top || cur->isa<
Proxy>())
return cur;
38 DLOG(
"cannot propagate {}, trying GVN", top);
39 if (cur->isa<
Bot>())
return i->second = def;
40 return i->second =
nullptr;
45const Def* SymExprOpt::Analysis::rewrite_imm_App(
const App* app) {
47 auto n = app->num_targs();
48 auto abstr_args = absl::FixedArray<const Def*>(n);
49 auto abstr_vars = absl::FixedArray<const Def*>(n);
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;
60 for (
size_t i = 0; i != n; ++i) {
61 if (abstr_vars[i])
continue;
64 auto vi = lam->tvar(i);
65 auto ai = abstr_args[i];
66 vars.emplace_back(vi);
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);
74 if (vars.size() == 1) {
75 lattice_[vi] = abstr_vars[i] = vi;
77 auto proxy =
world().
proxy(vi->type(), vars, 0, 0);
79 for (
auto p : proxy->ops()) {
81 auto vj = lam->tvar(j);
82 if (abstr_vars[j] || abstr_args[j] != ai)
continue;
83 lattice_[vj] = abstr_vars[j] = proxy;
86 DLOG(
"bundle: {}", proxy);
99 for (
size_t i = 0; i != n; ++i) {
100 if (
auto proxy = abstr_vars[i]->isa<Proxy>()) {
101 auto num = proxy->num_ops();
103 auto ai = abstr_args[i];
105 for (
auto p : proxy->ops()) {
107 auto vj = lam->tvar(j);
109 if (ai == abstr_args[j]) vars.emplace_back(vj);
113 auto new_num = vars.size();
116 auto vi = lam->tvar(i);
117 lattice_[vi] = abstr_vars[i] = vi;
118 DLOG(
"single: {}", vi);
119 }
else if (new_num != num) {
121 auto new_proxy =
world().
proxy(ai->type(), vars, 0, 0);
122 DLOG(
"split: {}", new_proxy);
124 for (
auto p : new_proxy->ops()) {
126 auto vj = lam->tvar(j);
127 if (p == vj) lattice_[vj] = abstr_vars[j] = new_proxy;
136 map(lam->var(), abstr_var);
137 lattice_[lam->var()] = abstr_var;
140 for (
auto d : lam->deps())
143 return world().
app(lam, abstr_args);
146 return Rewriter::rewrite_imm_App(app);
150 if (old_var == abstr)
return true;
151 auto proxy = abstr->isa<
Proxy>();
152 return proxy && proxy->
op(0) == old_var;
157 if (
auto l = lattice(old_lam->var()); l && l != old_lam->var()) {
160 size_t num_old = old_lam->num_tvars();
162 if (
auto i = lam2lam_.find(old_lam); i != lam2lam_.end())
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)));
174 size_t num_new = new_doms.size();
175 auto new_vars = absl::FixedArray<const Def*>(num_old);
177 lam2lam_[old_lam] = new_lam;
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);
184 if (
keep(old_var, abstr)) {
185 auto v = new_lam->
var(num_new, j++);
187 if (abstr != old_var)
map(abstr, v);
193 map(old_lam->var(), new_vars);
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));
206 return map(old_app,
new_world().app(new_lam, new_args));
210 return Rewriter::rewrite_imm_App(old_app);
const Def * callee() const
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
const Def * op(size_t i) const noexcept
const Def * var(nat_t a, nat_t i) noexcept
nat_t num_vars() noexcept
Lam * set(Filter filter, const Def *body)
static T as(const Def *def)
bool todo_
Set to true to indicate that you want to rerun all Phasees in your current fixed-point PhaseMan.
World & new_world()
Create new Defs into this.
World & world()=delete
Hides both and forbids direct access.
virtual const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite(const Def *)
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
const Def * rewrite_imm_App(const App *) final
const Def * app(const Def *callee, const Def *arg)
const Def * tuple(Defs ops)
const Proxy * proxy(const Def *type, Defs ops, u32 index, u32 tag)
Lam * mut_lam(const Pi *pi)
#define DLOG(...)
Vaporizes to nothingness in Debug build.
static bool keep(const Def *old_var, const Def *abstr)
Vector< const Def * > DefVec
static nat_t get_index(const Def *def)
Lam * isa_optimizable(Lam *lam)
These are Lams that are.