selfhost+test: route tagged-CALL arg through natural push (#21)
Wwstage call-arg-emit recognized tagged args only when the source was an IDENT (already-materialized var). For N_CALL returning a tagged-union, the natural-push path mis-routed: AX (tag) pushed twice, AX clobbered with widentag(=0) between pushes, DX (payload) dropped entirely. After POP, DI ← 0, SI ← tag — both reversed and the payload word lost. Class A runtime miscompile, masked by zero in-tree call sites of the shape until lib/encoding/utf8's iterator API surfaced it via pre-flight A probe. Fix aligns wwstage DOWN to cstage (rule 10). cgenutil.ww:pushargsrev aistagged guard now fires for N_CALL whose callee returns a tagged whose slot matches the param's tagged slot (mirrors cmd/w6c/cgen.c: 4216-4221's type_eq guard), and the natural-push fallthrough adds a tagged-CALL arm pushing R8/CX/DX/AX high→low by slot size (mirrors cmd/w6c/cgen.c:4373-4387). cgenexpr.ww:cgcall's per-arg pop-count picks up the same taggedcallslot helper so the next arg's POPQ doesn't land on residual tag/payload words. Sister-family to #11/#14 in the variant-widen ABI chain — call-site/ caller-side surface, distinct from callee-side #11 (param decompose) and scratch-side #14 (return slot). Fifth corpus-coverage-blind unmask this session (catalog: i64 div/mod CQO #16; wwstage IDENT- local /= no-op #16-B2; cstage signed-DATA module-scope #19; wwstage silent-zero arrays #19 mirror; #21 call-arg DX drop). Test: 720_tagged_call_arg asm-presence row (PUSHQ DX appears between CALL and next CALL, before PUSHQ AX) + 924_tagged_call_arg_ run 9xx semantic row (5 rows: 4-variant CALL-source, 4-variant IDENT-source regression guard, 2-variant ptr/err, multi-arg tagged + scalar). Bootstrap byte-id (ww2 == ww3 == ww4) holds.
This commit is contained in:
@@ -3024,6 +3024,12 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
let extra: i32 = 0;
|
||||
if (nodeisstr(c, a)) { extra = 1; };
|
||||
if (nodeisslice(c, a)) { extra = 2; };
|
||||
// #21: tagged-CALL arg was pushed AX/DX/CX/R8 high→low
|
||||
// by pushargsrev; size the per-arg pop to match so the
|
||||
// next arg's POPQ doesn't land on residual tag/payload
|
||||
// words and shift intidx out of sync.
|
||||
let tcs: i32 = taggedcallslot(c, a);
|
||||
if (tcs > 0) { extra = tcs / 8 - 1; };
|
||||
let words: i32 = 1 + extra;
|
||||
let w: i32 = 0;
|
||||
for (w < words) {
|
||||
|
||||
Reference in New Issue
Block a user