w6c+selfhost: match-arm scope/spill + alloc(structlit) sugar
Three gaps in the wwstage cgen relative to C w6c, plus a matching
C-side bug surfaced along the way.
cgmatch (selfhost) handles non-ident scrutinees: `match (foo())` now
spills the AX:DX:CX return triple into a 24B `@match_spill` slot
rather than reading garbage off BP+0. scanlocals counts the slot so
the prologue SUBQ stays in sync. For N_CALL we recover the return
type via fnretlookup so nullable dispatch picks the pointer-vs-null
discriminator. Mirrors @match_spill in cmd/w6c/cgen.c N_MATCH.
cgcall (selfhost) special-cases `alloc(structlit{...})`: lower to
rt_alloc(totsize) + per-field MOV* at the struct's field offsets,
mirroring cmd/w6c/cgen.c's existing path. Previously the structlit
fell into pushargsrev and produced wrong code.
check.ww's N_MCASE branch now pushes a fresh scope around each arm
body. Without this, `case let e: str` inside a fn with an outer
`let e: *T` collided with scopedefine's same-scope dedup, the inner
binding silently dropped, and references to `e` inside the arm
resolved through the outer type.
Both cgens save/restore the locals head around case bodies so arm
binds (and nested arm-body lets) don't leak past the arm — code
after the match resolves names back through the outer scope.
w6c gains `local_alloc`: same as `localoff` minus the dedup. N_MATCH
case-bind allocation switches to it. Previously `let e: *T` (8B)
shadowed by `case let e: str` (16B) reused the outer 8B slot and the
inner str.len store overflowed into the saved BP, segfaulting on
return.
Tests 26/26.
This commit is contained in:
@@ -119,6 +119,16 @@ fn scanlocals(c: *cgen, n: *node) i32 = {
|
||||
};};
|
||||
};
|
||||
};
|
||||
// `match (non-ident)` needs a 24B `@match_spill` scratch slot for
|
||||
// cgmatch to land the AX:DX:CX return triple. Mirrors C cgen's
|
||||
// localoff("@match_spill", ...). N_IDENT scrutinees read the slot
|
||||
// directly off the local — no spill needed.
|
||||
if (n.kind == nkind.N_MATCH) {
|
||||
let sc: *node = n.lhs;
|
||||
if (sc != nil) {
|
||||
if (sc.kind != nkind.N_IDENT) { total += 24; };
|
||||
};
|
||||
};
|
||||
// Match-arm binding (`case let v: T => ...`) gets a slot too.
|
||||
// Crucially we do NOT dedup these against c.locals: C cgen
|
||||
// handles a match as an expression with a by-value locals copy,
|
||||
|
||||
Reference in New Issue
Block a user