cgen: wwstage fnretlookup resolves cross-module callee f64 return type (#98/#101)

exprfloatkind's N_CALL arm only set the callee name for an N_IDENT
callee, so a module-qualified `mod.g()` callee never reached any
return-type lookup and fell through to integer (kind 0). Both f64
consumers then took the integer path for an imported f64-returning
fn: cgcast emitted MOVSXD instead of CVTTSD2SI (#101), and pushargsrev
spilled the call result as a GPR PUSHQ/POPQ instead of the MOVSD float
spill (#98) — one root, two symptoms.

Route the N_DOT callee through fnretlookupmod with the module
qualifier, mirroring nodeisslice / nodeisstr's #34 N_DOT arm, so a
cross-module f64 call resolves to kind 2 exactly like same-module
already does. This aligns wwstage UP to cstage, whose cg_isfloat reads
the resolved call result type directly (cmd/w6c/cgen.c:117,155) and is
correct for both cases. Consumers (cgcast, pushargsrev) unchanged.
This commit is contained in:
2026-05-25 13:48:31 +09:00
parent 6f8b658c17
commit 7b3abf0ec5

View File

@@ -1889,19 +1889,36 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
return 0;
};
if (k == nkind.N_CALL) {
// Look up the callee's declared return type — fnretlookup
// Look up the callee's declared return type — fnretlookupmod
// returns the type-AST. Routes float-returning fns through
// the X0 ABI so cglet / cgassign know to spill from X0.
let nm: str;
nm.ptr = nil; nm.len = 0;
if (n.lhs != nil) {
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
};
if (nm.len > 0) {
let rtyp: *node = fnretlookup(c, nm);
// N_DOT (cross-module callee, #98/#101): without the explicit
// arm a module-qualified `myf.g()` callee never reaches any
// lookup, so an imported f64-returning fn fell through to
// integer (0) — cgcast then emitted MOVSXD not CVTTSD2SI
// (#101) and pushargsrev spilled the result as a GPR not
// MOVSD (#98). Mirror nodeisslice / nodeisstr's #34 N_DOT arm
// so cross-module resolves to kind 2 like same-module does.
let callee: *node = n.lhs;
if (callee != nil) {
if (callee.kind == nkind.N_IDENT) {
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
if (isf32type(c, rtyp)) { return 1; };
if (isfloattype(c, rtyp)) { return 2; };
};
if (callee.kind == nkind.N_DOT) {
let cmod: str;
cmod.ptr = nil; cmod.len = 0;
if (callee.lhs != nil) {
if (callee.lhs.kind == nkind.N_IDENT) {
cmod = callee.lhs.str;
};
};
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
if (isf32type(c, rtyp)) { return 1; };
if (isfloattype(c, rtyp)) { return 2; };
};
};
return 0;
};
if (k == nkind.N_DOT) {