Skip to content

Aiur inlined function calls (@fn(args)) + blake3 G-function cleanup#500

Open
arthurpaulino wants to merge 2 commits into
mainfrom
ap/aiur-inline-calls
Open

Aiur inlined function calls (@fn(args)) + blake3 G-function cleanup#500
arthurpaulino wants to merge 2 commits into
mainfrom
ap/aiur-inline-calls

Conversation

@arthurpaulino

Copy link
Copy Markdown
Member

Commits

  1. Aiur: inlined function calls (@fn(args))

    Replaces Source.Term.app's unconstrained : Bool with a CallMode
    (normal | unconstrained | inlined). @fn(args) marks an inlined call:
    Toplevel.inlineCalls, run first in compile, splices the callee's body
    into the caller — each input Local bound to its argument via a let, the
    (recursively inline-expanded) body as the value. Inlining is forbidden for
    callees that are transitively inline-recursive.

    An inlined call compiles to no separate circuit and no call interface
    (no lookup, no output columns): the callee's work joins the caller's
    straight-line circuit. This lets a hot inner routine be written once and
    expanded into a single wide circuit, instead of paying the per-call
    state-rematerialization and the taller callee-circuit height.

    The mode only exists in the Source stage — inlineCalls eliminates
    .inlined before typechecking. Interpreters match the mode as _ (an
    inlined call executes identically to a normal one), so evaluation is
    unchanged. Callee params and body are alpha-renamed to fresh inl#N
    locals before argument binding, so nested @-calls cannot capture caller
    bindings.

  2. Aiur blake3: extract G-function word-ops into @-inlined helpers

    blake3_g_function was ~100 lines of inlined byte arithmetic: six
    little-endian carry chains, the add/xor/rotate quarter-round steps spelled
    out per byte. Rewritten as its eight-step dataflow over @-inlined word
    ops: ByteStream's existing u32_add / u32_xor, plus four
    right-rotations u32_rotr16/u32_rotr8 (byte moves) and
    u32_rotr12/u32_rotr7 (byte move + chained gadget), added to ByteStream
    next to the other unsigned-int ops. Still one circuit, byte-identical
    work. Includes the regenerated Aiur kernel.

Verification

  • All 56 pinned kernel-check FFT costs unchanged — full
    lake test -- --ignored ixvm run green (codegen/bytecode parity suite
    included). The refactor is cost-neutral by construction; the pins prove it.

Replace `Source.Term.app`'s `unconstrained : Bool` with a `CallMode`
(normal | unconstrained | inlined). `@fn(args)` marks an inlined call:
`Toplevel.inlineCalls`, run first in `compile`, splices the callee's
body into the caller — each input Local bound to its argument via a
let, the (recursively inline-expanded) body as the value. Inlining is
forbidden for callees that are transitively inline-recursive.

An inlined call compiles to no separate circuit and no call interface
(no lookup, no output columns): the callee's work joins the caller's
straight-line circuit. This lets a hot inner routine be written once
and expanded into a single wide circuit, instead of paying the
per-call state-rematerialization and the taller callee-circuit height.

The mode only exists in the Source stage — `inlineCalls` eliminates
`.inlined` before typechecking, and Check maps normal->false /
unconstrained->true into the existing downstream bool. Interpreters
match the mode as `_` (an inlined call executes identically to a
normal one), so evaluation is unchanged.

The pass expands bottom-up over the inline-call DAG (Kahn topo order),
so it is fuel-free and total. At each inline site the callee's inputs
and body are alpha-renamed to fresh `inl#N` locals before argument
binding, so nested `@`-calls cannot capture caller bindings; spliced
let-chains are hoisted out of strict argument positions (array
elements, operator operands, app arguments), which lowering would
otherwise reject. Also drops a `simp` arg in `compile_stages_of_ok`
that the final pipeline shape no longer needs.
blake3_g_function was ~100 lines of inlined byte arithmetic: six
little-endian carry chains, the add/xor/rotate quarter-round steps
spelled out per byte. Rewrite it as its eight-step dataflow over
`@`-inlined word ops: ByteStream's existing u32_add / u32_xor, plus
the four right-rotations u32_rotr16/u32_rotr8 (byte moves) and
u32_rotr12/u32_rotr7 (byte move + chained gadget), added to
ByteStream next to the other unsigned-int ops. Still one circuit,
byte-identical work.

Includes the regenerated Aiur kernel (`lake exe ix codegen`). All 56
kernel-check FFT costs unchanged (full `lake test -- --ignored ixvm`
run green).
@arthurpaulino
arthurpaulino force-pushed the ap/aiur-inline-calls branch from 9a10452 to b450039 Compare July 17, 2026 23:58
@arthurpaulino
arthurpaulino enabled auto-merge (squash) July 17, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant