diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index f800503a..2d71edd7 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -13675,12 +13675,21 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame) scr + idx * esz)); idx++; } - } else if (n->lhs->kind == N_IDENT) { + } else if (n->lhs->kind == N_IDENT + && localfind(*locals, n->lhs->str) != 0) { /* N_IDENT: word-copy rhs slot into * scratch. Whole 8B words via MOVQ; * trailing partial word via MOVL/MOVB * so we read no further than the - * source slot's declared size. */ + * source slot's declared size. + * + * #42 (#263): only a LOCAL ident has a + * BP slot. A module-global struct ident + * (localfind==0) falls to the addr-copy + * else below — aggarg_srcaddr lands + * g(SB) in SI. Pre-fix this read frame + * garbage off 0(BP). ww half landed + * F8-c6. */ int rhsoff = localfind(*locals, n->lhs->str); int k = 0; diff --git a/test/wcc/989_globstructret_run.c b/test/wcc/989_globstructret_run.c index 0bdcc538..b4c6e286 100644 --- a/test/wcc/989_globstructret_run.c +++ b/test/wcc/989_globstructret_run.c @@ -3,28 +3,19 @@ * GLOBAL struct ident by value (`return g;`) must copy g's bytes into the * return buffer. * - * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG): cgenstmt.ww cgreturn's - * ≤24B register-struct return path resolves an N_IDENT source via - * localfindnode and word-copies from its BP slot only `if (rl != nil)`. A - * module-global struct ident (rl==nil) hit no branch — after the @retscr - * zero-fill it copied NOTHING, so the callee returned a zeroed struct and g - * was never referenced. cstage is ALSO wrong: it copies frame garbage - * ((BP)/8(BP)), never g(SB). Both wrong (#263); the cstage half is filed as - * task #42. + * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG, now CLOSED both stages): + * the ≤24B register-struct return path word-copied an N_IDENT source from its + * BP slot only for a LOCAL ident. A module-global struct ident hit no branch + * (wwstage zero-filled the @retscr; cstage copied frame garbage ((BP)/8(BP)), + * never g(SB)). The ww half landed in F8-c6; the cstage half (route a global + * ident through the aggarg_srcaddr memcpy — LEAQ g(SB),SI) landed in ww-core + * TASK #42. Both stages now copy g's bytes and the .s is byte-identical. * - * THE WWSTAGE FIX (ww-runtime-correct): a global N_IDENT source is marked - * addrsrc, routing it through the existing memcpy path — aggargsrcaddr emits - * LEAQ g(SB),SI and the loop copies rsz bytes into @retscr. Locals keep the - * BP word-copy (byte-id preserved). cstage stays wrong → cs≠ww residual. - * - * Rows assert ww runtime-correct (the field-equality check returns 0) AND - * pin cstage's deterministic residual: garbage fields never satisfy the - * equality, so the cstage binary takes the else and returns 1. (#42 closes - * the cs side → these become cs==ww.) - * row | shape (return g; then check) | cs | ww - * -----------+-------------------------------------------+----+---- - * ret_16 | point{x=3,y=4} (rsz 16); x==3 && y==4 | 1 | 0 - * ret_24 | triple{a=5,b=6,c=7} (rsz 24); all three | 1 | 0 + * Rows assert the field-equality check returns 0 on both stages (cs==ww). + * row | shape (return g; then check) | exit + * -----------+-------------------------------------------+----- + * ret_16 | point{x=3,y=4} (rsz 16); x==3 && y==4 | 0 + * ret_24 | triple{a=5,b=6,c=7} (rsz 24); all three | 0 */ #include #include @@ -60,7 +51,7 @@ static const struct row rows[] = { " if (p.x == 3 && p.y == 4) { return 0; };\n" " return 1;\n" "};\n", - 1, 0 }, + 0, 0 }, { "ret_24", "package main;\n" @@ -72,7 +63,7 @@ static const struct row rows[] = { " if (p.a == 5 && p.b == 6 && p.c == 7) { return 0; };\n" " return 1;\n" "};\n", - 1, 0 }, + 0, 0 }, }; /* run_build — build+run `src` via `driver`; returns the binary's exit