MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
The clos Plugin

See also
mim::plug::clos

This plugin performs typed closure conversion: it turns functions that capture free variables into self-contained closures - a pair of a code pointer and an environment holding the captured values - so that every function becomes closed and can be lifted to the top level. Later it lowers these typed closures to untyped (code-ptr, env-ptr) pairs and turns exception-like basic blocks into setjmp/longjmp. The transformation is a pipeline of Phases (see below); the C++ implementation lives in mim::plug::clos.

Dependencies

plugin core;
plugin mem;
import compile;

Operations

mim::plug::clos::phase::Clos2SJLJ lowers exception-like basic-block closures to these operations.

BufPtr

An opaque pointer to a C jmp_buf; its size in bytes is provided by the runtime.

anx let BufPtr = mem.Ptr0 I8;

alloc_jmpbuf

Allocates a fresh jmp_buf and yields a pointer to it.

axm alloc_jmpbuf: mem.M 0 → [mem.M 0, BufPtr];

setjmp

Saves the current execution context into the jmp_buf (like C setjmp). Yields 0 on the initial call and the non-zero tag passed to clos.longjmp when jumped to.

axm setjmp: [mem.M 0, BufPtr] → [mem.M 0, I32];

longjmp

Restores the context saved in the jmp_buf, resuming right after the corresponding clos.setjmp and making it yield the given tag (like C longjmp).

axm longjmp: Cn [mem.M 0, BufPtr, I32];

Closure Attribute

attr

A marker wrapped around a Lam (or a use of it) that classifies how it is used. mim::plug::clos::phase::ClosConvPrep introduces these so that mim::plug::clos::phase::ClosConv sees a canonical program and can treat each kind of continuation appropriately:

  • returning: a returning continuation ("function"); fully closure converted.
  • free_bb: an ordinary basic block referenced from an enclosing scope (see mim::Lam::isa_basicblock).
  • fstclass_bb: a basic block used as a first-class value (passed around) rather than only called.
  • esc: a closure whose environment escapes its parent scope, so it is heap- instead of stack-allocated (introduced by mim::plug::clos::phase::LowerTypedClosPrep).
  • bottom: no special use; this is the identity marker and is normalized away by normalize_clos.
axm attr.(returning, free_bb, fstclass_bb, esc, bottom): {T: *} → T → T, normalize_clos;

Phases

The opt pipeline runs these in the order below, reusing clos.branch_clos as a repeated cleanup after the passes that introduce branch closures.

clos_conv_prep

Prepares for closure conversion by wrapping operands with the clos.attr markers above and eta-expanding branches and continuations (mim::plug::clos::phase::ClosConvPrep).

axm clos_conv_prep: compile.Phase;

clos_conv

The actual typed closure conversion (mim::plug::clos::phase::ClosConv).

axm clos_conv: compile.Phase;

branch_clos

Flattens a branch over closure literals back into a direct branch over the underlying Lams, inlining their environments (mim::plug::clos::phase::BranchClosElim).

axm branch_clos: compile.Phase;

lower_typed_clos_prep

Escape analysis; marks closures whose environment escapes with clos.attr.esc (mim::plug::clos::phase::LowerTypedClosPrep).

axm lower_typed_clos_prep: compile.Phase;

clos2sjlj

Lowers exception-like basic-block closures to setjmp/longjmp (mim::plug::clos::phase::Clos2SJLJ).

axm clos2sjlj: compile.Phase;

lower_typed_clos

Lowers typed closures to untyped (code-ptr, env-ptr) pairs, boxing or unboxing the environment (mim::plug::clos::phase::LowerTypedClos).

axm lower_typed_clos: compile.Phase;