selfhost/cmd/wcc + lib/ww: tinfo.slotsize SSoT + module-name TNAME fallback (Phase A.5)
A.4 left 74 fallback hits, all TNAME-flavored — 71 TNAME → TY_STRUCT
(natural-align vs slot-padded mismatch) + 3 module-name TNAME quirks
(`let l: lex;` where lex is both struct and imported module).
tinfo gains a slotsize: u64 field (96 → 104 bytes; amalloc bumped
to 112B per rule-7). size(T) stays Hare-natural at the user level;
cgen's slot storage now reads ti.slotsize for kinds where the two
differ. tinfofornode populates both:
- TSTRUCT: existing natural-align walk for r.size; new size-derived
align walk (sz≥8→8, ≥4→4, ≥2→2) for r.slotsize, rounded to 8.
Mirrors cgenutil.ww:2192-2218 registerstruct exactly.
- TTUPLE: parallel via tupleelemslot helper (primitives→8, str=16,
slice=24, ptr/fn/chan/i64/u64/int/uint/uintptr/f64=8, composite
→pt.slotsize, void=0).
- TARRAY: typearray sets slotsize = sub.slotsize * n. [N]i32 stays
4N (natural); [N]Triplet lifts to 16N (slot-padded). Reverts
A.4's r.size override since slot-pad now lives in slotsize.
- TFN/TENUM/TTAGGED/nullable: explicit slotsize. Default trail
`if r.slotsize == 0 then r.slotsize = r.size` catches TBANG.
- New fieldslotsize(ft) helper mirrors registerstruct's per-field
rule (struct→ft.slotsize, array→ft.slotsize, primitive→ft.size,
tagged→ft.size).
slotsize fast-path (cgenutil.ww) reads ti.slotsize for TY_STRUCT,
TY_TUPLE, TY_ARRAY; ti.size stays correct for PTR/SLICE/CHAN/FN/
STR/TAGGED/VOID (size == slotsize for those). Narrow scalars still
pad-to-8 at the read site (moving into slotsize would break
[N]i32 stride).
lib/ww/sym.ww adds scopelookuptype(s, name) — same FNV bucket+parent
walk as scopelookup but filtered on skind==SK_TYPE. resolvealias
calls it when bare-leaf scopelookup returns non-TYPE (e.g., the
SK_USE/SK_MOD short-circuit case). Fixes `let l: lex;` (mod=leaf)
AND `let t: tok;` (mod≠leaf, tok lives in package lex).
Post-A.5 fallback: 0 across full bootstrap. Reviewer's stricter
metric (zero fast-path MISSES when tinfo IS stamped) also 0;
remaining FB_NIL hits are value-expression nodes the checker
doesn't yet stamp — A.6 candidate.
Ragged-tail probe `struct{inner=3*i32, mark:i32}`: ti.size=16
(natural), ti.slotsize=24 (slot-padded). Cstage emits [N]<ragged>
stride=16 on the same source — latent divergence filed as #63.
Not exercised by selfhost, so bootstrap byte-identity holds today.
131/131 + 994 + 995 + bootstrap (ww2==ww3==ww4) all green.
This commit is contained in:
@@ -1941,45 +1941,27 @@ export fn letslotsize(c: *cgen, n: *node) i32 = {
|
||||
};
|
||||
|
||||
fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
// #61 audit §1.8 — A.3 / A.4 fast-path expansion. Read tinfo.size off
|
||||
// the populated type-expression node when the kind matches the cstage
|
||||
// natural-size SSoT. Coverage:
|
||||
// - pointer-like (PTR/CHAN/FN), slice, str, tagged
|
||||
// return ti.size directly (size already encodes the slot).
|
||||
// TY_TAGGED is safe now that tinfofornode folds `(*T | void)`
|
||||
// to 8B (#61 A.3 step 1, mirrors cmd/wcc/check.c:412-426).
|
||||
// - narrow scalars (BOOL/RUNE/I8..I32/U8..U32/ENUM) pad UP to 8 —
|
||||
// cstage's let_emit_size (cmd/w6c/cgen.c:691-720) spills every
|
||||
// primitive into an 8B stack slot regardless of tinfo.size.
|
||||
// Padding lives at the read site, not in tinfo.size, so size(T)
|
||||
// stays a faithful natural-width SSoT.
|
||||
// - #61 A.4 adds:
|
||||
// · TY_VOID returns 0 (mirrors the TNAME-"void" fallback arm).
|
||||
// Closes 56 N_TNAME-"void" / void-aliased (utf8.invalid,
|
||||
// overflow, done, more, ...) fallback hits — tinfofornode
|
||||
// now caches both the TNAME and its resolved body so future
|
||||
// calls on either land in the cache.
|
||||
// · TY_ARRAY returns ti.size when alen > 0 — tinfofornode's
|
||||
// TARRAY arm now applies the same struct-element round-to-8
|
||||
// cgen's fieldsize uses (#61 A.4 step 2), so [N]Struct's
|
||||
// stride matches. [_]T (alen=0) still routes through the
|
||||
// AST walker; letslotsize patches the length there.
|
||||
// TUPLE still flows through the fallback — slotsize sums raw element
|
||||
// sizes there, while tinfofornode TTUPLE mirrors cstage's natural
|
||||
// sum, and the two diverge for `(i32, str)`-style mixes (slot vs
|
||||
// natural per-element padding).
|
||||
//
|
||||
// TY_STRUCT deferred to A.5: tinfofornode TSTRUCT uses per-field
|
||||
// natural-align for offsets (mirroring cstage's resolve_type +
|
||||
// astsize, so `size(T)` stays natural), but registerstruct uses
|
||||
// size-derived alignment with nested structs slot-padded to 8
|
||||
// (cgenutil.ww:2178-2207). The two agree for the common 8B-aligned
|
||||
// shapes but diverge for "ragged tail" structs like
|
||||
// `struct { inner: struct{i32,i32,i32}, mark: i32 }` where the
|
||||
// inner struct's natural align (4) drops below cgen's nested-
|
||||
// struct contract (aln=8 for sz>=8). Closing the gap without
|
||||
// touching `size(T)`'s natural-width contract needs a separate
|
||||
// SSoT (e.g. tinfo.slotsize) — filed as A.5.
|
||||
// #61 audit §1.8 — A.3 / A.4 / A.5 fast-path expansion. Read the
|
||||
// slot-padded width off the populated type-expression node when the
|
||||
// kind matches the cstage natural-size SSoT. Coverage:
|
||||
// - pointer-like (PTR/CHAN/FN), slice, str, tagged: ti.size ===
|
||||
// ti.slotsize (slot already equals natural). TY_TAGGED is safe
|
||||
// now that tinfofornode folds `(*T | void)` to 8B (#61 A.3 step
|
||||
// 1, mirrors cmd/wcc/check.c:412-426).
|
||||
// - narrow scalars (BOOL/RUNE/I8..I32/U8..U32/ENUM/F32) pad UP to
|
||||
// 8 — cstage's let_emit_size (cmd/w6c/cgen.c:691-720) spills
|
||||
// every primitive into an 8B stack slot regardless of
|
||||
// tinfo.size. Pad-to-8 lives at the read site, not in
|
||||
// tinfo.slotsize, so `[N]i32` stride stays 4 (natural) — moving
|
||||
// the pad into ti.slotsize would lift array stride to 8/elem.
|
||||
// - TY_VOID returns 0 (mirrors the TNAME-"void" fallback arm,
|
||||
// same as #61 A.4).
|
||||
// - #61 A.5 adds: TY_STRUCT / TY_TUPLE / TY_ARRAY read ti.slotsize
|
||||
// (slot-padded). tinfofornode populates the slot total mirroring
|
||||
// cgenutil.ww registerstruct (size-derived align, nested struct
|
||||
// fields → si.totsize, final round to 8), and TARRAY threads
|
||||
// stride through sub.slotsize so `[N]Triplet` lifts to padded *
|
||||
// N. `size(T)` stays natural — split SSoT in tinfo.
|
||||
if (typn != nil && typn.type_ != nil) {
|
||||
let ti: *tinfo = typn.type_: *tinfo;
|
||||
let kk: tykind = ti.kind;
|
||||
@@ -1989,8 +1971,11 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
kk == tykind.TY_VOID) {
|
||||
return ti.size: i32;
|
||||
};
|
||||
if (kk == tykind.TY_STRUCT || kk == tykind.TY_TUPLE) {
|
||||
if (ti.slotsize > 0u64) { return ti.slotsize: i32; };
|
||||
};
|
||||
if (kk == tykind.TY_ARRAY) {
|
||||
if (ti.alen > 0u64) { return ti.size: i32; };
|
||||
if (ti.alen > 0u64) { return ti.slotsize: i32; };
|
||||
};
|
||||
if (kk == tykind.TY_BOOL || kk == tykind.TY_RUNE ||
|
||||
kk == tykind.TY_I8 || kk == tykind.TY_I16 ||
|
||||
|
||||
Reference in New Issue
Block a user