w6c+w6c_ww: size-keyed @tagscr — one tagged scratch per slot size (fix #44)
A fn mixing two tagged slot sizes smaller-first (regex compile(): 56B append-element widen then 64B sret return) hit the #15/#26c rule-7 grow-fatal — the single shared per-fn @tagscr is first-use-sized and its pinned offset can't grow. Key the scratch by slot size instead: @tagscr<sz>, one first-use-allocated slot per distinct size, all three sites (widen-store via_outer, widen-push, N_INDEX tagged-element assign) funnelled through cg_tagscr_slot / tagscradd in both stages. Single-size fns emit byte-identical asm to pre-fix (control row pinned + hand-cmp'd vs master w6c). 736's tagscr_size_grow_fatal fixture pinned the now-unreachable fatal; converted to a byte-id succ row. Runtime rows live in 926_tagscr_sizes_run.
This commit is contained in:
@@ -71,22 +71,31 @@ static int cg_aggargscr_sz;
|
||||
* Two cached slots match wwstage's `@`-prefix namespace exactly:
|
||||
* cg_tagbase — 8B base-register spill for cg_widen_tagged_store
|
||||
* via_outer (mirrors wwstage @tagbase, 1 site).
|
||||
* cg_tagscr — sized scratch shared across THREE sites: cg_widen_
|
||||
* @tagscr<sz> — sized scratch shared across THREE sites: cg_widen_
|
||||
* tagged_store via_outer write target, cg_widen_tagged_
|
||||
* push struct/tagged-source widen, N_INDEX tagged-element
|
||||
* assign. Mirrors wwstage @tagscr — wwstage shares the
|
||||
* slot via localadd `@`-prefix dedup against c.atlocals.
|
||||
* assign. Mirrors wwstage @tagscr<sz> — wwstage shares
|
||||
* the slot via localadd `@`-prefix dedup against
|
||||
* c.atlocals.
|
||||
*
|
||||
* Both stages now size at first use and fatal() if a later site asks
|
||||
* for more (rule 7: surface, don't silently corrupt the frame —
|
||||
* pinned offset can't grow in place once neighbours are allocated).
|
||||
* Both stages size at first use (per name). Pre-#44 the tagged scratch
|
||||
* was a SINGLE slot and a later site asking for a larger size fatal'd
|
||||
* (rule 7 — pinned offset can't grow in place once neighbours are
|
||||
* allocated); a fn mixing two tagged slot sizes smaller-first (regex
|
||||
* compile(): 56B append-element widen then 64B sret return) was
|
||||
* uncompilable. #44 keys the scratch by slot size — one cached slot
|
||||
* per distinct size, allocated in first-use order in BOTH stages, so
|
||||
* the grow-fatal is unreachable for @tagscr by construction. All
|
||||
* three sites funnel through cg_tagscr_slot (no other alloc path).
|
||||
* Per-fn convergence completed by #15 (#26c follow-up): wwstage
|
||||
* dropped its scanlocals pre-pass and aligned DOWN to cstage's
|
||||
* first-use shape. _sz tracks cached allocation size. */
|
||||
* first-use shape. */
|
||||
static int cg_tagbase;
|
||||
static int cg_tagbase_sz;
|
||||
static int cg_tagscr;
|
||||
static int cg_tagscr_sz;
|
||||
enum { CG_NTAGSCR = 16 };
|
||||
static int cg_tagscr_off[CG_NTAGSCR];
|
||||
static int cg_tagscr_sz[CG_NTAGSCR];
|
||||
static int cg_ntagscr;
|
||||
/* #34: per-fn @appendscr — 8B dst-pointer spill for the append()
|
||||
* struct-literal element fill (cg_structlit_fill DST_PTR_LOCAL needs
|
||||
* a BP-rooted slot to reload BX from across its internal cgexprs).
|
||||
@@ -1687,6 +1696,26 @@ localfind(Local *head, const char *name)
|
||||
return 0; /* 0 = not found (caller must verify) */
|
||||
}
|
||||
|
||||
/* cg_tagscr_slot — the ONLY alloc path for the per-fn tagged scratch
|
||||
* (#44). One cached slot per distinct slot size, named "@tagscr<sz>"
|
||||
* so wwstage's localadd name-dedup keys the same way; first-use
|
||||
* allocation order is the source order in both stages (byte-id). */
|
||||
static int
|
||||
cg_tagscr_slot(Cg *c, Local **locals_p, int sz)
|
||||
{
|
||||
for (int i = 0; i < cg_ntagscr; i++)
|
||||
if (cg_tagscr_sz[i] == sz)
|
||||
return cg_tagscr_off[i];
|
||||
if (cg_ntagscr >= CG_NTAGSCR)
|
||||
fatal("cg_tagscr_slot: more than %d distinct tagged "
|
||||
"scratch sizes in one fn", CG_NTAGSCR);
|
||||
cg_tagscr_off[cg_ntagscr] = local_alloc(c, locals_p,
|
||||
aprintf(c->a, "@tagscr%d", sz), sz, cg_frame);
|
||||
cg_tagscr_sz[cg_ntagscr] = sz;
|
||||
cg_ntagscr++;
|
||||
return cg_tagscr_off[cg_ntagscr - 1];
|
||||
}
|
||||
|
||||
/* cg_base_cap — load the capacity of a sub-slice's UNDERLYING storage
|
||||
* into `dst` for the #20 cap = base_cap - lo formula (drew: harec
|
||||
* eval.c:1017 slice cap-=start / eval.c:1024 array cap=length-start;
|
||||
@@ -2080,19 +2109,7 @@ cg_widen_tagged_store(Cg *c, Local **locals_p, Type *dst, Node *src,
|
||||
cg_tagbase_sz = 8;
|
||||
}
|
||||
ins2(c, A_MOVQ, areg(base_reg), amem(D_BP, base_spill));
|
||||
if (cg_tagscr != 0) {
|
||||
if (sz > cg_tagscr_sz)
|
||||
fatal("cg_widen_tagged_store: @tagscr "
|
||||
"cached sz %d, need %d (pinned offset "
|
||||
"can't grow in place; rule 7 — #15/#26c)",
|
||||
cg_tagscr_sz, sz);
|
||||
write_off = cg_tagscr;
|
||||
} else {
|
||||
write_off = local_alloc(c, locals_p, "@tagscr", sz,
|
||||
cg_frame);
|
||||
cg_tagscr = write_off;
|
||||
cg_tagscr_sz = sz;
|
||||
}
|
||||
write_off = cg_tagscr_slot(c, locals_p, sz);
|
||||
/* Pre-zero so str/scalar branches (which leave high words
|
||||
* untouched when sz exceeds the variant's footprint) still
|
||||
* deliver a clean slot to the copy-out. */
|
||||
@@ -2536,19 +2553,7 @@ cg_widen_tagged_push(Cg *c, Local **locals_p, Type *dst, Node *src, int sz)
|
||||
ins1(c, A_PUSHQ, areg(D_AX)); /* tag at +0 */
|
||||
return;
|
||||
}
|
||||
int scr;
|
||||
if (cg_tagscr != 0) {
|
||||
if (sz > cg_tagscr_sz)
|
||||
fatal("cg_widen_tagged_push: @tagscr cached sz %d, "
|
||||
"need %d (pinned offset can't grow in place; "
|
||||
"rule 7 — #15/#26c)",
|
||||
cg_tagscr_sz, sz);
|
||||
scr = cg_tagscr;
|
||||
} else {
|
||||
scr = local_alloc(c, locals_p, "@tagscr", sz, cg_frame);
|
||||
cg_tagscr = scr;
|
||||
cg_tagscr_sz = sz;
|
||||
}
|
||||
int scr = cg_tagscr_slot(c, locals_p, sz);
|
||||
/* Zero the scratch slot first so any pad word the store path
|
||||
* leaves untouched (struct payload shorter than the slot's value
|
||||
* area) reads as 0 on the callee. The store path then writes the
|
||||
@@ -5238,22 +5243,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* the function frame; no cleanup needed. */
|
||||
if ((is_arr || is_sl || is_ptr) && elem_tagged) {
|
||||
int ssz = esz;
|
||||
int scr;
|
||||
if (cg_tagscr != 0) {
|
||||
if (ssz > cg_tagscr_sz)
|
||||
fatal("N_INDEX tagged: "
|
||||
"@tagscr cached sz %d, "
|
||||
"need %d (pinned offset "
|
||||
"can't grow in place; "
|
||||
"rule 7 — #15/#26c)",
|
||||
cg_tagscr_sz, ssz);
|
||||
scr = cg_tagscr;
|
||||
} else {
|
||||
scr = local_alloc(c, &locals,
|
||||
"@tagscr", ssz, cg_frame);
|
||||
cg_tagscr = scr;
|
||||
cg_tagscr_sz = ssz;
|
||||
}
|
||||
int scr = cg_tagscr_slot(c, &locals, ssz);
|
||||
ins2(c, A_XORQ, areg(D_AX), areg(D_AX));
|
||||
for (int k = 0; k < ssz; k += 8)
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
@@ -11242,8 +11232,7 @@ cgfn(Cg *c, FILE *out, Node *fn)
|
||||
cg_aggargscr_sz = 0;
|
||||
cg_tagbase = 0;
|
||||
cg_tagbase_sz = 0;
|
||||
cg_tagscr = 0;
|
||||
cg_tagscr_sz = 0;
|
||||
cg_ntagscr = 0;
|
||||
cg_appendscr = 0;
|
||||
cg_sret_arg_off = 0;
|
||||
cg_sret_dest_off = 0;
|
||||
|
||||
Reference in New Issue
Block a user