From 1b4f25ac45a066abe4ffc5d48b49922728934908 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 6 Jun 2026 20:28:50 +0900 Subject: [PATCH] wcc/cgen: #119 scalar &fn global DATA via the #117 reloc helper (both-stage) --- cmd/w6c/cgen.c | 19 +++++++++++++++++++ selfhost/cmd/w6c/main.combined.ww | 23 ++++++++++++++++++++--- selfhost/cmd/wcc/cgen.ww | 23 ++++++++++++++++++++--- selfhost/cmd/wwdump/main.combined.ww | 23 ++++++++++++++++++++--- test/wcc/946_const_slice_aggregate_run.c | 15 +++++++++++++++ 5 files changed, 94 insertions(+), 9 deletions(-) diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index fa6ec624..65950829 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -15359,6 +15359,25 @@ emit_lets(Cg *c, FILE *out, Node *file) Node *r = d->rhs; while (r != NULL && r->kind == N_CAST) r = r->lhs; if (r == NULL) continue; + /* #119: a scalar `&fn` global — 8B zero ptr + * placeholder + the &fn->DATAR reloc (the #117 + * helper at its second consumer). Pre-#119 this + * fell through fold_int_literal -> continue -> no + * DATA -> undefined ref / garbage deref. */ + { + const char *fsym = node_fnptr_sym(c, r); + if (fsym != NULL) { + const char *sym = mod_mangle_value(c, + d->str, d->module); + fprintf(out, "DATAW %s(SB),\"", sym); + for (int i = 0; i < 8; i++) + emit_data_byte(out, 0); + fputs("\"\n", out); + fprintf(out, "DATAR %s+0(SB),%s(SB)\n", + sym, fsym); + continue; + } + } /* Same helper as emit_defs (#24): widens * the gate to cover N_UN(TK_MINUS/TILDE/PLUS, * leaf) so `let x: i8 = -1i8;` and friends diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index a282759c..d441347a 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -40247,8 +40247,10 @@ fn emitletdataw(c: *cgen, file: *node) void = { if (sz == 8 && !issg && fsz == 0 && !isarr8 && !istup && !istagged) { let v: u64 = 0u64; let ok: bool = true; + let fnp: bool = false; + let r: *node = nil; if (d.rhs != nil) { - let r: *node = d.rhs; + r = d.rhs; for (r != nil) { if (r.kind != nkind.N_CAST) { break; }; r = r.lhs; @@ -40258,9 +40260,24 @@ fn emitletdataw(c: *cgen, file: *node) void = { // int leaf folds. `let x: i8 = -1i8;` // arrives as N_UN(TK_MINUS, N_INTLIT) // after the typed-AST cast peel. - ok = foldintliteral(r, &v); + // #119: a scalar `&fn` global — the &fn->DATAR + // reloc (the #117 helper at its second consumer). + if (nodefnptr(c, r)) { fnp = true; } + else { ok = foldintliteral(r, &v); }; }; - if (ok) { + if (fnp) { + emitline("DATAW "); + emitsymnamehint(c, nm, d.nmod); + emitline("(SB),\""); + let zi: i32 = 0; + for (zi < 8) { emitdatawbyte(0u8); zi += 1; }; + emitline("\"\n"); + emitline("DATAR "); + emitsymnamehint(c, nm, d.nmod); + emitline("+0(SB),"); + emitfnname(c, r.lhs.str, c.curmod); + emitline("(SB)\n"); + } else if (ok) { emitline("DATAW "); emitsymnamehint(c, nm, d.nmod); emitline("(SB),\""); diff --git a/selfhost/cmd/wcc/cgen.ww b/selfhost/cmd/wcc/cgen.ww index 621c3f74..a049a523 100644 --- a/selfhost/cmd/wcc/cgen.ww +++ b/selfhost/cmd/wcc/cgen.ww @@ -2693,8 +2693,10 @@ fn emitletdataw(c: *cgen, file: *node) void = { if (sz == 8 && !issg && fsz == 0 && !isarr8 && !istup && !istagged) { let v: u64 = 0u64; let ok: bool = true; + let fnp: bool = false; + let r: *node = nil; if (d.rhs != nil) { - let r: *node = d.rhs; + r = d.rhs; for (r != nil) { if (r.kind != nkind.N_CAST) { break; }; r = r.lhs; @@ -2704,9 +2706,24 @@ fn emitletdataw(c: *cgen, file: *node) void = { // int leaf folds. `let x: i8 = -1i8;` // arrives as N_UN(TK_MINUS, N_INTLIT) // after the typed-AST cast peel. - ok = foldintliteral(r, &v); + // #119: a scalar `&fn` global — the &fn->DATAR + // reloc (the #117 helper at its second consumer). + if (nodefnptr(c, r)) { fnp = true; } + else { ok = foldintliteral(r, &v); }; }; - if (ok) { + if (fnp) { + emitline("DATAW "); + emitsymnamehint(c, nm, d.nmod); + emitline("(SB),\""); + let zi: i32 = 0; + for (zi < 8) { emitdatawbyte(0u8); zi += 1; }; + emitline("\"\n"); + emitline("DATAR "); + emitsymnamehint(c, nm, d.nmod); + emitline("+0(SB),"); + emitfnname(c, r.lhs.str, c.curmod); + emitline("(SB)\n"); + } else if (ok) { emitline("DATAW "); emitsymnamehint(c, nm, d.nmod); emitline("(SB),\""); diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 36e17eb2..04f2efbb 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -40247,8 +40247,10 @@ fn emitletdataw(c: *cgen, file: *node) void = { if (sz == 8 && !issg && fsz == 0 && !isarr8 && !istup && !istagged) { let v: u64 = 0u64; let ok: bool = true; + let fnp: bool = false; + let r: *node = nil; if (d.rhs != nil) { - let r: *node = d.rhs; + r = d.rhs; for (r != nil) { if (r.kind != nkind.N_CAST) { break; }; r = r.lhs; @@ -40258,9 +40260,24 @@ fn emitletdataw(c: *cgen, file: *node) void = { // int leaf folds. `let x: i8 = -1i8;` // arrives as N_UN(TK_MINUS, N_INTLIT) // after the typed-AST cast peel. - ok = foldintliteral(r, &v); + // #119: a scalar `&fn` global — the &fn->DATAR + // reloc (the #117 helper at its second consumer). + if (nodefnptr(c, r)) { fnp = true; } + else { ok = foldintliteral(r, &v); }; }; - if (ok) { + if (fnp) { + emitline("DATAW "); + emitsymnamehint(c, nm, d.nmod); + emitline("(SB),\""); + let zi: i32 = 0; + for (zi < 8) { emitdatawbyte(0u8); zi += 1; }; + emitline("\"\n"); + emitline("DATAR "); + emitsymnamehint(c, nm, d.nmod); + emitline("+0(SB),"); + emitfnname(c, r.lhs.str, c.curmod); + emitline("(SB)\n"); + } else if (ok) { emitline("DATAW "); emitsymnamehint(c, nm, d.nmod); emitline("(SB),\""); diff --git a/test/wcc/946_const_slice_aggregate_run.c b/test/wcc/946_const_slice_aggregate_run.c index c6eb52bd..84d6945e 100644 --- a/test/wcc/946_const_slice_aggregate_run.c +++ b/test/wcc/946_const_slice_aggregate_run.c @@ -129,6 +129,21 @@ static const struct row rows[] = { " if (len(tbl) != 3) { return 1; };\n" " return 0;\n" "};\n", 0, K_RUN, NULL }, + /* #119: scalar &fn module-globals — DISTINCT fns, each called back + * through the reloc (pre-#119: no DATA → undefined ref / garbage). */ + { "scalar_fnptr", + "package main;\n" + "fn fa(c: rune) bool = { return c == 'a'; };\n" + "fn fz(c: rune) bool = { return c == 'z'; };\n" + "let pf: *fn(c: rune) bool = &fa;\n" + "let pg: *fn(c: rune) bool = &fz;\n" + "export fn main() i32 = {\n" + " if (!(*pf)('a')) { return 1; };\n" + " if ((*pf)('z')) { return 2; };\n" + " if (!(*pg)('z')) { return 3; };\n" + " if ((*pg)('a')) { return 4; };\n" + " return 0;\n" + "};\n", 0, K_RUN, NULL }, /* honest boundary (rule 7): a non-tuple aggregate element (here a * bare []str) stays LOUD, symmetric both stages — #117 is NARROW to * the (str,*fn) tuple form, not the full slice-of-aggregate family. */