w6c+selfhost: cgen N_CAST signed narrow + peel !T on unsigned narrow

TY_RUNE excluded — wwstage primsize skips it; task #5 will collapse
both gates back to symmetric once type_isunsigned recurses TY_ENUM.
This commit is contained in:
2026-05-13 20:06:24 +09:00
parent 777c951fab
commit 388ab8a707
14 changed files with 421 additions and 32 deletions

View File

@@ -8159,21 +8159,25 @@ fn cgcast(c: *cgen, n: *node) void = {
// int↔int casts narrow via an explicit clamp before the early
// return so `(big_u64): u32` doesn't leak the upper 32 bits.
// Hare semantics: `expr: T` truncates to T's bit width (mod 2^n).
// Mirrors cmd/w6c/cgen.c's N_CAST clamp; signed-narrow targets
// (i8/i16/i32) stay no-ops until the assembler grows MOVSBQ /
// MOVSWQ / MOVSXD reg-reg forms.
// Mirrors cmd/w6c/cgen.c's N_CAST clamp. Unsigned narrow clears
// the upper bits via MOVL/ANDQ; signed narrow sign-extends via
// MOVSBQ/MOVSWQ/MOVSXD reg-reg so the sign bit propagates.
if (srcfk == 0 && dstfk == 0) {
let tn: *node = n.rhs;
// Walk through alias chains (`type random = u64`).
// Walk through alias chains (`type random = u64`) and the
// `!T` error-flag wrapper (`type invalid = !i32`) — the
// bang is a tagged-union marker, not a representational
// change, so it must not block the narrow-cast clamp.
for (tn != nil) {
if (tn.kind != nkind.N_TNAME) { tn = nil; }
if (tn.kind == nkind.N_TBANG) { tn = tn.lhs; }
else { if (tn.kind != nkind.N_TNAME) { tn = nil; }
else {
let nm: str = tn.str;
if (primsize(nm) > 0) { break; };
let alias: *node = aliaslookup(c, nm);
if (alias == nil) { tn = nil; }
else { tn = alias; };
};
}; };
};
if (tn != nil) {
let nm: str = tn.str;
@@ -8193,7 +8197,13 @@ fn cgcast(c: *cgen, n: *node) void = {
};
} else { if (is_bool) {
emitline("\tANDQ\t$255, AX\n");
}; };
} else { if (streq(nm, "i8")) {
emitline("\tMOVSBQ\tAX, AX\n");
} else { if (streq(nm, "i16")) {
emitline("\tMOVSWQ\tAX, AX\n");
} else { if (streq(nm, "i32")) {
emitline("\tMOVSXD\tAX, AX\n");
}; }; }; }; };
}; };
};
return;