wwstage: spill non-IDENT scrutinee at cgtypeassert (#200)
cgtypeassert kept scrutoff=0 when the scrutinee wasn't an N_IDENT (direct call result, arr[i], p.field, ?, paren-wrap of any of those), so the tag-load fell on (BP) — the saved-BP word — and the payload- load on +8(BP) — the return address. The wwstage repro returned 220 (garbage from RIP) where cstage returned 42 (impl-e1-resume sibling of #199/#201). Mirror cstage cmd/w6c/cgen.c:6300-6316 N_TYPEASSERT non-IDENT arm. Add an `else` branch after the existing N_IDENT path that resolves the tagged type via matchscrutt, alloc an @asrt_spill slot via matchspillsz/localalloc, cgexpr the LHS, then spill the AX/DX/CX tagged-return-ABI words: AX→+0 (tag), DX→+8 (word0), CX→+16 (word1, guarded on spill > 16). Subsequent tag-check + payload load indexes off the spill like the IDENT path. Helpers reused from cgmatch (cgenexpr.ww:1422-1460). cstage's cgtypeassert omits the cgmatch 4-word R8→+24 spill (rule-10 stage symmetry: rather than diverge into a 32B-payload case the test suite doesn't exercise, mirror cstage exactly and file the cstage omission inline). Filed inline: cstage cgtypeassert needs the same R8→+24 path cgmatch already has (drew's design rationale, blocked by the rule-10 floor today). 772_typeassert_nonident: 7 rows (call_as_size — the repro, call_as_str — CX→+16 spill + BX post-load, call_as_namedvoid — void-variant tag-check fires, payload load is a 0-byte no-op, call_as_fnptr — fn-ptr variant 8B word0, call_as_u8 / call_as_i16 — narrow scalar round-trip via MOVQ + MOVQ confirms no truncation, branched_call_as — runtime-chosen tag). Each row gated on cstage runtime + wwstage runtime + cs.s == ww.s byte-identity.
This commit is contained in:
@@ -18010,6 +18010,41 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
};
|
||||
} else {
|
||||
// Non-ident scrutinee (call result, arr[i], p.field, ?,
|
||||
// etc.). Mirror cgmatch's spill (cgenexpr.ww:1422-1460)
|
||||
// and cstage cmd/w6c/cgen.c:6300-6316: alloc an
|
||||
// `@asrt_spill` slot sized via matchspillsz, evaluate
|
||||
// the LHS, then copy the AX/DX/CX[/R8] return-ABI words
|
||||
// into the slot so the tag-check + payload load indexes
|
||||
// off memory like the IDENT path. Without this, scrutoff
|
||||
// stayed 0 and the tag read fell on (BP) — the saved-BP
|
||||
// word — and the payload read on +8(BP) — the return
|
||||
// address. Bug #200.
|
||||
scrutt = matchscrutt(c, lhs);
|
||||
let spillsz: i32 = matchspillsz(c, scrutt);
|
||||
scrutoff = localalloc(c, "@asrt_spill", spillsz, nil);
|
||||
cgexpr(c, lhs);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP)\n");
|
||||
if (!isnullabletype(scrutt)) {
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((scrutoff + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
// Mirror cstage cmd/w6c/cgen.c:6313-6315: only CX
|
||||
// → +16 when slot_size > 16. The 4-word case
|
||||
// (R8 → +24, slot_size > 24) is the cgmatch shape
|
||||
// (cgenexpr.ww:1454-1458, cmd/w6c/cgen.c:5988-5990)
|
||||
// but cstage cgtypeassert omits it; preserve the
|
||||
// asymmetry rather than diverge from rule 10
|
||||
// byte-id. Filed inline as a cstage twin task.
|
||||
if (spillsz > 16) {
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((scrutoff + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
let want: i32 = cgtagvariantidx(c, scrutt, n.rhs);
|
||||
|
||||
@@ -387,6 +387,41 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
};
|
||||
} else {
|
||||
// Non-ident scrutinee (call result, arr[i], p.field, ?,
|
||||
// etc.). Mirror cgmatch's spill (cgenexpr.ww:1422-1460)
|
||||
// and cstage cmd/w6c/cgen.c:6300-6316: alloc an
|
||||
// `@asrt_spill` slot sized via matchspillsz, evaluate
|
||||
// the LHS, then copy the AX/DX/CX[/R8] return-ABI words
|
||||
// into the slot so the tag-check + payload load indexes
|
||||
// off memory like the IDENT path. Without this, scrutoff
|
||||
// stayed 0 and the tag read fell on (BP) — the saved-BP
|
||||
// word — and the payload read on +8(BP) — the return
|
||||
// address. Bug #200.
|
||||
scrutt = matchscrutt(c, lhs);
|
||||
let spillsz: i32 = matchspillsz(c, scrutt);
|
||||
scrutoff = localalloc(c, "@asrt_spill", spillsz, nil);
|
||||
cgexpr(c, lhs);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP)\n");
|
||||
if (!isnullabletype(scrutt)) {
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((scrutoff + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
// Mirror cstage cmd/w6c/cgen.c:6313-6315: only CX
|
||||
// → +16 when slot_size > 16. The 4-word case
|
||||
// (R8 → +24, slot_size > 24) is the cgmatch shape
|
||||
// (cgenexpr.ww:1454-1458, cmd/w6c/cgen.c:5988-5990)
|
||||
// but cstage cgtypeassert omits it; preserve the
|
||||
// asymmetry rather than diverge from rule 10
|
||||
// byte-id. Filed inline as a cstage twin task.
|
||||
if (spillsz > 16) {
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((scrutoff + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
let want: i32 = cgtagvariantidx(c, scrutt, n.rhs);
|
||||
|
||||
@@ -18010,6 +18010,41 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
scrutoff = lc.off;
|
||||
scrutt = resolvetagged(c, lc.tnode);
|
||||
};
|
||||
} else {
|
||||
// Non-ident scrutinee (call result, arr[i], p.field, ?,
|
||||
// etc.). Mirror cgmatch's spill (cgenexpr.ww:1422-1460)
|
||||
// and cstage cmd/w6c/cgen.c:6300-6316: alloc an
|
||||
// `@asrt_spill` slot sized via matchspillsz, evaluate
|
||||
// the LHS, then copy the AX/DX/CX[/R8] return-ABI words
|
||||
// into the slot so the tag-check + payload load indexes
|
||||
// off memory like the IDENT path. Without this, scrutoff
|
||||
// stayed 0 and the tag read fell on (BP) — the saved-BP
|
||||
// word — and the payload read on +8(BP) — the return
|
||||
// address. Bug #200.
|
||||
scrutt = matchscrutt(c, lhs);
|
||||
let spillsz: i32 = matchspillsz(c, scrutt);
|
||||
scrutoff = localalloc(c, "@asrt_spill", spillsz, nil);
|
||||
cgexpr(c, lhs);
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(scrutoff: i64);
|
||||
emitline("(BP)\n");
|
||||
if (!isnullabletype(scrutt)) {
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((scrutoff + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
// Mirror cstage cmd/w6c/cgen.c:6313-6315: only CX
|
||||
// → +16 when slot_size > 16. The 4-word case
|
||||
// (R8 → +24, slot_size > 24) is the cgmatch shape
|
||||
// (cgenexpr.ww:1454-1458, cmd/w6c/cgen.c:5988-5990)
|
||||
// but cstage cgtypeassert omits it; preserve the
|
||||
// asymmetry rather than diverge from rule 10
|
||||
// byte-id. Filed inline as a cstage twin task.
|
||||
if (spillsz > 16) {
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((scrutoff + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
let want: i32 = cgtagvariantidx(c, scrutt, n.rhs);
|
||||
|
||||
Reference in New Issue
Block a user