MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
static_arg_opt.cpp
Go to the documentation of this file.
2
3namespace mim {
4
6 for (auto def : old_world().roots())
7 analyze(def);
8 return false; // no fixed-point necessary
9}
10
11void StaticArgOpt::analyze(const Def* def) {
12 if (auto [_, ins] = analyzed_.emplace(def); !ins) return;
13
14 if (auto app = def->isa<App>())
15 if (auto lam = app->callee()->isa_mut<Lam>(); lam && lam->has_var()) visit(app, lam);
16
17 for (auto d : def->deps())
18 analyze(d);
19}
20
21void StaticArgOpt::visit(const App* app, Lam* lam) {
22 auto mask = fe::Bitset();
23 for (size_t i = 0, n = lam->num_tdoms(); i != n; ++i)
24 if (app->targ(i) == lam->tvar(i)) mask.set(i);
25 if (mask.any()) lam2sites_[lam].emplace_back(std::move(mask)); // only lam's own body can mention lam's vars
26}
27
28fe::Bitset StaticArgOpt::statics(Lam* lam) {
29 if (auto i = lam2statics_.find(lam); i != lam2statics_.end()) return i->second;
30
31 // A *mutable* Pi is a dependent one; splitting it would require loop's doms to refer to wrap's vars.
32 auto i = lam2sites_.find(lam);
33 if (i == lam2sites_.end() || !lam->is_set() || !lam->is_closed() || lam->type()->isa_mut<Pi>())
34 return lam2statics_[lam] = fe::Bitset();
35
36 const auto& sites = i->second;
37 auto n = lam->num_tdoms();
38
39 // A static *function* arg is what SAT is after, as it exposes the loop's free var to inlining (Santos §7).
40 // So seed the split with the rightmost Pi-typed dom and keep only the sites forwarding it; ∀ if there is none.
41 auto pool = fe::Bitset();
42 for (size_t s = 0, e = sites.size(); s != e; ++s)
43 pool.set(s);
44 for (size_t d = n; d-- != 0;) {
45 if (!lam->tdom(d)->isa<Pi>()) continue;
46 auto seeded = false;
47 for (const auto& mask : sites)
48 seeded |= mask[d];
49 if (seeded)
50 for (size_t s = 0, e = sites.size(); s != e; ++s)
51 pool.set(s, sites[s][d]);
52 break;
53 }
54
55 auto res = fe::Bitset();
56 for (size_t d = 0; d != n; ++d)
57 res.set(d);
58 for (size_t s = 0, e = sites.size(); s != e; ++s)
59 if (pool[s]) res &= sites[s];
60 if (res.none()) return lam2statics_[lam] = fe::Bitset();
61
62 log().d("statics of {}: {}", lam, res);
63 return lam2statics_[lam] = res;
64}
65
67 if (!is_bootstrapping()) {
68 if (auto statics = this->statics(old_lam); statics.any()) {
69 auto& w = new_world();
70 auto n = old_lam->num_tdoms();
71 auto loop_doms = DefVec();
72 for (size_t i = 0; i != n; ++i)
73 if (!statics[i]) loop_doms.emplace_back(rewrite(old_lam->tdom(i)));
74
75 auto wrap = w.mut_lam(rewrite(old_lam->type())->as<Pi>())->set(old_lam->dbg_key());
76 auto loop = w.mut_lam(loop_doms, rewrite(old_lam->codom()))->set(old_lam->dbg_key());
77 loop->debug_suffix("_loop");
78 log().d("{} → wrap {}, loop {}", old_lam, wrap, loop);
79 old2wrap_loop_[old_lam] = {wrap, loop};
80
81 // The body lives in loop; the static vars stay wrap's and are free in loop.
82 DefVec vars(n), args;
83 for (size_t i = 0, j = 0; i != n; ++i) {
84 if (statics[i]) {
85 vars[i] = wrap->tvar(i);
86 } else {
87 vars[i] = loop->var(loop_doms.size(), j++);
88 args.emplace_back(wrap->tvar(i));
89 }
90 }
91
92 map(old_lam, wrap);
93 map(old_lam->var(), vars);
94 loop->set(rewrite(old_lam->filter()), rewrite(old_lam->body()));
95 wrap->app(false, loop, args);
96 return wrap;
97 }
98 }
99
100 return RWPhase::rewrite_mut_Lam(old_lam);
101}
102
103const Def* StaticArgOpt::rewrite_imm_App(const App* old_app) {
104 if (auto old_lam = old_app->callee()->isa_mut<Lam>(); old_lam && !is_bootstrapping()) {
105 if (auto statics = this->statics(old_lam); statics.any()) {
106 rewrite(old_lam); // make sure wrap/loop exist
107 if (auto i = old2wrap_loop_.find(old_lam); i != old2wrap_loop_.end()) {
108 auto loop = i->second.second;
109 auto n = old_lam->num_tdoms();
110 auto args = DefVec();
111 for (size_t i = 0; i != n; ++i) {
112 auto old_arg = old_app->targ(i);
113 if (!statics[i])
114 args.emplace_back(rewrite(old_arg));
115 else if (old_arg != old_lam->tvar(i))
116 return RWPhase::rewrite_imm_App(old_app); // not our class: go through wrap
117 }
118 invalidate();
119 return new_world().app(loop, args);
120 }
121 }
122 }
123
124 return RWPhase::rewrite_imm_App(old_app);
125}
126
127} // namespace mim
const Def * callee() const
Definition lam.h:275
Base class for all Defs.
Definition def.h:273
Defs deps() const noexcept
Definition def.cpp:468
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:580
DbgKey dbg_key() const
Cheap handle for other->set(this->dbg_key()).
Definition def.h:610
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:479
const Var * has_var()
Only returns not nullptr, if Var of this mutable has ever been created.
Definition def.h:483
A function.
Definition lam.h:113
const Def * filter() const
Definition lam.h:125
const Pi * type() const
Definition lam.h:133
const Def * body() const
Definition lam.h:126
const Def * codom() const
Definition lam.h:135
void invalidate(bool todo=true)
Signals that another round of fixed-point iteration is required, either as part of.
Definition phase.h:98
const fe::Log & log() const
Definition phase.h:79
const fe::Vector< std::string > & args()
Command-line arguments passed to this Phase's plugin via -X <plugin>:<arg>.
Definition phase.cpp:23
A dependent function type.
Definition lam.h:14
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
Definition phase.h:403
World & new_world()
Create new Defs into this.
Definition phase.h:452
World & old_world()
Get old Defs from here.
Definition phase.h:451
virtual const Def * map(const Def *old_def, const Def *new_def)
Definition rewrite.h:47
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:55
const Def * rewrite_mut_Lam(Lam *) final
bool analyze() final
Runs the optional pre-analysis on Phase::world, typically to a fixed point, before rewriting begins.
const Def * rewrite_imm_App(const App *) final
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:237
Definition ast.h:16
fe::Vector< const Def * > DefVec
Definition def.h:93