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:
@@ -8763,6 +8763,49 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* #265 fold-1: aggregate deref-rhs let-init
|
||||
* `let c: T = *p` (T a struct or array, >8B). Neither
|
||||
* the scalar tail below (one 8B word) nor a missing arm
|
||||
* (cstage dropped the copy entirely) materialised the
|
||||
* whole aggregate. cgexpr(rhs->lhs) leaves the SOURCE
|
||||
* ADDRESS in AX (a `*p` ident loads the pointer value;
|
||||
* `*(&s)` LEAQs the slot); memcpy sz bytes slot→slot via
|
||||
* SI — a MOVQ run plus a sized MOVL/MOVW/MOVB tail. N is
|
||||
* lu->size (sz), the #254 non-slot-padded ABI extent. Both
|
||||
* stages emit this identical sequence (rule-10); the by-
|
||||
* value RETURN ABI is fold-2 (#267). */
|
||||
if (n->rhs && n->rhs->kind == N_UN
|
||||
&& n->rhs->op == TK_STAR && lu
|
||||
&& (lu->kind == TY_STRUCT || lu->kind == TY_ARRAY)
|
||||
&& sz > 8) {
|
||||
cgexpr(c, n->rhs->lhs, *locals);
|
||||
ins2(c, A_MOVQ, areg(D_AX), areg(D_SI));
|
||||
int k = 0;
|
||||
for (; k + 8 <= sz; k += 8) {
|
||||
ins2(c, A_MOVQ, amem(D_SI, k), areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, off + k));
|
||||
}
|
||||
if (k + 4 <= sz) {
|
||||
ins2(c, A_MOVL, amem(D_SI, k), areg(D_AX));
|
||||
ins2(c, A_MOVL, areg(D_AX),
|
||||
amem(D_BP, off + k));
|
||||
k += 4;
|
||||
}
|
||||
if (k + 2 <= sz) {
|
||||
ins2(c, A_MOVW, amem(D_SI, k), areg(D_AX));
|
||||
ins2(c, A_MOVW, areg(D_AX),
|
||||
amem(D_BP, off + k));
|
||||
k += 2;
|
||||
}
|
||||
if (k + 1 <= sz) {
|
||||
ins2(c, A_MOVB, amem(D_SI, k), areg(D_AX));
|
||||
ins2(c, A_MOVB, areg(D_AX),
|
||||
amem(D_BP, off + k));
|
||||
k += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (n->rhs && sz == 8) {
|
||||
cgexpr(c, n->rhs, *locals);
|
||||
if (isf) {
|
||||
|
||||
Reference in New Issue
Block a user