w6c: tagged GLOBAL reassign emits the store
cstage silently dropped the store on reassigning a module-global tagged union; mirror the landed wwstage emission (tag+payload to g(SB) via the widener). Closes the cs half of the F8 #263 pair; the repro row flips to cs==ww==correct. Task #41.
This commit is contained in:
@@ -6909,7 +6909,27 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
if (!rhs_sret_call) {
|
if (!rhs_sret_call) {
|
||||||
int off = localfind(locals,
|
int off = localfind(locals,
|
||||||
n->lhs->str);
|
n->lhs->str);
|
||||||
if (off == 0) break;
|
if (off == 0) {
|
||||||
|
/* #41 (#263): a module-global
|
||||||
|
* tagged ident has no BP slot —
|
||||||
|
* LEAQ g(SB),BX then store
|
||||||
|
* tag+payload off BX (mirror the
|
||||||
|
* global-struct-field tagged arm
|
||||||
|
* above + the local arm below).
|
||||||
|
* Pre-fix this break dropped the
|
||||||
|
* store entirely; ww half landed
|
||||||
|
* in F8-c5. */
|
||||||
|
if (let_islet(n->lhs->str)) {
|
||||||
|
ins2(c, A_LEAQ,
|
||||||
|
masym(c, n->lhs->str),
|
||||||
|
areg(D_BX));
|
||||||
|
cg_widen_tagged_store(c,
|
||||||
|
&locals, lu, n->rhs,
|
||||||
|
D_BX, 0,
|
||||||
|
(int)lu->size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
cg_widen_tagged_store(c, &locals, lu,
|
cg_widen_tagged_store(c, &locals, lu,
|
||||||
n->rhs, D_BP, off, (int)lu->size);
|
n->rhs, D_BP, off, (int)lu->size);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -3,29 +3,20 @@
|
|||||||
* module-GLOBAL tagged-union ident (`g = expr`) must store the new tag and
|
* module-GLOBAL tagged-union ident (`g = expr`) must store the new tag and
|
||||||
* payload, not clobber only one word.
|
* payload, not clobber only one word.
|
||||||
*
|
*
|
||||||
* THE BUG (cat-A silent miscompile, #263 BOTH-WRONG): cgenexpr.ww cgassign's
|
* THE BUG (cat-A silent miscompile, #263 BOTH-WRONG, now CLOSED both stages):
|
||||||
* tagged-union reassignment arm delegated to cgwidentaggedstore ONLY for a
|
* cgassign's tagged-union reassignment arm delegated to the widener ONLY for a
|
||||||
* LOCAL ident (localfindnode != nil). A module-global tagged ident (lc==nil)
|
* LOCAL ident. A module-global tagged ident had no arm and fell through to the
|
||||||
* had no arm and fell through to the generic scalar store, which wrote one
|
* generic scalar store (wwstage clobbered the tag word; cstage dropped the
|
||||||
* word into the tag slot and left the payload stale. cstage is ALSO wrong:
|
* store entirely). The ww half landed in F8-c5; the cstage half (LEAQ g(SB),BX
|
||||||
* it drops the store entirely (the new value never reaches g) — so the repro
|
* then cg_widen_tagged_store off BX) landed in ww-core TASK #41 — both stages
|
||||||
* is cs≠ww residual until the cstage half lands (ww-core TASK #41).
|
* now store the full box and the .s is byte-identical.
|
||||||
*
|
*
|
||||||
* THE WWSTAGE FIX (ww-runtime-correct): add the lc==nil arm — LEAQ g(SB),BX
|
* Rows (cs==ww after the cstage half landed):
|
||||||
* then cgwidentaggedstore stores tag+payload off BX (mirrors the local arm
|
* row | shape | exit
|
||||||
* and the global-struct-field tagged arm). ww now stores the full box.
|
* ----------------+----------------------------------------+-----
|
||||||
* cstage stays wrong → the rows assert ww-correct AND pin cstage's
|
* reassign_i64 | g:(i64|void)=0; g=7; match i64 | 7
|
||||||
* documented-wrong value (store dropped → g keeps its init), so the residual
|
* reassign_str | g:(str|i64)=0; g="hello"; match str→len | 5
|
||||||
* is never misread as a regression.
|
* reassign_union | g:(i64|bool)=0; g=5; match i64 | 5
|
||||||
*
|
|
||||||
* Rows (per-driver expected — want_cs / want_ww):
|
|
||||||
* row | shape | cs | ww
|
|
||||||
* ----------------+----------------------------------------+----+----
|
|
||||||
* reassign_i64 | g:(i64|void)=0; g=7; match i64 | 0 | 7
|
|
||||||
* reassign_str | g:(str|i64)=0; g="hello"; match str→len | 88 | 5
|
|
||||||
* reassign_union | g:(i64|bool)=0; g=5; match i64 | 0 | 5
|
|
||||||
* (cstage drops the store → g keeps its init → the i64/void/i64-tag arm;
|
|
||||||
* #41 closes the cs side, at which point these become cs==ww.)
|
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -61,7 +52,7 @@ static const struct row rows[] = {
|
|||||||
" case void => return 99;\n"
|
" case void => return 99;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"};\n",
|
"};\n",
|
||||||
0, 7 },
|
7, 7 },
|
||||||
|
|
||||||
{ "reassign_str",
|
{ "reassign_str",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
@@ -73,7 +64,7 @@ static const struct row rows[] = {
|
|||||||
" case i64 => return 88;\n"
|
" case i64 => return 88;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"};\n",
|
"};\n",
|
||||||
88, 5 },
|
5, 5 },
|
||||||
|
|
||||||
{ "reassign_union",
|
{ "reassign_union",
|
||||||
"package main;\n"
|
"package main;\n"
|
||||||
@@ -85,7 +76,7 @@ static const struct row rows[] = {
|
|||||||
" case bool => return 77;\n"
|
" case bool => return 77;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"};\n",
|
"};\n",
|
||||||
0, 5 },
|
5, 5 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* run_build — build+run `src` via `driver`; returns the binary's exit
|
/* run_build — build+run `src` via `driver`; returns the binary's exit
|
||||||
|
|||||||
Reference in New Issue
Block a user