From ca4ff4b88217bab07d1801e2c1c2403c8481f7ce Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 12 Jun 2026 22:37:56 +0900 Subject: [PATCH] w6c: widen of a module-global struct ident copies the full payload cstage zero-filled the payload; mirror the landed wwstage emission. Flips the residual row to cs==ww==correct. Task #43. --- cmd/w6c/cgen.c | 16 +++++++++++-- test/wcc/989_globstructwiden_run.c | 37 ++++++++++++------------------ 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 2d71edd7..4ac2746e 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -2925,9 +2925,21 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src, if (src->kind == N_IDENT) { int soff = localfind(*locals_p, src->str); int ssz = (int)su->size; + int srcreg = D_BP, srcbase = soff; + if (soff == 0) { + /* #43 (#263): a module-global struct ident has + * no BP slot — land g(SB) in SI (aggarg_srcaddr) + * and copy the struct words into slot+8. Pre-fix + * the BP copy read frame garbage off 0(BP). ww + * half landed F8-c7. */ + if (aggarg_srcaddr(c, src, D_SI, *locals_p)) { + srcreg = D_SI; + srcbase = 0; + } + } int k = 0; while (k + 8 <= ssz) { - ins2(c, A_MOVQ, amem(D_BP, soff + k), + ins2(c, A_MOVQ, amem(srcreg, srcbase + k), areg(D_AX)); ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, write_off + 8 + k)); @@ -2942,7 +2954,7 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src, int lop = (tail == 4) ? A_MOVL : (tail == 1 ? A_MOVB : A_MOVQ); ins2(c, lop, - amem(D_BP, soff + k), areg(D_AX)); + amem(srcreg, srcbase + k), areg(D_AX)); ins2(c, lop, areg(D_AX), amem(D_BP, write_off + 8 + k)); } diff --git a/test/wcc/989_globstructwiden_run.c b/test/wcc/989_globstructwiden_run.c index f0298135..dba22b6d 100644 --- a/test/wcc/989_globstructwiden_run.c +++ b/test/wcc/989_globstructwiden_run.c @@ -3,27 +3,20 @@ * GLOBAL struct ident into a tagged union (`let x: (S | str) = gs;`) must * copy gs's full payload into the box, not just word0. * - * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG): cgwidentaggedstorebp's - * struct-payload arm keys off rhsstructpayload, which returns a struct name - * only for an N_STRUCTLIT or a LOCAL ident. A module-global struct ident - * returned empty, so the value fell to the scalar word0 widen arm — only the - * first 8 bytes reached the box, the rest stale/zero. cstage is ALSO wrong: - * it zero-fills the payload (gs is never read). Both wrong (#263); the cstage - * half is filed as task #43. + * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG, now CLOSED both stages): + * the struct-payload widen arm keyed off a local/literal-only struct-name + * lookup, so a module-global struct ident fell to the scalar word0 arm — only + * the first 8 bytes reached the box (wwstage), or the payload zero-filled + * (cstage, gs never read). The ww half landed in F8-c7; the cstage half (a + * global-struct-source branch — LEAQ g(SB),SI via aggarg_srcaddr, byte-copy + * into slot+8) landed in ww-core TASK #43. Both stages now copy the full + * payload and the .s is byte-identical. * - * THE WWSTAGE FIX (ww-runtime-correct): a dedicated global-struct-source arm - * (gated on structlookupchain so str/slice/tagged globals don't trip it) - * zero-fills the slot, lands g(SB) in SI via aggargsrcaddr, byte-copies the - * struct words into slot+8, and writes the variant tag. Local/literal - * sources keep their existing arms (byte-id). cstage stays wrong → cs≠ww. - * - * Rows assert ww runtime-correct (field-equality check → 0) AND pin cstage's - * deterministic residual: cstage zero-fills the payload → the fields read 0, - * never match → the match arm returns 2. (#43 closes cs → cs==ww.) - * row | shape | cs | ww - * -----------+---------------------------------------------+----+---- - * widen_16 | gp:{a=5,b=6}; (pt|str)=gp; match pt fields | 2 | 0 - * widen_24 | gp:{a=5,b=6,c=7}; (tri|str)=gp; match fields | 2 | 0 + * Rows assert the field-equality match returns 0 on both stages (cs==ww). + * row | shape | exit + * -----------+---------------------------------------------+----- + * widen_16 | gp:{a=5,b=6}; (pt|str)=gp; match pt fields | 0 + * widen_24 | gp:{a=5,b=6,c=7}; (tri|str)=gp; match fields | 0 */ #include #include @@ -60,7 +53,7 @@ static const struct row rows[] = { " case str => return 3;\n" " };\n" "};\n", - 2, 0 }, + 0, 0 }, { "widen_24", "package main;\n" @@ -73,7 +66,7 @@ static const struct row rows[] = { " case str => return 3;\n" " };\n" "};\n", - 2, 0 }, + 0, 0 }, }; /* run_build — build+run `src` via `driver`; returns the binary's exit