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;

Operations

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

%clos.BufPtr

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

let %clos.BufPtr = %mem.Ptr0 I8;

%clos.alloc_jmpbuf

Allocates a fresh jmp_buf and yields a pointer to it.

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

%clos.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 %clos.setjmp: [%mem.M 0, %clos.BufPtr] → [%mem.M 0, I32];

%clos.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 %clos.longjmp: Cn [%mem.M 0, %clos.BufPtr, I32];

Closure Attribute

%clos.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 %clos.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.

axm %clos.clos_conv_prep: %compile.Phase;
axm %clos.clos_conv: %compile.Phase;
axm %clos.branch_clos: %compile.Phase;
axm %clos.lower_typed_clos_prep: %compile.Phase;
axm %clos.clos2sjlj: %compile.Phase;
axm %clos.lower_typed_clos: %compile.Phase;