w6c+wwstage: full-size aggregate copy for deref-rhs let-init (#265 fold-1)
A `let c: T = *p` (T a struct or array, >8B) copied no full aggregate: cstage dropped the init entirely (c read garbage); wwstage emitted only the scalar `MOVQ AX,off(BP)` tail (first 8 bytes). Both wrong, differently — converge BOTH stages on a size-driven slot-to-slot memcpy: cgexpr the deref operand to the source address in AX, MOVQ AX,SI, then a MOVQ run plus a sized MOVL/MOVW/MOVB tail over the #254 non-slot-padded ABI extent (lu->size / structabisize for a struct, tinfo.size for an array). Mirror arms in cgen.c N_LET and cgenstmt.ww cglet, byte-identical (rule-10). Unblocks sha256's faithful `let copy = *h`. The by-value aggregate RETURN ABI (array/struct return truncates to AX) is fold-2 (#267, deferred). 949 gains 6 full-readback rows (every member written distinct + summed, so a truncated copy fails): struct{[4]u32} 16B, struct{[8]u32} 32B via both *(&s) and *p (sha256 shape), bare [4]u32, and non-8-mult tails ([3]u32 12B → MOVL, [11]u8 11B → MOVW+MOVB). w6c+wwdump combined.ww regen (#110). 61/61 949, test-unit 240, sizelint, smoke green.
This commit is contained in:
@@ -28858,6 +28858,78 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #265 fold-1: aggregate deref-rhs let-init `let c: T = *p`
|
||||
// (T a struct or array, >8B). cgexpr(rhs.lhs) leaves the
|
||||
// SOURCE ADDRESS in AX (a `*p` ident loads the pointer value;
|
||||
// `*(&s)` LEAQs the slot); memcpy N bytes slot→slot via SI — a
|
||||
// MOVQ run plus a sized MOVL/MOVW/MOVB tail. N is the #254
|
||||
// non-slot-padded ABI extent: structabisize for a struct (=
|
||||
// cstage lu->size), tinfo.size for an array. Pre-fix wwstage
|
||||
// copied only the first 8B (scalar tail below) and cstage
|
||||
// dropped the copy entirely — both wrong; converge on the full
|
||||
// copy (rule-10). Mirror of cstage cgen.c N_LET deref arm; the
|
||||
// by-value RETURN ABI is fold-2 (#267).
|
||||
if (rhs.kind == nkind.N_UN) { if (rhs.op == tkind.TK_STAR) {
|
||||
let ncopy: i32 = 0;
|
||||
let dsi: *structinfo = structlookupchain(c, tn);
|
||||
if (dsi != nil) {
|
||||
ncopy = structabisize(dsi);
|
||||
} else {
|
||||
let dti: *tinfo = nil;
|
||||
if (tn != nil) { dti = tn.type_: *tinfo; };
|
||||
for (dti != nil && dti.kind == tykind.TY_NAMED) {
|
||||
dti = dti.under;
|
||||
};
|
||||
if (dti != nil) {
|
||||
if (dti.kind == tykind.TY_ARRAY) {
|
||||
ncopy = dti.size: i32;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (ncopy > 8) {
|
||||
cgexpr(c, rhs.lhs);
|
||||
emitline("\tMOVQ\tAX, SI\n");
|
||||
let k: i32 = 0;
|
||||
for (k + 8 <= ncopy) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 8;
|
||||
};
|
||||
if (k + 4 <= ncopy) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 4;
|
||||
};
|
||||
if (k + 2 <= ncopy) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 2;
|
||||
};
|
||||
if (k + 1 <= ncopy) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 1;
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
}; };
|
||||
cgexpr(c, rhs);
|
||||
// Float local: cgexpr leaves the value in X0. Spill via
|
||||
// MOVSS (f32, 4B) or MOVSD (f64, 8B).
|
||||
|
||||
@@ -1718,6 +1718,78 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #265 fold-1: aggregate deref-rhs let-init `let c: T = *p`
|
||||
// (T a struct or array, >8B). cgexpr(rhs.lhs) leaves the
|
||||
// SOURCE ADDRESS in AX (a `*p` ident loads the pointer value;
|
||||
// `*(&s)` LEAQs the slot); memcpy N bytes slot→slot via SI — a
|
||||
// MOVQ run plus a sized MOVL/MOVW/MOVB tail. N is the #254
|
||||
// non-slot-padded ABI extent: structabisize for a struct (=
|
||||
// cstage lu->size), tinfo.size for an array. Pre-fix wwstage
|
||||
// copied only the first 8B (scalar tail below) and cstage
|
||||
// dropped the copy entirely — both wrong; converge on the full
|
||||
// copy (rule-10). Mirror of cstage cgen.c N_LET deref arm; the
|
||||
// by-value RETURN ABI is fold-2 (#267).
|
||||
if (rhs.kind == nkind.N_UN) { if (rhs.op == tkind.TK_STAR) {
|
||||
let ncopy: i32 = 0;
|
||||
let dsi: *structinfo = structlookupchain(c, tn);
|
||||
if (dsi != nil) {
|
||||
ncopy = structabisize(dsi);
|
||||
} else {
|
||||
let dti: *tinfo = nil;
|
||||
if (tn != nil) { dti = tn.type_: *tinfo; };
|
||||
for (dti != nil && dti.kind == tykind.TY_NAMED) {
|
||||
dti = dti.under;
|
||||
};
|
||||
if (dti != nil) {
|
||||
if (dti.kind == tykind.TY_ARRAY) {
|
||||
ncopy = dti.size: i32;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (ncopy > 8) {
|
||||
cgexpr(c, rhs.lhs);
|
||||
emitline("\tMOVQ\tAX, SI\n");
|
||||
let k: i32 = 0;
|
||||
for (k + 8 <= ncopy) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 8;
|
||||
};
|
||||
if (k + 4 <= ncopy) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 4;
|
||||
};
|
||||
if (k + 2 <= ncopy) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 2;
|
||||
};
|
||||
if (k + 1 <= ncopy) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 1;
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
}; };
|
||||
cgexpr(c, rhs);
|
||||
// Float local: cgexpr leaves the value in X0. Spill via
|
||||
// MOVSS (f32, 4B) or MOVSD (f64, 8B).
|
||||
|
||||
@@ -28858,6 +28858,78 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #265 fold-1: aggregate deref-rhs let-init `let c: T = *p`
|
||||
// (T a struct or array, >8B). cgexpr(rhs.lhs) leaves the
|
||||
// SOURCE ADDRESS in AX (a `*p` ident loads the pointer value;
|
||||
// `*(&s)` LEAQs the slot); memcpy N bytes slot→slot via SI — a
|
||||
// MOVQ run plus a sized MOVL/MOVW/MOVB tail. N is the #254
|
||||
// non-slot-padded ABI extent: structabisize for a struct (=
|
||||
// cstage lu->size), tinfo.size for an array. Pre-fix wwstage
|
||||
// copied only the first 8B (scalar tail below) and cstage
|
||||
// dropped the copy entirely — both wrong; converge on the full
|
||||
// copy (rule-10). Mirror of cstage cgen.c N_LET deref arm; the
|
||||
// by-value RETURN ABI is fold-2 (#267).
|
||||
if (rhs.kind == nkind.N_UN) { if (rhs.op == tkind.TK_STAR) {
|
||||
let ncopy: i32 = 0;
|
||||
let dsi: *structinfo = structlookupchain(c, tn);
|
||||
if (dsi != nil) {
|
||||
ncopy = structabisize(dsi);
|
||||
} else {
|
||||
let dti: *tinfo = nil;
|
||||
if (tn != nil) { dti = tn.type_: *tinfo; };
|
||||
for (dti != nil && dti.kind == tykind.TY_NAMED) {
|
||||
dti = dti.under;
|
||||
};
|
||||
if (dti != nil) {
|
||||
if (dti.kind == tykind.TY_ARRAY) {
|
||||
ncopy = dti.size: i32;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (ncopy > 8) {
|
||||
cgexpr(c, rhs.lhs);
|
||||
emitline("\tMOVQ\tAX, SI\n");
|
||||
let k: i32 = 0;
|
||||
for (k + 8 <= ncopy) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 8;
|
||||
};
|
||||
if (k + 4 <= ncopy) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 4;
|
||||
};
|
||||
if (k + 2 <= ncopy) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 2;
|
||||
};
|
||||
if (k + 1 <= ncopy) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(k: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
k += 1;
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
}; };
|
||||
cgexpr(c, rhs);
|
||||
// Float local: cgexpr leaves the value in X0. Spill via
|
||||
// MOVSS (f32, 4B) or MOVSD (f64, 8B).
|
||||
|
||||
Reference in New Issue
Block a user