cgen+test: copy struct >8B local-ident rhs in N_LET (#32)
let p2: T = p1; where T is a struct >8B and rhs is a local ident
silently dropped most of the copy. Cstage's N_LET fell past every
specialized rhs branch (str/tuple/tagged/structlit/call) without
matching the bare-ident case, then past the sz==8 fallback (false)
to the no-rhs zero-init (false: rhs present), emitting zero
instructions — the dest slot read fresh-stack zeros. Wwstage's
cglet fell to cgexpr+MOVQ AX which loads only the first qword
(cgident shape for struct ident), and for sz==16 slots the
str-init tail then stored a stale BX into +8. Reads after the
let saw whatever the stack held: silent partial copy.
Both stages now byte-copy src slot → dst slot per qword with
a sized tail (MOVL/MOVB) for natural sizes not 8-aligned.
Mirrors cg_widen_tagged_store's struct-ident payload copy.
744_letcopy_struct pins the four struct shapes (3×i32, i32+str,
i32+[]u8, i32+tagged) on asm-presence in both stages, cmp -s
byte-id, and runtime exit code via both drivers.
Scope: only N_IDENT rhs at the local-ident-found path. Filed as
siblings (no in-tree consumer today, bootstrap byte-id proves it):
- N_DOT / N_INDEX / N_UN(deref) struct rhs.
- Top-level (non-local) struct ident rhs.
- TY_TUPLE same-shape ident-copy bug.
Row (a) uses tri{a=11, b=22, c=33} structlit init for p1 to
isolate this fix from STATUS-3 #15/#26c (no-rhs zero-init sz=12
vs sz=16 slot-padded divergence between stages, separate task).
Row (d) runtime check uses only p2.a to isolate from match-on-
tagged-field scrutinee spill divergence (same task).
118/118 ok. ww2 == ww3 == ww4 byte-id holds.
This commit is contained in:
@@ -6532,6 +6532,45 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Struct ident copy: `let p2: T = p1;` where T is a struct
|
||||
* >8B and rhs is a local ident. Pre-fix the path fell
|
||||
* through to the `sz == 8` test (false) and emitted
|
||||
* nothing — the dst slot read whatever the stack held,
|
||||
* presenting as a silent zero copy on a fresh frame.
|
||||
* Per-qword MOVQ from src slot to dst slot, with a sized
|
||||
* tail (MOVL/MOVB) for natural sizes that aren't
|
||||
* 8-aligned (e.g. `struct { i32, i32, i32 }` is 12B).
|
||||
* Mirrors the slot-to-slot copy in cg_widen_tagged_store
|
||||
* for a TY_STRUCT payload (Task #32). */
|
||||
if (n->rhs && n->rhs->kind == N_IDENT && lu
|
||||
&& lu->kind == TY_STRUCT && sz > 8) {
|
||||
Local *src_l = NULL;
|
||||
for (Local *l = *locals; l; l = l->next)
|
||||
if (strcmp(l->name, n->rhs->str) == 0) {
|
||||
src_l = l; break;
|
||||
}
|
||||
if (src_l) {
|
||||
int soff = src_l->off;
|
||||
int k = 0;
|
||||
while (k + 8 <= sz) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, soff + k), areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, off + k));
|
||||
k += 8;
|
||||
}
|
||||
if (k < sz) {
|
||||
int tail = sz - k;
|
||||
int lop = (tail == 4) ? A_MOVL :
|
||||
(tail == 1) ? A_MOVB : A_MOVQ;
|
||||
ins2(c, lop,
|
||||
amem(D_BP, soff + k), areg(D_AX));
|
||||
ins2(c, lop, areg(D_AX),
|
||||
amem(D_BP, off + k));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n->rhs && sz == 8) {
|
||||
cgexpr(c, n->rhs, *locals);
|
||||
if (isf) {
|
||||
|
||||
Reference in New Issue
Block a user