w6c_ww: cgtypetest resolves non-ident scrutinees, no-spill tag compare (fix #45)

Pre-#45 wwstage `is` resolved only N_IDENT scrutinees; xs[i] / p.field
/ call() fell through with scrutoff=0 + scrutt=nil and emitted
MOVQ (BP),AX; CMPQ $0,AX — tag read off the saved-BP word, variant
clamped to 0 (SILENT cs≠ww; cstage cgexprs the scrutinee and compares
the real tag in AX). The non-ident arm now cgexprs the scrutinee (tag
lands in AX) and compares directly. NOT the `as` twin's @asrt_spill
(#200): cmp against cstage shows N_TYPETEST never spills — `as`
re-reads payload words after the check, `is` consumes only the tag,
and a spill would break rule-10 byte-id. Variant index resolves from
the STAMPED scrutinee type via flatvariantidx/flatslicevariantidx
(matchscrutt's node walk can't carry N_DOT through cgtypetest's
N_TTAGGED gate). Ident path untouched (control row + hand-cmp vs
pre-#45 w6c_ww). wwstage-only source change; cs==ww byte-id pinned
per row in 927_is_nonident_run.
This commit is contained in:
2026-06-04 04:40:39 +09:00
parent c2308a11c7
commit b2e4388792
5 changed files with 365 additions and 12 deletions

View File

@@ -20261,6 +20261,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
};
let scrutoff: i32 = 0;
let scrutt: *node = nil;
let nonident: bool = false;
if (lhs != nil) {
if (lhs.kind == nkind.N_IDENT) {
let lc: *local = localfindnode(c, lhs.str);
@@ -20268,13 +20269,44 @@ fn cgtypetest(c: *cgen, n: *node) void = {
scrutoff = lc.off;
scrutt = resolvetagged(c, lc.tnode);
};
} else {
// #45: non-ident scrutinee (xs[i], p.field, call).
// cstage N_TYPETEST never spills — cgexpr leaves the
// scrutinee's tag word in AX (tagged element/field/
// call reads load the tag first), so compare AX
// directly. The `as` twin's @asrt_spill (#200) is
// NOT mirrored here: `as` re-reads payload words
// after the check; `is` consumes only the tag, and
// a spill would diverge from cstage's asm (rule 10).
// Pre-#45 this fell through to scrutoff=0 and the
// tag read landed on (BP) — the saved-BP word.
nonident = true;
cgexpr(c, lhs);
};
};
let want: i32 = cgtagvariantidx(c, scrutt, n.rhs);
let want: i32 = 0;
if (nonident) {
// Variant index from the STAMPED scrutinee type (cstage:
// u = n->lhs->type) — matchscrutt's node-shape walk can't
// carry N_DOT (returns the scrut node, which the
// cgtagvariantidx N_TTAGGED gate rejects). flatvariantidx /
// flatslicevariantidx read .type_ off any stamped carrier.
if (n.rhs != nil) {
if (n.rhs.kind == nkind.N_TSLICE) {
want = flatslicevariantidx(c, lhs, n.rhs.lhs);
} else {
want = flatvariantidx(c, lhs, n.rhs);
};
};
} else {
want = cgtagvariantidx(c, scrutt, n.rhs);
};
if (want < 0) { want = 0; };
emitline("\tMOVQ\t");
emitoff(scrutoff: i64);
emitline("(BP), AX\n");
if (!nonident) {
emitline("\tMOVQ\t");
emitoff(scrutoff: i64);
emitline("(BP), AX\n");
};
let nel: str = mklabel(c, "is_ne");
let dnl: str = mklabel(c, "is_done");
emitline("\tCMPQ\t$");

View File

@@ -402,6 +402,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
};
let scrutoff: i32 = 0;
let scrutt: *node = nil;
let nonident: bool = false;
if (lhs != nil) {
if (lhs.kind == nkind.N_IDENT) {
let lc: *local = localfindnode(c, lhs.str);
@@ -409,13 +410,44 @@ fn cgtypetest(c: *cgen, n: *node) void = {
scrutoff = lc.off;
scrutt = resolvetagged(c, lc.tnode);
};
} else {
// #45: non-ident scrutinee (xs[i], p.field, call).
// cstage N_TYPETEST never spills — cgexpr leaves the
// scrutinee's tag word in AX (tagged element/field/
// call reads load the tag first), so compare AX
// directly. The `as` twin's @asrt_spill (#200) is
// NOT mirrored here: `as` re-reads payload words
// after the check; `is` consumes only the tag, and
// a spill would diverge from cstage's asm (rule 10).
// Pre-#45 this fell through to scrutoff=0 and the
// tag read landed on (BP) — the saved-BP word.
nonident = true;
cgexpr(c, lhs);
};
};
let want: i32 = cgtagvariantidx(c, scrutt, n.rhs);
let want: i32 = 0;
if (nonident) {
// Variant index from the STAMPED scrutinee type (cstage:
// u = n->lhs->type) — matchscrutt's node-shape walk can't
// carry N_DOT (returns the scrut node, which the
// cgtagvariantidx N_TTAGGED gate rejects). flatvariantidx /
// flatslicevariantidx read .type_ off any stamped carrier.
if (n.rhs != nil) {
if (n.rhs.kind == nkind.N_TSLICE) {
want = flatslicevariantidx(c, lhs, n.rhs.lhs);
} else {
want = flatvariantidx(c, lhs, n.rhs);
};
};
} else {
want = cgtagvariantidx(c, scrutt, n.rhs);
};
if (want < 0) { want = 0; };
emitline("\tMOVQ\t");
emitoff(scrutoff: i64);
emitline("(BP), AX\n");
if (!nonident) {
emitline("\tMOVQ\t");
emitoff(scrutoff: i64);
emitline("(BP), AX\n");
};
let nel: str = mklabel(c, "is_ne");
let dnl: str = mklabel(c, "is_done");
emitline("\tCMPQ\t$");

View File

@@ -20261,6 +20261,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
};
let scrutoff: i32 = 0;
let scrutt: *node = nil;
let nonident: bool = false;
if (lhs != nil) {
if (lhs.kind == nkind.N_IDENT) {
let lc: *local = localfindnode(c, lhs.str);
@@ -20268,13 +20269,44 @@ fn cgtypetest(c: *cgen, n: *node) void = {
scrutoff = lc.off;
scrutt = resolvetagged(c, lc.tnode);
};
} else {
// #45: non-ident scrutinee (xs[i], p.field, call).
// cstage N_TYPETEST never spills — cgexpr leaves the
// scrutinee's tag word in AX (tagged element/field/
// call reads load the tag first), so compare AX
// directly. The `as` twin's @asrt_spill (#200) is
// NOT mirrored here: `as` re-reads payload words
// after the check; `is` consumes only the tag, and
// a spill would diverge from cstage's asm (rule 10).
// Pre-#45 this fell through to scrutoff=0 and the
// tag read landed on (BP) — the saved-BP word.
nonident = true;
cgexpr(c, lhs);
};
};
let want: i32 = cgtagvariantidx(c, scrutt, n.rhs);
let want: i32 = 0;
if (nonident) {
// Variant index from the STAMPED scrutinee type (cstage:
// u = n->lhs->type) — matchscrutt's node-shape walk can't
// carry N_DOT (returns the scrut node, which the
// cgtagvariantidx N_TTAGGED gate rejects). flatvariantidx /
// flatslicevariantidx read .type_ off any stamped carrier.
if (n.rhs != nil) {
if (n.rhs.kind == nkind.N_TSLICE) {
want = flatslicevariantidx(c, lhs, n.rhs.lhs);
} else {
want = flatvariantidx(c, lhs, n.rhs);
};
};
} else {
want = cgtagvariantidx(c, scrutt, n.rhs);
};
if (want < 0) { want = 0; };
emitline("\tMOVQ\t");
emitoff(scrutoff: i64);
emitline("(BP), AX\n");
if (!nonident) {
emitline("\tMOVQ\t");
emitoff(scrutoff: i64);
emitline("(BP), AX\n");
};
let nel: str = mklabel(c, "is_ne");
let dnl: str = mklabel(c, "is_done");
emitline("\tCMPQ\t$");