wcc/ww: nodeisunsigned resolves module-global idents via the stamp

A bare module-global unsigned operand got signed IDIV/SAR/Jcc — the
predicate's ident arm only consulted the local table, so globals fell
through to signed (review finding #25). Read the stamp for the global
arm; corpus emission is unmoved (no bootstrap code div/shift/cmps a
bare unsigned global). 989_gunsigned_run pins cs==ww (red 3/8
pre-fix).
This commit is contained in:
2026-06-12 00:14:32 +09:00
parent 7afc4df652
commit 0625af1309
5 changed files with 237 additions and 21 deletions

View File

@@ -1722,14 +1722,19 @@ fn elemsizeofc(c: *cgen, t: *node) i32 = {
fn nodeisunsigned(c: *cgen, n: *node) bool = {
if (n == nil) { return false; };
let k: nkind = n.kind;
// #25 (F7-c5): collapse the whole N_IDENT arm onto the checker-stamped
// n.type_, dropping the localfindnode special-case. The prior arm read
// the local's declared tnode and returned `false` (signed) for a
// module-GLOBAL ident (localfindnode→nil) — so a `u64` global counter
// fed to / % >> or a relational got signed IDIV/SAR/JG instead of the
// unsigned DIV/SHR/JA cstage emits (type_isunsigned(n->type), cmd/w6c/
// cgen.c:2541). The N_DOT/N_CAST/N_INDEX/N_CALL arms below already read
// n.type_; this aligns the bare-ident arm to the same stamp. CLASS-M:
// the corpus HAS module-global unsigned counters on the divide/shift
// path, so the self-compile .s MOVES — every move is toward cstage
// (IDIV→DIV where the global's stamp is unsigned) and runtime-correct.
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) {
if (lc.tnode == nil) { return false; };
return typeisunsigned(lc.tnode.type_: *tinfo);
};
return false;
return typeisunsigned(n.type_: *tinfo);
};
if (k == nkind.N_DOT) {
return typeisunsigned(n.type_: *tinfo);