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);
17 for (
const auto& [flags, e] :
old_world().annexes())
23 for (
auto old_mut :
old_world().externals().muts()) {
24 auto new_def =
rewrite(old_mut);
26 if (
auto new_mut = new_def->isa_mut(); new_mut && old_mut->is_external() && !new_mut->is_external())
27 new_mut->externalize();
30 while (!worklist_.empty()) {
31 auto [lvm, lcm, old_lam, new_lam] = worklist_.front();
35 DLOG(
"in {} (lvm={}, lcm={})", new_lam, lvm_, lcm_);
36 if (old_lam->is_set()) new_lam->set(
rewrite(old_lam->filter()),
rewrite(old_lam->body()));
42Lam* LowerTypedClos::make_stub(
Lam* lam, Mode mode,
bool adjust_bb_type) {
43 assert(lam &&
"make_stub: not a lam");
48 auto new_dom = w.sigma(
DefVec(lam->num_doms(), [&](
auto i) ->
const Def* {
49 auto new_dom = rewrite(lam->dom(i));
51 if (mode == Unbox) return env_type();
52 if (mode == Box) return w.call<mem::Ptr0>(new_dom);
56 if (
Lam::isa_basicblock(lam) && adjust_bb_type) new_dom = insert_ret(new_dom, dummy_ret_->type());
57 auto new_lam = w.mut_lam(w.cn(new_dom))->set(lam->
dbg());
58 DLOG(
"stub {} ~> {}", lam, new_lam);
65 auto env = new_lam->num_vars() < 2 ? new_lam->var() : new_lam->var(ep);
70 if (!lcm) lcm = w.bot(w.call<
mem::M>(0));
73 env = e->set(
"closure_env");
74 }
else if (mode == Unbox) {
77 auto new_args = w.tuple(
DefVec(lam->num_doms(), [&](
auto i) {
78 return (i == ep) ? env : (lam->var(i) == mem::mem_var(lam)) ? lcm : new_lam->var(i);
80 assert(new_args->num_projs() == lam->num_doms());
81 assert(lam->num_doms() <= new_lam->num_doms());
82 map(lam->
var(), new_args);
90 auto old_env = lam->
var(ep);
94 }
else if (
auto sig = old_env->type()->isa<
Sigma>()) {
95 for (
size_t i = 0, e = sig->num_ops(); i != e; ++i)
97 lvm = old_env->proj(i);
103 worklist_.emplace(lvm, lcm, lam, new_lam);
110 if (
auto new_def =
lookup(def))
return new_def;
112 assert((!def->isa<
Var>() || !def->as<
Var>()->
binder()->
isa_mut<
Lam>()) &&
"Lam vars should appear in a map!");
120 auto env_type =
rewrite(ct->op(2));
121 return map(def, w.sigma({pi, env_type}));
127 assert(idx && *idx <= 2 &&
"unknown proj from closure tuple");
128 return map(def, *idx == 0 ? env_type() :
rewrite(proj->tuple())->proj(*idx - 1));
135 auto mode = (env->type()->isa<Idx>() ||
Axm::isa<mem::Ptr>(env->type())) ? Unbox : Box;
136 const Def* fn = make_stub(c.fnc_as_lam(), mode,
true);
137 if (env->type() == w.sigma()) {
138 env = w.bot(env_type());
139 }
else if (mode == Box) {
147 return map(def, w.tuple({fn, env}));
150 if (
auto lam = def->
isa_mut<
Lam>())
return make_stub(lam, No_Env,
false);
155 if (
auto var = def->isa<
Var>())
return map(def, w.var(
rewrite(var->binder())->as_mut()));
158 switch (def->
node()) {
170 auto new_ops =
DefVec(def->
num_ops(), [&](
auto i) { return rewrite(def->op(i)); });
171 if (
auto app = def->isa<
App>())
172 if (
auto p = app->callee()->isa<
Extract>();
174 new_ops[1] = insert_ret(new_ops[1], dummy_ret_);
175 auto new_def = def->
rebuild(w, new_type, new_ops);
180 for (
size_t i = 0, e = new_def->num_ops(); i != e; ++i)
181 if (def->
op(i) == lvm_ && new_def->
op(i)->
type() == w.call<
mem::M>(0)) new_def = new_def->
refine(i, lcm_);
183 if (new_type == w.call<
mem::M>(0)) {
186 }
else if (new_type->isa<
Sigma>()) {
187 for (
size_t i = 0, e = new_type->num_ops(); i != e; ++i)
188 if (new_type->op(i) == w.call<
mem::M>(0)) {
189 lcm_ = w.extract(new_def, i);
195 return map(def, new_def);
static auto isa(const Def *def)
constexpr Node node() const noexcept
const Def * refine(size_t i, const Def *new_op) const
T * isa_mut() const
If this is mutable, it will cast constness away and perform a dynamic_cast to T.
const Def * op(size_t i) const noexcept
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
const Def * rebuild(World &w, const Def *type, Defs ops) const
Def::rebuilds this Def while using new_op as substitute for its i'th Def::op.
constexpr size_t num_ops() const noexcept
static const Lam * isa_basicblock(const Def *d)
static std::optional< T > isa(const Def *def)
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?
World & new_world()
Create new Defs into this.
virtual void rewrite_annex(flags_t, Sym, const Def *)
World & old_world()
Get old Defs from here.
friend void swap(Rewriter &rw1, Rewriter &rw2) noexcept
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 * bot(const Def *type)
const Def * rewrite(const Def *def) final
void start() override
Actual entry.
#define DLOG(...)
Vaporizes to nothingness in Debug build.
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)
Vector< const Def * > DefVec
auto lookup(const C &container, const K &key)
Yields pointer to element (or the element itself if it is already a pointer), if found and nullptr ot...