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:
@@ -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$");
|
||||
|
||||
@@ -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$");
|
||||
|
||||
@@ -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$");
|
||||
|
||||
Reference in New Issue
Block a user