asmgate_test.ww absorbs 530_w6a_parsenum and 989_datargate_run: the strtoll-semantics identity rows plus the bare-minus reject against both assemblers with cross-stage .o byte-identity, and the undefined DATAR-slot loud reject (no .o written) with the defined-slot byte-identical ok path. The w6a_ww skip gates drop: the Make target declares both assemblers.
157 lines
5.5 KiB
Plaintext
157 lines
5.5 KiB
Plaintext
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);
|
|
};
|