test: port the asm-pattern observers to ww; byteid carrier partition empty

Four ww tests carry the last eight native byteid carriers' assertions:
asmwindow (753 convwrap beta/main/alpha order + window polarity, 754
slice stride + negative scale scan, 755 amp-dot-idx four rows, 758
first-CALL-line extraction + tab-framed disp literals, direct
w6c/w6c_ww never ww build), freenoop (930 byte-id strengthened to
per-stream compare + negative 'free' grep), structabi (946 param/ret
MOVSD windows with polarity tables and SEND/RECV agreement), mangle
(989_m1mangle needles + concat byte-id, glob order strengthened to
byte-lexicographic). Dead want/stage_mask row fields documented, not
invented into runtime legs; the w6c_ww-absent skip gates drop because
the Make target declares the tools.

BYTEID_WRAPPER_SOURCES, its bins, and test-native-byteid are deleted —
the native byte/artifact partition is EMPTY (11 -> 0 this session);
docs counts move to 123 carriers.
This commit is contained in:
2026-08-08 04:41:42 +09:00
parent fa4b9a134b
commit 81e7f95548
14 changed files with 890 additions and 2297 deletions

View File

@@ -0,0 +1,144 @@
package freenoop_test;
// free()-is-a-no-op byte-identity gate. Port of the retired native
// carrier test/wcc/930_free_noop_run.c; every assertion preserved.
//
// ww has no free by design (rt/alloc.s:30 — drop-amalloc); post-#27
// both stages evaluate free's operand for side effects and emit
// NOTHING else. Per row the inline source (prefixed exactly as the
// carrier wrote it, `package main;` + blank line) compiles through
// w6c AND w6c_ww with the asm on stdout; the stages must agree
// byte-for-byte and the NEGATIVE gate holds: no substring 'free'
// anywhere in the cstage output — no CALL free, no symbol reference
// (byte identity extends the proof to wwstage, as in the carrier).
//
// The carrier captured stdout+stderr MERGED (`> cs.s 2>&1`) and
// compared/grepped that one file; here the streams land separately
// and EACH is byte-compared and 'free'-grepped — at least as strict
// on both axes.
//
// Path discipline (the carrier's #8 note): no scratch path may carry
// the substring 'free' or the whole-output grep false-fails.
// testenv.fresh() is /tmp/<16 lowercase hex> — 'free' needs an 'r',
// which the hex alphabet cannot produce — and the source basename
// stays noopfr.ww, mirroring the carrier's naming.
//
// Dead data preserved as dead: the carrier's row table carried a
// `want` exit-code field its main() never read (no run leg existed);
// none is invented here. Runtime behavior lives in the r930_free_*
// wwfixtures per the retired carrier's header. Dropped machinery,
// not assertions: getpid()-keyed tmpdirs + rm/mkdir accounting
// (testenv.fresh/clean own scratch and assert cleanup).
import os;
import os.exec;
import strings;
import testenv;
import time;
fn fail(label: str, why: str) void = {
let m: str = strings.concat("freenoop 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;
};
// `drv noopfr.ww` with the asm on stdout — the carrier's exact shape
// (no -o), so the captured stdout IS the .s under comparison.
fn runstage(td: str, label: str, stage: str, drv: str,
out: *testenv.commandout) void = {
let av: []str = [];
append(av, drv);
append(av, "noopfr.ww");
testenv.runcommand(td, td, stage, av, tmo(), out);
let ok: bool = out.termination == exec.termination.EXIT
&& out.code == 0;
if (!ok) { fail(label, strings.concat(stage, " compile failed")); };
};
fn nooprow(label: str, src: str) void = {
let td: str = testenv.fresh();
testenv.writefile(strings.concat(td, "/noopfr.ww"),
strings.concat("package main;\n\n", src));
let cs: testenv.commandout;
runstage(td, label, "cstage", testenv.driver("w6c"), &cs);
let ws: testenv.commandout;
runstage(td, label, "wwstage", testenv.driver("w6c_ww"), &ws);
if (!testenv.same(cs.stdout, ws.stdout)) {
fail(label, "cs != ww .s");
};
if (!testenv.same(cs.stderr, ws.stderr)) {
fail(label, "cs != ww compile stderr");
};
if (testenv.has(cs.stdout, "free")
|| testenv.has(cs.stderr, "free")) {
fail(label, "'free' survives in the .s -- lowering is not a no-op");
};
testenv.clean(td);
};
// The five carrier rows: deref-after-free leak semantics, the N_DOT
// operand shape, operand side effects run per call, no stack damage
// across 1M no-op frees, and the verbatim Hare-port alloc/free
// round-trip (i64 sidesteps the filed narrow-pointee alloc(value)
// size divergence).
@test fn asmrows() void = {
nooprow("free_local_ptr_deref_after", strings.concat(
"export fn main() i32 = {\n",
" let x: i32 = 5;\n",
" let p: *i32 = &x;\n",
" free(p);\n",
" if (*p != 5) { return 1; };\n",
" return 0;\n",
"};\n"));
nooprow("free_struct_field", strings.concat(
"type holder = struct { p: *i32, n: i32 };\n",
"export fn main() i32 = {\n",
" let x: i32 = 3;\n",
" let h: holder = holder { p = &x, n = 4 };\n",
" free(h.p);\n",
" if (h.n != 4) { return 2; };\n",
" return 0;\n",
"};\n"));
nooprow("free_call_operand_effects", strings.concat(
"let g: i32 = 0;\n",
"fn bump(p: *i32) *i32 = {\n",
" g = g + 2;\n",
" return p;\n",
"};\n",
"export fn main() i32 = {\n",
" let x: i32 = 1;\n",
" free(bump(&x));\n",
" free(bump(&x));\n",
" if (g != 4) { return 3; };\n",
" return 0;\n",
"};\n"));
nooprow("free_loop_no_stack_damage", strings.concat(
"let g: i32 = 0;\n",
"fn bump(p: *i32) *i32 = {\n",
" g = g + 1;\n",
" return p;\n",
"};\n",
"export fn main() i32 = {\n",
" let x: i32 = 1;\n",
" let i: i32 = 0;\n",
" for (i < 1000000) {\n",
" free(bump(&x));\n",
" i += 1;\n",
" };\n",
" if (g != 1000000) { return 5; };\n",
" return 0;\n",
"};\n"));
nooprow("free_alloc_roundtrip", strings.concat(
"import rt;\n",
"export fn main() i32 = {\n",
" let p: *i64 = alloc(11i64)!;\n",
" free(p);\n",
" if (*p != 11i64) { return 4; };\n",
" return 0;\n",
"};\n"));
};