selfhost/cmd/wcc: TARRAY struct-stride + cache-bind resolved body (Phase A.4)
A.3 left wwstage slotsize at 134 fallback hits. Per-kind breakdown:
N_TARRAY 33 + N_TNAME 101 (of which 71 resolve to TY_STRUCT, 3 to
module-name quirks, 27 already had tinfo populated and were spurious
fallbacks via missed cache hits).
tinfofornode N_TNAME: existing arm already reached the resolved body
via aliaslookup → tinfofornode recursion (reviewer-61a3's "isn't
reaching body" hypothesis disproved by per-name instrumentation). A.4
binds the resolved-body node into the cache too — mirrors A.2's
TSTRUCT/TFN/TTUPLE/TTAGGED cycle-break pattern so future calls on
either node short-circuit.
tinfofornode N_TARRAY: when sub.kind == TY_STRUCT, round sub.size up
to 8 before stride. Mirrors registerstruct's slot-padded element
stride (cgenutil.ww:2156-2165 / :2233). Primitive elements stay
natural (slotsize's TARRAY walker also keeps them natural).
slotsize fast-path adds TY_VOID (size 0) and TY_ARRAY (gated on
alen > 0 so `[_]T` keeps routing through letslotsize). TY_STRUCT
deferred to A.5: tinfofornode TSTRUCT uses per-field natural-align
so size(T) stays natural at user level, but registerstruct uses
size-derived align with nested structs slot-padded — diverges on
ragged-tail shapes (`{inner=3*i32, mark: i32}` gives natural=16 vs
totsize=24). Proper A.5 design is a tinfo.slotsize SSoT distinct
from tinfo.size.
Module-name TNAME quirks (`let l: lex;` where lex is both a struct
and the imported module): resolvealias short-circuits on SK_MOD,
n.type_ stays nil, falls through to AST walker which structlookups
correctly. 3 hits in tree. A.5 work alongside TSTRUCT.
Post-A.4 fallback: wwdump 134→45, w6a 17→12, w6l 6→6, ww 12→11
(reviewer also measured w6c at 40). Total 169→74 across the corpus
(56% reduction). All 74 are TNAME → TY_STRUCT or module-name quirks.
131/131 + 994 + 995 + bootstrap (ww2==ww3==ww4) byte-identical.
This commit is contained in:
@@ -901,9 +901,25 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
// Mirrors astsize's TNAME fallback so the helpers stay in
|
||||
// lockstep until A.2 collapses each cgen size-walker onto
|
||||
// tinfo.size directly.
|
||||
//
|
||||
// #61 A.4: bind the resolved body too so future
|
||||
// tinfofornode calls on either the TNAME or its target
|
||||
// short-circuit on the cache hit instead of re-walking
|
||||
// the chain. Pre-bind matches A.2's TSTRUCT/TFN/TTUPLE/
|
||||
// TTAGGED cycle-break pattern (a self-referential
|
||||
// struct field's *T → TNAME → body would otherwise
|
||||
// re-enter the same chain).
|
||||
let body: *node = resolvealias(c, n);
|
||||
if (body != nil && body != n) {
|
||||
r = tinfofornode(c, body);
|
||||
let cached2: *tinfo = tinfocachelookup(c.tc, body);
|
||||
if (cached2 != nil) {
|
||||
r = cached2;
|
||||
} else {
|
||||
r = tinfofornode(c, body);
|
||||
if (r != nil) {
|
||||
tinfocachebind(c.tc, body, r);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} else { if (k == nkind.N_TBANG) {
|
||||
@@ -928,7 +944,22 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_INTLIT) { elen = n.rhs.uval; };
|
||||
};
|
||||
r = typearray(c.a, tinfofornode(c, n.lhs), elen);
|
||||
let sub: *tinfo = tinfofornode(c, n.lhs);
|
||||
r = typearray(c.a, sub, elen);
|
||||
// #61 A.4: cgen's registerstruct.totsize slot-pads each struct
|
||||
// to 8B (cgenutil.ww:2204-2205); fieldsize→[N]Struct stride
|
||||
// (cgenutil.ww:2156-2165) uses that totsize, so tinfo.size
|
||||
// must mirror the pad for byte-identity with the AST-walker
|
||||
// fallback. Primitives (str/i32/u8/...) keep their natural
|
||||
// stride — slotsize's TARRAY arm reads primsize directly,
|
||||
// not si.totsize. Only TY_STRUCT subs need the round.
|
||||
if (sub != nil && sub.kind == tykind.TY_STRUCT) {
|
||||
let stride: u64 = sub.size;
|
||||
if ((stride & 7u64) != 0u64) {
|
||||
stride = (stride + 7u64) & ~7u64;
|
||||
};
|
||||
r.size = stride * elen;
|
||||
};
|
||||
} else { if (k == nkind.N_TFN) {
|
||||
// Cstage cmd/wcc/check.c:437-466: function types are 8B / 8B
|
||||
// (call-target pointer shape). Pre-bind before recursing into
|
||||
|
||||
Reference in New Issue
Block a user