11Lam* isa_retvar(
const Def* def) {
12 if (
auto [var, lam] =
isa_var_proj<Lam>(def); var && lam && var == lam->ret_var())
return lam;
19 if (analyzed_)
return false;
24 auto visit = [&](
auto&& visit,
const Def* def) ->
void {
25 if (!done.emplace(def).second)
return;
28 lam2fscope_[lam] = lam;
29 log().d(
"scope: {} → {}", lam, lam);
30 auto nest =
Nest(lam);
31 for (
auto mut : nest.muts())
33 log().d(
"scope: {} → {}", bb_lam, lam);
34 lam2fscope_[bb_lam] = lam;
38 if (
auto mut = def->isa_mut()) {
40 for (
auto op : mut->deps())
43 for (
auto op : def->deps())
47 for (
auto def :
old_world().externals().muts())
53const Def* ClosConvPrep::eta_wrap(
const Def* old_op,
anno a) {
54 auto [entry, inserted] = old2wrapper_.emplace(old_op,
nullptr);
55 auto& wrapper = entry->second;
59 wrapper->app(
false,
rewrite(old_op), wrapper->
var());
64const Def* ClosConvPrep::rewrite_arg(
const App* app,
const Def* old_op,
size_t i,
size_t n) {
65 if (
auto lam = isa_retvar(old_op); lam && from_outer_scope(lam)) {
66 log().d(
"return var from an enclosing scope: {}", old_op);
70 log().d(
"BB from an enclosing scope: {}", old_op);
76 }
else if (
auto contlam = old_op->
isa_mut<Lam>()) {
80 log().d(
"eta-expand return continuation: {} → {}", old_op, wrapper);
86 log().d(
"first-class use of BB: {}", bb_lam);
91 if (isa_retvar(old_op)) {
92 log().d(
"first-class use of return var: {}", old_op);
99const Def* ClosConvPrep::rewrite_callee_op(
const Def* old_op) {
100 if (!old_op->isa_mut<Lam>()) {
101 auto wrapper = eta_wrap(old_op,
anno::bottom)->set(
"eta_br");
102 log().d(
"eta-wrap branch: {} → {}", old_op, wrapper);
113 auto body = mut && mut->is_set() ? mut->body()->isa<
App>() :
nullptr;
119 const Def* new_callee =
nullptr;
122 auto new_ops =
DefVec(sw.num_targets(), [&](
size_t i) { return rewrite_callee_op(sw.target(i)); });
123 new_callee = w.extract(w.tuple(new_ops),
rewrite(sw.index()));
130 auto arg = app->
arg();
131 if (arg->isa<
Var>()) {
134 auto new_args =
DefVec(arg->num_projs(),
135 [&, n = arg->num_projs()](
size_t i) { return rewrite_arg(app, arg->proj(n, i), i, n); });
136 new_arg = arg->
num_projs() == 1 ? new_args[0] : w.tuple(new_args);
139 return w.app(new_callee, new_arg);
const Pi * callee_type() const
const Def * callee() const
static auto isa(const Def *def)
Def * set(size_t i, const Def *)
Successively set from left to right.
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 * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
nat_t num_projs() const
Yields Def::arity(), if it is a Lit, or 1 otherwise.
static Lam * isa_mut_basicblock(const Def *d)
const fe::Log & log() const
A dependent function type.
static const Pi * isa_cn(const Def *d)
static const Pi * isa_returning(const Def *d)
World & new_world()
Create new Defs into this.
World & old_world()
Get old Defs from here.
const Def * rewrite_imm_App(const App *) override
virtual const Def * rewrite(const Def *)
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
const Def * call(const Def *callee, auto &&arg, Args &&... args)
const Def * rewrite_imm_App(const App *) final
bool analyze() final
Fills lam2fscope_: assigns each basicblock Lam to its enclosing returning Lam.
std::tuple< const Extract *, N * > isa_var_proj(const Def *def)
If def is a projection var#i of the Var of some mutable of type N, returns (projection,...
fe::Vector< const Def * > DefVec
GIDSet< const Def * > DefSet