cgen: copy all eightbytes when a non-call aggregate assigns into a field of an indexed element (#11b)
The arr[i].f=src legacy assign block enumerated scalar field-type arms then fell to a 1-word scalar default, so a non-call aggregate source (ident/dot/index) cgexpr'd only its first word into AX and stored one eightbyte — silent on BOTH stages (byte-id blind). The non-indexed bases (local/deref/chained/global) reach the general assign resolver's canonical aggargsrcaddr+aggcopy; the indexed arm short-circuited before it. Route the indexed base through the block's own proven &arr[i] spine into the same aggargsrcaddr+aggcopy emitters (DRY — no third copy), dual-site symmetric. Unlike #11's in-cap arm, the source is a memory address so aggcopy is a pure memcpy: float bits and the sub-8 tail transport verbatim, no loud-stop needed. Did not fall through to the general resolver because its cgplaceaddr N_INDEX arm rejects a *[N]S (TY_PTR) base (latent resolver gap, filed separately). Contained to the indexed base + non-call aggregate-field rhs; value-asserting pins redden under each stage's independent revert.
This commit is contained in:
@@ -10163,6 +10163,78 @@ fn cgassign(c: *cgen, n: *syntax.node) void = {
|
||||
// in AX; the scalar default's MOVQ/MOVL AX
|
||||
// store is the correct 1-word receive.
|
||||
};
|
||||
// #11b: a NON-call AGGREGATE source into an aggregate
|
||||
// field of an indexed element `arr[i].f = src` (src an
|
||||
// ident / .g / index). The scalar default below loads
|
||||
// only the source's FIRST word into AX and stores ONE
|
||||
// word — dropping the rest (a SILENT both-stage member
|
||||
// drop, the non-call twin of the #11 in-cap CALL arm
|
||||
// above; byte-id blind). Unlike #11's GP AX/DX/CX cursor
|
||||
// the source is a MEMORY address, so the shared mem-to-
|
||||
// mem aggcopy transports EVERY byte: a sub-8 tail (MOVL/
|
||||
// MOVW/MOVB) and float bits copy verbatim, so NO tail/
|
||||
// float/over-cap loud-stop is needed here (those #11
|
||||
// stops were register-cursor artefacts). Reuse the
|
||||
// block's own &arr[i] spine (proven for [N]S / *[N]S /
|
||||
// []S by the sibling arms) -> BX + fi.foff, then funnel
|
||||
// through aggargsrcaddr (src -> SI) + aggcopy — the ONE
|
||||
// copy emitter the non-indexed bases use (DRY, rule 8).
|
||||
// tsz natural (fi.fsz, type table). Mirrors cstage cgen.c.
|
||||
if (n.op == syntax.tkind.TK_ASSIGN
|
||||
&& n.rhs != nil
|
||||
&& n.rhs.kind != syntax.nkind.N_CALL) {
|
||||
let fk11b: *syntax.tinfo = tichase(fi.tnode.type_: *syntax.tinfo);
|
||||
let isagg11b: bool = false;
|
||||
if (fk11b != nil) {
|
||||
if (fk11b.kind == syntax.tykind.TY_STRUCT
|
||||
|| fk11b.kind == syntax.tykind.TY_ARRAY
|
||||
|| fk11b.kind == syntax.tykind.TY_TUPLE) {
|
||||
isagg11b = true;
|
||||
};
|
||||
};
|
||||
if (isagg11b) {
|
||||
let tsz11b: i32 = fi.fsz;
|
||||
if (tsz11b > 8) {
|
||||
// &arr[i].f -> BX (verbatim sibling-arm spine)
|
||||
cgexpr(c, idx);
|
||||
if (esz > 1) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(esz: i64);
|
||||
emitline(", CX\n");
|
||||
emitline("\tIMULQ\tCX, AX\n");
|
||||
};
|
||||
if (baseisarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
emitline("(BP), BX\n");
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
if (viaptr) { emitline("\tMOVQ\t(BX), BX\n"); };
|
||||
if (fi.foff != 0) {
|
||||
emitline("\tADDQ\t$");
|
||||
emitint(fi.foff: i64);
|
||||
emitline(", BX\n");
|
||||
};
|
||||
// spill dest across the source-address resolution
|
||||
// (the #270-1b order: aggargsrcaddr clobbers BX).
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
if (!aggargsrcaddr(c, n.rhs, "SI")) {
|
||||
let m11b: str = "#11b: aggregate field receive arr[i].f=src - source shape unwired (rule-7)\n";
|
||||
os.write(2, m11b.ptr, m11b.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
aggcopy(c, tsz11b);
|
||||
return;
|
||||
};
|
||||
// tsz<=8 aggregate: one word, the scalar default's
|
||||
// single store is the correct copy.
|
||||
};
|
||||
};
|
||||
// scalar plain `=`
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
|
||||
Reference in New Issue
Block a user