selfhost: mirror defer; e2e tests for LIFO ordering
C cgen has carried defer for a while (defers[] global + reverse walk on every return). Selfhost cgen now mirrors: - cgen struct: deferbuf (**node, LIFO stack) + defertop counter. - cgstmt N_DEFER: push n.lhs. - cgreturn: rundefers() at entry — same as the C cgen pattern. - cgfn fall-through return: rundefers() before zero-AX+RET. DEFER_MAX = 16 matches C cgen. Two new e2e rows: defer with an explicit `return acc;` (321 mod 256 = 65), and defer firing on an implicit void-fn fall-through (87). Both rows verified via the wwstage cgen too. Defer's semantics: queued exprs fire LIFO before the return expr is evaluated, so a return that reads memory mutated by a deferred call sees the post-defer state. Matches C cgen and Hare.
This commit is contained in:
@@ -145,6 +145,7 @@ type ffi = struct {
|
||||
};
|
||||
|
||||
def LOOP_MAX: i32 = 16;
|
||||
def DEFER_MAX: i32 = 16;
|
||||
|
||||
type cgen = struct {
|
||||
a: *arena,
|
||||
@@ -167,6 +168,8 @@ type cgen = struct {
|
||||
loopcontbuf: *str, // stack of cont labels for continue
|
||||
yieldtop: i32,
|
||||
yieldbuf: *str, // stack of match end labels for yield
|
||||
defertop: i32,
|
||||
deferbuf: **node, // stack of deferred exprs (LIFO at return)
|
||||
};
|
||||
|
||||
fn cgeninit(c: *cgen, a: *arena) void = {
|
||||
@@ -183,6 +186,8 @@ fn cgeninit(c: *cgen, a: *arena) void = {
|
||||
c.loopcontbuf = amalloc(a, (LOOP_MAX: u64) * 16u64): *str;
|
||||
c.yieldtop = 0;
|
||||
c.yieldbuf = amalloc(a, (LOOP_MAX: u64) * 16u64): *str;
|
||||
c.defertop = 0;
|
||||
c.deferbuf = amalloc(a, (DEFER_MAX: u64) * 8u64): **node;
|
||||
};
|
||||
|
||||
// localalloc — append a slot for `name` without dedup. Used for
|
||||
|
||||
Reference in New Issue
Block a user