selfhost+test: cgdot LEAQ-of-fn for module-qualified N_DOT (#12)
wwstage cgdot lacked a TY_FN branch for module-qualified N_DOT
rvalues. `let p = mod1.ping` fell through to the MOVQ/LEAQ-narrow
fallback, loading 8 prologue bytes from the fn's first instruction
instead of taking its address. Cstage cgdot already handled this
case (wired during #9, f1440bf).
Mirror cstage: gate on fnretlookup(c, fld) before the localloadop
fallback; emit `LEAQ <module>.<name>(SB), AX` via emitfnname with
the hint from lhs.str.
Extend 706_fnlabel_mangle: pos.ww now stores mod1.ping/mod2.ping
into local fn-pointer slots and dispatches through them in addition
to the existing direct calls. Expected exit 56 → 112. Regression
shape: without the new branch, MOVQ leaf(SB) loads the prologue
bytes; indirect call jumps into garbage → SIGSEGV.
ww2 == ww3 == ww4 byte-identical at the new emit.
This commit is contained in:
@@ -10723,6 +10723,18 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// fallback the C cgen takes when bt is NULL/tyerr.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
// `let p = mod.fn` — fn rvalue via N_DOT. Mirror of
|
||||
// cstage cgdot's TY_FN branch (mafn with module hint).
|
||||
// Without this the MOVQ leaf(SB) fallback below would
|
||||
// load 8 bytes of fn-prologue code into AX instead of
|
||||
// the fn address.
|
||||
let frt: *node = fnretlookup(c, fld);
|
||||
if (frt != nil) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, fld, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
let mqop: str = localloadop(c, letvartnode(c, fld));
|
||||
if (streq(mqop, "MOVQ")) {
|
||||
emitline("\tMOVQ\t");
|
||||
|
||||
@@ -1707,6 +1707,18 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// fallback the C cgen takes when bt is NULL/tyerr.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
// `let p = mod.fn` — fn rvalue via N_DOT. Mirror of
|
||||
// cstage cgdot's TY_FN branch (mafn with module hint).
|
||||
// Without this the MOVQ leaf(SB) fallback below would
|
||||
// load 8 bytes of fn-prologue code into AX instead of
|
||||
// the fn address.
|
||||
let frt: *node = fnretlookup(c, fld);
|
||||
if (frt != nil) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, fld, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
let mqop: str = localloadop(c, letvartnode(c, fld));
|
||||
if (streq(mqop, "MOVQ")) {
|
||||
emitline("\tMOVQ\t");
|
||||
|
||||
@@ -10723,6 +10723,18 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// fallback the C cgen takes when bt is NULL/tyerr.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
// `let p = mod.fn` — fn rvalue via N_DOT. Mirror of
|
||||
// cstage cgdot's TY_FN branch (mafn with module hint).
|
||||
// Without this the MOVQ leaf(SB) fallback below would
|
||||
// load 8 bytes of fn-prologue code into AX instead of
|
||||
// the fn address.
|
||||
let frt: *node = fnretlookup(c, fld);
|
||||
if (frt != nil) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitfnname(c, fld, lhs.str);
|
||||
emitline("(SB), AX\n");
|
||||
return;
|
||||
};
|
||||
let mqop: str = localloadop(c, letvartnode(c, fld));
|
||||
if (streq(mqop, "MOVQ")) {
|
||||
emitline("\tMOVQ\t");
|
||||
|
||||
Reference in New Issue
Block a user