selfhost: graduate N_* defs to nkind enum

This commit is contained in:
2026-05-12 04:54:23 +09:00
parent d20674a5ad
commit 3affe01705
13 changed files with 2007 additions and 1995 deletions

View File

@@ -5,17 +5,17 @@
// then by assembling + linking + running the result.
//
// Current coverage:
// - decls: N_FILE, N_FNDECL (params, frame for locals, prologue
// - decls: nkind.N_FILE, nkind.N_FNDECL (params, frame for locals, prologue
// + dual-epilogue suppression; FFI body-less fn skipped)
// - stmts: N_BLOCK, N_RETURN, N_EXPRSTMT, N_LET (no init),
// N_LET (int-literal / ident / call / N_BIN init),
// N_IF (with optional else), N_FOR (cond-only and full
// init/cond/post), N_BREAK, N_CONTINUE
// - exprs: N_INTLIT, N_IDENT (local/param), N_BIN with full op
// - stmts: nkind.N_BLOCK, nkind.N_RETURN, nkind.N_EXPRSTMT, nkind.N_LET (no init),
// nkind.N_LET (int-literal / ident / call / nkind.N_BIN init),
// nkind.N_IF (with optional else), nkind.N_FOR (cond-only and full
// init/cond/post), nkind.N_BREAK, nkind.N_CONTINUE
// - exprs: nkind.N_INTLIT, nkind.N_IDENT (local/param), nkind.N_BIN with full op
// coverage (+/-/*/// %, &/|/^, <</>>, comparisons with
// signed-vs-unsigned dispatch, &&/||), N_UN (- ! ~ &amp; *),
// N_CALL (recursive R-to-L push, pop into argregs L-to-R),
// N_ASSIGN to local idents (plain and compound +=/-=)
// signed-vs-unsigned dispatch, &&/||), nkind.N_UN (- ! ~ &amp; *),
// nkind.N_CALL (recursive R-to-L push, pop into argregs L-to-R),
// nkind.N_ASSIGN to local idents (plain and compound +=/-=)
//
// Type info is shallow — frame slots are 8 bytes per local, all loads
// /stores are MOVQ. Programs that mix i8/i32/i64 locals work but spill
@@ -41,7 +41,7 @@ use cgendecl;
//
// `type error = str;` makes `error` a struct-shape alias. We track
// alias→target so isstrtype / isslicetype / structlookup can
// resolve through the chain. Only direct N_TNAME aliases are mapped;
// resolve through the chain. Only direct nkind.N_TNAME aliases are mapped;
// `type p = struct {...}` is handled by collectstructs.
type aliasent = struct {
@@ -54,10 +54,10 @@ fn collectaliases(c: *cgen, file: *node) void = {
c.aliases = nil;
let d: *node = file.list;
for (d != nil) {
if (d.kind == N_TYPEDECL) {
if (d.kind == nkind.N_TYPEDECL) {
let body: *node = d.lhs;
if (body != nil) {
if (body.kind != N_TSTRUCT) {
if (body.kind != nkind.N_TSTRUCT) {
let a: *aliasent = amalloc(c.a, 32u64): *aliasent;
a.aname = d.str;
a.target = body;
@@ -90,11 +90,11 @@ fn aliaslookup(c: *cgen, name: str) *node = {
fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (e == nil) { return false; };
let k: i32 = e.kind;
if (k == N_INTLIT) { *out = e.uval; return true; };
if (k == N_RUNELIT) { *out = e.uval; return true; };
if (k == N_TRUE) { *out = 1u64; return true; };
if (k == N_FALSE) { *out = 0u64; return true; };
if (k == N_IDENT) {
if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
if (k == nkind.N_TRUE) { *out = 1u64; return true; };
if (k == nkind.N_FALSE) { *out = 0u64; return true; };
if (k == nkind.N_IDENT) {
let m: *enummember = prev;
for (m != nil) {
if (streq(m.mname, e.str)) {
@@ -105,7 +105,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
};
return false;
};
if (k == N_BIN) {
if (k == nkind.N_BIN) {
let a: u64;
let b: u64;
if (!enumevalmember(prev, e.lhs, &a)) { return false; };
@@ -129,7 +129,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (op == tkind.TK_RSHIFT) { *out = a >> b; return true; };
return false;
};
if (k == N_UN) {
if (k == nkind.N_UN) {
let v: u64;
if (!enumevalmember(prev, e.lhs, &v)) { return false; };
let op: i32 = e.op;
@@ -145,10 +145,10 @@ fn collectenums(c: *cgen, file: *node) void = {
c.enums = nil;
let d: *node = file.list;
for (d != nil) {
if (d.kind == N_TYPEDECL) {
if (d.kind == nkind.N_TYPEDECL) {
let body: *node = d.lhs;
if (body != nil) {
if (body.kind == N_TENUM) {
if (body.kind == nkind.N_TENUM) {
let et: *enumtype = amalloc(c.a, 48u64): *enumtype;
et.ename = d.str;
et.storage = body.lhs;
@@ -226,7 +226,7 @@ fn resolvetype(c: *cgen, t: *node) *node = {
let depth: i32 = 0;
for (depth < 16) {
if (cur == nil) { return nil; };
if (cur.kind != N_TNAME) { return cur; };
if (cur.kind != nkind.N_TNAME) { return cur; };
let nm: str = cur.str;
let next: *node = aliaslookup(c, nm);
if (next == nil) { return cur; };
@@ -239,8 +239,8 @@ fn resolvetype(c: *cgen, t: *node) *node = {
// ---- struct registry ------------------------------------------------
//
// Per-file map from struct name → list of fields with computed offsets
// and sizes. Built when cgfile walks N_TYPEDECL with N_TSTRUCT lhs.
// N_DOT and N_ASSIGN consult this to resolve `s.field` for struct or
// and sizes. Built when cgfile walks nkind.N_TYPEDECL with nkind.N_TSTRUCT lhs.
// nkind.N_DOT and nkind.N_ASSIGN consult this to resolve `s.field` for struct or
// *struct bases.
type fieldinfo = struct {
@@ -263,12 +263,12 @@ type structinfo = struct {
type local = struct {
name: str,
off: i32,
tnode: *node, // declared type expr (N_TNAME / N_TPTR / ...) or nil
tnode: *node, // declared type expr (nkind.N_TNAME / nkind.N_TPTR / ...) or nil
lnext: *local,
};
// strlit — interned string literal record. Emitted as a DATA directive
// after all functions; cgexpr N_STRLIT loads (LEAQ ptr, MOVQ len).
// after all functions; cgexpr nkind.N_STRLIT loads (LEAQ ptr, MOVQ len).
type strlit = struct {
label: str, // "_S_<seq>"
bytes: str,
@@ -352,7 +352,7 @@ fn cgeninit(c: *cgen, a: *arena) void = {
// match-arm bindings, which C cgen allocates via cgexpr's by-value
// `locals` list — so two separate matches each get fresh slots even
// when their bind names collide. scanlocals follows the same rule
// for N_MCASE.
// for nkind.N_MCASE.
fn localalloc(c: *cgen, name: str, sz: i32, tnode: *node) i32 = {
let asz: i32 = sz;
if (asz < 8) { asz = 8; };
@@ -380,7 +380,7 @@ fn localadd(c: *cgen, name: str, sz: i32, tnode: *node) i32 = {
//
// On a dedup hit we also overwrite the stored tnode to match
// the new declaration's type. C reads `n->lhs->type` (filled
// by the checker) at every N_DOT/N_CAST site; we read
// by the checker) at every nkind.N_DOT/nkind.N_CAST site; we read
// `lc.tnode`, so it must follow source order. Without this,
// a later `let m: *node` inside a branch keeps an earlier
// `let m: i32`'s tnode and `m.next` falls into the SB fallback.
@@ -552,16 +552,16 @@ fn internstrlit(c: *cgen, bytes: str) str = {
fn emitdefconstants(c: *cgen, file: *node) void = {
let d: *node = file.list;
for (d != nil) {
if (d.kind == N_DEF) {
if (d.kind == nkind.N_DEF) {
let r: *node = d.rhs;
let v: u64 = 0u64;
let ok: bool = false;
if (r != nil) {
if (r.kind == N_INTLIT) { v = r.uval; ok = true; };
if (r.kind == N_RUNELIT) { v = r.uval; ok = true; };
if (r.kind == N_TRUE) { v = 1u64; ok = true; };
if (r.kind == N_FALSE) { v = 0u64; ok = true; };
if (r.kind == N_NIL) { v = 0u64; ok = true; };
if (r.kind == nkind.N_INTLIT) { v = r.uval; ok = true; };
if (r.kind == nkind.N_RUNELIT) { v = r.uval; ok = true; };
if (r.kind == nkind.N_TRUE) { v = 1u64; ok = true; };
if (r.kind == nkind.N_FALSE) { v = 0u64; ok = true; };
if (r.kind == nkind.N_NIL) { v = 0u64; ok = true; };
};
if (ok) {
emitline("DATA ");
@@ -691,7 +691,7 @@ fn collectfnrets(c: *cgen, file: *node) void = {
c.fnrets = nil;
let d: *node = file.list;
for (d != nil) {
if (d.kind == N_FNDECL) {
if (d.kind == nkind.N_FNDECL) {
let f: *fnret = amalloc(c.a, 32u64): *fnret;
f.fname = d.str;
f.rtype = d.lhs;
@@ -716,7 +716,7 @@ fn fnretlookup(c: *cgen, name: str) *node = {
//
// `def NAME: T = LIT;` becomes a DATA symbol the C-side w6c emits; an
// ident reference loads it via `MOVQ NAME(SB), AX`. We collect them at
// file load and consult on N_IDENT lookup.
// file load and consult on nkind.N_IDENT lookup.
type defent = struct {
dname: str,
@@ -728,7 +728,7 @@ fn collectdefs(c: *cgen, file: *node) void = {
c.defs = nil;
let d: *node = file.list;
for (d != nil) {
if (d.kind == N_DEF) {
if (d.kind == nkind.N_DEF) {
let e: *defent = amalloc(c.a, 32u64): *defent;
e.dname = d.str;
e.drhs = d.rhs;
@@ -784,7 +784,7 @@ fn collectmods(c: *cgen, file: *node) void = {
// Mirror collectfnrets' shape exactly (plain prepend in one
// branch). Earlier nested-if/early-return variants tickled a
// wwstage cgen bug that dropped most prepends.
if (d.kind == N_FNDECL) {
if (d.kind == nkind.N_FNDECL) {
if (d.exported == 0) {
if (d.module.len > 0) {
if (!streq(d.str, "main")) {
@@ -797,7 +797,7 @@ fn collectmods(c: *cgen, file: *node) void = {
};
};
};
if (d.kind == N_DEF) {
if (d.kind == nkind.N_DEF) {
if (d.exported == 0) {
if (d.module.len > 0) {
let m: *modent = amalloc(c.a, 48u64): *modent;
@@ -808,7 +808,7 @@ fn collectmods(c: *cgen, file: *node) void = {
};
};
};
if (d.kind == N_TYPEDECL) {
if (d.kind == nkind.N_TYPEDECL) {
if (d.exported == 0) {
if (d.module.len > 0) {
let m: *modent = amalloc(c.a, 48u64): *modent;
@@ -819,7 +819,7 @@ fn collectmods(c: *cgen, file: *node) void = {
};
};
};
if (d.kind == N_LET) {
if (d.kind == nkind.N_LET) {
if (d.exported == 0) {
if (d.module.len > 0) {
let m: *modent = amalloc(c.a, 48u64): *modent;
@@ -872,15 +872,15 @@ fn fficollect(c: *cgen, file: *node) void = {
if (file == nil) { return; };
let d: *node = file.list;
for (d != nil) {
if (d.kind == N_FNDECL) {
if (d.kind == nkind.N_FNDECL) {
let a: *node = d.attr;
for (a != nil) {
if (a.kind == N_ATTR) {
if (a.kind == nkind.N_ATTR) {
let aname: str = a.str;
if (streq(aname, "symbol")) {
let symnode: *node = a.list;
if (symnode != nil) {
if (symnode.kind == N_STRLIT) {
if (symnode.kind == nkind.N_STRLIT) {
let f: *ffi = amalloc(c.a, 48u64): *ffi;
f.ident = d.str;
f.symbol = symnode.str;