w6c: keep unwrap destination off the call stack

This commit is contained in:
2026-08-09 03:44:12 +09:00
parent a030268c52
commit edacb40bfe
3 changed files with 113 additions and 28 deletions

View File

@@ -271,3 +271,81 @@ fn dotbaserow(label: str, src: str, needle: str) void = {
"export fn main() i32 = { return 0; };\n"),
"\tMOVQ\t$32, CX\n");
};
fn unwrapaligncheck(label: str, stage: str, s: str) void = {
let w: str = probewindow(label, stage, s);
let call: i32 = testenv.pos(w, "\tCALL\tmain.mkpair(SB)\n");
if (call < 0) {
fail(label, strings.concat(stage, ": no CALL main.mkpair"));
};
let pre: str = strings.sub(w, 0, call);
let post: str = strings.sub(w, call, w.len);
if (testenv.has(pre, "\tPUSHQ\tBX\n")) {
fail(label, strings.concat(stage,
": destination PUSHQ remains outstanding at CALL"));
};
if (!testenv.has(pre, "\tMOVQ\tBX, -")) {
fail(label, strings.concat(stage,
": destination address is not spilled BP-relative"));
};
if (!testenv.has(post, "\tMOVQ\t-")
|| !testenv.has(post, "(BP), BX\n")) {
fail(label, strings.concat(stage,
": destination address is not reloaded after CALL"));
};
if (!testenv.has(w, "TEXT main.probe,$16")) {
fail(label, strings.concat(stage,
": dedicated address spill is absent from the frame"));
};
};
fn commandexit(dir: str, name: str, av: []str) i32 = {
let co: testenv.commandout;
testenv.runcommand(dir, dir, name, av, tmo(), &co);
if (co.termination != exec.termination.EXIT) { return -1; };
return co.code;
};
@test fn unwrapcallalign() void = {
let label: str = "global_unwrap_call_alignment";
let td: str = testenv.fresh();
let src: str = strings.concat(
"package main;\n",
"type e = !i32;\n",
"type pair = struct { a: i64, b: i64 };\n",
"type box = struct { f: pair, guard: i64 };\n",
"fn mkpair(x: f64) (pair | e) = {\n",
" return pair { a = 111i64, b = 222i64 };\n",
"};\n",
"let gb: box = box {\n",
" f = pair { a = 9i64, b = 9i64 }, guard = 7i64\n",
"};\n",
"fn probe() i32 = {\n",
" gb.f = mkpair(1.25f64)!;\n",
" if (gb.f.a != 111i64 || gb.f.b != 222i64",
" || gb.guard != 7i64) { return 91; };\n",
" return 37;\n",
"};\n",
"export fn main() i32 = { return probe(); };\n");
testenv.writefile(strings.concat(td, "/src.ww"), src);
emitstage(td, label, "cstage", testenv.driver("w6c"), "cs.s");
emitstage(td, label, "wwstage", testenv.driver("w6c_ww"), "ws.s");
let cs: str = testenv.readfile(strings.concat(td, "/cs.s"));
let ws: str = testenv.readfile(strings.concat(td, "/ws.s"));
unwrapaligncheck(label, "cstage", cs);
unwrapaligncheck(label, "wwstage", ws);
if (!testenv.same(cs, ws)) {
fail(label, "cstage vs wwstage asm differs");
};
let out: str = strings.concat(td, "/unwrapalign");
let bav: []str = [testenv.driver("ww"), "build", "-o", out,
"src.ww"];
if (commandexit(td, "build", bav) != 0) {
fail(label, "runtime pin build failed");
};
let rav: []str = [out];
if (commandexit(td, "run", rav) != 37) {
fail(label, "payload/neighbor runtime exit != 37");
};
testenv.clean(td);
};