cgen: loop/yield/defer fixed-max buffers raw-ptr → []T (#9)

Phase 0 #9. cgen struct fields loopendbuf/loopcontbuf/yieldbuf/
deferbuf change from `*str`/`**node` over-allocated arena chunks
to `[]str`/`[]*node` slices. The 4 alloc sites in cgeninit drop
the byte-count form (`LOOP_MAX*24u64`, `DEFER_MAX*8u64`) for
element-count (`LOOP_MAX: u64`, `DEFER_MAX: u64`). 10 caller
sites in cgenstmt.ww/cgenexpr.ww use `[i]` indexing which works
identically for slice-shaped struct fields.

Two-line let-then-assign idiom for the 4 inits is a real checker
limitation: alloc's element-deferred `[]u8` → `[]T` retype only
fires in let-init (checkletassign N_TSLICE LHS), and cglet's
alloc-slice writeback shortcut (cgenstmt.ww:577) only fires in
let-init too. Direct `c.field = alloc([], N)!` would silently
emit a scalar alloc with a junk slice header. Filed #49 for the
checker enhancement; the let-then-assign is Hare-idiomatic in
the meantime.

Verified 132/132 + 995_self_rebuild byte-identity.
This commit is contained in:
2026-05-21 02:58:30 +09:00
parent 775b271dc7
commit 4972ab4a5c
3 changed files with 36 additions and 36 deletions

View File

@@ -21544,12 +21544,12 @@ type cgen = struct {
// before walking the body.
fnret: *node, // declared return type of current fn (or nil)
looptop: i32,
loopendbuf: *str, // stack of end labels for break
loopcontbuf: *str, // stack of cont labels for continue
loopendbuf: []str, // stack of end labels for break
loopcontbuf: []str, // stack of cont labels for continue
yieldtop: i32,
yieldbuf: *str, // stack of match end labels for yield
yieldbuf: []str, // stack of match end labels for yield
defertop: i32,
deferbuf: **node, // stack of deferred exprs (LIFO at return)
deferbuf: []*node, // stack of deferred exprs (LIFO at return)
// Variadic-call gather state. cgcall bumps this on each gather
// emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per
// callsite; mirrors cstage's mklabel("vararg_d/sl") freshness
@@ -21609,16 +21609,16 @@ fn cgeninit(c: *cgen, a: *arena) void = {
// persist across cgfn calls within one file. cgfile resets them
// at the start of each compilation unit.
c.looptop = 0;
// #35: per-slot stride is sizeof(str); the bare 16 is the str=16
// width and undershoots under str=24, so indices past (LOOP_MAX*16)/24
// = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot
// over-alloc under str=16 is harmless under the bump arena.
c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
let loopendbuf: []str = alloc([], LOOP_MAX: u64)!;
c.loopendbuf = loopendbuf;
let loopcontbuf: []str = alloc([], LOOP_MAX: u64)!;
c.loopcontbuf = loopcontbuf;
c.yieldtop = 0;
c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
let yieldbuf: []str = alloc([], LOOP_MAX: u64)!;
c.yieldbuf = yieldbuf;
c.defertop = 0;
c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node;
let deferbuf: []*node = alloc([], DEFER_MAX: u64)!;
c.deferbuf = deferbuf;
};
// localalloc — append a slot for `name` without dedup. Used for

View File

@@ -469,12 +469,12 @@ type cgen = struct {
// before walking the body.
fnret: *node, // declared return type of current fn (or nil)
looptop: i32,
loopendbuf: *str, // stack of end labels for break
loopcontbuf: *str, // stack of cont labels for continue
loopendbuf: []str, // stack of end labels for break
loopcontbuf: []str, // stack of cont labels for continue
yieldtop: i32,
yieldbuf: *str, // stack of match end labels for yield
yieldbuf: []str, // stack of match end labels for yield
defertop: i32,
deferbuf: **node, // stack of deferred exprs (LIFO at return)
deferbuf: []*node, // stack of deferred exprs (LIFO at return)
// Variadic-call gather state. cgcall bumps this on each gather
// emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per
// callsite; mirrors cstage's mklabel("vararg_d/sl") freshness
@@ -534,16 +534,16 @@ fn cgeninit(c: *cgen, a: *arena) void = {
// persist across cgfn calls within one file. cgfile resets them
// at the start of each compilation unit.
c.looptop = 0;
// #35: per-slot stride is sizeof(str); the bare 16 is the str=16
// width and undershoots under str=24, so indices past (LOOP_MAX*16)/24
// = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot
// over-alloc under str=16 is harmless under the bump arena.
c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
let loopendbuf: []str = alloc([], LOOP_MAX: u64)!;
c.loopendbuf = loopendbuf;
let loopcontbuf: []str = alloc([], LOOP_MAX: u64)!;
c.loopcontbuf = loopcontbuf;
c.yieldtop = 0;
c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
let yieldbuf: []str = alloc([], LOOP_MAX: u64)!;
c.yieldbuf = yieldbuf;
c.defertop = 0;
c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node;
let deferbuf: []*node = alloc([], DEFER_MAX: u64)!;
c.deferbuf = deferbuf;
};
// localalloc — append a slot for `name` without dedup. Used for

View File

@@ -21544,12 +21544,12 @@ type cgen = struct {
// before walking the body.
fnret: *node, // declared return type of current fn (or nil)
looptop: i32,
loopendbuf: *str, // stack of end labels for break
loopcontbuf: *str, // stack of cont labels for continue
loopendbuf: []str, // stack of end labels for break
loopcontbuf: []str, // stack of cont labels for continue
yieldtop: i32,
yieldbuf: *str, // stack of match end labels for yield
yieldbuf: []str, // stack of match end labels for yield
defertop: i32,
deferbuf: **node, // stack of deferred exprs (LIFO at return)
deferbuf: []*node, // stack of deferred exprs (LIFO at return)
// Variadic-call gather state. cgcall bumps this on each gather
// emit and uses it to mint `@vararg_d_N` / `@vararg_sl_N` per
// callsite; mirrors cstage's mklabel("vararg_d/sl") freshness
@@ -21609,16 +21609,16 @@ fn cgeninit(c: *cgen, a: *arena) void = {
// persist across cgfn calls within one file. cgfile resets them
// at the start of each compilation unit.
c.looptop = 0;
// #35: per-slot stride is sizeof(str); the bare 16 is the str=16
// width and undershoots under str=24, so indices past (LOOP_MAX*16)/24
// = 10 would spill into the next amalloc. Bumped to 24/slot; +8/slot
// over-alloc under str=16 is harmless under the bump arena.
c.loopendbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
let loopendbuf: []str = alloc([], LOOP_MAX: u64)!;
c.loopendbuf = loopendbuf;
let loopcontbuf: []str = alloc([], LOOP_MAX: u64)!;
c.loopcontbuf = loopcontbuf;
c.yieldtop = 0;
c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 24u64): *str;
let yieldbuf: []str = alloc([], LOOP_MAX: u64)!;
c.yieldbuf = yieldbuf;
c.defertop = 0;
c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node;
let deferbuf: []*node = alloc([], DEFER_MAX: u64)!;
c.deferbuf = deferbuf;
};
// localalloc — append a slot for `name` without dedup. Used for