9std::array<const Def*, 3> split(
const Def* def) {
10 auto new_ops =
DefVec(def->num_projs() - 2,
nullptr);
11 auto&
w = def->world();
14 for (
size_t i = 0; i < def->num_projs(); i++) {
24 auto remaining = def->is_intro() ?
w.tuple(new_ops) :
w.sigma(new_ops);
25 if (new_ops.size() == 1 && remaining != new_ops[0]) {
27 remaining = new_ops[0];
29 return {mem, env, remaining};
32const Def* rebuild(
const Def* mem,
const Def* env,
Defs remaining) {
33 auto&
w = mem->world();
34 auto new_ops =
DefVec(remaining.size() + 2, [&](
auto i) ->
const Def* {
35 static_assert(Clos_Env_Param == 1);
36 if (i == 0) return mem;
37 if (i == 1) return env;
38 return remaining[i - 2];
40 return w.tuple(new_ops);
45void Clos2SJLJ::get_exn_closures(
const Def* def,
DefSet& visited) {
46 if (!def->is_term() || def->isa_mut<
Lam>() || visited.contains(def))
return;
49 auto lam =
c.fnc_as_lam();
50 if (
c.is_basicblock() && !ignore_.contains(lam)) {
51 def->world().DLOG(
"FOUND exn closure: {}",
c.fnc_as_lam());
52 lam2tag_[
c.fnc_as_lam()] = {lam2tag_.size() + 1,
c.env()};
54 get_exn_closures(
c.env(), visited);
56 for (
auto op : def->ops()) get_exn_closures(op, visited);
60void Clos2SJLJ::get_exn_closures() {
66 auto p2 = p->tuple()->isa<
Extract>();
67 if (p2 && p2->tuple()->isa<
Tuple>()) {
70 auto branches = p2->tuple()->ops();
71 for (
auto b : branches) {
74 ignore_.emplace(
c.fnc_as_lam());
75 world().DLOG(
"IGNORE {}",
c.fnc_as_lam());
81 get_exn_closures(app->arg(), visited);
84Lam* Clos2SJLJ::get_throw(
const Def* dom) {
86 auto [p, inserted] = dom2throw_.emplace(dom,
nullptr);
87 auto& tlam = p->second;
88 if (inserted || !tlam) {
89 tlam =
w.mut_con(
clos_sub_env(dom,
w.sigma({jb_type(), rb_type(), tag_type()})))->set(
"throw");
90 auto [m0, env, var] = split(tlam->var());
91 auto [jbuf, rbuf, tag] = env->projs<3>();
97 ignore_.emplace(tlam);
102Lam* Clos2SJLJ::get_lpad(
Lam* lam,
const Def* rb) {
104 auto [p, inserted] = lam2lpad_.emplace(
w.tuple({lam, rb}),
nullptr);
105 auto& lpad = p->second;
106 if (inserted || !lpad) {
107 auto [_, env_type, dom] = split(lam->dom());
109 auto [
m, env, __] = split(lpad->var());
112 auto [m2, args] =
w.call<
mem::load>(
Defs{m1, arg_ptr})->projs<2>();
113 auto full_args = (lam->num_doms() == 3) ? rebuild(m2, env, {args}) : rebuild(m2, env, args->ops());
114 lpad->app(
false, lam, full_args);
115 ignore_.emplace(lpad);
123 if (lam2tag_.empty())
return;
143 auto branches =
DefVec(lam2tag_.size() + 1);
145 auto env = w.tuple(body->args().view().subspan(1));
147 auto [m, env_var, _] = split(new_callee->var());
148 auto new_args =
DefVec(env->num_projs() + 1, [&](
size_t i) { return (i == 0) ? m : env_var->proj(i - 1); });
149 new_callee->app(
false, body->callee(), new_args);
150 branches[0] =
clos_pack(env, new_callee, branch_type);
153 for (
auto [exn_lam, p] : lam2tag_) {
155 branches[i] =
clos_pack(env, get_lpad(exn_lam, cur_rbuf_), branch_type);
158 auto m0 = body->arg(0);
159 assert(m0->type() == w.annex<
mem::M>());
160 auto [m1, tag] = w.call<
setjmp>(
Defs{m0, cur_jbuf_})->projs<2>();
163 auto branch = w.extract(w.tuple(branches), tag);
168 if (
auto c =
isa_clos_lit(def); c && lam2tag_.contains(c.fnc_as_lam())) {
170 auto [i, _] = lam2tag_[c.fnc_as_lam()];
171 auto tlam = get_throw(c.fnc_as_lam()->dom());
172 return clos_pack(w.tuple({cur_jbuf_, cur_rbuf_, w.lit_idx(i)}), tlam, c.type());
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
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).
Def * reset(size_t i, const Def *def)
Successively reset from left to right.
const Def * filter() const
static const Lam * isa_cn(const Def *d)
Lam * set(Filter filter, const Def *body)
const Def * call(Id id, Args &&... args)
Complete curried call of annexes obeying implicits.
const Def * rewrite(const Def *) override
void enter() override
Invoked just before Pass::rewriteing PassMan::curr_mut's body.
ClosLit isa_clos_lit(const Def *def, bool fn_isa_lam=true)
Tries to match a closure literal.
Sigma * clos_type(const Pi *pi)
Creates a typed closure type from pi.
static constexpr size_t Clos_Env_Param
Describes where the environment is placed in the argument list.
const Def * clos_sub_env(const Def *tup_or_sig, const Def *new_env)
const Def * clos_pack(const Def *env, const Def *fn, const Def *ct=nullptr)
Pack a typed closure. This assumes that fn expects the environment as its Clos_Env_Paramth argument.
const Def * clos_apply(const Def *closure, const Def *args)
Apply a closure to arguments.
const Sigma * isa_clos_type(const Def *def)
const Def * op(trait o, const Def *type)
const Def * op_slot(const Def *type, const Def *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 *mem)
Lam * mut_con(World &w)
Yields con[mem.M].
Vector< const Def * > DefVec
GIDSet< const Def * > DefSet