From a030268c52d3c50897a801dbea7e9da2d77d810f Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sun, 9 Aug 2026 03:38:03 +0900 Subject: [PATCH] wcc: build generated labels at their exact size --- selfhost/cmd/wcc/cgen.ww | 55 +++++++++++++++------------------- test/asm/dataemit_test.ww | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 31 deletions(-) diff --git a/selfhost/cmd/wcc/cgen.ww b/selfhost/cmd/wcc/cgen.ww index d1e3a254..b125f6f1 100644 --- a/selfhost/cmd/wcc/cgen.ww +++ b/selfhost/cmd/wcc/cgen.ww @@ -822,40 +822,35 @@ fn emitoff(v: i64) void = { // avoid cross-module same-leaf collisions (task #13); w6a accepts // '.' in label-cont (lex.c:18). fn mklabel(c: *cgen, prefix: str) str = { - let buf: [128]u8; - let i: i32 = 0; let mname: str = c.curmod; + let fname: str = c.fnname; + let ns: str = strconv.i64tos(c.labelseq: i64, strconv.base.DEC); + c.labelseq += 1; + let total: i32 = mname.len + fname.len + prefix.len + ns.len + 2; + if (mname.len > 0) { total += 1; }; + let p: []u8 = alloc([], (total: u64) + 1u64)!; + let i: i32 = 0; let j: i32 = 0; for (j < mname.len) { - buf[i] = mname[j]; + p[i] = mname[j]; i += 1; j += 1; }; - if (mname.len > 0) { buf[i] = '.'; i += 1; }; - let fname: str = c.fnname; + if (mname.len > 0) { p[i] = '.'; i += 1; }; j = 0; for (j < fname.len) { - buf[i] = fname[j]; + p[i] = fname[j]; i += 1; j += 1; }; - buf[i] = '_'; i += 1; + p[i] = '_'; i += 1; j = 0; for (j < prefix.len) { - buf[i] = prefix[j]; + p[i] = prefix[j]; i += 1; j += 1; }; - buf[i] = '_'; i += 1; - let ns: str = strconv.i64tos(c.labelseq: i64, strconv.base.DEC); + p[i] = '_'; i += 1; let n: i32 = ns.len; let dk: i32 = 0; - for (dk < n) { buf[i + dk] = ns.ptr[dk]; dk += 1; }; - c.labelseq += 1; - let total: i32 = i + n; - let p: []u8 = alloc([], (total: u64) + 1u64)!; - let k: i32 = 0; - for (k < total) { - p[k] = buf[k]; - k += 1; - }; + for (dk < n) { p[i + dk] = ns.ptr[dk]; dk += 1; }; p[total] = 0u8; let r: str; r.ptr = p.ptr; @@ -917,22 +912,20 @@ fn internstrlit(c: *cgen, bytes: str) str = { // #49: per-unit prefix so two str-bearing packages don't both emit // `_S_0`.. and collide at w6l link. Pure function of the module path // (matching mklabel's spelling), so the self-host fixed-point holds. - let buf: [128]u8; - let i: i32 = 0; let mname: str = c.curmod; - let j: i32 = 0; - for (j < mname.len) { buf[i] = mname[j]; i += 1; j += 1; }; - if (mname.len > 0) { buf[i] = '.'; i += 1; }; - buf[i] = 95u8; i += 1; buf[i] = 83u8; i += 1; buf[i] = 95u8; i += 1; // "_S_" let ns: str = strconv.i64tos(c.strlitseq: i64, strconv.base.DEC); + c.strlitseq += 1; + let total: i32 = mname.len + ns.len + 3; + if (mname.len > 0) { total += 1; }; + let p: []u8 = alloc([], (total: u64) + 1u64)!; + let i: i32 = 0; + let j: i32 = 0; + for (j < mname.len) { p[i] = mname[j]; i += 1; j += 1; }; + if (mname.len > 0) { p[i] = '.'; i += 1; }; + p[i] = 95u8; i += 1; p[i] = 83u8; i += 1; p[i] = 95u8; i += 1; let n: i32 = ns.len; let dk: i32 = 0; - for (dk < n) { buf[i + dk] = ns.ptr[dk]; dk += 1; }; - c.strlitseq += 1; - let total: i32 = i + n; - let p: []u8 = alloc([], (total: u64) + 1u64)!; - let k: i32 = 0; - for (k < total) { p[k] = buf[k]; k += 1; }; + for (dk < n) { p[i + dk] = ns.ptr[dk]; dk += 1; }; p[total] = 0u8; let lab: str; lab.ptr = p.ptr; diff --git a/test/asm/dataemit_test.ww b/test/asm/dataemit_test.ww index 6994ae7b..e09b80e2 100644 --- a/test/asm/dataemit_test.ww +++ b/test/asm/dataemit_test.ww @@ -338,3 +338,65 @@ fn strdefcheck(label: str, stage: str, s: str, sym: str, wantlea: str, "export fn main() i32 = { return 0; };\n"), "TEXT beta.bfn", "LEAQ\tbeta._S_", "alpha.MSG(SB)"); }; + +fn longident(prefix: str) str = { + let run: str = "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"; + return strings.concat(prefix, run, run, run); +}; + +@test fn longgeneratednames() void = { + let fnname: str = longident("f"); + let fsrc: str = strings.concat( + "package main;\n", + "fn ", fnname, "() i32 = {\n", + " if (true) { return 42; };\n", + " return 1;\n", + "};\n", + "export fn main() i32 = { return ", fnname, "(); };\n"); + let ftd: str = testenv.fresh(); + testenv.writefile(strings.concat(ftd, "/src.ww"), fsrc); + emitstage(ftd, "long_function_label", "cstage", + testenv.driver("w6c"), "cs.s"); + emitstage(ftd, "long_function_label", "wwstage", + testenv.driver("w6c_ww"), "ws.s"); + let fcs: str = testenv.readfile(strings.concat(ftd, "/cs.s")); + let fws: str = testenv.readfile(strings.concat(ftd, "/ws.s")); + let textneedle: str = strings.concat("TEXT main.", fnname, ",$0"); + let labelneedle: str = strings.concat("main.", fnname, "_end_"); + if (!testenv.has(fcs, textneedle) || !testenv.has(fws, textneedle) + || !testenv.has(fcs, labelneedle) || !testenv.has(fws, labelneedle)) { + fail("long_function_label", "full generated label missing"); + }; + if (!testenv.same(fcs, fws)) { + fail("long_function_label", "cstage vs wwstage asm differs"); + }; + testenv.clean(ftd); + + let modname: str = longident("p"); + let ssrc: str = strings.concat( + "package ", modname, ";\n", + "export fn f() i32 = {\n", + " let s: str = \"x\";\n", + " return s.len;\n", + "};\n"); + let std: str = testenv.fresh(); + testenv.writefile(strings.concat(std, "/src.ww"), ssrc); + emitstage(std, "long_strlit_label", "cstage", + testenv.driver("w6c"), "cs.s"); + emitstage(std, "long_strlit_label", "wwstage", + testenv.driver("w6c_ww"), "ws.s"); + let scs: str = testenv.readfile(strings.concat(std, "/cs.s")); + let sws: str = testenv.readfile(strings.concat(std, "/ws.s")); + let leaneedle: str = strings.concat("LEAQ\t", modname, + "._S_0(SB), AX"); + let dataneedle: str = strings.concat("DATA ", modname, + "._S_0(SB),\"x\\x00\""); + if (!testenv.has(scs, leaneedle) || !testenv.has(sws, leaneedle) + || !testenv.has(scs, dataneedle) || !testenv.has(sws, dataneedle)) { + fail("long_strlit_label", "full DATA/LEAQ label missing"); + }; + if (!testenv.same(scs, sws)) { + fail("long_strlit_label", "cstage vs wwstage asm differs"); + }; + testenv.clean(std); +};