8const Def* insert_ret(
const Def* def,
const Def* ret) {
9 auto n = def->num_projs();
10 auto new_ops =
DefVec(n + 1, [&](
auto i) {
return (i == n) ? ret : def->proj(n, i); });
11 auto&
w = def->world();
12 return def->is_intro() ?
w.tuple(new_ops) :
w.sigma(new_ops);
17 while (!worklist_.empty()) {
18 auto [lvm, lcm, old_lam, new_lam] = worklist_.front();
22 log().d(
"enter {} (lvm = {}, lcm = {})", new_lam, lvm_, lcm_);
23 if (old_lam->is_set()) new_lam->set(
rewrite(old_lam->filter()),
rewrite(old_lam->body()));
27Lam* LowerTypedClos::make_stub(
Lam* lam, Mode mode,
bool adjust_bb_type) {
28 assert(lam &&
"make_stub: not a lam");
35 assert(!telescope || mode == No_Env);
36 auto new_dom = telescope ?
rewrite(lam->
dom()) : w.sigma(
DefVec(nd, [&](auto i) -> const
Def* {
39 if (mode == Unbox)
return env_type();
40 if (mode == Box)
return w.call<
mem::Ptr0>(new_dom);
44 if (
Lam::isa_basicblock(lam) && adjust_bb_type) new_dom = insert_ret(new_dom, dummy_ret()->type());
45 auto new_lam = w.mut_lam(w.cn(new_dom))->set(lam->
dbg_key());
46 log().d(
"stub {} → {}", lam, new_lam);
53 auto nv = new_lam->num_vars();
54 auto env = nv < 2 ? new_lam->var() : new_lam->var(nv, ep);
59 if (!lcm) lcm = w.bot(w.call<
mem::M>(0));
62 env = e->set(
"closure_env");
63 }
else if (mode == Unbox) {
67 auto new_args =
w.tuple(
DefVec(nd, [&](
auto i) {
68 return (i == ep) ? env : (lam->
var(nvo, i) ==
mem::mem_var(lam)) ? lcm : new_lam->var(nv, i);
70 assert(new_args->num_projs() == lam->
num_doms());
71 assert(lam->
num_doms() <= new_lam->num_doms());
82 if (!lvm && ep < lam->num_vars()) {
87 }
else if (
auto sig = old_env->type()->isa<Sigma>()) {
88 for (
size_t i = 0, e = sig->num_ops(); i != e; ++i)
90 lvm = old_env->proj(e, i);
91 lcm = env->proj(e, i);
96 worklist_.emplace(lvm, lcm, lam, new_lam);
102 if (
auto new_def =
lookup(def))
return new_def;
104 assert((!def->isa<
Var>() || !def->as<
Var>()->
binder()->
isa_mut<
Lam>()) &&
"Lam vars should appear in a map!");
112 auto env_type =
rewrite(ct->op(2));
113 return map(def, w.sigma({pi, env_type}));
119 assert(idx && *idx <= 2 &&
"unknown proj from closure tuple");
120 return map(def, *idx == 0 ? env_type() :
rewrite(proj->tuple())->proj(2, *idx - 1));
127 auto mode = (env->type()->isa<Idx>() ||
Axm::isa<mem::Ptr>(env->type())) ? Unbox : Box;
128 const Def* fn = make_stub(c.fnc_as_lam(), mode,
true);
129 if (env->type() == w.sigma()) {
130 env = w.bot(env_type());
131 }
else if (mode == Box) {
139 return map(def, w.tuple({fn, env}));
142 if (
auto lam = def->
isa_mut<
Lam>())
return make_stub(lam, No_Env,
false);
147 if (
auto var = def->isa<
Var>())
return map(def, w.var(
rewrite(var->binder())->as_mut()));
156 auto new_arg = insert_ret(
rewrite(app->
arg()), dummy_ret());
166 switch (def->
node()) {
186 if (new_type == w.call<
mem::M>(0)) {
189 }
else if (new_type->isa<
Sigma>()) {
190 for (
size_t i = 0, e = new_type->num_ops(); i != e; ++i)
191 if (new_type->op(i) == w.call<
mem::M>(0)) {
192 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
nat_t num_vars() noexcept
auto projs(Projector auto 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)
nat_t num_doms() const noexcept
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)
World & new_world()
Create new Defs into this.
const Def * lookup(const Def *) override
Lookup old_def by searching in reverse through the stack of maps.
World & old_world()
Get old Defs from here.
const Def * rewrite_imm_App(const App *) override
virtual const Def * rewrite_mut(Def *)
const Def * map(const Def *old_def, const Def *new_def)
virtual const Def * rewrite_imm(const Def *)
virtual const Def * rewrite(const Def *)
A variable introduced by a binder (mutable).
Def * binder() const
The binder of this Var.
const Def * app(const Def *callee, const Def *arg)
const Def * extract(const Def *d, const Def *i)
const Def * rewrite(const Def *def) final
void finalize() final
Run after all roots have been walked but still before the two worlds are swapped.
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.
bool is_telescope_cn(const Def *def)
Inserting the environment would shift the indices a telescope's Var refers to, so ClosConv leaves suc...
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