cgen: str chained <expr>.field = v store -> 3-word -- Phase 2 G2 (both stages)
Storing a str into a field reached through a *struct-valued expression (e.g. r.sym.flag = v) wrote only 2 words (ptr,len), dropping cap -- the second STORE-cluster fold. Direct transfer of G1 (c692923): the prior arm spilled only ptr/len across the base eval; now spill the full value (PUSHQ CX/BX/AX) after the rhs eval and before the base-expr eval (the stack slot insulates it, base-formation-agnostic), stage the *struct ptr in DX (off the AX/BX/CX str convention), store ptr/len/cap at foff+{0,8,16}. Mirrors the s.f=v oracle (cgen.c:2603); G2 adds the spill the oracle skips because the oracle's base is a slot read, not a clobbering expr. Kind-gated (TY_STR/typeisstr, never size==24). cstage==wwstage byte-identical at the store site.
test/wcc/938: table-driven write-then-read-cap over depth-2 (r.sym.f=) and depth-3 (r.a.b.f=) chained bases, both asm-confirmed to hit the chained arm. rhs is a cap!=len str; all 3 slot words pre-poisoned via a non-G2 direct store; full {ptr,len,cap} triple asserted. fail-before/pass-after verified on both drivers.
main.combined.ww regenerated via the canonical make path (md5-stable).
This commit is contained in:
@@ -3140,21 +3140,30 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
break;
|
||||
}
|
||||
if (fu && fu->kind == TY_STR) {
|
||||
/* str rhs: (AX=ptr, BX=len). Stash
|
||||
* both, then load the struct ptr
|
||||
* into CX and write both halves. */
|
||||
/* str IS []u8: rhs leaves AX=ptr,
|
||||
* BX=len, CX=cap (#1/Phase 3). Spill
|
||||
* all three across the base-expr eval
|
||||
* (it may clobber any reg), stage the
|
||||
* *struct ptr 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, areg(D_AX));
|
||||
cgexpr(c, n->lhs->lhs, locals);
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
areg(D_CX));
|
||||
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));
|
||||
} else {
|
||||
cgexpr(c, n->rhs, locals);
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
|
||||
Reference in New Issue
Block a user