selfhost/cmd/wcc: extend tinfo coverage + graduate slotsize fast-path (Phase A.2)
tinfofornode (check.ww) covers six more kinds:
- N_TARRAY: typearray on recursed element, size = esz * elen.
- N_TFN: 8B/8B; recurse on ret.
- N_TENUM: storage size/align (default i32 → 4B). Mirrors cstage
check.c:531-542.
- N_TTUPLE: raw element sum + max-align. Mirrors check.c:329-345.
- N_TSTRUCT: per-field align, round total to maxalign. Mirrors
check.c:280-340 / :468-527.
- N_TTAGGED: 8B tag + (max(variant)+7)&~7, al ≥ 8. Mirrors
check.c:347-435.
Cycle-prone arms (TFN/TTUPLE/TSTRUCT/TTAGGED) pre-bind the in-progress
tinfo into the cache BEFORE recursing on subfields so self-referential
shapes (`type node = struct { next: *node, … }`) terminate. Pre-fix
wwdump_ww segfaulted on its own combined source.
More population sites in exprtype: every primitive literal arm
(N_FLOATLIT/N_STRLIT/N_RUNELIT/N_TRUE/N_FALSE/N_VOIDLIT/N_NIL —
A.1 only had N_INTLIT), N_IDENT (propagate from sym.decl.lhs.type_,
eagerly tinfofornode + cache if not yet visited), resolvewalk type-expr
stamping, and resolvefnbody now recurses into N_PARAM.lhs (pre-#61 the
param type-exprs were never walked — every param had nil type_).
slotsize (cgenutil.ww) gains a fast-path: when n.type_ is set AND the
kind is PTR / SLICE / CHAN / FN / STR, return ti.size: i32 directly.
The fallback walker stays alive for primitive scalars, enums, named
structs, inline composites, TARRAY — those need cstage's let_emit_size
slot-pad-to-8 contract (cmd/w6c/cgen.c:691-720) which tinfo doesn't
carry. A.3+ moves padding into the fast-path.
TY_TAGGED *not* in the fast-path (reviewer-61a2 caught this) —
tinfofornode's TTAGGED arm doesn't implement cstage's nullable-pointer
fold (check.c:412-426: `(*T | void) → 8B`). Self-host code happens not
to use that shape today, but the divergence would land latent. Pull
TAGGED until A.3 folds nullable into tinfofornode.
A.2 fallback-hit count under wwdump build: 1554 fast vs 2187 fallback —
partial graduation; expected. 131/131 + 994 + 995 + bootstrap
byte-identical (ww2==ww3==ww4).
This commit is contained in:
@@ -1941,6 +1941,31 @@ export fn letslotsize(c: *cgen, n: *node) i32 = {
|
||||
};
|
||||
|
||||
fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
// #61 audit §1.8 — A.2 graduation: read tinfo.size off the populated
|
||||
// type-expression node when its kind matches the cstage natural-size
|
||||
// SSoT. Filtered set covers shapes whose tinfo.size already encodes
|
||||
// the cgen slot-size contract: pointer-like (PTR/CHAN/FN), slice
|
||||
// (SLICE), and str (STR). Other kinds flow through the fallback
|
||||
// walker. TAGGED stays out because cstage's resolve_type folds
|
||||
// `(*T | void)` to a single 8B pointer (cmd/wcc/check.c:412-426)
|
||||
// but tinfofornode's TTAGGED arm doesn't yet — graduating TAGGED
|
||||
// would shrink that fold's slot from 16 to 8 on the wwstage side.
|
||||
// Primitive scalars + enums + inline TUPLE / TSTRUCT also keep
|
||||
// flowing through the fallback walker because cgen's slot-pad-to-8
|
||||
// contract (cmd/w6c/cgen.c let_emit_size:691-720 and the per-field
|
||||
// slot rounding in registerstruct/letslotsize) lives there, not in
|
||||
// tinfo.size. Subsequent sub-commits collapse the remaining shapes
|
||||
// onto the same pivot once cstage parity catches up (#61 Phase A —
|
||||
// see the audit doc for the staged plan).
|
||||
if (typn != nil && typn.type_ != nil) {
|
||||
let ti: *tinfo = typn.type_: *tinfo;
|
||||
let kk: tykind = ti.kind;
|
||||
if (kk == tykind.TY_PTR || kk == tykind.TY_SLICE ||
|
||||
kk == tykind.TY_CHAN || kk == tykind.TY_FN ||
|
||||
kk == tykind.TY_STR) {
|
||||
return ti.size: i32;
|
||||
};
|
||||
};
|
||||
if (typn == nil) { return 8; };
|
||||
let k: nkind = typn.kind;
|
||||
// `!T` carries T's memory layout; the error-tag bit lives in the
|
||||
|
||||
Reference in New Issue
Block a user