wcc/ww: is/as on a module-global tagged ident loads from g(SB)
The global tagged ident operand read saved BP instead of the global: 'is' compared garbage as the tag; 'as' never had a payload. Route the load through the g(SB) base — tag at +0, payload at +8, cap at +16 for str (one mechanism, both consumers). The 'is' half aligns ww UP (cs==ww pinned); the 'as' half is a both-wrong pair — cstage spills an uninitialized payload register (its N_TYPEASSERT assumes cgexpr filled AX/DX/CX; filed as task #46), so its rows assert ww-runtime-correct with the cs divergence documented until #46 lands. Review item #18.
This commit is contained in:
@@ -23353,12 +23353,20 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
let scrutoff: i32 = 0;
|
||||
let scrutt: *node = nil;
|
||||
let nonident: bool = false;
|
||||
let globalident: bool = false;
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, lhs.str);
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
} else {
|
||||
// #18 is-half (align-UP): global tagged ident — tag word at
|
||||
// g(SB)+0, no BP slot. cstage N_TYPETEST is uniformly cgexpr
|
||||
// (MOVQ g(SB),AX); pre-fix the !nonident emit read 0(BP)=saved BP.
|
||||
let gt: *node = letvartnode(c, lhs.str);
|
||||
scrutt = resolvetagged(c, gt);
|
||||
globalident = true;
|
||||
};
|
||||
} else {
|
||||
// #45: non-ident scrutinee (xs[i], p.field, call).
|
||||
@@ -23414,9 +23422,15 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
want = cgtagvariantidx(c, scrutt, n.rhs);
|
||||
};
|
||||
if (!nonident) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
if (globalident) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitsymname(c, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
};
|
||||
};
|
||||
let nel: str = mklabel(c, "is_ne");
|
||||
let dnl: str = mklabel(c, "is_done");
|
||||
@@ -23496,6 +23510,29 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
} else {
|
||||
// #18 as-half (#263 ww-runtime-correct; cstage N_TYPEASSERT on a
|
||||
// global tagged ident spills uninitialized DX as the payload —
|
||||
// task #46). No BP slot: copy the box words from g(SB) into a
|
||||
// fresh @asrt_spill so the tag-check + payload load below index
|
||||
// off memory like a local. cs!=ww residual until #46 lands.
|
||||
let gt: *node = letvartnode(c, lhs.str);
|
||||
scrutt = resolvetagged(c, gt);
|
||||
let gsz: i32 = matchspillsz(c, scrutt);
|
||||
scrutoff = localalloc(c, "@asrt_spill", gsz, nil);
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
let gk: i32 = 0;
|
||||
for (gk < gsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(gk: i64, "AX");
|
||||
emitline(", DX\n");
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((scrutoff + gk): i64);
|
||||
emitline("(BP)\n");
|
||||
gk += 8;
|
||||
};
|
||||
};
|
||||
} else {
|
||||
// Non-ident scrutinee (call result, arr[i], p.field, ?,
|
||||
|
||||
@@ -582,12 +582,20 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
let scrutoff: i32 = 0;
|
||||
let scrutt: *node = nil;
|
||||
let nonident: bool = false;
|
||||
let globalident: bool = false;
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, lhs.str);
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
} else {
|
||||
// #18 is-half (align-UP): global tagged ident — tag word at
|
||||
// g(SB)+0, no BP slot. cstage N_TYPETEST is uniformly cgexpr
|
||||
// (MOVQ g(SB),AX); pre-fix the !nonident emit read 0(BP)=saved BP.
|
||||
let gt: *node = letvartnode(c, lhs.str);
|
||||
scrutt = resolvetagged(c, gt);
|
||||
globalident = true;
|
||||
};
|
||||
} else {
|
||||
// #45: non-ident scrutinee (xs[i], p.field, call).
|
||||
@@ -643,9 +651,15 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
want = cgtagvariantidx(c, scrutt, n.rhs);
|
||||
};
|
||||
if (!nonident) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
if (globalident) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitsymname(c, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
};
|
||||
};
|
||||
let nel: str = mklabel(c, "is_ne");
|
||||
let dnl: str = mklabel(c, "is_done");
|
||||
@@ -725,6 +739,29 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
} else {
|
||||
// #18 as-half (#263 ww-runtime-correct; cstage N_TYPEASSERT on a
|
||||
// global tagged ident spills uninitialized DX as the payload —
|
||||
// task #46). No BP slot: copy the box words from g(SB) into a
|
||||
// fresh @asrt_spill so the tag-check + payload load below index
|
||||
// off memory like a local. cs!=ww residual until #46 lands.
|
||||
let gt: *node = letvartnode(c, lhs.str);
|
||||
scrutt = resolvetagged(c, gt);
|
||||
let gsz: i32 = matchspillsz(c, scrutt);
|
||||
scrutoff = localalloc(c, "@asrt_spill", gsz, nil);
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
let gk: i32 = 0;
|
||||
for (gk < gsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(gk: i64, "AX");
|
||||
emitline(", DX\n");
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((scrutoff + gk): i64);
|
||||
emitline("(BP)\n");
|
||||
gk += 8;
|
||||
};
|
||||
};
|
||||
} else {
|
||||
// Non-ident scrutinee (call result, arr[i], p.field, ?,
|
||||
|
||||
@@ -23353,12 +23353,20 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
let scrutoff: i32 = 0;
|
||||
let scrutt: *node = nil;
|
||||
let nonident: bool = false;
|
||||
let globalident: bool = false;
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, lhs.str);
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
} else {
|
||||
// #18 is-half (align-UP): global tagged ident — tag word at
|
||||
// g(SB)+0, no BP slot. cstage N_TYPETEST is uniformly cgexpr
|
||||
// (MOVQ g(SB),AX); pre-fix the !nonident emit read 0(BP)=saved BP.
|
||||
let gt: *node = letvartnode(c, lhs.str);
|
||||
scrutt = resolvetagged(c, gt);
|
||||
globalident = true;
|
||||
};
|
||||
} else {
|
||||
// #45: non-ident scrutinee (xs[i], p.field, call).
|
||||
@@ -23414,9 +23422,15 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
want = cgtagvariantidx(c, scrutt, n.rhs);
|
||||
};
|
||||
if (!nonident) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
if (globalident) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitsymname(c, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP), AX\n");
|
||||
};
|
||||
};
|
||||
let nel: str = mklabel(c, "is_ne");
|
||||
let dnl: str = mklabel(c, "is_done");
|
||||
@@ -23496,6 +23510,29 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
} else {
|
||||
// #18 as-half (#263 ww-runtime-correct; cstage N_TYPEASSERT on a
|
||||
// global tagged ident spills uninitialized DX as the payload —
|
||||
// task #46). No BP slot: copy the box words from g(SB) into a
|
||||
// fresh @asrt_spill so the tag-check + payload load below index
|
||||
// off memory like a local. cs!=ww residual until #46 lands.
|
||||
let gt: *node = letvartnode(c, lhs.str);
|
||||
scrutt = resolvetagged(c, gt);
|
||||
let gsz: i32 = matchspillsz(c, scrutt);
|
||||
scrutoff = localalloc(c, "@asrt_spill", gsz, nil);
|
||||
emitline("\tLEAQ\t");
|
||||
emitsymname(c, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
let gk: i32 = 0;
|
||||
for (gk < gsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitdispreg(gk: i64, "AX");
|
||||
emitline(", DX\n");
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((scrutoff + gk): i64);
|
||||
emitline("(BP)\n");
|
||||
gk += 8;
|
||||
};
|
||||
};
|
||||
} else {
|
||||
// Non-ident scrutinee (call result, arr[i], p.field, ?,
|
||||
|
||||
Reference in New Issue
Block a user