diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index 38f4762b..67ef2aca 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -1889,18 +1889,35 @@ 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); - if (isf32type(c, rtyp)) { return 1; }; - if (isfloattype(c, rtyp)) { return 2; }; + // 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; };