wcc_ww/cgen: #101 narrow-alias fill-stride via aliasprimsize SSoT

A struct-literal array fill sized a narrow-alias element off a bare
primsize(name): `type my32 = u32` gave primsize("my32")=0, so the
element width defaulted to 8 and a [3]my32 strode MOVQ -24/-16/-8 —
field n collided with arr[2] (kw1_101 run exit 1). cstage chases
my32->u32->4 (MOVL stride-4) at the twin sites and is runtime-correct;
this is a ww-only align-up, cs untouched.

Fix: a new aliasprimsize(c, nm) SSoT helper — primsize(nm), else an
aliaslookup-chase N_TNAME loop then primsize — and route the SIZE-use
primsize() family through it. The 7 c-bearing bare-no-chase size-use
sites are routed: cgen:993 (letemitsize), cgenstmt:1896 (cgarrlitfillbp),
cgenutil:1579 (elemsizeofc fallback)/1657+1665 (nodeprimwidth)/4791
(cgstructlitfill = the kw1_101 site), cgenexpr:6902 (cgcall vararg esz).
This is the rule-13 close-by-construction shape (one accessor for
"resolved primitive size"), not a per-site patch.

kw1_101 is the SOLE asm mover (byte-id NO->YES, run 1->0, MOVL
stride-4); every other routed site is latent/byte-neutral. Bootstrap:
all 5 combined units stay w6c==w6c_ww byte-identical. sizelint 0,
peellint 0, test-unit 296/296.

Scope fence (rob route-7-decline-6 ruling): three DESIGNED-exemption
sites carry inline primsize-ok annotations — elemsizeof :1475/:1499 and
paramfieldsize :3541 are structural (no-`c`, non-chasing) BY DESIGN;
their alias-chasing twin elemsizeofc is the routed :1579 leg. These are
the #109 peellint-whitelist seeds. Three further declines are already
correct chasing paths, not bare-no-chase bug shapes (typenodeprimresolved
:2026 / exprprimresolved :2063 are the chase machinery itself; cgassign
:7631 already chases via typenodeprimresolved, #11). The ~17 GUARD sites
(is-primitive dispatch) + the peellint finale are the committed #109
follow-on. Threading `c` into the structural sizers is dormant #110.

#101
This commit is contained in:
2026-06-06 10:04:37 +09:00
parent c9cfa52624
commit 45f5415209
7 changed files with 159 additions and 21 deletions

View File

@@ -402,6 +402,36 @@ static const struct row rows[] = {
" if (xs[0]: i64 + xs[1]: i64 + xs[2]: i64 != 18) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
/* #101: NARROW-alias struct-FILL stride (the cgstructlitfill
* :4791 leg, twin of esub_2lvl's INDEX leg). Pre-fold ww sized
* the [3]my32 element off primsize("my32")=0 → 8B-default stride,
* so the fill stored at -24/-16/-8 and field n collided with
* arr[2] (run exit 1); cs chased my32→u32→4 (MOVL stride-4). The
* aliasprimsize route aligns ww UP — kw1_101 was the SOLE corpus
* mover (cs0/ww1 byteid-NO → byteid-YES + run 0). */
{ "kw1_101",
"package main;\n"
"type my32 = u32;\n"
"type S = struct { arr: [3]my32, n: int };\n"
"export fn main() i32 = {\n"
" let s = S { arr = [10u32, 20u32, 30u32], n = 4 };\n"
" if (s.arr[0] + s.arr[1] + s.arr[2] != 60u32) { return 1; };\n"
" if (s.n != 4) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
/* #101 control: a DIFFERENT narrow width (u16, stride-2 MOVW)
* proves the routed esz is width-general, not a 4-only patch.
* fld n must survive the fill untouched. */
{ "kw1_ctl16",
"package main;\n"
"type my16 = u16;\n"
"type S2 = struct { arr: [4]my16, n: int };\n"
"export fn main() i32 = {\n"
" let s = S2 { arr = [1u16, 2u16, 3u16, 4u16], n = 9 };\n"
" if (s.arr[0] + s.arr[1] + s.arr[2] + s.arr[3] != 10u16) { return 1; };\n"
" if (s.n != 9) { return 1; };\n"
" return 0;\n"
"};\n", 0, 0, K_RUN, NULL, NULL },
/* ---- c4: cast/is/try family */
{ "strcast_2lvl",
"package main;\n"