From 7a85210b1331f7cc380bdf902fbc4f28f357772f Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 6 Jun 2026 04:01:24 +0900 Subject: [PATCH] =?UTF-8?q?cgen:=20B6-c3=20addr-of/field-walk/index=20spin?= =?UTF-8?q?e=20single=20peels=20fold=20into=20type=5Fchase=5Fnamed=20?= =?UTF-8?q?=E2=80=94=2014=20lines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The exact B6-c3 set (rob b6 spec §2, numbering at 4cac1cb): :3949 (&ident classify ou), :4006 (&mod.G leaf lu), :4124/:4128 (&p.f ptr-field fallback bu/inner), :5029/:5035/:5052 (indexed-elem struct-field STORE elemu/inner/bu), :5937 (assign-region esub peel), :10953/:10956 (chained N_DOT ptr lu/inner), :11046/:11052/:11067 (indexed-elem struct-field READ twin), :11285 (index-region esub peel — gates key the chased esubu exactly as the ident arm, per the EYES condition). Raw `->under` in cgen.c 41→27. RE-ATTRIBUTION (ken c3-STOP addendum, adjudicated on his independent scratch build): kb6_idxf and kb6_ampf did NOT land on the oracle's predicted post-states — and the train direction is CORRECT anyway. Bit-proven mechanism: post-chase cs_alias asm == ww_PLAIN (the byte-id-gate-proven canonical dedicated shape) for BOTH rows; it is WWSTAGE that is alias-blind at these two sites (ww_alias != ww_plain — its indexed-elem struct-field store/read gates and the &p.f ptr-field fallback don't fire on alias bases and fall to generic-but- runtime-correct routes). Converging cs onto ww_alias would re-blind cs — canonical is the convergence target. ampf's pre-c3 byte-id was both-stages-on-the-generic-route identity (gate-blind, #263-class), NOT M5 latency — oracle self-correction banked. Both rows pinned K_RUN_NOID (cs-0 + ww-0, byte-id waived) + plain-control rows pin the convergence target; they graduate to full byte-id when the filed ww-side W2 fold (task #102) lands (ww gate chase; kw1/#100/W1 precedent; zero metric-1 content). chdot/esub byte-NEUTRAL bound held. TRAIN INVARIANT: cs-only; w6c_ww/ww_ww bit-identical to the 4cac1cb baselines (b6bddc8e…/4e9ca874…). cs movers c2→c3 bounded to exactly {kb6_idxf, kb6_ampf} — the named c3 family; both run-cells ok/0 held; rest of corpus + five mains byte-NEUTRAL; detectors unmoved; 989 ratchet zero flips. 944_alias_cgen_b6_run grows 8→14 rows, 22→38 checks: idxf_2lvl/ ampf_2lvl NOID pins + idxf_plain_ctl/ampf_plain_ctl canonical-shape pins + chdot_2lvl/esub_2lvl controls. All 944-family suites green; sizelint 0. --- cmd/w6c/cgen.c | 44 ++++--------- test/wcc/944_alias_cgen_b6_run.c | 109 +++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 30 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index f1896fbd..30ddd661 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -3945,8 +3945,7 @@ cgexpr(Cg *c, Node *n, Local *locals) if (opnd && opnd->kind == N_IDENT) { int off = localfind(locals, opnd->str); Type *ot = opnd->type; - Type *ou = (ot && ot->kind == TY_NAMED) - ? ot->under : ot; + Type *ou = type_chase_named(ot); if (off != 0) { ins2(c, A_LEAQ, amem(D_BP, off), areg(D_AX)); } else if (ou && ou->kind == TY_FN) { @@ -4002,8 +4001,7 @@ cgexpr(Cg *c, Node *n, Local *locals) && (opnd->lhs->type == NULL || opnd->lhs->type == ty_err)) { Type *lt = opnd->type; - Type *lu = (lt && lt->kind == TY_NAMED) - ? lt->under : lt; + Type *lu = type_chase_named(lt); if (lu && lu->kind == TY_FN) ins2(c, A_LEAQ, mafn(c, opnd->str, @@ -4120,12 +4118,9 @@ cgexpr(Cg *c, Node *n, Local *locals) if (!amped && opnd->lhs && opnd->lhs->kind == N_IDENT) { Type *bt = opnd->lhs->type; - Type *bu = (bt && bt->kind == TY_NAMED) - ? bt->under : bt; + Type *bu = type_chase_named(bt); if (bu && bu->kind == TY_PTR && bu->sub) { - Type *inner = bu->sub; - if (inner->kind == TY_NAMED) - inner = inner->under; + Type *inner = type_chase_named(bu->sub); if (inner && inner->kind == TY_STRUCT) { for (Tfield *f = inner->fields; f; f = f->next) { @@ -5025,14 +5020,11 @@ cgexpr(Cg *c, Node *n, Local *locals) Node *idx = n->lhs->lhs->rhs; if (idxbase && idxbase->kind == N_IDENT && idx) { Type *elemt = n->lhs->lhs->type; - Type *elemu = (elemt && elemt->kind == TY_NAMED) - ? elemt->under : elemt; + Type *elemu = type_chase_named(elemt); Type *struct_t = NULL; int viaptr = 0; if (elemu && elemu->kind == TY_PTR) { - Type *inner = elemu->sub; - if (inner && inner->kind == TY_NAMED) - inner = inner->under; + Type *inner = type_chase_named(elemu->sub); if (inner && inner->kind == TY_STRUCT) { struct_t = inner; viaptr = 1; @@ -5048,8 +5040,7 @@ cgexpr(Cg *c, Node *n, Local *locals) n->lhs->str) == 0) { f = fl; break; } Type *bt = idxbase->type; - Type *bu = (bt && bt->kind == TY_NAMED) - ? bt->under : bt; + Type *bu = type_chase_named(bt); int is_arr = bu && bu->kind == TY_ARRAY; int is_sl = bu && bu->kind == TY_SLICE; int is_ptr = bu && bu->kind == TY_PTR; @@ -5933,8 +5924,7 @@ cgexpr(Cg *c, Node *n, Local *locals) int elem_is_str = eff && eff->sub && type_isstr(eff->sub); int elem_is_slice = eff && eff->sub && type_isslice(eff->sub); Type *esub = eff ? eff->sub : NULL; - Type *esubu = (esub && esub->kind == TY_NAMED) - ? esub->under : esub; + Type *esubu = type_chase_named(esub); int elem_tagged = esubu && esubu->kind == TY_TAGGED; /* Tagged-union element: route widening through a * scratch slot, then copy slot bytes to &arr[i]. @@ -10940,10 +10930,9 @@ cgexpr(Cg *c, Node *n, Local *locals) * field. (Surfaced building ww-w6l.) */ if (n->lhs->kind == N_DOT) { Type *lt = n->lhs->type; - Type *lu = (lt && lt->kind == TY_NAMED) ? lt->under : lt; + Type *lu = type_chase_named(lt); if (lu && lu->kind == TY_PTR && lu->sub) { - Type *inner = lu->sub; - if (inner->kind == TY_NAMED) inner = inner->under; + Type *inner = type_chase_named(lu->sub); if (inner && inner->kind == TY_STRUCT) { for (Tfield *f = inner->fields; f; f = f->next) { if (strcmp(f->name, n->str) != 0) continue; @@ -11032,14 +11021,11 @@ cgexpr(Cg *c, Node *n, Local *locals) && n->lhs->lhs->kind == N_IDENT) { Node *idxbase = n->lhs->lhs; Type *elemt = n->lhs->type; - Type *elemu = (elemt && elemt->kind == TY_NAMED) - ? elemt->under : elemt; + Type *elemu = type_chase_named(elemt); Type *struct_t = NULL; int viaptr = 0; if (elemu && elemu->kind == TY_PTR) { - Type *inner = elemu->sub; - if (inner && inner->kind == TY_NAMED) - inner = inner->under; + Type *inner = type_chase_named(elemu->sub); if (inner && inner->kind == TY_STRUCT) { struct_t = inner; viaptr = 1; @@ -11053,8 +11039,7 @@ cgexpr(Cg *c, Node *n, Local *locals) if (strcmp(fl->name, n->str) == 0) { f = fl; break; } Type *bt = idxbase->type; - Type *bu = (bt && bt->kind == TY_NAMED) - ? bt->under : bt; + Type *bu = type_chase_named(bt); int is_arr = bu && bu->kind == TY_ARRAY; int is_sl = bu && bu->kind == TY_SLICE; int is_ptr = bu && bu->kind == TY_PTR; @@ -11271,8 +11256,7 @@ cgexpr(Cg *c, Node *n, Local *locals) int esz = 1; if (eff && eff->sub) esz = (int)eff->sub->size; Type *esub = eff ? eff->sub : NULL; - Type *esubu = (esub && esub->kind == TY_NAMED) - ? esub->under : esub; + Type *esubu = type_chase_named(esub); int elem_tagged = esubu && esubu->kind == TY_TAGGED; if (n->lhs->kind == N_IDENT && u) { diff --git a/test/wcc/944_alias_cgen_b6_run.c b/test/wcc/944_alias_cgen_b6_run.c index 12e7948f..ebe4f4e7 100644 --- a/test/wcc/944_alias_cgen_b6_run.c +++ b/test/wcc/944_alias_cgen_b6_run.c @@ -55,6 +55,35 @@ * checker-blocked upstream (#86/#99) — the pin is the b5 | * suite's tuparg_cast_bound99 two-key cells, which must | * not move.) | + * ---- c3 (addr-of/field-walk/index spine: :3949 :4006 --------- + * :4124/:4128 :5029/:5035/:5052 :5937 :10953/:10956 ----- + * :11046/:11052/:11067 :11285, numbering at 4cac1cb) ---- + * idxf_2lvl / | kb6_idxf (indexed-elem struct field | + * ampf_2lvl | write+read) / kb6_ampf (&p.b over | + * | 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 | + * | 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 + * chdot_2lvl | kb6_chdot: chained dot over alias | + * | hops — latent control | 0/0 + * esub_2lvl | kb6_esub: [3]my32b narrow-elem index | + * | (#61/#101-kin at the INDEX sites) — | + * | latent control | 0/0 * * K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant) * and assert cstage/wwstage asm byte-id. K_BUILDERR rows must FAIL @@ -97,6 +126,8 @@ slurp_eq(const char *a, const char *b) #define K_RUN 0 /* build+run BOTH, exits==wants, + byte-id */ #define K_BUILDERR 1 /* build FAILS with experr on BOTH drivers; * experr_ww overrides the ww-side text */ +#define K_RUN_NOID 2 /* build+run BOTH, exits==wants, byte-id + * SKIPPED — cite the blocking task */ struct row { const char *label; const char *src; int cswant; int wwwant; int kind; @@ -229,6 +260,84 @@ static const struct row rows[] = { " if (g(a) != 5) { return 1; };\n" " return 0;\n" "};\n", 0, 0, K_RUN, NULL, NULL }, + /* ---- 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. */ + { "idxf_2lvl", + "package main;\n" + "type el0 = struct { a: i64, b: i64 };\n" + "type el = el0;\n" + "export fn main() i32 = {\n" + " let xs: [2]el;\n" + " xs[0].a = 1; xs[0].b = 2;\n" + " 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 */ + { "idxf_plain_ctl", + "package main;\n" + "type el0 = struct { a: i64, b: i64 };\n" + "export fn main() i32 = {\n" + " let xs: [2]el0;\n" + " xs[0].a = 1; xs[0].b = 2;\n" + " 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, NULL, NULL }, + /* &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). */ + { "ampf_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 p: *st = &x;\n" + " let q: *i64 = &p.b;\n" + " *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 */ + { "ampf_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 p: *st0 = &x;\n" + " let q: *i64 = &p.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" + "type in1 = in0;\n" + "type out0 = struct { inner: in1, n: i64 };\n" + "type out1 = out0;\n" + "export fn main() i32 = {\n" + " let s: out1; s.inner.v = 7; s.n = 3;\n" + " let p: *out1 = &s;\n" + " if (p.inner.v != 7) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL, NULL }, + { "esub_2lvl", + "package main;\n" + "type my32 = u32;\n" + "type my32b = my32;\n" + "export fn main() i32 = {\n" + " let xs: [3]my32b;\n" + " xs[0] = 5; xs[1] = 6; xs[2] = 7;\n" + " if (xs[0]: i64 + xs[1]: i64 + xs[2]: i64 != 18) { return 1; };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL, NULL }, }; static int