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:
@@ -7481,19 +7481,56 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* local ident used to fall PAST the spread arm
|
||||
* into the single-value stores with the
|
||||
* N_SPREAD node (cstage garbage store; wwstage
|
||||
* silently SKIPPED it — divergent). Deferred
|
||||
* source shape, task #37. */
|
||||
* silently SKIPPED it — divergent). */
|
||||
if (vn->kind == N_SPREAD) {
|
||||
if (!vn->lhs || vn->lhs->kind != N_IDENT)
|
||||
fatal("#34: append() spread source "
|
||||
/* #35: only a {ptr,len,cap}-headered
|
||||
* source reads as a header below; a
|
||||
* [N]T array place IS its storage —
|
||||
* the ident path used to read its
|
||||
* first 16 data bytes as ptr/len,
|
||||
* silently. Loud until wired (task
|
||||
* #27); str shares the slice header
|
||||
* layout. */
|
||||
Type *itu = vn->lhs
|
||||
? type_chase_named(vn->lhs->type) : NULL;
|
||||
if (itu == NULL || (itu->kind != TY_SLICE
|
||||
&& itu->kind != TY_STR))
|
||||
fatal("#35: append() spread source "
|
||||
"shape unsupported (rule-7)");
|
||||
if (localfind(locals, vn->lhs->str) == 0)
|
||||
fatal("#34: append() spread source "
|
||||
"ident is not a local (rule-7)");
|
||||
}
|
||||
if (vn->kind == N_SPREAD &&
|
||||
vn->lhs && vn->lhs->kind == N_IDENT) {
|
||||
int it_off = localfind(locals, vn->lhs->str);
|
||||
int it_off = 0;
|
||||
int it_scr = 0;
|
||||
if (vn->lhs->kind == N_IDENT)
|
||||
it_off = localfind(locals, vn->lhs->str);
|
||||
if (it_off == 0) {
|
||||
/* #35: place-chain source (deref
|
||||
* spine, indexed chain, global
|
||||
* ident — the regex.ha:569/820
|
||||
* dup shapes) resolves its header
|
||||
* ADDRESS through cgplaceaddr
|
||||
* ONCE, pre-grow: the chain's
|
||||
* rvalues run exactly once (the
|
||||
* #49 split's pre-grow half) and
|
||||
* every iteration re-reads
|
||||
* .ptr/.len THROUGH the spilled
|
||||
* header post-grow (the live
|
||||
* re-derivation half). A header
|
||||
* reached through a buffer the
|
||||
* grow reallocs keeps Hare's
|
||||
* stale-base hole — see the #49
|
||||
* comment below. Rvalue sources
|
||||
* (CALL, slicing exprs) have no
|
||||
* place — loud, task #27. Fresh
|
||||
* spill slot per SITE for the
|
||||
* same nesting reason as
|
||||
* @apphdrscr above. */
|
||||
if (!cgplaceaddr(c, vn->lhs, D_BX, locals))
|
||||
fatal("#35: append() spread source "
|
||||
"shape unsupported (rule-7)");
|
||||
it_scr = local_alloc(c, &locals,
|
||||
"@appsprscr", 8, cg_frame);
|
||||
ins2(c, A_MOVQ, areg(D_BX),
|
||||
amem(D_BP, it_scr));
|
||||
}
|
||||
int load_op = fldloadop(esub, esz);
|
||||
/* push counter (i) on stack */
|
||||
ins2(c, A_SUBQ, aimm(8), areg(D_SP));
|
||||
@@ -7502,7 +7539,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
char *le = mklabel(c, "spr_e");
|
||||
label(c, ll);
|
||||
ins2(c, A_MOVQ, amem(D_SP, 0), areg(D_CX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_off + 8), areg(D_DX));
|
||||
if (it_scr != 0) {
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_scr), areg(D_DX));
|
||||
ins2(c, A_MOVQ, amem(D_DX, 8), areg(D_DX));
|
||||
} else
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_off + 8), areg(D_DX));
|
||||
ins2(c, A_CMPQ, areg(D_DX), areg(D_CX));
|
||||
ins1(c, A_JGE, abranch(le));
|
||||
if (el_wide) {
|
||||
@@ -7522,7 +7563,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, aimm(esz), areg(D_AX));
|
||||
ins2(c, A_IMULQ, areg(D_AX), areg(D_CX));
|
||||
}
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_off), areg(D_BX));
|
||||
if (it_scr != 0) {
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_scr), areg(D_BX));
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_BX));
|
||||
} else
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_off), areg(D_BX));
|
||||
ins2(c, A_ADDQ, areg(D_CX), areg(D_BX));
|
||||
cg_append_slot(c, sn_direct, sn_off,
|
||||
sn_scr, esz, D_DX);
|
||||
@@ -7553,7 +7598,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
continue;
|
||||
}
|
||||
/* AX = items.ptr[i] */
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_off), areg(D_BX));
|
||||
if (it_scr != 0) {
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_scr), areg(D_BX));
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_BX));
|
||||
} else
|
||||
ins2(c, A_MOVQ, amem(D_BP, it_off), areg(D_BX));
|
||||
if (esz > 1) {
|
||||
ins2(c, A_MOVQ, aimm(esz), areg(D_AX));
|
||||
ins2(c, A_IMULQ, areg(D_AX), areg(D_CX));
|
||||
|
||||
Reference in New Issue
Block a user