MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
tail_rec_elim.cpp
Go to the documentation of this file.
2
3#include "mim/nest.h"
4
5namespace mim {
6
7bool TailRecElim::is_tail_rec(Lam* lam) {
8 if (auto i = tail_rec_.find(lam); i != tail_rec_.end()) return i->second;
9
10 auto ret_var = lam->ret_var();
11 if (!ret_var || !lam->is_set() || !lam->is_closed()) return tail_rec_[lam] = false;
12
13 // Scan the (immutable) op graphs of all muts in lam's nest for a call `lam (..., lam's ret var)`.
14 auto nest = Nest(lam);
15 DefSet done;
16 auto found = false;
17 auto visit = [&](auto&& visit, const Def* def) -> void {
18 if (found || def->isa_mut() || !done.emplace(def).second) return;
19 if (auto app = def->isa<App>(); app && app->callee() == lam && app->args().back() == ret_var) {
20 found = true;
21 return;
22 }
23 for (auto op : def->deps())
24 visit(visit, op);
25 };
26 for (auto mut : nest.muts())
27 if (mut->is_set())
28 for (auto op : mut->deps())
29 visit(visit, op);
30
31 return tail_rec_[lam] = found;
32}
33
35 if (!is_bootstrapping() && is_tail_rec(old)) {
36 auto& w = new_world();
37 auto rec = w.mut_lam(rewrite(old->type())->as<Pi>())->set(old->dbg());
38 auto n = rec->num_doms();
39 auto loop = rec->stub(w.cn(rec->doms().view().rsubspan(1)));
40 DLOG("old {} -> (rec: {}, loop: {})", old, rec, loop);
41 old2rec_loop_[old] = {rec, loop};
42 map(old, rec);
43
44 // The body lives in loop; its vars replace old's vars - except the ret var, which stays rec's.
45 DefVec loop_args(n - 1), loop_vars(n);
46 for (size_t i = 0; i != n - 1; ++i) {
47 loop_args[i] = rec->var(n, i);
48 loop_vars[i] = loop->var(n - 1, i);
49 }
50 loop_vars.back() = rec->var(n, n - 1);
51 map(old->var(), w.tuple(loop_vars));
52
53 loop->set(rewrite(old->filter()), rewrite(old->body()));
54 rec->app(false, loop, loop_args);
55 return rec;
56 }
57
58 return RWPhase::rewrite_mut_Lam(old);
59}
60
62 if (auto old = app->callee()->isa_mut<Lam>(); old && !is_bootstrapping() && is_tail_rec(old)) {
63 rewrite(old); // make sure rec/loop exist
64 auto [rec, loop] = old2rec_loop_[old];
65 auto new_args = DefVec(app->args().size(), [&](size_t i) { return rewrite(app->arg(app->num_args(), i)); });
66 if (new_args.back() == rec->vars().back()) return new_world().app(loop, new_args.view().rsubspan(1));
67 return new_world().app(rec, new_args);
68 }
69
70 return RWPhase::rewrite_imm_App(app);
71}
72
73} // namespace mim
const Def * callee() const
Definition lam.h:276
Base class for all Defs.
Definition def.h:261
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
Definition def.h:527
const Def * var(nat_t a, nat_t i) noexcept
Definition def.h:441
Dbg dbg() const
Definition def.h:556
A function.
Definition lam.h:110
const Def * filter() const
Definition lam.h:122
const Pi * type() const
Definition lam.h:130
const Def * body() const
Definition lam.h:123
A dependent function type.
Definition lam.h:14
World & new_world()
Create new Defs into this.
Definition phase.h:368
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
Definition phase.h:356
virtual const Def * map(const Def *old_def, const Def *new_def)
Definition rewrite.h:45
virtual const Def * rewrite(const Def *)
Definition rewrite.cpp:56
const Def * rewrite_mut_Lam(Lam *) final
const Def * rewrite_imm_App(const App *) final
const Def * app(const Def *callee, const Def *arg)
Definition world.cpp:205
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Definition log.h:94
Definition ast.h:14
Vector< const Def * > DefVec
Definition def.h:79
GIDSet< const Def * > DefSet
Definition def.h:76
@ App
Definition def.h:109