MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
copy_prop.cpp
Go to the documentation of this file.
2
3#include <mim/pass/beta_red.h>
4#include <mim/pass/eta_exp.h>
5
6#include "mim/plug/mem/mem.h"
7
8namespace mim::plug::mem {
9
11 auto [app, var_lam] = isa_apped_mut_lam(def);
12 if (!isa_workable(var_lam) || (bb_only_ && Lam::isa_returning(var_lam))) return def;
13
14 auto n = app->num_targs();
15 if (n == 0) return app;
16
17 auto [it, _] = lam2info_.emplace(var_lam, std::tuple(Lattices(n), (Lam*)nullptr, DefVec(n)));
18 auto& [lattice, prop_lam, old_args] = it->second;
19
20 if (mem::mem_var(var_lam)) lattice[0] = Lattice::Keep;
21 if (std::ranges::all_of(lattice, [](auto l) { return l == Lattice::Keep; })) return app;
22
23 DefVec new_args, new_doms, appxy_ops = {var_lam};
24 auto& args = data(var_lam);
25 args.resize(n);
26
27 for (size_t i = 0; i != n; ++i) {
28 switch (lattice[i]) {
29 case Lattice::Dead: break;
30 case Lattice::Prop:
31 if (app->arg(n, i)->has_dep(Dep::Proxy)) {
32 world().DLOG("found proxy within app: {}@{} - wait till proxy is gone", var_lam, app);
33 return app;
34 } else if (args[i] == nullptr) {
35 args[i] = app->arg(n, i);
36 } else if (args[i] != app->arg(n, i)) {
37 appxy_ops.emplace_back(world().lit_nat(i));
38 } else {
39 assert(args[i] == app->arg(n, i));
40 }
41 break;
42 case Lattice::Keep:
43 new_doms.emplace_back(var_lam->var(n, i)->type());
44 new_args.emplace_back(app->arg(n, i));
45 break;
46 default: fe::unreachable();
47 }
48 }
49
50 world().DLOG("app->args(): {, }", app->args());
51 world().DLOG("args: {, }", args);
52 world().DLOG("new_args: {, }", new_args);
53
54 if (appxy_ops.size() > 1) {
55 auto appxy = proxy(app->type(), appxy_ops, Appxy);
56 world().DLOG("appxy: '{}': {, }", appxy, appxy_ops);
57 return appxy;
58 }
59
60 assert(new_args.size() < n);
61 if (prop_lam == nullptr || !std::ranges::equal(old_args, args)) {
62 old_args = args;
63 auto prop_dom = world().sigma(new_doms);
64 auto new_pi = world().pi(prop_dom, var_lam->codom());
65 prop_lam = var_lam->stub(new_pi);
66
67 world().DLOG("new prop_lam: {}", prop_lam);
68 if (beta_red_) beta_red_->keep(prop_lam);
69 if (eta_exp_) eta_exp_->new2old(prop_lam, var_lam);
70
71 size_t j = 0;
72 auto new_vars = DefVec(n, [&, prop_lam = prop_lam](size_t i) -> Ref {
73 switch (lattice[i]) {
74 case Lattice::Dead: return proxy(var_lam->var(n, i)->type(), {var_lam, world().lit_nat(i)}, Varxy);
75 case Lattice::Prop: return args[i];
76 case Lattice::Keep: return prop_lam->var(j++);
77 default: fe::unreachable();
78 }
79 });
80
81 prop_lam->set(var_lam->reduce(world().tuple(new_vars)));
82 }
83
84 world().DLOG("var_lam => prop_lam: {}: {} => {}: {}", var_lam, var_lam->dom(), prop_lam, prop_lam->dom());
85 auto res = app->world().app(prop_lam, new_args);
86
87 // Don't optimize again. Also, keep this line here at the very bottom as this invalidates all references.
88 Lam* key = prop_lam; // prop_lam is a Lam*& which might get invalidated by the very insertion happening next.
89 lam2info_.insert_or_assign(key, std::tuple(Lattices(new_doms.size(), Lattice::Keep), (Lam*)nullptr, DefVec()));
90 return res;
91}
92
94 world().DLOG("found proxy: {}", proxy);
95 auto var_lam = proxy->op(0)->as_mut<Lam>();
96 auto& [lattice, prop_lam, old_args] = lam2info_[var_lam];
97
98 if (proxy->tag() == Varxy) {
99 auto i = Lit::as(proxy->op(1));
100 if (auto& l = lattice[i]; l == Lattice::Dead) {
101 l = Lattice::Prop;
102 world().DLOG("Dead -> Prop: @{}#{}", var_lam, i);
103 return undo_visit(var_lam);
104 }
105 } else {
106 assert(proxy->tag() == Appxy);
107 for (auto ops = proxy->ops(); auto op : ops.subspan(1)) {
108 auto i = Lit::as(op);
109 if (auto& l = lattice[i]; l != Lattice::Keep) {
110 l = Lattice::Keep;
111 world().DLOG("Prop -> Keep: @{}#{}", var_lam, i);
112 }
113 }
114
115 return undo_visit(var_lam);
116 }
117
118 return No_Undo;
119}
120
121} // namespace mim::plug::mem
void keep(Lam *lam)
Definition beta_red.h:16
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Definition def.h:455
const Def * op(size_t i) const
Definition def.h:269
auto ops() const
Definition def.h:268
void new2old(Lam *new_lam, Lam *old_lam)
Definition eta_exp.h:22
undo_t undo_visit(Def *mut) const
Definition pass.h:273
A function.
Definition lam.h:103
static const Lam * isa_returning(Ref d)
Definition lam.h:140
static T as(Ref def)
Definition def.h:768
World & world()
Definition pass.h:296
const Proxy * proxy(Ref type, Defs ops, u32 tag=0)
Definition pass.h:75
Pi * stub(Ref type)
Definition lam.h:88
u32 tag() const
Definition def.h:832
Helper class to retrieve Infer::arg if present.
Definition def.h:86
This is a thin wrapper for absl::InlinedVector<T, N, / A> which in turn is a drop-in replacement for ...
Definition vector.h:16
Ref app(Ref callee, Ref arg)
Definition world.cpp:186
const Pi * pi(Ref dom, Ref codom, bool implicit=false)
Definition world.h:255
Ref sigma(Defs ops)
Definition world.cpp:230
Ref rewrite(Ref) override
Definition copy_prop.cpp:10
undo_t analyze(const Proxy *) override
Definition copy_prop.cpp:93
The mem Plugin
Definition mem.h:11
Ref mem_var(Lam *lam)
Returns the memory argument of a function if it has one.
Definition mem.h:38
Vector< const Def * > DefVec
Definition def.h:62
std::pair< const App *, Lam * > isa_apped_mut_lam(const Def *def)
Definition lam.h:256
Lam * isa_workable(Lam *lam)
These are Lams that are neither nullptr, nor Lam::is_external, nor Lam::is_unset.
Definition lam.h:251
size_t undo_t
Definition pass.h:14
static constexpr undo_t No_Undo
Definition pass.h:15