package asmgate_test; // Assembler input gates, w6a vs w6a_ww on hand-written asm the // compiler never emits. Ports of the retired native carriers // test/wcc/530_w6a_parsenum.c and 989_datargate_run.c; every // assertion preserved. // // parsenum (530, F14 #62) — w6a_ww's parsenum must match the C // twin's strtoll(s,end,0) (cmd/w6a/lex.c:30): `$ 5` skips the // whitespace (→5), `$08` stops at the octal-invalid '8' (→0), and a // bare `-(BP)` is a loud reject on BOTH stages. Identity rows // (including the canonical control shapes w6c does emit) must // produce byte-identical .o across the two assemblers. // // datargate (989, #59 F15 c5) — a DATAR against a slot never defined // by DATAW is a loud reject on both stages with NO .o written (the // pre-c5 wwstage silently dropped the R_X86_64_64 reloc under rc=0); // the DATAW-then-DATAR shape assembles on both stages to a // byte-identical .o (rule 10). // // Dropped C machinery, not assertions: the w6a_ww absent-tool skip // gates (the Make target declares both assemblers) and per-file // unlink accounting (testenv.clean). import os; import os.exec; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("asmgate FAIL: ", label, " -- ", why, "\n"); os.write(2, m.ptr, m.len: u64); assert(false); }; fn tmo() time.duration = { return (240i64 * (time.second: i64)): time.duration; }; // -1 encodes an abnormal (non-EXIT) termination, never a valid code. 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; }; fn assemble(td: str, tool: str, tag: str, src: str, obj: str) i32 = { let av: []str = [testenv.driver(tool), "-o", obj, src]; return runcode(td, tag, av); }; // ---- parsenum (530) ---------------------------------------------------- @test fn parsenum() void = { let td: str = testenv.fresh(); let labels: []str = ["ws_after_dollar", "leading_zero", "plain_imm", "plain_imm_eight", "hex_imm", "zero_imm", "neg_indir", "pos_indir"]; // rows 0-1 are the strtoll edge shapes; the rest are the // canonical controls w6c actually emits (no regression) let texts: []str = [ "TEXT main,$16\n\tMOVQ\t$ 5, AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t$08, AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t$5, AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t$8, AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t$0x1f, AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t$0, AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t-8(BP), AX\n\tRET\n", "TEXT main,$16\n\tMOVQ\t8(BP), AX\n\tRET\n", ]; let i: i32 = 0; for (i < 8) { let src: str = strings.concat(td, "/", labels[i], ".s"); let co: str = strings.concat(td, "/", labels[i], "_c.o"); let wo: str = strings.concat(td, "/", labels[i], "_w.o"); testenv.writefile(src, texts[i]); if (assemble(td, "w6a", strings.concat("c_", labels[i]), src, co) != 0) { fail("parsenum", strings.concat(labels[i], ": cstage assemble failed")); }; if (assemble(td, "w6a_ww", strings.concat("w_", labels[i]), src, wo) != 0) { fail("parsenum", strings.concat(labels[i], ": wwstage assemble failed")); }; if (!testenv.same(testenv.readfile(co), testenv.readfile(wo))) { fail("parsenum", strings.concat(labels[i], ": .o differ across assemblers")); }; i += 1; }; // reject row: no digit after the sign — loud on both stages let rsrc: str = strings.concat(td, "/bare_minus_indir.s"); testenv.writefile(rsrc, "TEXT main,$16\n\tMOVQ\t-(BP), AX\n\tRET\n"); if (assemble(td, "w6a", "c_bare_minus", rsrc, strings.concat(td, "/bare_minus_c.o")) == 0) { fail("parsenum", "bare_minus_indir: cstage accepted, want reject"); }; if (assemble(td, "w6a_ww", "w_bare_minus", rsrc, strings.concat(td, "/bare_minus_w.o")) == 0) { fail("parsenum", "bare_minus_indir: wwstage accepted, want reject"); }; testenv.clean(td); }; // ---- datargate (989) --------------------------------------------------- @test fn datargate() void = { let td: str = testenv.fresh(); let bads: str = strings.concat(td, "/bad.s"); let oks: str = strings.concat(td, "/ok.s"); testenv.writefile(bads, "TEXT f,$0\n\tRET\n\tDATAR x+0(SB), f(SB)\n"); testenv.writefile(oks, strings.concat( "TEXT f,$0\n\tRET\n", "DATAW x(SB),\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n", "\tDATAR x+0(SB), f(SB)\n")); // bad: both stages loud, and the reject must not write a .o let tools: []str = ["w6a", "w6a_ww"]; let t: i32 = 0; for (t < 2) { let obj: str = strings.concat(td, "/bad_", tools[t], ".o"); if (assemble(td, tools[t], strings.concat("bad_", tools[t]), bads, obj) == 0) { fail("datargate", strings.concat(tools[t], ": rc=0 on an undefined DATAR slot (reloc dropped?)")); }; if (testenv.exists(obj)) { fail("datargate", strings.concat(tools[t], ": .o written on the reject path")); }; t += 1; }; // ok: both stages rc=0, .o present, byte-identical (rule 10) let cobj: str = strings.concat(td, "/ok_c.o"); let wobj: str = strings.concat(td, "/ok_w.o"); if (assemble(td, "w6a", "ok_c", oks, cobj) != 0 || !testenv.exists(cobj)) { fail("datargate", "cstage failed the defined-slot path"); }; if (assemble(td, "w6a_ww", "ok_w", oks, wobj) != 0 || !testenv.exists(wobj)) { fail("datargate", "wwstage failed the defined-slot path"); }; if (!testenv.same(testenv.readfile(cobj), testenv.readfile(wobj))) { fail("datargate", "cs/ww .o differ on the defined-slot path"); }; testenv.clean(td); };