From 140755d22193d36c05fda3c90013eaf29d08ed88 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 6 Jun 2026 02:22:57 +0900 Subject: [PATCH] =?UTF-8?q?cgen:=20B5-c3=20#89=20cgreturn=20return-positio?= =?UTF-8?q?n=20widen=20=E2=80=94=20rt/vu=20chase,=20trace-first?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trace at the c2 tip (rebuilt binaries, #80-c4 form): ret_widen's mk() emitted `MOVQ -16(BP),AX / MOVQ AX,DX / MOVQ $0,CX` — the scalar shuffle arm, payload word 1 ZEROED (s.b/e.aux dropped, cs silent exit 1). Deciding predicate: the vu single peel left an alias struct source TY_NAMED → isstruct false → scalar arm. The rt single peel was the succ half: a 2-LEVEL alias return type stayed NAMED → the whole tagged-return block was skipped → no tag synthesis at any return (kb5_succ's three paired return-position insertions). Fix = the three granted peels (bare-return rt, value-return rt, vu) → type_chase_named; the route predicates (istagged/isstruct/istuple/ passthrough) key on the chased vu. Raw `->under` in cgen.c 62→59. #89 CLOSES. TRAIN INVARIANT holds: cs-only; _ww binaries bit-identical to the bcd948d baseline md5s. cs movers vs the c2 tip bounded to EXACTLY the return-route family: ret_widen, kb4_xret, kna_ret_errunion, kb5_succ. Zero ww movers; detectors pinned (kb4_xampdef stays 139/139 #94; def93/x93/l2_local stay cs-SEGV — c4's targets; fill/tuparg/v2 families unchanged). Graduations (cs1/ww0 BYTE-DIVERGE → 0/0 BYTE-ID): g89_ret_widen (the banked spelling), g89_ret_errunion (the live e.aux truncation seed), and succ_2lvl flips K_RUN_NOID → K_RUN exactly as C1-CORR-1 predicted (pins-follow-the-layer). g89_ret_named_ctl (bare NAMED control) held 0/0 byte-id throughout. 944_alias_cgen_b5_run 25→28 rows (75 checks); 944 family green; sizelint 0. --- cmd/w6c/cgen.c | 17 ++++--- test/wcc/944_alias_cgen_b5_run.c | 87 +++++++++++++++++++++++++++----- 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 3a83f357..731ea942 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -12243,8 +12243,7 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame) * is producing the void variant. Emit its tag; the payload is * undefined (void has size 0). */ if (n->lhs == NULL && cg_ret_type) { - Type *rt = cg_ret_type; - if (rt->kind == TY_NAMED) rt = rt->under; + Type *rt = type_chase_named(cg_ret_type); if (rt && rt->kind == TY_TAGGED) { /* #38b: an sret-classified tagged return (slot * > the AX/DX/CX/R8 cursor) writes the void- @@ -12283,12 +12282,18 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame) } } if (n->lhs && cg_ret_type) { - Type *rt = cg_ret_type; - if (rt->kind == TY_NAMED) rt = rt->under; + /* #89: the single peel left a 2-level alias return + * type NAMED (rt — the whole tagged block skipped, no + * tag synthesis) and an alias struct source NAMED (vu + * — isstruct missed, the scalar arm shuffled word0 + * into DX and ZEROED the rest of the payload). Both + * silent; ww routes via rhsstructpayload→ + * structlookupchain since B2-c2 and is the runtime- + * correct reference. */ + Type *rt = type_chase_named(cg_ret_type); if (rt && rt->kind == TY_TAGGED) { Type *vt = n->lhs->type; - Type *vu = (vt && vt->kind == TY_NAMED) - ? vt->under : vt; + Type *vu = type_chase_named(vt); int istagged = vu && vu->kind == TY_TAGGED; /* #263: passthrough forwards the source's AX/DX/CX * unchanged — correct ONLY when the source already diff --git a/test/wcc/944_alias_cgen_b5_run.c b/test/wcc/944_alias_cgen_b5_run.c index 8a5b6c6c..58f72f01 100644 --- a/test/wcc/944_alias_cgen_b5_run.c +++ b/test/wcc/944_alias_cgen_b5_run.c @@ -32,12 +32,10 @@ * | cgexpr INLINE set (B6), NOT the | * | :2456 funnel (C1-CORR-2, corrects | * | rob R2) — byte-id waived until B6 | 0/0 - * succ_bound_c3 | kb5_succ: `?`-success remap over | - * | 2-lvl alias result — both-correct | - * | divergent at RETURN positions only | - * | (:12278/:12318/:12322 family, | - * | C1-CORR-1) — joins c3's graduation | - * | set; byte-id waived until c3 | 0/0 + * succ_2lvl | kb5_succ: `?`-success remap over | + * | 2-lvl alias result — was divergent | + * | at RETURN positions only (C1-CORR-1)| + * | — GRADUATED at c3 with the rt chase | 0/0 * null_2lvl | kb5_null: nullable fold + deref | * | (type_isnullable/nullable_ptr_tag) | * | — divergence flip | 0/0 @@ -92,6 +90,15 @@ * | fatal gave way to the #129 A.2 | * | foldability loud — now fill0-class | * | both-loud (twin texts) | err/err + * ---- c3 (#89: cgreturn return-position widen rt/vu chase) ------ + * g89_ret_widen | alias-struct return into union — | + * | was cs word0-to-DX + CX zeroed | + * | (payload dropped, silent exit 1) | 0/0 + * g89_ret_errunion | 1-LVL alias error-union return — | + * | cs MOVQ AX,DX dropped e.aux (the | + * | live-truncation seed) | 0/0 + * g89_ret_named_ctl | bare NAMED struct return control — | + * | held 0/0 byte-id throughout | 0/0 * * K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant) * and assert cstage/wwstage asm byte-id. K_RUN_NOID asserts both run @@ -270,11 +277,11 @@ static const struct row rows[] = { " };\n" " return 0;\n" "};\n", 0, 0, K_RUN_NOID, NULL }, /* byte-id: B6 */ - /* C1-CORR-1: the residual divergence is exactly three paired - * return-position tag syntheses — the cgreturn return-route - * family (:12278/:12318/:12322). Joins c3's graduation set - * (pins-follow-the-layer); flips to K_RUN there. */ - { "succ_bound_c3", + /* C1-CORR-1 → GRADUATED at c3: the residual divergence was + * exactly three paired return-position tag syntheses — the + * cgreturn return-route family; the c3 rt chase closed it + * (pins-follow-the-layer, ken c1-boundary addendum). */ + { "succ_2lvl", "package main;\n" "type e0 = !i64;\n" "type r0 = (i64 | e0);\n" @@ -293,7 +300,7 @@ static const struct row rows[] = { " case e0 => { return 2; };\n" " };\n" " return 0;\n" - "};\n", 0, 0, K_RUN_NOID, NULL }, /* byte-id: c3 */ + "};\n", 0, 0, K_RUN, NULL }, /* graduated: #89 (B5-c3) */ { "null_2lvl", "package main;\n" "type np0 = (*i64 | void);\n" @@ -555,6 +562,62 @@ static const struct row rows[] = { " return 0;\n" "};\n", 0, 0, K_BUILDERR, "#129 A.2 scope" }, + /* ---- c3: #89 — the cgreturn rt/vu single peels left a 2-level + * alias RETURN TYPE un-tagged (no tag synthesis at all, the succ + * shape) and an alias-struct SOURCE un-structed (the scalar arm + * shuffled word0 into DX and ZEROED the rest — s.b/e.aux + * dropped, cs silent exit 1, ww runtime-correct since B2-c2). */ + { "g89_ret_widen", + "package main;\n" + "type base = struct { a: size, b: size };\n" + "type ali = base;\n" + "fn mk() (void | ali) = {\n" + " let x: ali;\n" + " x.a = 4; x.b = 9;\n" + " return x;\n" + "};\n" + "export fn main() i32 = {\n" + " match (mk()) {\n" + " case let s: ali => { if (s.b != 9) { return 1; }; };\n" + " case void => { return 2; };\n" + " };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL }, + { "g89_ret_errunion", + "package main;\n" + "type failure = struct { code: i32, aux: size };\n" + "type myerr = failure;\n" + "fn work(bad: bool) (i32 | myerr) = {\n" + " if (bad) {\n" + " let e: myerr;\n" + " e.code = 7; e.aux = 99;\n" + " return e;\n" + " };\n" + " return 42;\n" + "};\n" + "export fn main() i32 = {\n" + " match (work(true)) {\n" + " case let e: myerr => { if (e.aux != 99) { return 1; }; };\n" + " case i32 => { return 2; };\n" + " };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL }, + { "g89_ret_named_ctl", + "package main;\n" + "type base = struct { a: size, b: size };\n" + "fn make() (void | base) = {\n" + " let x: base;\n" + " x.a = 4; x.b = 9;\n" + " return x;\n" + "};\n" + "export fn main() i32 = {\n" + " let v = make();\n" + " match (v) {\n" + " case let s: base => { if (s.b != 9) { return 1; }; };\n" + " case void => { return 2; };\n" + " };\n" + " return 0;\n" + "};\n", 0, 0, K_RUN, NULL }, }; static int