package dataemit_test; // Direct-w6c asm-shape gate over data/def emission and let lowering. // Port of the retired native carriers test/wcc/719_signed_data_emit.c, // 724_letdecl_zeroinit.c, 744_letcopy_struct.c and // 746_strdef_inline.c; every assertion preserved. Runtime rows are // owned elsewhere (test/lang/{signed_data_emit,local_zeroinit, // void_error_singleton}_test.ww, test/wcc/data/r744_letcopy_*) — the // directive-shape needles, zero-init/copy windows and count floors // here are the unowned remainder; 744's load-count floor still // catches a both-stages-identical partial copy that runtime checks // and byte-id both miss. // // 719 (#19): the whole .s must carry the EXACT `DATAW (SB), // ""` row — the payload rendered per emit_data_byte's // printable/escape contract (printable ASCII raw, else \xNN) — so a // future cgen refactor emitting the slot via a different directive // cannot slip past green semantics. Whole-file needle as in the C. // // 724 (STATUS-3 #22): the bare `let x: T;` 8B slot zero-init // `MOVQ $0, -` must appear inside [TEXT main.produce .. RET); the // byte-id leg is the actual #22 fix pin. // // 744 (STATUS-6 #32): `MOVQ\t-` source-slot load count floors // {1,3,4,4} over [TEXT main.produce .. next TEXT). // // 746 (#12): both str-def value-reference shapes must inline the // strlit pair (LEAQ ._S_ + MOVQ $39,) and never the bogus // `alpha.MSG(SB)` symbol load inside [TEXT sym .. RET). Per #49 the // strlit label carries the USE-site module's prefix. // // Byte-id legs ride every row as in the C. Dropped C machinery, not // assertions: w6c_ww-absent skip gates, getpid()-keyed /tmp names, // slurp caps. The `package main;` prefix reproduces wwtest_fputs // where the carrier injected it. import os; import os.exec; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("dataemit 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 emitstage(td: str, label: str, stage: str, drv: str, outname: str) void = { let av: []str = []; append(av, drv); append(av, "-o"); append(av, outname); append(av, "src.ww"); let co: testenv.commandout; testenv.runcommand(td, td, stage, av, tmo(), &co); let ok: bool = co.termination == exec.termination.EXIT && co.code == 0; if (!ok) { fail(label, strings.concat(stage, " compile failed")); }; }; // [first `sym` .. first `retneedle` after it), widened to EOF when // retneedle is missing and mustret == 0. fn asmwindow(label: str, stage: str, s: str, sym: str, retneedle: str, mustret: i32) str = { let fp: i32 = testenv.pos(s, sym); if (fp < 0) { fail(label, strings.concat(stage, ": no ", sym, " in .s")); }; let tail: str = strings.sub(s, fp, s.len); let rp: i32 = testenv.pos(tail, retneedle); if (rp < 0) { if (mustret != 0) { fail(label, strings.concat(stage, ": no RET inside ", sym)); }; return tail; }; return strings.sub(tail, 0, rp); }; // One 719 row: exact DATAW payload needle in both stages' .s, then // byte-id. fn datawrow(label: str, src: str, sym: str, bytes: str) void = { let td: str = testenv.fresh(); 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")); let needle: str = strings.concat("DATAW ", sym, "(SB),\"", bytes, "\""); if (!testenv.has(cs, needle)) { fail(label, strings.concat("cstage: ", needle, " missing")); }; if (!testenv.has(ws, needle)) { fail(label, strings.concat("wwstage: ", needle, " missing")); }; if (!testenv.same(cs, ws)) { fail(label, "cstage vs wwstage asm differs"); }; testenv.clean(td); }; // 719: two's-complement little-endian payloads at the declared // element width; 100 == 'd' and 56 == '8' stay raw per // emit_data_byte's printable arm. @test fn signeddataemit() void = { datawrow("i8_neg", strings.concat( "package main;\n", "let x: i8 = -1i8;\n", "fn main() i32 = { return 0; };\n"), "main.x", "\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff"); datawrow("i16_neg", strings.concat( "package main;\n", "let x: i16 = -2i16;\n", "fn main() i32 = { return 0; };\n"), "main.x", "\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff"); datawrow("i32_neg", strings.concat( "package main;\n", "let x: i32 = -100i32;\n", "fn main() i32 = { return 0; };\n"), "main.x", "\\x9c\\xff\\xff\\xff\\xff\\xff\\xff\\xff"); datawrow("i64_neg", strings.concat( "package main;\n", "let x: i64 = -1000i64;\n", "fn main() i32 = { return 0; };\n"), "main.x", "\\x18\\xfc\\xff\\xff\\xff\\xff\\xff\\xff"); datawrow("i8_arr", strings.concat( "package main;\n", "let a: [4]i8 = [1i8, -2i8, 3i8, -4i8];\n", "fn main() i32 = { return 0; };\n"), "main.a", "\\x01\\xfe\\x03\\xfc"); datawrow("i16_arr", strings.concat( "package main;\n", "let a: [4]i16 = [1i16, -2i16, 3i16, -4i16];\n", "fn main() i32 = { return 0; };\n"), "main.a", "\\x01\\x00\\xfe\\xff\\x03\\x00\\xfc\\xff"); datawrow("i32_arr", strings.concat( "package main;\n", "let a: [3]i32 = [10i32, -20i32, 30i32];\n", "fn main() i32 = { return 0; };\n"), "main.a", "\\x0a\\x00\\x00\\x00\\xec\\xff\\xff\\xff\\x1e\\x00\\x00\\x00"); datawrow("i64_arr", strings.concat( "package main;\n", "let a: [2]i64 = [100i64, -200i64];\n", "fn main() i32 = { return 0; };\n"), "main.a", strings.concat( "d\\x00\\x00\\x00\\x00\\x00\\x00\\x00", "8\\xff\\xff\\xff\\xff\\xff\\xff\\xff")); }; // One 724 row: zero-init store inside the produce window on both // stages, then the #22 fix-pin byte-id. fn zeroinitrow(label: str, src: str) void = { let td: str = testenv.fresh(); 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")); let cw: str = asmwindow(label, "cstage", cs, "TEXT main.produce", "RET", 0); let ww: str = asmwindow(label, "wwstage", ws, "TEXT main.produce", "RET", 0); if (!testenv.has(cw, "MOVQ\t$0, -")) { fail(label, "cstage: no `MOVQ $0, -K(BP)` zero-init in produce body"); }; if (!testenv.has(ww, "MOVQ\t$0, -")) { fail(label, "wwstage: no `MOVQ $0, -K(BP)` zero-init in produce body"); }; if (!testenv.same(cs, ws)) { fail(label, "cstage vs wwstage asm differs"); }; testenv.clean(td); }; @test fn letdeclzeroinit() void = { // The utf8.invalid shape. zeroinitrow("bang_void_letdecl", strings.concat( "package main;\n", "type invalid = !void;\n", "export fn produce() (i32 | invalid) = {\n", " let e: invalid;\n", " return e;\n", "};\n")); // The utf8.done / utf8.more shape. zeroinitrow("void_alias_letdecl", strings.concat( "package main;\n", "type done = void;\n", "export fn produce() (i32 | done) = {\n", " let d: done;\n", " return d;\n", "};\n")); }; // One 744 row: `MOVQ\t-` load-count floor over [TEXT main.produce .. // next TEXT) on both stages, then byte-id. fn letcopyrow(label: str, src: str, minloads: i32) void = { let td: str = testenv.fresh(); 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")); letcopycheck(label, "cstage", cs, minloads); letcopycheck(label, "wwstage", ws, minloads); if (!testenv.same(cs, ws)) { fail(label, "cstage vs wwstage asm differs"); }; testenv.clean(td); }; fn letcopycheck(label: str, stage: str, s: str, minloads: i32) void = { let bp: i32 = testenv.pos(s, "TEXT main.produce"); if (bp < 0) { fail(label, strings.concat(stage, ": no TEXT produce label in .s")); }; let tail: str = strings.sub(s, bp, s.len); let ep: i32 = testenv.pos(strings.sub(tail, 1, tail.len), "\nTEXT "); let w: str = tail; if (ep >= 0) { w = strings.sub(tail, 0, 1 + ep); }; if (testenv.occurrences(w, "MOVQ\t-") < minloads) { fail(label, strings.concat(stage, ": too few `MOVQ -K(BP), AX` source loads in produce ", "(copy missing)")); }; }; // 744 shapes per the #32 brief: p1 structlit-inits where a bare decl // would hit the pre-existing #15/#26c non-8-multiple zero-init // divergence; the tagged row checks only p2.a for the same reason. @test fn letcopystruct() void = { letcopyrow("tri_i32", strings.concat( "package main;\n", "type tri = struct { a: i32, b: i32, c: i32 };\n", "export fn produce() i32 = {\n", " let p1: tri = tri{a=11, b=22, c=33};\n", " let p2: tri = p1;\n", " if (p2.a != 11) { return 11; };\n", " if (p2.b != 22) { return 12; };\n", " if (p2.c != 33) { return 13; };\n", " return 0;\n", "};\n"), 1); letcopyrow("field_str", strings.concat( "package main;\n", "type ws = struct { a: i32, s: str };\n", "export fn produce() i32 = {\n", " let p1: ws;\n", " p1.a = 7; p1.s = \"hi\";\n", " let p2: ws = p1;\n", " if (p2.a != 7) { return 11; };\n", " if (p2.s.len != 2) { return 12; };\n", " return 0;\n", "};\n"), 3); letcopyrow("field_slice", strings.concat( "package main;\n", "type wsl = struct { a: i32, b: []u8 };\n", "export fn produce() i32 = {\n", " let raw: [3]u8 = [1: u8, 2: u8, 3: u8];\n", " let p1: wsl;\n", " p1.a = 9; p1.b = raw[0:3];\n", " let p2: wsl = p1;\n", " if (p2.a != 9) { return 11; };\n", " if (p2.b.len != 3) { return 12; };\n", " return 0;\n", "};\n"), 4); letcopyrow("field_tagged", strings.concat( "package main;\n", "type tag = (i32 | str);\n", "type wtg = struct { a: i32, t: tag };\n", "export fn produce() i32 = {\n", " let p1: wtg = wtg{a=5, t=42: tag};\n", " let p2: wtg = p1;\n", " if (p2.a != 5) { return 11; };\n", " return 0;\n", "};\n"), 4); }; // One 746 row: strlit-inline pair present, bogus SB symbol load // absent, inside [TEXT sym .. RET) on both stages, then byte-id. fn strdefrow(label: str, src: str, sym: str, wantlea: str, bad: str) void = { let td: str = testenv.fresh(); 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")); strdefcheck(label, "cstage", cs, sym, wantlea, bad); strdefcheck(label, "wwstage", ws, sym, wantlea, bad); if (!testenv.same(cs, ws)) { fail(label, "cstage vs wwstage asm differs"); }; testenv.clean(td); }; fn strdefcheck(label: str, stage: str, s: str, sym: str, wantlea: str, bad: str) void = { let w: str = asmwindow(label, stage, s, sym, "\tRET", 1); if (!testenv.has(w, wantlea)) { fail(label, strings.concat(stage, ": want_lea ", wantlea, " missing inside ", sym)); }; if (!testenv.has(w, "MOVQ\t$39,")) { fail(label, strings.concat(stage, ": want_len MOVQ $39, missing inside ", sym)); }; if (testenv.has(w, bad)) { fail(label, strings.concat(stage, ": bogus ", bad, " symbol load inside ", sym)); }; }; @test fn strdefinline() void = { strdefrow("bare_ident_strdef", strings.concat( "package alpha;\n", "def MSG: str = \"strdef_inline_pin_aaaaaaaaaaaaaaa_43chr\";\n", "export fn afn() str = { return MSG; };\n", "export fn main() i32 = { return 0; };\n"), "TEXT alpha.afn", "LEAQ\talpha._S_", "alpha.MSG(SB)"); strdefrow("mod_qualified_strdef", strings.concat( "package alpha;\n", "def MSG: str = \"strdef_inline_pin_aaaaaaaaaaaaaaa_43chr\";\n", "package beta;\n", "import alpha;\n", "export fn bfn() str = { return alpha.MSG; };\n", "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); };