fibers B1.0a: plumb abi(.pure), emit bails (lock)

First implementation step of Stream B1 (fibers). Make the inert abi(.pure)
ABI carry an is_pure flag through lowering, with LLVM emission deliberately
bailing loudly until B1.0b — the lock half of the lock->green cadence.

- IR Function.is_pure, set from fd.abi == .pure at both declareFunction
  decl sites.
- funcWantsImplicitCtx skips .pure (no synthetic __sx_ctx, mirroring the
  .c skip): a pure fn reads args from ABI registers, an implicit ctx would
  occupy a register slot the asm doesn't expect.
- both body-lowering paths bypass lowerValueBody for .pure: lower the asm
  body as statements + cap with unreachable. A pure body has no sx return
  (the asm rets itself), so the implicit-return diagnostic must not fire.
- emit_llvm Pass 2 bails loudly when func.is_pure (build-gating nonzero
  exit) rather than emit a framed body, whose epilogue would corrupt a
  context switch's deliberate SP-in != SP-out.

examples/1800-concurrency-pure-asm.sx: one host example (no .build pin --
the bail fires before instruction selection, so it is host-independent),
locked to the bail snapshot. B1.0b flips emit to LLVM's naked attribute +
asm-only body and pins the example per-arch.

The sx-facing name is "pure" throughout (field, diagnostic); LLVM's naked
attribute is only the B1.0b lowering mechanism. Suite green (722/0).
This commit is contained in:
agra
2026-06-20 14:34:53 +03:00
parent 7044b8133b
commit dd363ca877
9 changed files with 207 additions and 100 deletions

View File

@@ -408,6 +408,17 @@ pub const LLVMEmitter = struct {
// its only references are in comptime code, so DCE drops the leftover
// declaration. See current/PLAN-COMPILER-VM.md (S3).
if (func.is_compiler_domain) continue;
// B1.0a (lock): `abi(.pure)` emission is not implemented yet — the
// LLVM `naked` attribute + asm-only body land in B1.0b. Bail LOUDLY
// (build-gating, like a comptime failure) rather than emit a framed
// body, whose prologue/epilogue would corrupt the deliberate
// SP-in ≠ SP-out of a context switch. See current/PLAN-FIBERS.md.
if (func.is_pure) {
const fname = self.ir_mod.types.getString(func.name);
std.debug.print("error: `abi(.pure)` function '{s}' LLVM emission not yet implemented\n", .{fname});
self.comptime_failed = true;
continue;
}
self.emitFunction(&func, @intCast(i));
}