wcc/ww: cgcall drain pops widened GP words before the float arm
The arg-drain loop checked node_isfloat before popping a widened arg's GP words, so a float arg adjacent to a widened (tagged) arg read the wrong stack slot: the f64 took the widened payload (#30), or the float arm ate the tag word into X0 and the payload landed in DI as the tag (#48). One missing branch, two manifestations — mirror cstage's widen-first pop (cgen.c:9650-9665). Review items #30+#48 (fold reviewer-verified one-mechanism against the cstage twin).
This commit is contained in:
@@ -7756,6 +7756,36 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
a = a.next;
|
||||
continue;
|
||||
};
|
||||
// Widen-first pop (#30/#48): a concrete arg widened into a
|
||||
// tagged-union param was pushed as slotsize/8 GP words (tag +
|
||||
// payload). Drain those words into the INTEGER arg cursor
|
||||
// BEFORE the float check below — else a widened f64-source box
|
||||
// gets misclassified as a float arg (its tag word drained into
|
||||
// X0, #48), and a float arg FOLLOWING a widened arg reads the
|
||||
// widened box's leftover payload word (#30). Mirror of cstage's
|
||||
// precomputed widen[i] branch (cmd/w6c/cgen.c cgcall, popped
|
||||
// before node_isfloat). argtaggedwidensz is the shared SSoT with
|
||||
// pushargsrev's push count.
|
||||
let dwsz: i32 = argtaggedwidensz(c, a, dparam);
|
||||
if (dwsz >= 16) {
|
||||
let dwb: i32 = dwsz / 8;
|
||||
let dwk: i32 = 0;
|
||||
for (dwk < dwb) {
|
||||
if (intidx < 6) {
|
||||
emitline("\tPOPQ\t");
|
||||
emitline(argregname(intidx));
|
||||
emitline("\n");
|
||||
intidx += 1;
|
||||
} else {
|
||||
stackslots += 1;
|
||||
};
|
||||
popped += 1;
|
||||
dwk += 1;
|
||||
};
|
||||
if (dparam != nil) { dparam = dparam.next; };
|
||||
a = a.next;
|
||||
continue;
|
||||
};
|
||||
let fk: i32 = 0;
|
||||
if (a != nil) {
|
||||
let at: *tinfo = a.type_: *tinfo;
|
||||
|
||||
Reference in New Issue
Block a user