cstage+selfhost+test: full-element store for [N]str array literals (#21)
[N]str array literals wrote only the .ptr half of each element.
cstage used esz=16 from `lu->sub->size` and a single per-element
MOVQ → .len trailed uninitialized stack residue. Wwstage was worse:
primsize("str")=0 fell through to esz=8, so element i+1's ptr-MOVQ
clobbered element i's .len slot, scrambling everything.
Worker-18 sidestepped during #18 by rewriting array primer rows to
[N]i64.
cstage cgen.c N_ARRLIT TY_STR branch: emit AX → base+i*16 then
BX → base+i*16+8. Repeat-`...` path mirrored. type_isstr handles
TY_UNTYPED_STR + TY_NAMED-aliased-str.
Wwstage cgenstmt.ww: isstrel flag conditionally drives the two-MOVQ
store in both the per-element walk and the repeat fill. The dispatch
loop was refactored to unify FIELD/ellipsis branches via isellip,
cleaning up the duplicated arms.
Wwstage cgenutil.ww slotsize/letslotsize: TNAME-"str" element gets
esz=16, replacing the primsize=0 → 8B fallback. Without this the
frame collapsed to 24B for [3]str.
Slice (24B), struct, tuple, tagged element arrays have the same root
cause but distinct width/layout concerns — deferred to #35 per rob.
Test 711 (arrlit_str_full): 7 rows × 2 stages = 14 fixtures —
str_lens_3el, str_ptrs_3el, str_repeat_5el (TK_ELLIPSIS), bool_3el,
rune_3el, i32_3el, i64_3el. Rune relies on the pre-existing esz==4
→ MOVL path (incidental correctness); sibling slot types pinned as
regression nets.
Followups filed: #34 (wwstage cgindex truncate on [N]str bare-let
read side, surfaced by this fix), #35 (composite element types),
#36 (primsize-returns-0-default-to-8 cleanup).
This commit is contained in:
@@ -1346,8 +1346,15 @@ export fn letslotsize(c: *cgen, n: *node) i32 = {
|
||||
let esz: i32 = 8;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
// Composite primitive: `str` is 16B
|
||||
// (ptr+len) — primsize returns 0 for
|
||||
// it, so it'd slot 8B without this.
|
||||
if (streq(elemn.str, "str")) {
|
||||
esz = 16;
|
||||
} else {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
};
|
||||
let cnt: i32 = 0;
|
||||
@@ -1455,8 +1462,14 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
let en: str = elemn.str;
|
||||
// `str` is a composite primitive (ptr+len, 16B);
|
||||
// primsize returns 0 for it, so without this
|
||||
// explicit case a `[N]str` would slot 8B/elem,
|
||||
// collapsing the per-element stride and losing
|
||||
// every .len half.
|
||||
if (streq(en, "str")) { esz = 16; };
|
||||
let ps: i32 = primsize(en);
|
||||
if (ps > 0) { esz = ps; }
|
||||
if (esz == 8) { if (ps > 0) { esz = ps; }
|
||||
else {
|
||||
// Named struct / aliased type: size off
|
||||
// the structinfo if present, else follow
|
||||
@@ -1473,7 +1486,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
esz = slotsize(c, al);
|
||||
};
|
||||
}; };
|
||||
};
|
||||
}; };
|
||||
} else { if (elemn.kind == nkind.N_TTAGGED) {
|
||||
// Tagged-union element: full slot (8 tag +
|
||||
// padded max payload). Matches C cgen's
|
||||
|
||||
Reference in New Issue
Block a user