selfhost+cstage+test: graduate frame growth to first-use+fail-loud (#15)
Subsumes #36. Drop wwstage scanlocals pre-pass; both stages converge on first-use+fail-loud frame growth, rule-10 polarity DOWN to leaner side. #36's surfaces (frame-total divergence on match-arm case-let; sibling offset divergence in variadic+iter+match-prev compositions) close naturally — running-max c.frame includes every first-use binding. selfhost/cmd/wcc: add atlocals persistent @-prefix registry surviving cgblock save/restore; add cgoutbuf/cgoutmode/cgout_enable/disable/flush for deferred prologue (emit body to buffer, finalise c.frame, then TEXT/SUBQ + flush); localadd @-prefix dedups against atlocals + fail-louds on size-grow (rule 7 — no silent truncate); cgreturn-tagged routes through @retscr (was colliding with @tagscr on arg-widen sizes); variadic gather esz uses raw primsize (rune->4) not slotsize (rune->8) — matches cstage and fixes the #36 sibling runtime miscompile in non-leaf variadic+iter+match-prev callees. cmd/w6c/cgen.c: drop the over-allocation hack ("for byte-id with wwstage scanlocals reservation") since wwstage no longer over-reserves; add fail-loud on @sretscr size-grow; @tagscr sites pass actual slot_sz instead of stale c.tagscrsz. 748_size_strategy_convergence: table-driven 4 rows x 2 stages (tag_variadic_runearm, trim_iter_match_prev, variadic_gather_rune_stride, leaf_baseline). Each exercises a #36 surface shape; 8/8 ok. Net -1565 lines. Sister latents filed as cosmetic (cs/ws frame size drift on multiple-variadic-call fns): labelseq drift + varargseq stuck at 0 — both bootstrap-byte-id safe (ww2==ww3==ww4 holds since both ww2 and ww3 are wwstage outputs). make test 122/122; ww2==ww3==ww4 byte-id holds via 995_self_rebuild.
This commit is contained in:
@@ -193,13 +193,19 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
};
|
||||
if (needswiden) {
|
||||
let rsz: i32 = slotsize(c, c.fnret);
|
||||
// Use c.tagscrsz so the first @tagscr allocation in
|
||||
// the fn lands a slot sized to the *max* across all
|
||||
// uses (scanlocals bumped to rsz here). Hardcoding 24
|
||||
// truncated 32B-slot returns and overwrote adjacent
|
||||
// locals during the pre-zero loop (#38).
|
||||
let scroff: i32 = localadd(c, "@tagscr",
|
||||
c.tagscrsz, nil);
|
||||
// @retscr (not @tagscr) for the return materialise
|
||||
// path. Cstage cmd/w6c/cgen.c cgreturn uses
|
||||
// `@retscr` here and reserves the @tagscr SSoT
|
||||
// for arg-widen / non-BP-base store / N_INDEX
|
||||
// tagged-element write. Sharing the name in a fn
|
||||
// that BOTH returns a 32B tagged AND pushes a
|
||||
// smaller tagged arg fatals localadd's @-prefix
|
||||
// size-grow guard (rule 7); routing returns
|
||||
// through their own slot keeps each cache
|
||||
// monotonic. Hardcoding 24 truncated 32B-slot
|
||||
// returns and overwrote adjacent locals during
|
||||
// the pre-zero loop (#38).
|
||||
let scroff: i32 = localadd(c, "@retscr", rsz, nil);
|
||||
emitline("\tXORQ\tAX, AX\n");
|
||||
let zz: i32 = 0;
|
||||
for (zz < rsz) {
|
||||
@@ -299,7 +305,8 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
// the SysV "return the pointer" discipline. Two rhs shapes
|
||||
// are wired: N_IDENT (word-copy from rhs slot to *(dest))
|
||||
// and N_STRUCTLIT (cgstructlitfill with mode=1 PTR_LOCAL).
|
||||
if (c.sretargoff != 0) {
|
||||
let sretargoff: i32 = localfind(c, "@sretarg");
|
||||
if (sretargoff != 0) {
|
||||
let scs: i32 = sretretsize(c, c.fnret);
|
||||
if (scs > 0) {
|
||||
// sret return-forwarding (task #9 follow-up to
|
||||
@@ -317,7 +324,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
c.sretforward = 1;
|
||||
cgexpr(c, rhs);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(c.sretargoff: i64);
|
||||
emitoff(sretargoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tBP, SP\n");
|
||||
emitline("\tPOPQ\tBP\n");
|
||||
@@ -346,14 +353,14 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
// each field store. disp = 0 because
|
||||
// the dest pointer IS the struct base.
|
||||
cgstructlitfill(c, sret_si, rhs,
|
||||
1, c.sretargoff, emptys,
|
||||
1, sretargoff, emptys,
|
||||
0, scs);
|
||||
};
|
||||
} else {
|
||||
let rl: *local = localfindnode(c, rhs.str);
|
||||
if (rl != nil) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(c.sretargoff: i64);
|
||||
emitoff(sretargoff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
let k: i32 = 0;
|
||||
for (k + 8 <= scs) {
|
||||
@@ -387,7 +394,7 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
||||
};
|
||||
// sret return: RAX = dest pointer.
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(c.sretargoff: i64);
|
||||
emitoff(sretargoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tBP, SP\n");
|
||||
emitline("\tPOPQ\tBP\n");
|
||||
|
||||
Reference in New Issue
Block a user