From 05f7af76d189c816e46c2b4bffce2384243fb4cb Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 6 Jun 2026 04:57:03 +0900 Subject: [PATCH] wcc_ww/cgen: W2 #102 indexed-elem field store + &-field gates chase the alias chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two ww-side gates from ken's B6-c3 STOP re-attribution (.ai/ken-b6-oracle.md addendum): WWSTAGE was the alias-blind side at exactly two cgenexpr.ww sites, both keyed on a bare name-keyed structlookup that only holds struct-decl names, so an alias-NAMED spelling missed and fell to the generic-but-runtime-correct route — byte-divergent from the canonical dedicated shape cs pins post-B6-c3: (1) `arr[i].f = v` indexed-elem struct-field STORE arm (the write twin of the task-#8 READ arm, which already chases via tichase); (2) `&p.f` ptr-field fallback in the TK_AMP N_DOT single-dot leg. REVIEW AMENDMENT (reviewer-W2, rob's close-by-construction obligation): the proof-sweep of the two arms found ONE same-class survivor — (3) the value-struct `&x.f` leg, one leg below (2) in the same single-DOT arm, same alias-blind bare structlookup. Probe rW2_ampv reproduced the identical bit-proven mechanism (ww_alias != ww_plain; cs_alias == ww_plain) at both base and the frozen tip; the other in-arm routes are clean (letvar* global helpers chase, str/len pseudo-field alias legs are filed-loud #96, chained depth>=2 resolves via tinfo). Same chase applied; arm survivor count is now zero by the same grep+probe construction. All three now resolve through structlookupchain (#22) — the name layer's own alias-chain accessor (the cstage transitive-peel mirror), already consumed by the sibling `p.f = v` assign arm and cgdot's pointer-to-struct read. Plain rows short-circuit at its structlookup head, so non-alias emission is byte-identical by construction; alias rows land on the same structinfo as their plain twins, so the dedicated emission converges bit-exactly. esz stays sound: elemsizeofc reads the chased stamped tinfo (#8 leg). Convergence proven with ken's pre-staged W2 instrument: ww_alias == ww_plain bit-IDENTICAL for kb6_idxf and kb6_ampf (cmp exit 0), which also lands cs==ww byte-id on both rows; plain controls byte-id held and their ww asm unchanged base->tip. Full ken-corpus matrix vs the B6-tip baseline: movers are exactly {kb6_idxf, kb6_ampf} NO->YES; detectors unmoved (kw1_101 cs0/ww1, fill2 both-loud, tuparg_c cs0/ww1, fsarg2/fsarg0/try pinned texts verbatim, B5/B6 graduations all byte-id). Zero behavioral change on any accepted program, zero acceptance change in either direction. ww-only: zero C-source bytes; cs binaries (w6c/ww/w6a/w6l) md5 bit-identical base->tip; w6c_ww + wwdump main.combined.ww regen'd via make, idempotent. 989 lib ratchet: zero flips (31 byte-identical / 9 pinned-divergent #59 / 3 pinned-wwreject #59 across 43 units). 944_alias_cgen_b6_run: idxf_2lvl + ampf_2lvl graduate K_RUN_NOID -> K_RUN (the two restored byte-id cells) — B6-c3's mutation teeth restored (reviewer-B6 N-a closes); + amendment rows ampv_2lvl / ampv_plain_ctl pin the third gate (checks 61 -> 69). All 9 944-family suites green; sizelint 0; make test-unit "all 292 tests passed". --- selfhost/cmd/w6c/main.combined.ww | 41 +++++++++++++---- selfhost/cmd/wcc/cgenexpr.ww | 41 +++++++++++++---- selfhost/cmd/wwdump/main.combined.ww | 41 +++++++++++++---- test/wcc/944_alias_cgen_b6_run.c | 67 ++++++++++++++++++++-------- 4 files changed, 145 insertions(+), 45 deletions(-) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 9c698388..571601cd 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -25470,6 +25470,16 @@ fn cgun(c: *cgen, n: *node) void = { let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-field: &p.f where p:*T. + // #102 (ken B6-c3 re-attribution): an + // alias-NAMED pointee misses the bare + // name-keyed lookup, so &p.f fell to the + // generic cgplaceaddr route — runtime- + // correct but byte-divergent from the + // dedicated shape cs pins post-B6-c3. + // structlookupchain (#22) chases the alias + // chain; plain rows short-circuit at its + // structlookup head, byte-id by + // construction. if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; let sname: str; @@ -25478,7 +25488,7 @@ fn cgun(c: *cgen, n: *node) void = { if (inner.kind == nkind.N_TNAME) { sname = inner.str; }; }; if (sname.len > 0) { - let si: *structinfo = structlookup(c, sname); + let si: *structinfo = structlookupchain(c, inner); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { @@ -25497,9 +25507,13 @@ fn cgun(c: *cgen, n: *node) void = { }; }; // Value-struct local: &o.f. + // #102 review-found sibling: same + // alias-blind miss one leg below the + // &p.f gate — an alias-NAMED value + // struct fell to the generic route. + // Same chase, same construction. if (lkind == nkind.N_TNAME) { - let sname: str = tn.str; - let si: *structinfo = structlookup(c, sname); + let si: *structinfo = structlookupchain(c, tn); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { @@ -29555,22 +29569,31 @@ fn cgassign(c: *cgen, n: *node) void = { // array's element (#61). let elemt: *node = idxelemtn(tn); let baseisarray: bool = tn.kind == nkind.N_TARRAY; - let sname: str; - sname.ptr = nil; sname.len = 0; + let snode: *node = nil; let viaptr: bool = false; if (elemt != nil) { if (elemt.kind == nkind.N_TPTR) { let inner: *node = elemt.lhs; if (inner != nil) { if (inner.kind == nkind.N_TNAME) { - sname = inner.str; + snode = inner; viaptr = true; };}; } else { if (elemt.kind == nkind.N_TNAME) { - sname = elemt.str; + snode = elemt; };}; }; - if (sname.len > 0) { - let si: *structinfo = structlookup(c, sname); + // #102 (ken B6-c3 re-attribution): an alias-NAMED + // element misses the bare name-keyed lookup, so + // `arr[i].f = v` fell to the generic place route — + // runtime-correct but byte-divergent from the + // dedicated shape cs pins post-B6-c3 (the READ twin + // above already chases via tichase, task #8). + // structlookupchain (#22) chases the alias chain; + // plain rows short-circuit at its structlookup + // head, byte-id by construction. esz stays sound: + // elemsizeofc reads the chased stamped tinfo (#8). + if (snode != nil) { + let si: *structinfo = structlookupchain(c, snode); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index ce6c13a9..74369d59 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -4454,6 +4454,16 @@ fn cgun(c: *cgen, n: *node) void = { let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-field: &p.f where p:*T. + // #102 (ken B6-c3 re-attribution): an + // alias-NAMED pointee misses the bare + // name-keyed lookup, so &p.f fell to the + // generic cgplaceaddr route — runtime- + // correct but byte-divergent from the + // dedicated shape cs pins post-B6-c3. + // structlookupchain (#22) chases the alias + // chain; plain rows short-circuit at its + // structlookup head, byte-id by + // construction. if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; let sname: str; @@ -4462,7 +4472,7 @@ fn cgun(c: *cgen, n: *node) void = { if (inner.kind == nkind.N_TNAME) { sname = inner.str; }; }; if (sname.len > 0) { - let si: *structinfo = structlookup(c, sname); + let si: *structinfo = structlookupchain(c, inner); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { @@ -4481,9 +4491,13 @@ fn cgun(c: *cgen, n: *node) void = { }; }; // Value-struct local: &o.f. + // #102 review-found sibling: same + // alias-blind miss one leg below the + // &p.f gate — an alias-NAMED value + // struct fell to the generic route. + // Same chase, same construction. if (lkind == nkind.N_TNAME) { - let sname: str = tn.str; - let si: *structinfo = structlookup(c, sname); + let si: *structinfo = structlookupchain(c, tn); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { @@ -8539,22 +8553,31 @@ fn cgassign(c: *cgen, n: *node) void = { // array's element (#61). let elemt: *node = idxelemtn(tn); let baseisarray: bool = tn.kind == nkind.N_TARRAY; - let sname: str; - sname.ptr = nil; sname.len = 0; + let snode: *node = nil; let viaptr: bool = false; if (elemt != nil) { if (elemt.kind == nkind.N_TPTR) { let inner: *node = elemt.lhs; if (inner != nil) { if (inner.kind == nkind.N_TNAME) { - sname = inner.str; + snode = inner; viaptr = true; };}; } else { if (elemt.kind == nkind.N_TNAME) { - sname = elemt.str; + snode = elemt; };}; }; - if (sname.len > 0) { - let si: *structinfo = structlookup(c, sname); + // #102 (ken B6-c3 re-attribution): an alias-NAMED + // element misses the bare name-keyed lookup, so + // `arr[i].f = v` fell to the generic place route — + // runtime-correct but byte-divergent from the + // dedicated shape cs pins post-B6-c3 (the READ twin + // above already chases via tichase, task #8). + // structlookupchain (#22) chases the alias chain; + // plain rows short-circuit at its structlookup + // head, byte-id by construction. esz stays sound: + // elemsizeofc reads the chased stamped tinfo (#8). + if (snode != nil) { + let si: *structinfo = structlookupchain(c, snode); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 4dfe08c2..0e3989b1 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -25470,6 +25470,16 @@ fn cgun(c: *cgen, n: *node) void = { let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-field: &p.f where p:*T. + // #102 (ken B6-c3 re-attribution): an + // alias-NAMED pointee misses the bare + // name-keyed lookup, so &p.f fell to the + // generic cgplaceaddr route — runtime- + // correct but byte-divergent from the + // dedicated shape cs pins post-B6-c3. + // structlookupchain (#22) chases the alias + // chain; plain rows short-circuit at its + // structlookup head, byte-id by + // construction. if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; let sname: str; @@ -25478,7 +25488,7 @@ fn cgun(c: *cgen, n: *node) void = { if (inner.kind == nkind.N_TNAME) { sname = inner.str; }; }; if (sname.len > 0) { - let si: *structinfo = structlookup(c, sname); + let si: *structinfo = structlookupchain(c, inner); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { @@ -25497,9 +25507,13 @@ fn cgun(c: *cgen, n: *node) void = { }; }; // Value-struct local: &o.f. + // #102 review-found sibling: same + // alias-blind miss one leg below the + // &p.f gate — an alias-NAMED value + // struct fell to the generic route. + // Same chase, same construction. if (lkind == nkind.N_TNAME) { - let sname: str = tn.str; - let si: *structinfo = structlookup(c, sname); + let si: *structinfo = structlookupchain(c, tn); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { @@ -29555,22 +29569,31 @@ fn cgassign(c: *cgen, n: *node) void = { // array's element (#61). let elemt: *node = idxelemtn(tn); let baseisarray: bool = tn.kind == nkind.N_TARRAY; - let sname: str; - sname.ptr = nil; sname.len = 0; + let snode: *node = nil; let viaptr: bool = false; if (elemt != nil) { if (elemt.kind == nkind.N_TPTR) { let inner: *node = elemt.lhs; if (inner != nil) { if (inner.kind == nkind.N_TNAME) { - sname = inner.str; + snode = inner; viaptr = true; };}; } else { if (elemt.kind == nkind.N_TNAME) { - sname = elemt.str; + snode = elemt; };}; }; - if (sname.len > 0) { - let si: *structinfo = structlookup(c, sname); + // #102 (ken B6-c3 re-attribution): an alias-NAMED + // element misses the bare name-keyed lookup, so + // `arr[i].f = v` fell to the generic place route — + // runtime-correct but byte-divergent from the + // dedicated shape cs pins post-B6-c3 (the READ twin + // above already chases via tichase, task #8). + // structlookupchain (#22) chases the alias chain; + // plain rows short-circuit at its structlookup + // head, byte-id by construction. esz stays sound: + // elemsizeofc reads the chased stamped tinfo (#8). + if (snode != nil) { + let si: *structinfo = structlookupchain(c, snode); if (si != nil) { let fi: *fieldinfo = si.fields; for (fi != nil) { diff --git a/test/wcc/944_alias_cgen_b6_run.c b/test/wcc/944_alias_cgen_b6_run.c index 0a166db5..50eeecf8 100644 --- a/test/wcc/944_alias_cgen_b6_run.c +++ b/test/wcc/944_alias_cgen_b6_run.c @@ -63,22 +63,27 @@ * | alias ptr): the c3 chase moved cs | * | onto the PLAIN-canonical dedicated | * | shape (cs_alias == ww_PLAIN, bit- | - * | proven, ken c3-STOP addendum) — but | - * | WWSTAGE is the alias-blind side at | - * | these two sites (ww_alias != | - * | ww_plain, generic-but-correct | - * | routes). Two-cell NOID pins; byte-id | - * | graduates with the filed ww-side W2 | - * | fold, task #102 (ww indexed-elem | - * | field gates + &p.f fallback don't | - * | fire on alias bases). ampf's pre-c3 | - * | byte-id was both-on-generic | + * | proven, ken c3-STOP addendum) — and | + * | WWSTAGE was the alias-blind side at | + * | these two sites (generic-but-correct | + * | routes). GRADUATED to full byte-id | + * | by the W2 ww fold, task #102 (the | + * | two gates now chase the alias chain | + * | via structlookupchain). ampf's | + * | pre-c3 byte-id was both-on-generic | * | identity, not latency (oracle | * | self-correction) | 0/0 * idxf_plain_ctl / | plain no-alias twins — pin the | * ampf_plain_ctl | canonical dedicated shape byte-id | * | BOTH stages (the convergence target | * | the NOID rows graduate onto) | 0/0 + * ampv_2lvl / | W2-review-found #102 sibling: &x.f | + * ampv_plain_ctl | over an alias-NAMED VALUE struct — | + * | the leg one below the &p.f gate had | + * | the same alias-blind bare lookup | + * | (ww_alias != ww_plain; cs_alias == | + * | ww_plain, same bit-proven mechanism).| + * | Chased in the W2 review amendment | 0/0 * chdot_2lvl | kb6_chdot: chained dot over alias | * | hops — latent control | 0/0 * esub_2lvl | kb6_esub: [3]my32b narrow-elem index | @@ -296,11 +301,11 @@ static const struct row rows[] = { /* ---- c3: addr-of/field-walk/index spine */ /* The c3 chase put cs on the PLAIN-canonical dedicated shape * (cs_alias == ww_PLAIN, bit-proven — ken c3-STOP addendum); - * WWSTAGE is the alias-blind side here: its indexed-elem - * struct-field store/read gates don't fire on alias bases and - * fall to a generic-but-correct route. Byte-id waived until the - * filed ww-side W2 fold (task #102) lands; idxf_plain_ctl pins the - * convergence target. */ + * WWSTAGE was the alias-blind side here: its indexed-elem + * struct-field store gate fell to a generic-but-correct route + * on alias bases. GRADUATED: the W2 ww fold (task #102) chases + * the alias chain (structlookupchain), restoring full byte-id — + * idxf_plain_ctl pins the canonical shape both rows now share. */ { "idxf_2lvl", "package main;\n" "type el0 = struct { a: i64, b: i64 };\n" @@ -311,7 +316,7 @@ static const struct row rows[] = { " xs[1].a = 3; xs[1].b = 4;\n" " if (xs[1].b != 4 || xs[0].b != 2) { return 1; };\n" " return 0;\n" - "};\n", 0, 0, K_RUN_NOID, NULL, NULL }, /* byte-id: task #102 */ + "};\n", 0, 0, K_RUN, NULL, NULL }, /* graduated: #102 (W2) */ { "idxf_plain_ctl", "package main;\n" "type el0 = struct { a: i64, b: i64 };\n" @@ -325,7 +330,7 @@ static const struct row rows[] = { /* &p.b ptr-field fallback twin of the same re-attribution: the * pre-c3 byte-id here was BOTH stages on the generic spine * (gate-blind identity, not M5 latency — oracle self-correction - * banked in ken's c3-STOP addendum). */ + * banked in ken's c3-STOP addendum). GRADUATED with #102 (W2). */ { "ampf_2lvl", "package main;\n" "type st0 = struct { a: i64, b: i64 };\n" @@ -337,7 +342,7 @@ static const struct row rows[] = { " *q = 9;\n" " if (x.b != 9) { return 1; };\n" " return 0;\n" - "};\n", 0, 0, K_RUN_NOID, NULL, NULL }, /* byte-id: task #102 */ + "};\n", 0, 0, K_RUN, NULL, NULL }, /* graduated: #102 (W2) */ { "ampf_plain_ctl", "package main;\n" "type st0 = struct { a: i64, b: i64 };\n" @@ -349,6 +354,32 @@ static const struct row rows[] = { " if (x.b != 9) { return 1; };\n" " return 0;\n" "};\n", 0, 0, K_RUN, NULL, NULL }, + /* W2-review-found #102 sibling: the value-struct &x.f leg sits + * one leg below the &p.f gate in the same cgun single-DOT arm + * and had the same alias-blind bare structlookup (ww_alias != + * ww_plain, cs_alias == ww_plain — the c3-STOP bit-test + * mechanism verbatim). Chased in the W2 review amendment. */ + { "ampv_2lvl", + "package main;\n" + "type st0 = struct { a: i64, b: i64 };\n" + "type st = st0;\n" + "export fn main() i32 = {\n" + " let x: st; x.a = 1; x.b = 2;\n" + " let q: *i64 = &x.b;\n" + " *q = 9;\n" + " if (x.b != 9) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL, NULL }, /* amendment: #102 (W2) */ + { "ampv_plain_ctl", + "package main;\n" + "type st0 = struct { a: i64, b: i64 };\n" + "export fn main() i32 = {\n" + " let x: st0; x.a = 1; x.b = 2;\n" + " let q: *i64 = &x.b;\n" + " *q = 9;\n" + " if (x.b != 9) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL, NULL }, { "chdot_2lvl", "package main;\n" "type in0 = struct { v: i64 };\n"