wcc+w6c_ww: append() spread place-chain sources via cgplaceaddr (#35)
#35 (fold-5 blocker, PG6): the append() spread arm dispatched on SOURCE node kind — ident-local only; both fold-5 dup shapes loud-rejected on BOTH stages: deref-spine `append(dup, (*tsp)[0].caps...)` (add_thread regex.ha:569/572) and indexed `append(res, ts[0].caps...)` (search ha:820). Route every non-ident-local source through cgplaceaddr (the established place choke-point: C1 stores, C1.25 aggregate fields, FA1 append targets, #49 element sources): the source header ADDRESS resolves ONCE, pre-grow, into a fresh per-site @appsprscr spill, and every loop iteration re-reads .ptr/.len THROUGH the spilled header after the grow. This adapts the #49 split ruling to the spread's full-range copy: the chain's rvalues (deref-root pointer expr, index exprs) evaluate exactly once PRE-grow — an index reading the dst's len sees the pre-append value — while the source data base and len re-derive live each iteration, so a source header aliasing the dst header re-roots post-realloc. A header reached through a buffer the grow reallocs reads the STALE copy — bit-identical under the non-reclaiming rt/malloc, the same documented #49 stale-base hole (pinned by the spread_selfalias_chain row). Ident-local sources keep the legacy BP-disp emission byte-identical. New loudness with the same fix: the spread source's stamped type must chase to TY_SLICE/TY_STR — a [N]T array ident source previously read its first 16 DATA bytes as a {ptr,len} header, silently. Array wiring plus the remaining rvalue sources (CALL, slicing exprs) stay loud, filed task #27. Global-ident sources now resolve on cstage but are blocked by a pre-existing wwstage checker reject ("let: not assignable", task #29) — no dual-stage row until that closes. 806_append_place: reject_spread_src GRADUATES to a runtime row (spread_place_deref, the old reject source verbatim + readback); new rows spread_dup_copy (PG6 verbatim: both fold-5 shapes, 56B capture elements, copy-semantics mutation pin, want 139), spread_place_kinds (str 24B headers / narrow i32 / empty deref source), spread_growth_place (40-elem spread crossing cap doublings), spread_selfalias_chain (source header inside the dst's grown buffer), and the two new loud-tail rejects (CALL rvalue, [N]T array) pinning the "#35:" diagnostic on both stages. 87 fixtures green (was 70), per-row cs/ww asm byte-cmp included. Unblocks regex fold-5a: add_thread regex.ha:569/572 + search ha:820 spreads go from loud-bound to real spread.
This commit is contained in:
@@ -59,8 +59,21 @@
|
||||
* elem_kinds_place | place-resolved SOURCE × every other | 79
|
||||
* | element kind (scalar/narrow/str/slice/ |
|
||||
* | tagged via the pre-existing arms) |
|
||||
* reject_spread_src | non-ident spread SOURCE through a deref | BUILD_FAIL
|
||||
* | target (the #35 designed boundary) |
|
||||
* spread_place_deref | append(*p, (*q)[i].xs...) — the old #35 | 81
|
||||
* | reject source, graduated (cgplaceaddr) |
|
||||
* spread_dup_copy | PG6: deref-spine + indexed 56B-struct | 139
|
||||
* | spread sources (regex.ha:569/820 dup |
|
||||
* | shapes) + copy-semantics pin |
|
||||
* spread_place_kinds | place-sourced spread × str header / | 82
|
||||
* | narrow i32 / empty deref source |
|
||||
* spread_growth_place | 40-elem place-sourced spread crossing | 83
|
||||
* | cap doublings (dst base moves mid-loop) |
|
||||
* spread_selfalias_chain| source header inside the dst's grown | 119
|
||||
* | buffer — #49 stale-base hole pin |
|
||||
* reject_spread_call_src| CALL rvalue spread source — #35 | BUILD_FAIL
|
||||
* | residual (task #27) |
|
||||
* reject_spread_array_src| [N]T array spread source — was a | BUILD_FAIL
|
||||
* | silent 16-byte garbage header read |
|
||||
* reject_call_src | CALL rvalue element source — the #49 | BUILD_FAIL
|
||||
* | loud tail (#42-style bound) |
|
||||
*
|
||||
@@ -596,22 +609,169 @@ static const struct row rows[] = {
|
||||
"};\n",
|
||||
79, NULL },
|
||||
|
||||
/* The FA4 designed boundary (task #35, old #37): a spread SOURCE that is
|
||||
* not an ident local must stay loud even now that the deref
|
||||
* TARGET resolves. */
|
||||
{ "reject_spread_src",
|
||||
/* #35 graduation: the FA4-era designed boundary — a place-chain
|
||||
* spread SOURCE — now resolves through cgplaceaddr (header
|
||||
* address pre-grow, ptr/len re-read through it per iteration).
|
||||
* This row is the OLD reject source verbatim, now with elements
|
||||
* and a readback. */
|
||||
{ "spread_place_deref",
|
||||
"package main;\n"
|
||||
"type holder = struct { tag: i64, xs: []i64 };\n"
|
||||
"fn dup(p: *[]i64, q: *[]holder, i: i64) void = {\n"
|
||||
"\tappend(*p, (*q)[i].xs...);\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet inner: []i64 = [];\n"
|
||||
"\tappend(inner, 5);\n"
|
||||
"\tappend(inner, 9);\n"
|
||||
"\tlet ys: []i64 = [];\n"
|
||||
"\tlet hs: []holder = [];\n"
|
||||
"\tappend(hs, holder { tag = 1, xs = inner });\n"
|
||||
"\tdup(&ys, &hs, 0);\n"
|
||||
"\tif (len(ys) != 2) { return 1; };\n"
|
||||
"\tif (ys[0] != 5 || ys[1] != 9) { return 2; };\n"
|
||||
"\treturn 81;\n"
|
||||
"};\n",
|
||||
81, NULL },
|
||||
|
||||
/* #35, the fold-5 dup shapes (PG6): (a) deref-spine source
|
||||
* `(*tsp)[0].caps...` (add_thread regex.ha:569/572), (b) indexed
|
||||
* source `ts[0].caps...` (search ha:820), 56B struct elements;
|
||||
* plus the COPY-semantics pin — mutating the dup must not touch
|
||||
* the source. */
|
||||
{ "spread_dup_copy",
|
||||
"package main;\n"
|
||||
"type capture = struct {\n"
|
||||
"\tcontent: str,\n"
|
||||
"\tstart: size,\n"
|
||||
"\tstart_bytesize: size,\n"
|
||||
"\tend: size,\n"
|
||||
"\tend_bytesize: size,\n"
|
||||
"};\n"
|
||||
"type thr = struct { pc: size, caps: []capture };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet c0: []capture = [];\n"
|
||||
"\tappend(c0, capture { content = \"x\", start = 3: size, start_bytesize = 3: size, end = 8: size, end_bytesize = 8: size });\n"
|
||||
"\tappend(c0, capture { content = \"yz\", start = 5: size, start_bytesize = 5: size, end = 9: size, end_bytesize = 9: size });\n"
|
||||
"\tlet ts: []thr = [];\n"
|
||||
"\tappend(ts, thr { pc = 0: size, caps = c0 });\n"
|
||||
"\tlet tsp = &ts;\n"
|
||||
"\tlet dup: []capture = [];\n"
|
||||
"\tappend(dup, (*tsp)[0].caps...);\n"
|
||||
"\tif (len(dup) != 2) { return 1; };\n"
|
||||
"\tif (len(dup[1].content) != 2 || dup[1].content[0] != 'y') { return 2; };\n"
|
||||
"\tlet res: []capture = [];\n"
|
||||
"\tappend(res, ts[0].caps...);\n"
|
||||
"\tif (len(res) != 2) { return 3; };\n"
|
||||
"\tif (res[0].end != 8 || res[1].start != 5) { return 4; };\n"
|
||||
"\tdup[0].start = 100: size;\n"
|
||||
"\tif (ts[0].caps[0].start != 3) { return 5; };\n"
|
||||
"\tlet acc = dup[0].start + dup[1].end + res[0].start + res[1].end_bytesize\n"
|
||||
"\t\t+ ts[0].caps[0].end + (len(dup): size) * 5;\n"
|
||||
"\treturn acc: i32;\n"
|
||||
"};\n",
|
||||
139, NULL },
|
||||
|
||||
/* #35 element kinds through a PLACE source: str 24B headers,
|
||||
* narrow i32 (scalar load/store width), and the empty source
|
||||
* (zero-iteration loop) through a deref. */
|
||||
{ "spread_place_kinds",
|
||||
"package main;\n"
|
||||
"type holder = struct { tag: i64, ss: []str, ns: []i32 };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet h = holder { tag = 1, ss = [], ns = [] };\n"
|
||||
"\tappend(h.ss, \"ab\");\n"
|
||||
"\tappend(h.ss, \"cde\");\n"
|
||||
"\tappend(h.ns, 7: i32);\n"
|
||||
"\tlet hs: []holder = [];\n"
|
||||
"\tappend(hs, h);\n"
|
||||
"\tlet ss: []str = [];\n"
|
||||
"\tappend(ss, hs[0].ss...);\n"
|
||||
"\tif (len(ss) != 2) { return 1; };\n"
|
||||
"\tif (len(ss[0]) != 2 || ss[0][1] != 'b') { return 2; };\n"
|
||||
"\tif (len(ss[1]) != 3 || ss[1][2] != 'e') { return 3; };\n"
|
||||
"\tlet ns: []i32 = [];\n"
|
||||
"\tappend(ns, hs[0].ns...);\n"
|
||||
"\tif (len(ns) != 1 || ns[0] != 7) { return 4; };\n"
|
||||
"\tlet empty: []i64 = [];\n"
|
||||
"\tlet ep = ∅\n"
|
||||
"\tlet acc: []i64 = [];\n"
|
||||
"\tappend(acc, (*ep)...);\n"
|
||||
"\tif (len(acc) != 0) { return 5; };\n"
|
||||
"\treturn 82;\n"
|
||||
"};\n",
|
||||
82, NULL },
|
||||
|
||||
/* #35 growth across cap: a 40-element place-sourced spread into a
|
||||
* non-empty dst crosses several cap doublings — rt_ensure moves
|
||||
* the dst base mid-loop; every slot lands because the dst header
|
||||
* re-reads post-grow each iteration. */
|
||||
{ "spread_growth_place",
|
||||
"package main;\n"
|
||||
"type holder = struct { tag: i64, xs: []i64 };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet big: []i64 = [];\n"
|
||||
"\tlet i: i64 = 0;\n"
|
||||
"\tfor (i < 40) { append(big, i); i += 1; };\n"
|
||||
"\tlet hs: []holder = [];\n"
|
||||
"\tappend(hs, holder { tag = 2, xs = big });\n"
|
||||
"\tlet dst: []i64 = [];\n"
|
||||
"\tappend(dst, 100);\n"
|
||||
"\tappend(dst, hs[0].xs...);\n"
|
||||
"\tif (len(dst) != 41) { return 1; };\n"
|
||||
"\tif (dst[0] != 100 || dst[1] != 0 || dst[40] != 39) { return 2; };\n"
|
||||
"\treturn 83;\n"
|
||||
"};\n",
|
||||
83, NULL },
|
||||
|
||||
/* #35 aliasing: the source HEADER lives inside the dst's own
|
||||
* buffer (xs[0].kids reached through xs.ptr); the first grow
|
||||
* reallocs that buffer. The pre-grow-resolved header address then
|
||||
* reads the STALE copy — bit-identical under the non-reclaiming
|
||||
* rt/malloc, the documented #49 stale-base hole. Pins that the
|
||||
* spread terminates AND copies the right elements. */
|
||||
{ "spread_selfalias_chain",
|
||||
"package main;\n"
|
||||
"type tnode = struct { v: i64, kids: []tnode };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet inner: []tnode = [];\n"
|
||||
"\tappend(inner, tnode { v = 7, kids = [] });\n"
|
||||
"\tappend(inner, tnode { v = 9, kids = [] });\n"
|
||||
"\tlet xs: []tnode = [];\n"
|
||||
"\tappend(xs, tnode { v = 1, kids = inner });\n"
|
||||
"\tappend(xs, xs[0].kids...);\n"
|
||||
"\tif (len(xs) != 3) { return 1; };\n"
|
||||
"\tif (xs[0].v != 1 || xs[1].v != 7 || xs[2].v != 9) { return 2; };\n"
|
||||
"\treturn (81 + xs[1].v * 2 + xs[2].v * 2 + (len(xs): i64) * 2): i32;\n"
|
||||
"};\n",
|
||||
119, NULL },
|
||||
|
||||
/* The #35 residual boundary (task #27): a CALL rvalue spread
|
||||
* source has no place to resolve — stays loud until a
|
||||
* scratch-receive route lands. */
|
||||
{ "reject_spread_call_src",
|
||||
"package main;\n"
|
||||
"fn mk() []i64 = { let r: []i64 = []; append(r, 5); return r; };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet xs: []i64 = [];\n"
|
||||
"\tappend(xs, mk()...);\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "#34: append() spread source shape unsupported (rule-7)" },
|
||||
BUILD_FAIL, "#35: append() spread source shape unsupported (rule-7)" },
|
||||
|
||||
/* The #35 residual boundary (task #27): a [N]T ARRAY source place
|
||||
* IS its storage, not a {ptr,len,cap} header — pre-guard the
|
||||
* ident path silently read its first 16 data bytes as ptr/len.
|
||||
* Loud until wired. */
|
||||
{ "reject_spread_array_src",
|
||||
"package main;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet a: [2]i64 = [3, 4];\n"
|
||||
"\tlet xs: []i64 = [];\n"
|
||||
"\tappend(xs, a...);\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "#35: append() spread source shape unsupported (rule-7)" },
|
||||
|
||||
/* The #49 boundary: a CALL rvalue source has no place to resolve
|
||||
* — stays loud (the #42-style bound) until a scratch-receive
|
||||
|
||||
Reference in New Issue
Block a user