11bool isa_cnt(
const App* body,
const Def* def,
size_t i) {
12 return Pi::isa_returning(body->callee_type()) && body->arg() == def && i == def->num_ops() - 1;
15const Def* isa_br(
const App* body,
const Def* def) {
16 if (!
Pi::isa_cn(body->callee_type()))
return nullptr;
17 auto proj = body->callee()->isa<
Extract>();
18 return (proj && proj->tuple() == def && proj->tuple()->isa<
Tuple>()) ? proj->tuple() :
nullptr;
21bool isa_callee_br(
const App* body,
const Def* def,
size_t i) {
22 if (!
Pi::isa_cn(body->callee_type()))
return false;
23 return isa_callee(def, i) || isa_br(body, def);
26Lam* isa_retvar(
const Def* def) {
27 if (
auto [var, lam] =
isa_var_proj<Lam>(def); var && lam && var == lam->ret_var())
return lam;
34 if (analyzed_)
return false;
39 auto visit = [&](
auto&& visit,
const Def* def) ->
void {
40 if (!done.emplace(def).second)
return;
43 lam2fscope_[lam] = lam;
44 DLOG(
"scope {} -> {}", lam, lam);
45 auto nest =
Nest(lam);
46 for (
auto mut : nest.muts())
48 DLOG(
"scope {} -> {}", bb_lam, lam);
49 lam2fscope_[bb_lam] = lam;
53 if (
auto mut = def->isa_mut()) {
55 for (
auto op : mut->deps())
58 for (
auto op : def->deps())
68const Def* ClosConvPrep::eta_wrap(
const Def* old_op,
attr a) {
69 auto [entry, inserted] = old2wrapper_.emplace(old_op,
nullptr);
70 auto& wrapper = entry->second;
74 wrapper->app(
false,
rewrite(old_op), wrapper->
var());
79const Def* ClosConvPrep::rewrite_arg(
const App* app,
const Def* old_op) {
80 auto arg = app->
arg();
82 for (; i < arg->num_projs(); i++)
83 if (arg->proj(i) == old_op)
break;
85 if (
auto lam = isa_retvar(old_op); lam && from_outer_scope(lam)) {
86 DLOG(
"found return var from enclosing scope: {}", old_op);
90 DLOG(
"found BB from enclosing scope {}", old_op);
93 if (isa_cnt(app, arg, i)) {
96 }
else if (
auto contlam = old_op->
isa_mut<
Lam>()) {
100 DLOG(
"eta expanded return cont: {} -> {}", old_op, wrapper);
105 if (!isa_callee_br(app, arg, i)) {
107 DLOG(
"found firstclass use of BB: {}", bb_lam);
112 if (isa_retvar(old_op)) {
113 DLOG(
"found firstclass use of return var: {}", old_op);
121const Def* ClosConvPrep::rewrite_callee_op(
const Def* old_op) {
122 if (!old_op->isa_mut<
Lam>()) {
123 auto wrapper = eta_wrap(old_op,
attr::bottom)->set(
"eta_br");
124 DLOG(
"eta wrap branch: {} -> {}", old_op, wrapper);
135 auto body = mut && mut->is_set() ? mut->body()->isa<
App>() :
nullptr;
136 if (!body || !
Pi::isa_cn(body->callee_type()))
return RWPhase::rewrite_imm_App(app);
141 const Def* new_callee =
nullptr;
144 auto branches = br->tuple();
145 if (branches->isa<
Tuple>() && branches->
type()->isa<
Arr>()) {
147 =
DefVec(branches->num_ops(), [&](
size_t i) { return rewrite_callee_op(branches->op(i)); });
148 new_callee = w.extract(w.tuple(new_ops),
rewrite(br->index()));
156 auto arg = app->
arg();
157 if (arg->isa<
Var>()) {
160 auto new_args =
DefVec(arg->num_projs(), [&](
size_t i) { return rewrite_arg(app, arg->proj(i)); });
161 new_arg = arg->
num_projs() == 1 ? new_args[0] : w.tuple(new_args);
164 return w.app(new_callee, new_arg);
const Pi * callee_type() const
const Def * callee() const
A (possibly paramterized) Array.
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)
Only for mutables.
Builds a nesting tree for all mutables/binders.
A dependent function type.
static const Pi * isa_cn(const Def *d)
Is this a continuation - i.e. is the Pi::codom mim::Bottom?
static const Pi * isa_returning(const Def *d)
Is this a continuation (Pi::isa_cn) which has a Pi::ret_pi?
World & new_world()
Create new Defs into this.
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
World & old_world()
Get old Defs from here.
virtual const Def * rewrite(const Def *)
Data constructor for a Sigma.
A variable introduced by a binder (mutable).
const Def * call(const Def *callee, T &&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.
#define DLOG(...)
Vaporizes to nothingness in Debug build.
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,...
Vector< const Def * > DefVec
GIDSet< const Def * > DefSet
const App * isa_callee(const Def *def, size_t i)