w6c+wwstage: aggregate let-init copy for ident-array/N_DOT/N_INDEX rhs (#268 fold-1b) — close addressable-rhs copy family

#265 fold-1 landed the deref-rhs aggregate copy as one slot→slot memcpy
loop fed from a source address in SI. fold-1b adds the remaining
addressable-rhs source-address setups, all routed into that SAME loop:

  - array IDENT `let c: [N]T = s`  — LEAQ the source slot into SI.
    Pre-fix both stages truncated to the 8B scalar tail.
  - N_DOT field `let c: A = o.i`   — cg_dotchain_addr / dotchainaddr
    (#253) lands &(o.i) in SI. Pre-fix truncated to 8B.
  - N_INDEX element `let c: A = a[i]` — the &base[i] spine (#252:
    scaled index + LEAQ base) lands the element address in SI. Pre-fix
    scalar-loaded the element address as a value → segfault.

Size (the #254 non-slot-padded ABI extent) comes from the declared let
type for every shape (lu->size / structabisize|tinfo.size), independent
of the rhs; only the per-rhs address setup differs. The deref arm
becomes one branch of the unified arm. Struct-IDENT keeps its own #32
slot-copy arm above (unchanged). With those, the whole addressable-rhs
let-init-copy family is closed by construction: struct-ident / array-
ident / deref / N_DOT / N_INDEX all full-copy, both stages byte-identical
(rule-10).

949 gains 9 full-readback rows (every member written distinct + summed,
so a partial copy fails): array-ident 16B/32B + 12B(MOVL)/11B(MOVW+MOVB)
tails; N_DOT struct-field 16B + array-field 32B + 11B-tail struct field;
N_INDEX struct element 16B/32B. The N_INDEX source array is populated
through a `*inner` to `&a[i]` (the #135/#252 store path) because the
array-of-struct element direct store (`a[i].m[j]=v` / `a[i]=s` / struct-
array literal) segfaults on a SEPARATE pre-existing bug, reported
alongside this fold. w6c+wwdump combined.ww regen (#110). 70/70 949,
test-unit 241, sizelint, smoke green.
This commit is contained in:
2026-06-02 11:22:01 +09:00
parent dfa9771f42
commit bb2f4e1dfe
5 changed files with 517 additions and 140 deletions

View File

@@ -822,6 +822,114 @@ static const struct row rows[] = {
" return (c[0]+c[1]+c[2]+c[3]+c[4]+c[5]\n"
" +c[6]+c[7]+c[8]+c[9]+c[10]): i32;\n"
"};\n", 66, 1 },
/* #265 fold-1b (#268) the remaining addressable-rhs aggregate let-
* init copy axes, all routed through the SAME memcpy loop as the
* deref rows above via a per-rhs source-address setup: an array
* IDENT `= s` (LEAQ slot), an N_DOT field `= o.i` (cg_dotchain_addr),
* an N_INDEX element `= a[i]` (the &base[i] spine). Pre-fix array-
* ident/N_DOT truncated to the first 8B and N_INDEX scalar-loaded the
* element address (segfault); both stages converged on the full copy
* (rule-10, byteid=1). Each row writes DISTINCT values to ALL members
* and sums EVERY member back, so a truncated/partial copy fails. With
* the deref rows + the #32 struct-ident arm this closes the whole
* addressable-rhs let-init-copy family: struct-ident / array-ident /
* deref / N_DOT / N_INDEX. The N_INDEX source array is populated
* through a `*inner` to `&a[i]` (the #135/#252 store path), NOT the
* array-of-struct-element direct store (`a[i].m[j]=v` / `a[i]=s`),
* which segfaults on a SEPARATE pre-existing bug reported alongside
* this fold; the populate stays off that path so the row isolates the
* copy. */
{ "ai_array16",
"package main;\n"
"export fn main() i32 = {\n"
" let s: [4]u32;\n"
" s[0]=11u32; s[1]=22u32; s[2]=33u32; s[3]=44u32;\n"
" let c: [4]u32 = s;\n"
" return (c[0]+c[1]+c[2]+c[3]): i32;\n"
"};\n", 110, 1 },
{ "ai_array32",
"package main;\n"
"export fn main() i32 = {\n"
" let s: [8]u32;\n"
" s[0]=1u32; s[1]=2u32; s[2]=3u32; s[3]=4u32;\n"
" s[4]=5u32; s[5]=6u32; s[6]=7u32; s[7]=8u32;\n"
" let c: [8]u32 = s;\n"
" return (c[0]+c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]): i32;\n"
"};\n", 36, 1 },
{ "ai_tail12",
"package main;\n"
"export fn main() i32 = {\n"
" let s: [3]u32;\n"
" s[0]=7u32; s[1]=8u32; s[2]=9u32;\n"
" let c: [3]u32 = s;\n"
" return (c[0]+c[1]+c[2]): i32;\n"
"};\n", 24, 1 },
{ "ai_tail11",
"package main;\n"
"export fn main() i32 = {\n"
" let s: [11]u8;\n"
" s[0]=1u8; s[1]=2u8; s[2]=3u8; s[3]=4u8; s[4]=5u8;\n"
" s[5]=6u8; s[6]=7u8; s[7]=8u8; s[8]=9u8; s[9]=10u8;\n"
" s[10]=11u8;\n"
" let c: [11]u8 = s;\n"
" return (c[0]+c[1]+c[2]+c[3]+c[4]+c[5]\n"
" +c[6]+c[7]+c[8]+c[9]+c[10]): i32;\n"
"};\n", 66, 1 },
{ "dot_struct16",
"package main;\n"
"type inner = struct { m: [4]u32 };\n"
"type outer = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let o: outer;\n"
" o.i.m[0]=10u32; o.i.m[1]=20u32; o.i.m[2]=30u32; o.i.m[3]=40u32;\n"
" let c: inner = o.i;\n"
" return (c.m[0]+c.m[1]+c.m[2]+c.m[3]): i32;\n"
"};\n", 100, 1 },
{ "dot_arr32",
"package main;\n"
"type outer = struct { o: [8]u32 };\n"
"export fn main() i32 = {\n"
" let x: outer;\n"
" x.o[0]=1u32; x.o[1]=2u32; x.o[2]=3u32; x.o[3]=4u32;\n"
" x.o[4]=5u32; x.o[5]=6u32; x.o[6]=7u32; x.o[7]=8u32;\n"
" let c: [8]u32 = x.o;\n"
" return (c[0]+c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]): i32;\n"
"};\n", 36, 1 },
{ "dot_tail11",
"package main;\n"
"type inner = struct { m: [11]u8 };\n"
"type outer = struct { i: inner };\n"
"export fn main() i32 = {\n"
" let o: outer;\n"
" o.i.m[0]=1u8; o.i.m[1]=2u8; o.i.m[2]=3u8; o.i.m[3]=4u8;\n"
" o.i.m[4]=5u8; o.i.m[5]=6u8; o.i.m[6]=7u8; o.i.m[7]=8u8;\n"
" o.i.m[8]=9u8; o.i.m[9]=10u8; o.i.m[10]=11u8;\n"
" let c: inner = o.i;\n"
" return (c.m[0]+c.m[1]+c.m[2]+c.m[3]+c.m[4]+c.m[5]\n"
" +c.m[6]+c.m[7]+c.m[8]+c.m[9]+c.m[10]): i32;\n"
"};\n", 66, 1 },
{ "idx_struct16",
"package main;\n"
"type inner = struct { m: [4]u32 };\n"
"export fn main() i32 = {\n"
" let a: [2]inner;\n"
" let p: *inner = &a[1];\n"
" p.m[0]=10u32; p.m[1]=20u32; p.m[2]=30u32; p.m[3]=40u32;\n"
" let c: inner = a[1];\n"
" return (c.m[0]+c.m[1]+c.m[2]+c.m[3]): i32;\n"
"};\n", 100, 1 },
{ "idx_struct32",
"package main;\n"
"type inner = struct { m: [8]u32 };\n"
"export fn main() i32 = {\n"
" let a: [2]inner;\n"
" let p: *inner = &a[1];\n"
" p.m[0]=1u32; p.m[1]=2u32; p.m[2]=3u32; p.m[3]=4u32;\n"
" p.m[4]=5u32; p.m[5]=6u32; p.m[6]=7u32; p.m[7]=8u32;\n"
" let c: inner = a[1];\n"
" return (c.m[0]+c.m[1]+c.m[2]+c.m[3]\n"
" +c.m[4]+c.m[5]+c.m[6]+c.m[7]): i32;\n"
"};\n", 36, 1 },
{ NULL, NULL, 0, 0 }
};