fibers: rename ABI variant .pure -> .naked
"pure" universally means side-effect-free (GCC __attribute__((pure)), FP purity, D's pure) — the opposite of a register-clobbering context switch. The concept is "naked": no compiler-generated prologue/epilogue, body is raw asm that emits its own ret. That is the established term everywhere (LLVM's naked function attribute — which we literally emit — plus Zig callconv(.naked), Rust #[naked], GCC/Clang __attribute__ ((naked))). Rename the keyword + everything keyed off it so concept, surface, field, and the emitted LLVM attribute all agree. - ast.zig: ABI enum variant pure -> naked (+ doc). - parser: accept abi(.naked); error text updated. - IR Function.is_pure -> is_naked; type_resolver/decl/generic/pack/ emit_llvm references updated; diagnostics say abi(.naked). - examples 1800-1803 renamed *-pure-* -> *-naked-* (source + expected/ snapshots; .ir/.exit/.stdout/.stderr are byte-identical — the emitted IR is unchanged, only the keyword spelling differs). - docs (PLAN-FIBERS, CHECKPOINT-FIBERS, PLAN-POST-METATYPE, the design roadmap, the compiler-API checkpoint/design) updated; the naming rationale now records why .naked over .pure. No semantic change — pure cosmetics. Suite green (725/0).
This commit is contained in:
@@ -513,11 +513,11 @@ pub fn detectContextDecl(decls: []const *const Node) bool {
|
||||
pub fn funcWantsImplicitCtx(self: *const Lowering, fd: *const ast.FnDecl) bool {
|
||||
if (!self.implicit_ctx_enabled) return false;
|
||||
if (fd.abi == .c) return false;
|
||||
// An `abi(.pure)` function has no frame and no synthetic params — its body
|
||||
// An `abi(.naked)` function has no frame and no synthetic params — its body
|
||||
// is a single asm block reading args from ABI registers. No implicit
|
||||
// `__sx_ctx` (it would occupy a register slot the asm doesn't expect).
|
||||
// See Function.is_pure.
|
||||
if (fd.abi == .pure) return false;
|
||||
// See Function.is_naked.
|
||||
if (fd.abi == .naked) return false;
|
||||
// A BODILESS `abi(.compiler)` decl (compiler-API surface) is dispatched by name
|
||||
// to a Zig/VM handler with exactly the declared args; an implicit `__sx_ctx`
|
||||
// prepend would shift every arg (breaking the handler's arity check). No sx
|
||||
@@ -2315,7 +2315,7 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
|
||||
func.source_file = self.current_source_file;
|
||||
func.is_variadic = is_variadic;
|
||||
func.has_implicit_ctx = wants_ctx;
|
||||
func.is_pure = (fd.abi == .pure);
|
||||
func.is_naked = (fd.abi == .naked);
|
||||
self.extern_name_map.put(name, c_name) catch {};
|
||||
self.fn_decl_fids.put(fd, fid) catch {};
|
||||
return;
|
||||
@@ -2329,7 +2329,7 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
|
||||
func.source_file = self.current_source_file;
|
||||
func.is_variadic = is_variadic;
|
||||
func.has_implicit_ctx = wants_ctx;
|
||||
func.is_pure = (fd.abi == .pure);
|
||||
func.is_naked = (fd.abi == .naked);
|
||||
if (weldedCompilerFn(self, fd, name)) func.compiler_welded = true;
|
||||
// A BODIED `abi(.compiler)` function is a user compiler-domain function (e.g. a
|
||||
// post-link callback): the VM runs its sx body, but it NEVER runs in the binary
|
||||
@@ -2660,13 +2660,13 @@ pub fn lowerFunctionBodyInto(self: *Lowering, fd: *const ast.FnDecl, fid: FuncId
|
||||
const user_param_base: u32 = if (wants_ctx) 1 else 0;
|
||||
if (wants_ctx) self.current_ctx_ref = Ref.fromIndex(0);
|
||||
|
||||
// An `abi(.pure)` (naked) function has no frame: its params arrive in ABI
|
||||
// An `abi(.naked)` (naked) function has no frame: its params arrive in ABI
|
||||
// registers and are read directly by the asm body (e.g. `swap_context`'s
|
||||
// `from`/`to`). Spilling them to allocas would (a) need a frame and (b) emit
|
||||
// `store i64 %0, …` — "cannot use argument of naked function" (LLVM verifier).
|
||||
// Leave the LLVM args declared-but-unused (the verifier allows that); the asm
|
||||
// references the registers.
|
||||
if (fd.abi != .pure) for (fd.params, 0..) |p, i| {
|
||||
if (fd.abi != .naked) for (fd.params, 0..) |p, i| {
|
||||
const pty = self.resolveParamType(&p);
|
||||
const slot = self.builder.alloca(pty);
|
||||
const param_ref = Ref.fromIndex(@intCast(i + user_param_base));
|
||||
@@ -2685,8 +2685,8 @@ pub fn lowerFunctionBodyInto(self: *Lowering, fd: *const ast.FnDecl, fid: FuncId
|
||||
// Lower the function body (set target_type to return type for implicit returns)
|
||||
const saved_target = self.target_type;
|
||||
self.target_type = if (ret_ty != .void and ret_ty != .noreturn) ret_ty else null;
|
||||
if (self.builder.currentFunc().is_pure) {
|
||||
// `abi(.pure)`: the body is a single asm block that emits its own `ret`.
|
||||
if (self.builder.currentFunc().is_naked) {
|
||||
// `abi(.naked)`: the body is a single asm block that emits its own `ret`.
|
||||
// There is no sx-level value return — lower the statements and cap the
|
||||
// block with `unreachable` (control never falls back into sx). This
|
||||
// bypasses the implicit-return machinery, which would otherwise reject
|
||||
@@ -2818,10 +2818,10 @@ pub fn lowerFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, i
|
||||
const user_param_base_lf: u32 = if (wants_ctx_lf) 1 else 0;
|
||||
if (wants_ctx_lf) self.current_ctx_ref = Ref.fromIndex(0);
|
||||
|
||||
// `abi(.pure)` (naked): params arrive in registers, read directly by the asm
|
||||
// `abi(.naked)` (naked): params arrive in registers, read directly by the asm
|
||||
// body — no frame, no alloca/store (which the LLVM verifier rejects on a
|
||||
// naked function). See the sibling guard in the other body-lowering path.
|
||||
if (fd.abi != .pure) for (fd.params, 0..) |p, i| {
|
||||
if (fd.abi != .naked) for (fd.params, 0..) |p, i| {
|
||||
const pty = self.resolveParamType(&p);
|
||||
// Allocate stack slot for param, store initial value.
|
||||
// Refs 0..N-1 are reserved for function parameters by beginFunction.
|
||||
@@ -2843,8 +2843,8 @@ pub fn lowerFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8, i
|
||||
// Lower the function body, capturing the last expression's value for implicit return
|
||||
const saved_target = self.target_type;
|
||||
self.target_type = if (ret_ty != .void and ret_ty != .noreturn) ret_ty else null;
|
||||
if (self.builder.currentFunc().is_pure) {
|
||||
// `abi(.pure)`: asm-only body that rets itself — see the sibling path
|
||||
if (self.builder.currentFunc().is_naked) {
|
||||
// `abi(.naked)`: asm-only body that rets itself — see the sibling path
|
||||
// above. Lower statements, cap with `unreachable`; emission is B1.0b.
|
||||
self.lowerBlock(fd.body);
|
||||
if (!self.currentBlockHasTerminator()) self.builder.emitUnreachable();
|
||||
|
||||
Reference in New Issue
Block a user