diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index 4ac2746e..4220182c 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -2611,7 +2611,8 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src, for (int k = 0; k < sz; k += 8) ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, write_off + k)); - if (src->kind == N_IDENT) { + if (src->kind == N_IDENT + && localfind(*locals_p, src->str) != 0) { int soff = localfind(*locals_p, src->str); for (int k = 0; k < ssz; k += 8) { ins2(c, A_MOVQ, amem(D_BP, soff + k), @@ -2619,6 +2620,21 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src, ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, write_off + 8 + k)); } + } else if (src->kind == N_IDENT) { + /* #44 (#263): a module-global tagged ident + * source has no BP slot — land gi(SB) in SI + * (aggarg_srcaddr) and copy the inner box into + * slot+8. Pre-fix the BP copy read frame garbage + * off 0(BP). ww half landed F8-c8. */ + if (aggarg_srcaddr(c, src, D_SI, *locals_p)) { + for (int k = 0; k < ssz; k += 8) { + ins2(c, A_MOVQ, + amem(D_SI, k), areg(D_AX)); + ins2(c, A_MOVQ, areg(D_AX), + amem(D_BP, + write_off + 8 + k)); + } + } } else { /* #38b: an sret-classified call result is in * memory (AX = dest pointer), not the cursor — diff --git a/test/wcc/989_globtagwiden_run.c b/test/wcc/989_globtagwiden_run.c index 6e279510..69f32715 100644 --- a/test/wcc/989_globtagwiden_run.c +++ b/test/wcc/989_globtagwiden_run.c @@ -4,29 +4,20 @@ * must copy gi's whole box as the nested payload, not store its tag as the * payload. * - * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG): cgwidentaggedstorebp's - * #218 nested-tagged-source arm is gated on rhstaggedident, which returns nil - * for a module-global tagged ident (local-only). So srctagged was false and a - * global tagged source fell to the scalar word0 widen arm — gi's TAG word - * landed as the box payload, the real value lost. cstage is ALSO wrong: it - * copies frame garbage (saved-BP / return-address), never gi(SB). Both wrong, - * divergent (#263); the cstage half is filed as task #44. + * THE BUG (cat-A silent miscompile, #263 BOTH-WRONG, now CLOSED both stages): + * the #218 nested-tagged-source arm was gated local-only, so a module-global + * tagged source fell to the scalar word0 widen arm — gi's TAG word landed as + * the box payload (wwstage), or frame garbage was copied, never gi(SB) + * (cstage). The ww half landed in F8-c8; the cstage half (the nested arm's + * N_IDENT copy grows a global branch — LEAQ gi(SB),SI via aggarg_srcaddr, copy + * the inner box into slot+8) landed in ww-core TASK #44. Both stages now copy + * the whole box and the .s is byte-identical. * - * THE WWSTAGE FIX (ww-runtime-correct): srctagged also recognises a global - * tagged ident, and the nested arm's N_IDENT copy grows a global branch — - * LEAQ gi(SB),SI via aggargsrcaddr, then copy the inner box (ssz bytes) into - * slot+8 with the outer tag at slot+0. Local sources keep the BP copy - * (byte-id). cstage stays wrong → cs≠ww residual. - * - * cstage's residual is FRAME GARBAGE (non-deterministic across stack - * layouts), so — unlike the deterministic #263 members — the cstage rows - * assert only that cstage DIVERGES (got != the runtime-correct value and the - * build succeeded), not a pinned value. The wwstage rows assert the exact - * runtime-correct value. (#44 closes the cs side → cstage will then match.) - * row | shape | ww | cs - * ----------+-----------------------------------------+----+-------- - * nest_47 | gi:inner=47; (inner|str)=gi; match→v | 47 | != 47 (garbage) - * nest_99 | gi:inner=99; (inner|str)=gi; match→v | 99 | != 99 (garbage) + * Rows assert the exact runtime-correct value on both stages (cs==ww). + * row | shape | exit + * ----------+-----------------------------------------+----- + * nest_47 | gi:inner=47; (inner|str)=gi; match→v | 47 + * nest_99 | gi:inner=99; (inner|str)=gi; match→v | 99 */ #include #include @@ -154,28 +145,16 @@ main(void) drivers[d].name, drivers[d].drv); continue; } - int is_ww = (d == 1); for (int i = 0; i < n; i++) { total++; int got = run_build(drivers[d].drv, &rows[i], i); - if (is_ww) { - /* align-to-runtime-correct: exact value. */ - if (got != rows[i].want_ww) { - fprintf(stderr, "globtagwiden_run[wwstage][%s]:" - " exit=%d want=%d\n", rows[i].label, - got, rows[i].want_ww); - fail++; - } - } else { - /* #263 residual: cstage built but diverges from the - * runtime-correct value (frame garbage, #44). */ - if (got == -1 || got == rows[i].want_ww) { - fprintf(stderr, "globtagwiden_run[cstage][%s]:" - " exit=%d expected build-ok and !=%d " - "(#263 residual, task #44)\n", - rows[i].label, got, rows[i].want_ww); - fail++; - } + /* #44 CLOSED: cs==ww at the exact runtime-correct value + * on both drivers (the .s is byte-identical). */ + if (got != rows[i].want_ww) { + fprintf(stderr, "globtagwiden_run[%s][%s]:" + " exit=%d want=%d\n", drivers[d].name, + rows[i].label, got, rows[i].want_ww); + fail++; } } }