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:
@@ -17870,11 +17870,17 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// str rhs: AX=ptr, BX=len. Stash both,
|
||||
// compute addr in CX so the pop pair
|
||||
// restores AX/BX intact.
|
||||
// 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.
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
@@ -17887,21 +17893,25 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
emitline("(BP), DX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
emitline("(BP), DX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, CX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(CX), CX\n"); };
|
||||
emitline("\tADDQ\tAX, DX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(DX), DX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitdispreg(fi.foff: i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitdispreg((fi.foff + 8): i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitdispreg((fi.foff + 16): i64, "DX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -4042,11 +4042,17 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// str rhs: AX=ptr, BX=len. Stash both,
|
||||
// compute addr in CX so the pop pair
|
||||
// restores AX/BX intact.
|
||||
// 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.
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
@@ -4059,21 +4065,25 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
emitline("(BP), DX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
emitline("(BP), DX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, CX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(CX), CX\n"); };
|
||||
emitline("\tADDQ\tAX, DX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(DX), DX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitdispreg(fi.foff: i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitdispreg((fi.foff + 8): i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitdispreg((fi.foff + 16): i64, "DX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -17870,11 +17870,17 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
// str rhs: AX=ptr, BX=len. Stash both,
|
||||
// compute addr in CX so the pop pair
|
||||
// restores AX/BX intact.
|
||||
// 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.
|
||||
if (isstrtype(c, fi.tnode)) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tCX\n");
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
cgexpr(c, idx);
|
||||
@@ -17887,21 +17893,25 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
emitline("(BP), DX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), CX\n");
|
||||
emitline("(BP), DX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, CX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(CX), CX\n"); };
|
||||
emitline("\tADDQ\tAX, DX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(DX), DX\n"); };
|
||||
emitline("\tPOPQ\tAX\n");
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
emitline("\tPOPQ\tCX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitdispreg(fi.foff: i64, "CX");
|
||||
emitdispreg(fi.foff: i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitdispreg((fi.foff + 8): i64, "CX");
|
||||
emitdispreg((fi.foff + 8): i64, "DX");
|
||||
emitline("\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitdispreg((fi.foff + 16): i64, "DX");
|
||||
emitline("\n");
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user