From ac63951d54b122033707cb80a7496b7dd5bcdd69 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 5 Jun 2026 11:43:35 +0900 Subject: [PATCH] =?UTF-8?q?w6c/cgen:=20#71=20chained-dot=20walks=20chase?= =?UTF-8?q?=20alias-typed=20hops=20=E2=80=94=20direct=20offsets,=20byte-id?= =?UTF-8?q?=20graduation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rob probe-ruled F1 enrollment (fold-or-file decided by the dispatch test): the chained-dot STORE walk, its READ twin, and the addr-of sibling each single-peeled every hop's type, so an alias-typed field (type fa = inner; outer{x: fa}) aborted the offset-folding fast arm and fell to the generic address spine — store via cgplaceaddr (PUSHQ/LEAQ/ADDQ/POPQ), read via ADDQ-per-hop. Runtime-correct BOTH stages; byte-id NO vs wwstage's folded direct MOVQ offsets (reviewer-62r diamond find). Chasing the walk hops (+ the read arm's leaf gate and the two ptr-root sub peels) flips cs onto the fast arm = wwstage's asm exactly. Blast radius measured per rob's caution: bootstrap asm cmp-identical vs the pristine 738d7f4 scratch on all five main.combined.ww, 989 lib_byteid pins unchanged (31/9/3), every control row byte-id — the flip moves ONLY the #71 shapes. test: 944_alias_accept_run +2 rows, both decl orders: nested store + last-field readback; the fwd row adds the &v.y.b addr-of + deref-write leg. Mutation-checked at the 738d7f4 scratch: both rows byte-id-diff there; 70/70 green here. Also graduates the reviewer-F1 slicefield rows: their `.len` readbacks ride this walk, so the 7 K_RUN_CS rows from commit 1 flip to K_RUN (byte-id) here. --- cmd/w6c/cgen.c | 27 +++++++++------ test/wcc/944_alias_accept_run.c | 61 +++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index c3de178e..42d79f33 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -4053,8 +4053,9 @@ cgexpr(Cg *c, Node *n, Local *locals) int abort = 0; while (cur && cur->kind == N_DOT && cur->lhs) { Type *pt = cur->lhs->type; - Type *pu = (pt && pt->kind == TY_NAMED) - ? pt->under : pt; + /* Transitive chase (#71) — addr-of sibling of the + * chained-dot walks. */ + Type *pu = type_chase_named(pt); if (!pu) { abort = 1; break; } if (cur == opnd && (pu->kind == TY_SLICE || pu->kind == TY_STR)) { @@ -5517,8 +5518,12 @@ cgexpr(Cg *c, Node *n, Local *locals) int abort = 0; while (cur && cur->kind == N_DOT && cur->lhs) { Type *pt = cur->lhs->type; - Type *pu = (pt && pt->kind == TY_NAMED) - ? pt->under : pt; + /* Transitive chase (#71): an alias-typed hop left pu + * TY_NAMED -> abort -> the generic cgplaceaddr spine + * (PUSHQ/LEAQ/ADDQ/POPQ) while wwstage emits the direct + * offset store. Runtime-correct both; chasing converges + * cs onto the fast direct arm = wwstage's asm. */ + Type *pu = type_chase_named(pt); if (!pu) { abort = 1; break; } if (cur == n->lhs && (pu->kind == TY_SLICE || pu->kind == TY_STR)) { @@ -5530,8 +5535,7 @@ cgexpr(Cg *c, Node *n, Local *locals) /* `*T` root: dereference at emit time; * walk through pointee struct fields. * Last-hop only (root is a bare ident). */ - Type *sub = (pu->sub->kind == TY_NAMED) - ? pu->sub->under : pu->sub; + Type *sub = type_chase_named(pu->sub); if (sub && sub->kind == TY_STRUCT) { pu = sub; ptr_root = 1; @@ -10298,7 +10302,10 @@ cgexpr(Cg *c, Node *n, Local *locals) * stale. Sibling of the pointer-chain branch further down. */ if (n->lhs && n->lhs->kind == N_DOT) { Type *lt0 = n->lhs->type; - Type *lu0 = (lt0 && lt0->kind == TY_NAMED) ? lt0->under : lt0; + /* Transitive chase (#71) — the READ twin of the chained-dot + * store walk; an alias-typed hop skipped this arm onto the + * ADDQ-per-hop address spine while wwstage folds the offsets. */ + Type *lu0 = type_chase_named(lt0); int leaf_is_pseudo = lu0 && n->str && (lu0->kind == TY_SLICE || lu0->kind == TY_STR) && (strcmp(n->str, "ptr") == 0 @@ -10313,8 +10320,7 @@ cgexpr(Cg *c, Node *n, Local *locals) int abort = 0; while (cur && cur->kind == N_DOT && cur->lhs) { Type *pt = cur->lhs->type; - Type *pu = (pt && pt->kind == TY_NAMED) - ? pt->under : pt; + Type *pu = type_chase_named(pt); if (!pu) { abort = 1; break; } if (cur == n && (pu->kind == TY_SLICE || pu->kind == TY_STR)) { @@ -10329,8 +10335,7 @@ cgexpr(Cg *c, Node *n, Local *locals) * is a bare ident) — `*T`-field mid- * chain keeps its cgexpr-based pointer- * field branch further down. */ - Type *sub = (pu->sub->kind == TY_NAMED) - ? pu->sub->under : pu->sub; + Type *sub = type_chase_named(pu->sub); if (sub && sub->kind == TY_STRUCT) { pu = sub; ptr_root = 1; diff --git a/test/wcc/944_alias_accept_run.c b/test/wcc/944_alias_accept_run.c index 37d23157..1de3d89c 100644 --- a/test/wcc/944_alias_accept_run.c +++ b/test/wcc/944_alias_accept_run.c @@ -50,6 +50,10 @@ * | store/push word0-only; CS-ONLY until | * | F2 lands the wwstage half; base ctl | * | + the #54-bound `as` row pinned loud | 0(cs) + * nested_alias_field_* | task #71: alias-typed nested-field | + * | store/read/addr-of walks fold to | + * | direct offsets (byte-id graduation, | + * | both decl orders) | 0 * * K_RUN rows also assert cstage/wwstage asm byte-id (acceptance * graduations land byte-identical — F0's accept side was wwstage). @@ -275,10 +279,9 @@ static const struct row rows[] = { * noise() call clobbers BX/CX so stale-register luck can't pass a * word0-only header. Unprobed sibling gates are LOUD-tripwired, * pinned by the #73 row at the end of this block. Rows whose - * `.len` readback rides the chained-dot READ walk are K_RUN_CS - * here (runtime-correct both stages; cs takes the generic spine - * pre-#71) and flip to K_RUN at the #71 walk-chase commit, which - * graduates their byte-id. */ + * `.len` readback rides the chained-dot READ walk entered as + * K_RUN_CS (runtime-correct both stages; cs took the generic + * spine) and graduated to K_RUN with the #71 walk chase. */ { "slicefield_store_2lvl", "package main;\n" "type sl = []int;\n" @@ -294,7 +297,7 @@ static const struct row rows[] = { " if (b.s[2] != 900) { return 2; };\n" " if (b.s.len != 3) { return 3; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "slicefield_range_2lvl", "package main;\n" "type sl = []int;\n" @@ -311,7 +314,7 @@ static const struct row rows[] = { " if (x < 700) { return 3; };\n" " };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "strfield_store_2lvl", "package main;\n" "type s1t = str;\n" @@ -323,7 +326,7 @@ static const struct row rows[] = { " b.n = 5;\n" " if (b.s.len != 5) { return 1; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "slicefield_structlit_2lvl", "package main;\n" "type sl = []int;\n" @@ -336,7 +339,7 @@ static const struct row rows[] = { " if (b.s.len != 3) { return 2; };\n" " if (b.s[2] != 900) { return 3; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "slicefield_viaptr_2lvl", "package main;\n" "type sl = []int;\n" @@ -350,7 +353,7 @@ static const struct row rows[] = { " if (p.s.len != 3) { return 1; };\n" " if (p.s[2] != 900) { return 2; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "slicefield_chainstore_2lvl", "package main;\n" "type sl = []int;\n" @@ -364,7 +367,7 @@ static const struct row rows[] = { " if (v.i.s.len != 3) { return 1; };\n" " if (v.i.s[2] != 900) { return 2; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "slicefield_ptrchain_2lvl", "package main;\n" "type sl = []int;\n" @@ -381,7 +384,7 @@ static const struct row rows[] = { " if (i.s.len != 3) { return 1; };\n" " if (i.s[2] != 900) { return 2; };\n" " return 0;\n" - "};\n", 0, K_RUN_CS, NULL }, /* ->K_RUN at the #71 walk-chase commit */ + "};\n", 0, K_RUN, NULL }, { "slicefield_chainread_2lvl", "package main;\n" "type sl = []int;\n" @@ -749,6 +752,42 @@ static const struct row rows[] = { " };\n" " return 0;\n" "};\n", 0, K_RUN, NULL }, + /* ---- task #71 (rob probe-ruled F1 enrollment): nested fields + * whose TYPES are aliases. The chained-dot store/read/addr-of + * walks single-peeled each hop, aborted on the alias, and fell + * to the generic PUSHQ/LEAQ/ADDQ/POPQ address spine — runtime- + * correct but byte-id NO vs wwstage's folded direct offsets. + * Chasing the walks converges cs onto the direct arm = ww's asm. + * Distinct values; the LAST field of the SECOND member checked. */ + { "nested_alias_field_norm", + "package main;\n" + "type fa = inner;\n" + "type inner = struct { a: size, b: size };\n" + "type outer = struct { x: fa, y: fa };\n" + "export fn main() i32 = {\n" + " let v: outer;\n" + " v.x.a = 4; v.x.b = 9;\n" + " v.y.a = 7; v.y.b = 3;\n" + " if (v.x.b != 9) { return 1; };\n" + " if (v.y.b != 3) { return 2; };\n" + " return 0;\n" + "};\n", 0, K_RUN, NULL }, + { "nested_alias_field_fwd", + "package main;\n" + "type outer = struct { x: fa, y: fa };\n" + "type fa = inner;\n" + "type inner = struct { a: size, b: size };\n" + "export fn main() i32 = {\n" + " let v: outer;\n" + " v.x.a = 4; v.x.b = 9;\n" + " v.y.a = 7; v.y.b = 3;\n" + " if (v.x.b != 9) { return 1; };\n" + " if (v.y.b != 3) { return 2; };\n" + " let pa = &v.y.b;\n" + " *pa = 11;\n" + " if (v.y.b != 11) { return 3; };\n" + " return 0;\n" + "};\n", 0, K_RUN, NULL }, /* banked row L2-3 (`v as ali` readback) trips task #54's as-binding * aggregate-init bound — LOUD both stages today; fold the row into * #54's pin set on its fold (do not drop). Pinned here as the