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:
@@ -18819,22 +18819,31 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let ft: *tinfo = tf.type_;
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (typeisstr(ft)) {
|
||||
// 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);
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(tf.offset: i64, "CX");
|
||||
emitdispreg(tf.offset: i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((tf.offset + 8u64): i64, "CX");
|
||||
emitdispreg((tf.offset + 8u64): i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitdispreg((tf.offset + 16u64): i64, "DX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -4991,22 +4991,31 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let ft: *tinfo = tf.type_;
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (typeisstr(ft)) {
|
||||
// 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);
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(tf.offset: i64, "CX");
|
||||
emitdispreg(tf.offset: i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((tf.offset + 8u64): i64, "CX");
|
||||
emitdispreg((tf.offset + 8u64): i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitdispreg((tf.offset + 16u64): i64, "DX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -18819,22 +18819,31 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let ft: *tinfo = tf.type_;
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
if (typeisstr(ft)) {
|
||||
// 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);
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, base);
|
||||
emitline("\tMOVQ\tAX, CX\n");
|
||||
emitline("\tMOVQ\tAX, DX\n");
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(tf.offset: i64, "CX");
|
||||
emitdispreg(tf.offset: i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((tf.offset + 8u64): i64, "CX");
|
||||
emitdispreg((tf.offset + 8u64): i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitdispreg((tf.offset + 16u64): i64, "DX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user