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:
@@ -28853,6 +28853,22 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #270-1c: an AGGREGATE (struct/array/tuple) element of
|
||||
// an array literal — the scalar per-element store below
|
||||
// writes only the first 8 bytes (unpopulated tail). Fill
|
||||
// each element slot from its literal (cgstructlitfillbp)
|
||||
// or source ident (word-copy). esz is the element's
|
||||
// natural size (cstage esub->size).
|
||||
let esubti: *tinfo = nil;
|
||||
if (elemn != nil) { esubti = elemn.type_: *tinfo; };
|
||||
for (esubti != nil && esubti.kind == tykind.TY_NAMED) {
|
||||
esubti = esubti.under;
|
||||
};
|
||||
let isagg: bool = esubti != nil
|
||||
&& (esubti.kind == tykind.TY_STRUCT
|
||||
|| esubti.kind == tykind.TY_ARRAY
|
||||
|| esubti.kind == tykind.TY_TUPLE);
|
||||
if (isagg) { esz = esubti.size: i32; };
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
// float element → store FROM X0 (MOVSS/MOVSD): cgexpr
|
||||
// leaves a float in X0 and for f32 the #104 CVTSD2SS
|
||||
@@ -28876,31 +28892,88 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (isstrel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
if (isagg) {
|
||||
if (e.kind == nkind.N_STRUCTLIT) {
|
||||
let esi: *structinfo = structlookupchain(c, elemn);
|
||||
cgstructlitfillbp(c, esi, e, off + idx * esz);
|
||||
} else { if (e.kind == nkind.N_IDENT) {
|
||||
let sl: *local = localfindnode(c, e.str);
|
||||
let soff: i32 = 0;
|
||||
if (sl != nil) { soff = sl.off; };
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= esz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= esz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= esz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= esz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 1;
|
||||
};
|
||||
} else {
|
||||
let m1c: str = "#270-1c: array-literal aggregate element shape unsupported (rule-7)\n";
|
||||
os.write(2, m1c.ptr, m1c.len: u64);
|
||||
os.exit(1);
|
||||
}; };
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
cgexpr(c, e);
|
||||
if (isstrel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat && isagg) {
|
||||
let m1cr: str = "#270-1c: `...` repeat of an aggregate array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m1cr.ptr, m1cr.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// AX (and BX for str) still holds the last stored value;
|
||||
// fill remaining slots up to the declared length with it.
|
||||
if (repeat) {
|
||||
|
||||
@@ -1488,6 +1488,22 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #270-1c: an AGGREGATE (struct/array/tuple) element of
|
||||
// an array literal — the scalar per-element store below
|
||||
// writes only the first 8 bytes (unpopulated tail). Fill
|
||||
// each element slot from its literal (cgstructlitfillbp)
|
||||
// or source ident (word-copy). esz is the element's
|
||||
// natural size (cstage esub->size).
|
||||
let esubti: *tinfo = nil;
|
||||
if (elemn != nil) { esubti = elemn.type_: *tinfo; };
|
||||
for (esubti != nil && esubti.kind == tykind.TY_NAMED) {
|
||||
esubti = esubti.under;
|
||||
};
|
||||
let isagg: bool = esubti != nil
|
||||
&& (esubti.kind == tykind.TY_STRUCT
|
||||
|| esubti.kind == tykind.TY_ARRAY
|
||||
|| esubti.kind == tykind.TY_TUPLE);
|
||||
if (isagg) { esz = esubti.size: i32; };
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
// float element → store FROM X0 (MOVSS/MOVSD): cgexpr
|
||||
// leaves a float in X0 and for f32 the #104 CVTSD2SS
|
||||
@@ -1511,31 +1527,88 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (isstrel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
if (isagg) {
|
||||
if (e.kind == nkind.N_STRUCTLIT) {
|
||||
let esi: *structinfo = structlookupchain(c, elemn);
|
||||
cgstructlitfillbp(c, esi, e, off + idx * esz);
|
||||
} else { if (e.kind == nkind.N_IDENT) {
|
||||
let sl: *local = localfindnode(c, e.str);
|
||||
let soff: i32 = 0;
|
||||
if (sl != nil) { soff = sl.off; };
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= esz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= esz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= esz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= esz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 1;
|
||||
};
|
||||
} else {
|
||||
let m1c: str = "#270-1c: array-literal aggregate element shape unsupported (rule-7)\n";
|
||||
os.write(2, m1c.ptr, m1c.len: u64);
|
||||
os.exit(1);
|
||||
}; };
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
cgexpr(c, e);
|
||||
if (isstrel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat && isagg) {
|
||||
let m1cr: str = "#270-1c: `...` repeat of an aggregate array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m1cr.ptr, m1cr.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// AX (and BX for str) still holds the last stored value;
|
||||
// fill remaining slots up to the declared length with it.
|
||||
if (repeat) {
|
||||
|
||||
@@ -28853,6 +28853,22 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// #270-1c: an AGGREGATE (struct/array/tuple) element of
|
||||
// an array literal — the scalar per-element store below
|
||||
// writes only the first 8 bytes (unpopulated tail). Fill
|
||||
// each element slot from its literal (cgstructlitfillbp)
|
||||
// or source ident (word-copy). esz is the element's
|
||||
// natural size (cstage esub->size).
|
||||
let esubti: *tinfo = nil;
|
||||
if (elemn != nil) { esubti = elemn.type_: *tinfo; };
|
||||
for (esubti != nil && esubti.kind == tykind.TY_NAMED) {
|
||||
esubti = esubti.under;
|
||||
};
|
||||
let isagg: bool = esubti != nil
|
||||
&& (esubti.kind == tykind.TY_STRUCT
|
||||
|| esubti.kind == tykind.TY_ARRAY
|
||||
|| esubti.kind == tykind.TY_TUPLE);
|
||||
if (isagg) { esz = esubti.size: i32; };
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
// float element → store FROM X0 (MOVSS/MOVSD): cgexpr
|
||||
// leaves a float in X0 and for f32 the #104 CVTSD2SS
|
||||
@@ -28876,31 +28892,88 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (isstrel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
if (isagg) {
|
||||
if (e.kind == nkind.N_STRUCTLIT) {
|
||||
let esi: *structinfo = structlookupchain(c, elemn);
|
||||
cgstructlitfillbp(c, esi, e, off + idx * esz);
|
||||
} else { if (e.kind == nkind.N_IDENT) {
|
||||
let sl: *local = localfindnode(c, e.str);
|
||||
let soff: i32 = 0;
|
||||
if (sl != nil) { soff = sl.off; };
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= esz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= esz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= esz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= esz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 1;
|
||||
};
|
||||
} else {
|
||||
let m1c: str = "#270-1c: array-literal aggregate element shape unsupported (rule-7)\n";
|
||||
os.write(2, m1c.ptr, m1c.len: u64);
|
||||
os.exit(1);
|
||||
}; };
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
cgexpr(c, e);
|
||||
if (isstrel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
};
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat && isagg) {
|
||||
let m1cr: str = "#270-1c: `...` repeat of an aggregate array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m1cr.ptr, m1cr.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// AX (and BX for str) still holds the last stored value;
|
||||
// fill remaining slots up to the declared length with it.
|
||||
if (repeat) {
|
||||
|
||||
Reference in New Issue
Block a user