ascii: graduate digitval to (i32 | void); selfhost tagged ABI follow-on

ascii.digitval returns (i32 | void) instead of an i32 -1 sentinel.
Two callers updated to match-on the result (lib/ww/lex/lex.ww escape
parse, selfhost/test/smoke.ww probe 6).

`!` would have been more idiomatic at both call sites — both have
verified isxdigit beforehand — but the selfhost parser doesn't yet
recognize postfix `!`/`?`, so using them in bootstrap-bound code
breaks the 993/995 byte-identity gates. Match is fine for now.

Selfhost cgen follow-on for the 8-byte-rounded tagged-union ABI
(landed in 1e2f55a for the C side):
- cgenutil.slotsize: tagged size = 8 (tag) + max(payload), padded to
  8-byte multiple. Was hardcoded 24.
- cgendecl prologue: spill size/8 arg registers, not always 3.
- cgenstmt cglet tagged-call path: spill the CX value-word only when
  the slot is >16 bytes.

All three were emitting 3-register patterns appropriate to (T | str)
sized unions and overflowing the new 16-byte (i32 | void) slots.
This commit is contained in:
2026-05-12 02:10:10 +09:00
parent 4085742853
commit 2f385cec00
9 changed files with 173 additions and 99 deletions

View File

@@ -702,7 +702,21 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
};
return total;
};
if (k == N_TTAGGED){ return 24; };
if (k == N_TTAGGED){
// Slot = 8 (tag) + max(variant payload sizes), rounded up
// to an 8-byte multiple so the reg-passing ABI (size/8
// words) doesn't drop the last value register. Mirrors C
// cgen's resolve_type for N_TTAGGED.
let v: *node = typn.list;
let maxsz: i32 = 0;
for (v != nil) {
let sz: i32 = slotsize(c, v);
if (sz > maxsz) { maxsz = sz; };
v = v.next;
};
let pad: i32 = (maxsz + 7) & ~7;
return 8 + pad;
};
if (k == N_TNAME) {
let nm: str = typn.str;
if (streq(nm, "str")) { return 16; };