wcc/ww: store through a *tagged pointer widens, both stages (#17)
The N_UN/TK_STAR plain-deref assign arm fell to a single fldstoreop for every pointee, so `*p = v` with p:*tagged wrote the rhs into the tag word and never the payload -- identically in both stages, leaving the byte-id gate green while the store corrupted the tag (#263-class, gate-blind). Gate on TY_TAGGED and route through cg_widen_tagged_store into a scratch slot, then word-copy to the destination -- the proven runtime-index arm. Scalar pointees keep the single-store path unchanged.
This commit is contained in:
@@ -7038,6 +7038,33 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
Type *pu = type_chase_named(pt);
|
||||
Type *vt = (pu && pu->kind == TY_PTR) ? pu->sub : NULL;
|
||||
vt = type_chase_named(vt);
|
||||
/* #17: tagged-union pointee. The scalar tail below stores
|
||||
* only the first 8B (fldstoreop MOVQ) — rhs lands in the
|
||||
* tag word and the payload is dropped, corrupting the
|
||||
* union. Materialise the widened value (tag + payload
|
||||
* words, nullable fold, tag remap) into a tag scratch via
|
||||
* cg_widen_tagged_store, then word-copy scratch → *p.
|
||||
* Mirrors the index-element tagged arm (cgen.c:6487-6531);
|
||||
* the dest is just the pointer, so no base-addr dance. */
|
||||
if (vt && vt->kind == TY_TAGGED) {
|
||||
int ssz = (int)vt->size;
|
||||
int scr = cg_tagscr_slot(c, &locals, ssz);
|
||||
ins2(c, A_XORQ, areg(D_AX), areg(D_AX));
|
||||
for (int k = 0; k < ssz; k += 8)
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, scr + k));
|
||||
cg_widen_tagged_store(c, &locals, vt, n->rhs,
|
||||
D_BP, scr, ssz);
|
||||
cgexpr(c, n->lhs->lhs, locals); /* AX = pointer */
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_BX));
|
||||
for (int k = 0; k < ssz; k += 8) {
|
||||
ins2(c, A_MOVQ, amem(D_BP, scr + k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* `*p = v` for *f64 / *f32: cgexpr leaves the value in X0,
|
||||
* not AX. Spill X0 to the stack, evaluate the pointer
|
||||
* (clobbers AX/BX freely), then reload X0 and MOVSD/MOVSS
|
||||
|
||||
Reference in New Issue
Block a user