7bool TailRecElim::is_tail_rec(
Lam* lam) {
8 if (
auto i = tail_rec_.find(lam); i != tail_rec_.end())
return i->second;
10 auto ret_var = lam->ret_var();
11 if (!ret_var || !lam->is_set() || !lam->is_closed())
return tail_rec_[lam] =
false;
14 auto nest = Nest(lam);
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) {
23 for (
auto op : def->deps())
26 for (
auto mut : nest.muts())
28 for (
auto op : mut->deps())
31 return tail_rec_[lam] = found;
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};
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);
50 loop_vars.back() = rec->var(n, n - 1);
51 map(old->
var(), w.tuple(loop_vars));
54 rec->app(
false, loop, loop_args);
58 return RWPhase::rewrite_mut_Lam(old);
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));
70 return RWPhase::rewrite_imm_App(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 * var(nat_t a, nat_t i) noexcept
const Def * filter() const
A dependent function type.
World & new_world()
Create new Defs into this.
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
virtual const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite(const Def *)
const Def * rewrite_mut_Lam(Lam *) final
const Def * rewrite_imm_App(const App *) final
const Def * app(const Def *callee, const Def *arg)
#define DLOG(...)
Vaporizes to nothingness in Debug build.
Vector< const Def * > DefVec
GIDSet< const Def * > DefSet