From 7b3abf0ec5fcb2e2bf5d286b042eedc6f17ba762 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 25 May 2026 13:48:31 +0900 Subject: [PATCH] cgen: wwstage fnretlookup resolves cross-module callee f64 return type (#98/#101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- selfhost/cmd/wcc/cgenutil.ww | 37 ++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) 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; };