cgen: str arr[i].field = v store -> 3-word -- Phase 2 G1 (both stages)
Storing a str into a field of an indexed element (arr[i].f = v) wrote only 2 words (ptr,len), dropping cap -- the write-side mirror of the arrfield read (c3bbe17), and the first STORE-cluster fold. The trap: the index scale (IMULQ via CX) clobbers CX=cap and the index-expr eval clobbers AX=ptr before the store. Fix composes two proven oracles -- arr[i]=v (cgen.c:3650) spills the value (PUSHQ CX/BX/AX) across the index/address computation, then s.f=v (cgen.c:2603) stages the dst address in DX (off the AX/BX/CX str convention) and stores ptr/len/cap at foff+{0,8,16}. Kind-gated (TY_STR/isstrtype, never size==24). cstage==wwstage byte-identical.
test/wcc/937: table-driven write-then-read-cap over [N]S / []S / [N]*S arr[i].f= ; rhs is a runtime cap!=len str (not a literal, which would be cap==len); all 3 slot words pre-poisoned via a DIFFERENT already-3-word store path so a stale 2-word store is detectable; asserts the full {ptr,len,cap} triple. Meaningful only now the reads are 3-word. fail-before/pass-after verified on both drivers.
main.combined.ww regenerated via the canonical make path (md5-stable).
This commit is contained in:
@@ -2916,11 +2916,21 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
}
|
||||
if (n->op == TK_ASSIGN
|
||||
&& fu && fu->kind == TY_STR) {
|
||||
/* str rhs: AX=ptr, BX=len.
|
||||
* Stash both, compute addr
|
||||
* in CX so the pop pair
|
||||
* restores AX/BX cleanly. */
|
||||
/* str IS []u8: rhs leaves
|
||||
* AX=ptr, BX=len, CX=cap
|
||||
* (#1/Phase 3). Spill all
|
||||
* three across the index/
|
||||
* address computation
|
||||
* (IMULQ's CX scratch
|
||||
* clobbers cap), stage
|
||||
* &arr[i] in DX off the str
|
||||
* AX/BX/CX convention
|
||||
* (mirrors s.f=v), then store
|
||||
* the full triple at
|
||||
* foff+0/+8/+16. */
|
||||
cgexpr(c, n->rhs, locals);
|
||||
ins1(c, A_PUSHQ,
|
||||
areg(D_CX));
|
||||
ins1(c, A_PUSHQ,
|
||||
areg(D_BX));
|
||||
ins1(c, A_PUSHQ,
|
||||
@@ -2937,28 +2947,33 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (is_arr)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP, off),
|
||||
areg(D_CX));
|
||||
areg(D_DX));
|
||||
else
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, off),
|
||||
areg(D_CX));
|
||||
areg(D_DX));
|
||||
ins2(c, A_ADDQ,
|
||||
areg(D_AX),
|
||||
areg(D_CX));
|
||||
areg(D_DX));
|
||||
if (viaptr)
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_CX, 0),
|
||||
areg(D_CX));
|
||||
amem(D_DX, 0),
|
||||
areg(D_DX));
|
||||
ins1(c, A_POPQ,
|
||||
areg(D_AX));
|
||||
ins1(c, A_POPQ,
|
||||
areg(D_BX));
|
||||
ins1(c, A_POPQ,
|
||||
areg(D_CX));
|
||||
ins2(c, A_MOVQ,
|
||||
areg(D_AX),
|
||||
amem(D_CX, foff + 0));
|
||||
amem(D_DX, foff + 0));
|
||||
ins2(c, A_MOVQ,
|
||||
areg(D_BX),
|
||||
amem(D_CX, foff + 8));
|
||||
amem(D_DX, foff + 8));
|
||||
ins2(c, A_MOVQ,
|
||||
areg(D_CX),
|
||||
amem(D_DX, foff + 16));
|
||||
break;
|
||||
}
|
||||
if (n->op == TK_ASSIGN) {
|
||||
|
||||
Reference in New Issue
Block a user