w6c+wwstage: [N]struct literal element store (#270-1c)
`let x: [2]inner = [inner{..}, inner{..}]` left the array unpopulated:
the N_ARRLIT per-element store handled scalar/str/float ONLY, so a
struct/array/tuple element hit the multi-word-store gap and stored just
the first 8 bytes (cs0/ww0). Both stages symmetric-broken; converge on
the populated result (#263).
Fix: an aggregate element of an array literal fills each element slot
from its source — cg_structlit_fill_bp for an N_STRUCTLIT element,
word-copy for an N_IDENT element (reusing COMMIT 2's per-element copy
shape). esz is the element's natural size (cstage esub->size). cgen.c
N_ARRLIT arm + cgenstmt.ww cglet. An aggregate `...` repeat and other
element shapes hard-stop loud (rule-7).
949 rows: arrlit_structlit, arrlit_structident (8B struct, byteid=1,
full readback). All 96 pass; test-unit 241 green; smoke OK.
This commit is contained in:
@@ -8783,6 +8783,15 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
&& lu->kind == TY_ARRAY) {
|
||||
Type *esub = lu->sub;
|
||||
int esz = esub ? (int)esub->size : 1;
|
||||
/* #270-1c: an AGGREGATE (struct/array/tuple) element
|
||||
* of an array literal — the scalar per-element MOVQ
|
||||
* below stores only the first 8 bytes (unpopulated
|
||||
* tail). Fill each element slot from its literal
|
||||
* (cg_structlit_fill_bp) or source ident (word-copy). */
|
||||
Type *esubu = type_chase_named(esub);
|
||||
int is_agg = esubu && (esubu->kind == TY_STRUCT
|
||||
|| esubu->kind == TY_ARRAY
|
||||
|| esubu->kind == TY_TUPLE);
|
||||
int is_str_el = type_isstr(esub);
|
||||
/* float element → store FROM X0; the AX path stores
|
||||
* raw double low-bits, garbage for f32 (#122, twin of
|
||||
@@ -8810,8 +8819,60 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
repeat = 1;
|
||||
break;
|
||||
}
|
||||
cgexpr(c, e, *locals);
|
||||
int base = off + idx * esz;
|
||||
if (is_agg) {
|
||||
if (e->kind == N_STRUCTLIT) {
|
||||
cg_structlit_fill_bp(c, locals,
|
||||
esubu, e, base);
|
||||
} else if (e->kind == N_IDENT) {
|
||||
int soff = localfind(*locals,
|
||||
e->str);
|
||||
int k = 0;
|
||||
for (; k + 8 <= esz; k += 8) {
|
||||
ins2(c, A_MOVQ,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ,
|
||||
areg(D_AX),
|
||||
amem(D_BP, base + k));
|
||||
}
|
||||
if (k + 4 <= esz) {
|
||||
ins2(c, A_MOVL,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVL,
|
||||
areg(D_AX),
|
||||
amem(D_BP, base + k));
|
||||
k += 4;
|
||||
}
|
||||
if (k + 2 <= esz) {
|
||||
ins2(c, A_MOVW,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVW,
|
||||
areg(D_AX),
|
||||
amem(D_BP, base + k));
|
||||
k += 2;
|
||||
}
|
||||
if (k + 1 <= esz) {
|
||||
ins2(c, A_MOVB,
|
||||
amem(D_BP, soff + k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVB,
|
||||
areg(D_AX),
|
||||
amem(D_BP, base + k));
|
||||
k += 1;
|
||||
}
|
||||
} else {
|
||||
fatal("#270-1c: array-literal "
|
||||
"aggregate element shape "
|
||||
"unsupported (rule-7)");
|
||||
}
|
||||
last = e;
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
cgexpr(c, e, *locals);
|
||||
if (is_str_el) {
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BP, base));
|
||||
@@ -8827,6 +8888,9 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
||||
last = e;
|
||||
idx++;
|
||||
}
|
||||
if (repeat && is_agg)
|
||||
fatal("#270-1c: `...` repeat of an aggregate "
|
||||
"array-literal element not wired (rule-7)");
|
||||
if (repeat && last) {
|
||||
/* fill remaining slots with the value still in
|
||||
* AX (and BX for str). */
|
||||
|
||||
Reference in New Issue
Block a user