8const Def* insert_ret(
const Def* def,
const Def* ret) {
9 auto new_ops =
DefVec(def->num_projs() + 1, [&](
auto i) { return (i == def->num_projs()) ? ret : def->proj(i); });
10 auto&
w = def->world();
11 return def->is_intro() ?
w.tuple(new_ops) :
w.sigma(new_ops);
18 if (
auto new_mut = new_def->isa_mut(); new_mut && old_mut->
is_external() && !new_mut->is_external())
19 new_mut->externalize();
23 while (!worklist_.empty()) {
24 auto [lvm, lcm, old_lam, new_lam] = worklist_.front();
28 log().d(
"enter {} (lvm = {}, lcm = {})", new_lam, lvm_, lcm_);
29 if (old_lam->is_set()) new_lam->set(
rewrite(old_lam->filter()),
rewrite(old_lam->body()));
33Lam* LowerTypedClos::make_stub(
Lam* lam, Mode mode,
bool adjust_bb_type) {
34 assert(lam &&
"make_stub: not a lam");
39 auto new_dom = w.sigma(
DefVec(lam->num_doms(), [&](
auto i) ->
const Def* {
40 auto new_dom = rewrite(lam->dom(i));
42 if (mode == Unbox) return env_type();
43 if (mode == Box) return w.call<mem::Ptr0>(new_dom);
47 if (
Lam::isa_basicblock(lam) && adjust_bb_type) new_dom = insert_ret(new_dom, dummy_ret()->type());
48 auto new_lam = w.mut_lam(w.cn(new_dom))->set(lam->
dbg_key());
49 log().d(
"stub {} → {}", lam, new_lam);
56 auto env = new_lam->num_vars() < 2 ? new_lam->var() : new_lam->var(ep);
61 if (!lcm) lcm = w.bot(w.call<
mem::M>(0));
64 env = e->set(
"closure_env");
65 }
else if (mode == Unbox) {
68 auto new_args = w.tuple(
DefVec(lam->num_doms(), [&](
auto i) {
69 return (i == ep) ? env : (lam->var(i) == mem::mem_var(lam)) ? lcm : new_lam->var(i);
71 assert(new_args->num_projs() == lam->num_doms());
72 assert(lam->num_doms() <= new_lam->num_doms());
73 map(lam->
var(), new_args);
83 if (!lvm && ep < lam->num_vars()) {
84 auto old_env = lam->
var(ep);
88 }
else if (
auto sig = old_env->type()->isa<Sigma>()) {
89 for (
size_t i = 0, e = sig->num_ops(); i != e; ++i)
91 lvm = old_env->proj(i);
97 worklist_.emplace(lvm, lcm, lam, new_lam);
104 if (
auto new_def =
lookup(def))
return new_def;
106 assert((!def->isa<
Var>() || !def->as<
Var>()->
binder()->
isa_mut<
Lam>()) &&
"Lam vars should appear in a map!");
114 auto env_type =
rewrite(ct->op(2));
115 return map(def, w.sigma({pi, env_type}));
121 assert(idx && *idx <= 2 &&
"unknown proj from closure tuple");
122 return map(def, *idx == 0 ? env_type() :
rewrite(proj->tuple())->proj(*idx - 1));
129 auto mode = (env->type()->isa<Idx>() ||
Axm::isa<mem::Ptr>(env->type())) ? Unbox : Box;
130 const Def* fn = make_stub(c.fnc_as_lam(), mode,
true);
131 if (env->type() == w.sigma()) {
132 env = w.bot(env_type());
133 }
else if (mode == Box) {
141 return map(def, w.tuple({fn, env}));
144 if (
auto lam = def->
isa_mut<
Lam>())
return make_stub(lam, No_Env,
false);
149 if (
auto var = def->isa<
Var>())
return map(def, w.var(
rewrite(var->binder())->as_mut()));
160 auto new_arg = insert_ret(
rewrite(app->
arg()), dummy_ret());
162 return new_world().app(new_callee, new_arg);
165 return RWPhase::rewrite_imm_App(app);
172 switch (def->
node()) {
192 if (new_type == w.call<
mem::M>(0)) {
195 }
else if (new_type->isa<
Sigma>()) {
196 for (
size_t i = 0, e = new_type->num_ops(); i != e; ++i)
197 if (new_type->op(i) == w.call<
mem::M>(0)) {
198 lcm_ = w.extract(new_def, i);
const Pi * callee_type() const
const Def * callee() const
static auto isa(const Def *def)
constexpr Node node() const noexcept
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
DbgKey dbg_key() const
Cheap handle for other->set(this->dbg_key()).
const Def * var(nat_t a, nat_t i) noexcept
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
bool is_external() const noexcept
static const Lam * isa_basicblock(const Def *d)
static std::optional< T > isa(const Def *def)
const fe::Log & log() const
A dependent function type.
static const Pi * isa_basicblock(const Def *d)
Is this a continuation (Pi::isa_cn) that is not Pi::isa_returning?
bool is_bootstrapping() const
Returns whether we are currently bootstrapping (rewriting annexes).
virtual const Def * rewrite_root(const Def *def)
Rewrites a root - i.e. an annex or an external.
World & new_world()
Create new Defs into this.
World & old_world()
Get old Defs from here.
virtual const Def * rewrite_mut(Def *)
virtual const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite_imm(const Def *)
virtual const Def * rewrite(const Def *)
virtual const Def * lookup(const Def *old_def)
Lookup old_def by searching in reverse through the stack of maps.
A variable introduced by a binder (mutable).
Def * binder() const
The binder of this Var.
const Def * rewrite(const Def *def) final
void finalize() final
Run after all roots have been walked - but for an RWPhase still before the two worlds are swapped.
void rewrite_external(Def *) final
const Def * rewrite_imm(const Def *def) final
const Def * rewrite_imm_App(const App *) final
ClosLit isa_clos_lit(const Def *def, bool fn_isa_lam=true)
Tries to match a closure literal.
const Sigma * isa_clos_type(const Def *def)
size_t env_param(Defs doms)
Describes where the environment is placed in the argument list: right after a leading mem....
const Def * mem_var(Lam *lam)
Returns the memory argument of a function if it has one.
const Def * op_alloc(const Def *type, const Def *as, const Def *mem)
fe::View< const Def * > Defs
fe::Vector< const Def * > DefVec