Files
ww/test/asm/ampfn_test.ww
Hojun-Cho 49464efdc5 test: port the amp-fn LEAQ observer to ww; retire 764_amp_fn_ident
The five symmetric rows compile their r764_amp_fn_ident_* fixture
sources in place (runtime owned by those fixtures; pre-fix junk-store
still exits 0, so the LEAQ window is the discriminator) and keep the
cs==ws byte-id leg. The cross-module row stays cstage-only pending
#184; its wwstage/byte-id legs graduate with that task.
2026-08-08 15:05:34 +09:00

128 lines
4.6 KiB
Plaintext

package ampfn_test;
// Direct-w6c asm-window gate over `&fn` address-of lowering (#180).
// Port of the retired native carrier test/wcc/764_amp_fn_ident.c;
// every unowned assertion preserved. Runtime for the five symmetric
// rows is owned by the r764_amp_fn_ident_* fixtures (their sources
// are compiled here IN PLACE so fixture and window can never drift);
// pre-fix those fixtures still exit 0 on the junk store — the LEAQ
// presence below is the actual discriminator the corpus cannot own.
//
// Rows 1-5: the cstage .s must contain the row's `LEAQ <sym>(SB)`
// line (absent pre-#180: the cgen N_UN TK_AMP IDENT arm had no TY_FN
// branch, so the assign site stored stale AX junk), and cstage vs
// wwstage .s must be byte-identical (rule 10; the carrier compared
// driver __root.s — same emitter output, direct w6c form per the
// residual audit).
//
// cross_module: `&pkg.fn` over a real import tree. CSTAGE-ONLY —
// wwstage bails asserttyped on the N_UN TK_AMP N_DOT-mod-ident shape
// (open #184); its build/run and byte-id legs graduate when #184
// lifts. The M1 path-mangled `LEAQ wcamffn764mod.somefn(SB)` and the
// build+run exit 0 are pinned; separate fresh trees keep the -S
// compile and the full build from sharing a stale sepwork.
import os;
import os.exec;
import strings;
import testenv;
import time;
fn fail(label: str, why: str) void = {
let m: str = strings.concat("ampfn FAIL: ", label, " -- ", why, "\n");
os.write(2, m.ptr, m.len: u64);
assert(false);
};
fn tmo() time.duration = {
return (180i64 * (time.second: i64)): time.duration;
};
fn emit(td: str, label: str, stage: str, drv: str, src: str,
outname: str) void = {
let av: []str = [drv, "-o", strings.concat(td, "/", outname), src];
let co: testenv.commandout;
testenv.runcommand(td, td, stage, av, tmo(), &co);
if (co.termination != exec.termination.EXIT || co.code != 0) {
fail(label, strings.concat(stage, " compile failed"));
};
};
fn leaqrow(label: str, fixture: str, needle: str) void = {
let src: str = strings.concat(testenv.repo(),
"/test/wcc/data/r764_amp_fn_ident_", fixture, "/case.ww");
let td: str = testenv.fresh();
emit(td, label, "cstage", testenv.driver("w6c"), src, "cs.s");
emit(td, label, "wwstage", testenv.driver("w6c_ww"), src, "ws.s");
let cs: str = testenv.readfile(strings.concat(td, "/cs.s"));
let ws: str = testenv.readfile(strings.concat(td, "/ws.s"));
if (!testenv.has(cs, needle)) {
fail(label, strings.concat("missing `", needle,
"` in cstage .s (silent TK_AMP IDENT drop)"));
};
if (!testenv.same(cs, ws)) {
fail(label, "cstage vs wwstage asm differs");
};
testenv.clean(td);
};
@test fn ampfnleaq() void = {
leaqrow("minimal", "minimal", "LEAQ\tmain.add1(SB)");
leaqrow("branched_callee", "branched", "LEAQ\tmain.bb(SB)");
leaqrow("alias_chain", "alias_chain", "LEAQ\tmain.add1(SB)");
leaqrow("fn_with_args", "args", "LEAQ\tmain.many(SB)");
leaqrow("fn_tuple_return", "tuple_return", "LEAQ\tmain.pair(SB)");
};
fn xmodtree() str = {
let td: str = testenv.fresh();
assert(os.mkdir(strings.concat(td, "/wcamffn764mod"), 493) == 0);
testenv.writefile(
strings.concat(td, "/wcamffn764mod/wcamffn764mod.ww"),
strings.concat(
"package wcamffn764mod;\n",
"export fn somefn(x: i32) i32 = { return x + 1; };\n"));
testenv.writefile(strings.concat(td, "/main764.ww"), strings.concat(
"package main;\n",
"import wcamffn764mod;\n",
"export fn main() i32 = {\n",
" let f = &wcamffn764mod.somefn;\n",
" return 0;\n",
"};\n"));
return td;
};
fn runcode(dir: str, name: str, argv: []str) i32 = {
let co: testenv.commandout;
testenv.runcommand(dir, dir, name, argv, tmo(), &co);
if (co.termination != exec.termination.EXIT) { return -1; };
return co.code;
};
@test fn crossmodule() void = {
let tda: str = xmodtree();
let av: []str = [testenv.driver("ww"), "build", "-S", "-o",
strings.concat(tda, "/main764"), "main764.ww"];
if (runcode(tda, "compile", av) != 0) {
fail("cross_module", "cstage ww build -S failed");
};
let s: str = testenv.readfile(
strings.concat(tda, "/main764.sepwork/__root.s"));
if (!testenv.has(s, "LEAQ\twcamffn764mod.somefn(SB)")) {
fail("cross_module",
"missing path-mangled LEAQ wcamffn764mod.somefn(SB)");
};
testenv.clean(tda);
let tdb: str = xmodtree();
let bav: []str = [testenv.driver("ww"), "build", "-o",
strings.concat(tdb, "/main764"), "main764.ww"];
if (runcode(tdb, "build", bav) != 0) {
fail("cross_module", "cstage ww build failed");
};
let rav: []str = [strings.concat(tdb, "/main764")];
if (runcode(tdb, "run", rav) != 0) {
fail("cross_module", "run-exit != 0");
};
testenv.clean(tdb);
};