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 : FPPass(man, std::format("copy_prop (bb_only: {})", bb_only))
12 , beta_red_(man.find<BetaRed>())
13 , eta_exp_(man.find<EtaExp>())
14 , bb_only_(bb_only) {}
15
16const Def* CopyProp::rewrite(const Def* def) {
17 auto [app, var_lam] = isa_apped_mut_lam(def);
18 if (!isa_workable(var_lam) || (bb_only_ && Lam::isa_returning(var_lam))) return def;
19
20 auto n = app->num_targs();
21 if (n == 0) return app;
22
23 auto [it, _] = lam2info_.emplace(var_lam, std::tuple(Lattices(n), (Lam*)nullptr, DefVec(n)));
24 auto& [lattice, prop_lam, old_args] = it->second;
25
26 if (mem::mem_var(var_lam)) lattice[0] = Lattice::Keep;
27 if (std::ranges::all_of(lattice, [](auto l) { return l == Lattice::Keep; })) return app;
28
29 DefVec new_args, new_doms, appxy_ops = {var_lam};
30 auto& args = data(var_lam);
31 args.resize(n);
32
33 for (size_t i = 0; i != n; ++i) {
34 switch (lattice[i]) {
35 case Lattice::Dead: break;
36 case Lattice::Prop:
37 if (app->arg(n, i)->has_dep(Dep::Proxy)) {
38 world().DLOG("found proxy within app: {}@{} - wait till proxy is gone", var_lam, app);
39 return app;
40 } else if (args[i] == nullptr) {
41 args[i] = app->arg(n, i);
42 } else if (args[i] != app->arg(n, i)) {
43 appxy_ops.emplace_back(world().lit_nat(i));
44 } else {
45 assert(args[i] == app->arg(n, i));
46 }
47 break;
48 case Lattice::Keep:
49 new_doms.emplace_back(var_lam->var(n, i)->type());
50 new_args.emplace_back(app->arg(n, i));
51 break;
52 default: fe::unreachable();
53 }
54 }
55
56 world().DLOG("app->args(): {, }", app->args());
57 world().DLOG("args: {, }", args);
58 world().DLOG("new_args: {, }", new_args);
59
60 if (appxy_ops.size() > 1) {
61 auto appxy = proxy(app->type(), appxy_ops, Appxy);
62 world().DLOG("appxy: '{}': {, }", appxy, appxy_ops);
63 return appxy;
64 }
65
66 assert(new_args.size() < n);
67 if (prop_lam == nullptr || !std::ranges::equal(old_args, args)) {
68 old_args = args;
69 auto prop_dom = world().sigma(new_doms);
70 auto new_pi = world().pi(prop_dom, var_lam->codom());
71 prop_lam = var_lam->stub(new_pi);
72
73 world().DLOG("new prop_lam: {}", prop_lam);
74 if (beta_red_) beta_red_->keep(prop_lam);
75 if (eta_exp_) eta_exp_->new2old(prop_lam, var_lam);
76
77 size_t j = 0;
78 auto new_vars = DefVec(n, [&, prop_lam = prop_lam](size_t i) -> const Def* {
79 switch (lattice[i]) {
80 case Lattice::Dead: return proxy(var_lam->var(n, i)->type(), {var_lam, world().lit_nat(i)}, Varxy);
81 case Lattice::Prop: return args[i];
82 case Lattice::Keep: return prop_lam->var(j++);
83 default: fe::unreachable();
84 }
85 });
86
87 prop_lam->set(var_lam->reduce(world().tuple(new_vars)));
88 }
89
90 world().DLOG("var_lam => prop_lam: {}: {} => {}: {}", var_lam, var_lam->dom(), prop_lam, prop_lam->dom());
91 auto res = app->world().app(prop_lam, new_args);
92
93 // Don't optimize again. Also, keep this line here at the very bottom as this invalidates all references.
94 Lam* key = prop_lam; // prop_lam is a Lam*& which might get invalidated by the very insertion happening next.
95 lam2info_.insert_or_assign(key, std::tuple(Lattices(new_doms.size(), Lattice::Keep), (Lam*)nullptr, DefVec()));
96 return res;
97}
98
100 world().DLOG("found proxy: {}", proxy);
101 auto var_lam = proxy->op(0)->as_mut<Lam>();
102 auto& [lattice, prop_lam, old_args] = lam2info_[var_lam];
103
104 if (proxy->tag() == Varxy) {
105 auto i = Lit::as(proxy->op(1));
106 if (auto& l = lattice[i]; l == Lattice::Dead) {
107 l = Lattice::Prop;
108 world().DLOG("Dead -> Prop: @{}#{}", var_lam, i);
109 return undo_visit(var_lam);
110 }
111 } else {
112 assert(proxy->tag() == Appxy);
113 for (auto ops = proxy->ops(); auto op : ops.subspan(1)) {
114 auto i = Lit::as(op);
115 if (auto& l = lattice[i]; l != Lattice::Keep) {
116 l = Lattice::Keep;
117 world().DLOG("Prop -> Keep: @{}#{}", var_lam, i);
118 }
119 }
120
121 return undo_visit(var_lam);
122 }
123
124 return No_Undo;
125}
126
127} // namespace mim::plug::mem
Optimistically performs β-reduction (aka inlining).
Definition beta_red.h:9
Base class for all Defs.
Definition def.h:251
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
FPPass(PassMan &man, std::string name)
Definition pass.h:268
undo_t undo_visit(Def *mut) const
Definition pass.h:303
A function.
Definition lam.h:109
static const Lam * isa_returning(const Def *d)
Definition lam.h:142
static T as(const Def *def)
Definition def.h:816
World & world()
Definition pass.h:326
const Proxy * proxy(const Def *type, Defs ops, u32 tag=0)
Definition pass.h:79
PassMan & man()
Definition pass.h:34
friend class PassMan
Definition pass.h:105
Pi * stub(const Def *type)
Definition lam.h:91
const Def * sigma(Defs ops)
Definition world.cpp:278
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:196
const Pi * pi(const Def *dom, const Def *codom, bool implicit=false)
Definition world.h:264
const Def * rewrite(const Def *) override
Definition copy_prop.cpp:16
undo_t analyze(const Proxy *) override
Definition copy_prop.cpp:99
CopyProp(PassMan &man, bool bb_only=false)
Definition copy_prop.cpp:10
The mem Plugin
Definition mem.h:11
const Def * mem_var(Lam *lam)
Returns the memory argument of a function if it has one.
Definition mem.h:38
The tuple Plugin
Vector< const Def * > DefVec
Definition def.h:77
@ Proxy
Definition def.h:128
std::pair< const App *, Lam * > isa_apped_mut_lam(const Def *def)
Definition lam.h:350
Lam * isa_workable(Lam *lam)
These are Lams that are neither nullptr, nor Lam::is_external, nor Lam::is_unset.
Definition lam.h:345
size_t undo_t
Definition pass.h:18
Value * find(IndexMap< Indexer, Key, Value * > &map, Key key)
Definition indexmap.h:71
static constexpr undo_t No_Undo
Definition pass.h:19
Definition span.h:122