fibers B1.0c: support params in abi(.pure) (read from registers)

Adversarial review of B1.0b found a param-bearing abi(.pure) function
emitted invalid LLVM ("cannot use argument of naked function" — loud
verifier error, not silent) because the param-alloca loop spilled the
args to stack slots, which a naked function cannot have.

Fixed forward — this ENABLES the B1.3 context-switch use case rather
than rejecting it: gate the param-alloca loop on fd.abi != .pure in
decl.zig (both body-lowering paths) and generic.zig. A naked function's
args stay in their ABI registers and are read directly by the asm body
(e.g. swap_context reads from/to from x0/x1); the LLVM args are
declared-but-unused, which the verifier allows.

examples/1803-concurrency-pure-asm-param.sx: naked add(a, b) reads x0/x1
(add x0, x0, x1; ret) -> 40 + 2 = 42. aarch64-pinned.

Pack abi(.pure) (variadic + naked — nonsensical, can't read a runtime
pack from registers) left unsupported: pack.zig's param loop is
intertwined with comptime-param/#insert handling, so that case still
hits the loud verifier error. Documented in the checkpoint.

Also updates PLAN-FIBERS / CHECKPOINT-FIBERS for B1.0 completion.
B1.0 complete. Suite green (725/0).
This commit is contained in:
agra
2026-06-20 16:36:31 +03:00
parent 4b384788e6
commit b631590574
10 changed files with 148 additions and 66 deletions

View File

@@ -128,7 +128,10 @@ pub fn monomorphizeFunction(self: *Lowering, fd: *const ast.FnDecl, mangled_name
defer scope.deinit();
self.scope = &scope;
{
// `abi(.pure)` (naked): no frame — params arrive in registers, read by the
// asm body, never spilled to allocas (the LLVM verifier rejects a naked
// function that uses its arguments). Mirrors the decl-path guard.
if (fd.abi != .pure) {
var param_idx: u32 = if (wants_ctx) 1 else 0;
for (fd.params) |p| {
if (isTypeParamDecl(&p, fd.type_params)) continue;