ww: rename toolchain to w-prefix + hare-style build/run/test driver

Plan 9-style w-prefix on the per-arch tools, disambiguating from the
real Plan 9 6c/6a/6l in ref/plan9front/:

    cmd/wwc/      → cmd/wcc/        libwwc.a → libwcc.a
    cmd/6{c,a,l}  → cmd/w6{c,a,l}   binary names too
    test/wwc/     → test/wcc/       6 test files w/ w6 prefix
    selfhost/cmd  mirror in lockstep
    bootstrap/amd64/{w6c,w6a,w6l}   snapshot binaries (gitignored)
    WW_6{C,A,L}   → WW_W6{C,A,L}    env-var overrides

Plan 9 source-tree refs ("Plan 9 6c shape", ref/plan9front/, etc.)
preserved. Hare-style driver, both C and ww sides:

    ww test [path]   discover *_test.ww in a directory module, run
                     each; single-file mode for `ww test foo.ww`
    Module-by-name   `ww build foo` resolves to foo.ww or foo/foo.ww
                     via search path (cwd : -I dirs : $WW_LIB)
    Default-to-cwd   `ww build` / `ww test` build the cwd module
    Run pass-through `ww run path arg1 arg2` reaches the program

lib/os: getcwd (79) and getdents64 (217) syscalls power `.` resolution
and directory enumeration on the ww side.

Makefile: wwstage tool deps now include lib/os/os.ww (+ lib/strconv
for wwdump_ww) so lib/* edits force their rebuild instead of leaving
stale binaries — surfaced when test 995 first failed against a stale
w6c_ww built before the lib/os additions.

Test 993 byte-identical parity gate (C-side ww vs ww-side ww_ww on a
build corpus) stays green; all 19 tests pass.
This commit is contained in:
2026-05-11 13:49:27 +09:00
parent e217cd32d1
commit 2c33228b7e
96 changed files with 2129 additions and 973 deletions

View File

@@ -2,7 +2,7 @@
# test/run — driver for `make test`. Plan 9 rc-flavoured but plain sh.
#
# Walks the test/ tree:
# test/wwc/<NNN>_<name>.c → out/bin/test_<name> binary, run it.
# test/wcc/<NNN>_<name>.c → out/bin/test_<name> binary, run it.
# test/lang/<phase>/*.ww → compile/run via $WW, compare stdout/exit
# with header comments (// expected: ...).
# Exit non-zero on first failure.
@@ -16,7 +16,7 @@ fail=0
ran=0
# ---- C-side unit tests --------------------------------------------------
for t in test/wwc/*.c; do
for t in test/wcc/*.c; do
[ -f "$t" ] || continue
name=${t##*/}
name=${name%.c}

View File

@@ -2,7 +2,7 @@
* 000_smoke Phase 0 smoke test.
*
* Asserts:
* - libwwc symbols (newarena/amalloc/freearena, fatal/errorf/warnf)
* - libwcc symbols (newarena/amalloc/freearena, fatal/errorf/warnf)
* are linkable.
* - `ww -V` exits 0 and prints the configured version.
*/

View File

@@ -22,7 +22,7 @@ run6c(const char *src, char **out)
char cmd[256];
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
snprintf(cmd, sizeof cmd, "%s/6c %s 2>&1", bin, path);
snprintf(cmd, sizeof cmd, "%s/w6c %s 2>&1", bin, path);
FILE *p = popen(cmd, "r");
if (p == NULL) { unlink(path); return -1; }
size_t cap = 4096, n = 0;
@@ -72,7 +72,7 @@ main(void)
char *out = NULL;
int rc = run6c(rows[i].src, &out);
if (rc != 0) {
fprintf(stderr, "row %d: 6c rc=%d\n", i, rc);
fprintf(stderr, "row %d: w6c rc=%d\n", i, rc);
fail++;
free(out);
continue;
@@ -84,7 +84,7 @@ main(void)
}
free(out);
}
if (fail) { fprintf(stderr, "%d/%d 6c tests failed\n", fail, n); return 1; }
printf("6c: %d/%d ok\n", n, n);
if (fail) { fprintf(stderr, "%d/%d w6c tests failed\n", fail, n); return 1; }
printf("w6c: %d/%d ok\n", n, n);
return 0;
}

View File

@@ -1,6 +1,6 @@
/*
* 500_asm assembler smoke. Drive 6c on a tiny program, feed the
* output to 6a, then read back the .o magic to confirm we produced
* 500_asm assembler smoke. Drive w6c on a tiny program, feed the
* output to w6a, then read back the .o magic to confirm we produced
* a valid ELF64 relocatable object.
*/
#include <stdio.h>
@@ -39,10 +39,10 @@ main(void)
fclose(f);
char cmd[512];
snprintf(cmd, sizeof cmd, "%s/6c -o %s %s", bin, asmf, src);
if (run(cmd) != 0) { fprintf(stderr, "6c fail: %s\n", programs[i]); fail++; continue; }
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s", bin, obj, asmf);
if (run(cmd) != 0) { fprintf(stderr, "6a fail: %s\n", programs[i]); fail++; continue; }
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s", bin, asmf, src);
if (run(cmd) != 0) { fprintf(stderr, "w6c fail: %s\n", programs[i]); fail++; continue; }
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s", bin, obj, asmf);
if (run(cmd) != 0) { fprintf(stderr, "w6a fail: %s\n", programs[i]); fail++; continue; }
FILE *of = fopen(obj, "rb");
if (of == NULL) { fail++; continue; }
@@ -56,7 +56,7 @@ main(void)
}
}
unlink(src); unlink(asmf); unlink(obj);
if (fail) { fprintf(stderr, "%d/%d 6a tests failed\n", fail, n); return 1; }
printf("6a: %d/%d ok\n", n, n);
if (fail) { fprintf(stderr, "%d/%d w6a tests failed\n", fail, n); return 1; }
printf("w6a: %d/%d ok\n", n, n);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* 600_6l linker smoke. Drive 6c 6a 6l on a tiny program,
* 600_6l linker smoke. Drive w6c w6a w6l on a tiny program,
* confirm the result is a static ELF executable with no PT_INTERP.
*/
#include <stdio.h>
@@ -24,12 +24,12 @@ main(void)
fclose(f);
char cmd[1024];
snprintf(cmd, sizeof cmd, "%s/6c -o %s %s", bin, asmf, src);
if (system(cmd) != 0) { fprintf(stderr, "6c failed\n"); return 1; }
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s", bin, obj, asmf);
if (system(cmd) != 0) { fprintf(stderr, "6a failed\n"); return 1; }
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s", bin, exe, obj);
if (system(cmd) != 0) { fprintf(stderr, "6l failed\n"); return 1; }
snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s", bin, asmf, src);
if (system(cmd) != 0) { fprintf(stderr, "w6c failed\n"); return 1; }
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s", bin, obj, asmf);
if (system(cmd) != 0) { fprintf(stderr, "w6a failed\n"); return 1; }
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s", bin, exe, obj);
if (system(cmd) != 0) { fprintf(stderr, "w6l failed\n"); return 1; }
/* validate ELF magic + e_type=EXEC */
FILE *of = fopen(exe, "rb");
@@ -62,6 +62,6 @@ main(void)
}
unlink(src); unlink(asmf); unlink(obj); unlink(exe);
printf("6l: ok\n");
printf("w6l: ok\n");
return 0;
}

View File

@@ -4,7 +4,7 @@
* undefined external. Linking should pull only the needed member;
* the other one's bad reference must NOT cause a link error.
*
* If 6l were still pulling all members, this test would fail with
* If w6l were still pulling all members, this test would fail with
* "undefined reference to 'this_symbol_does_not_exist'".
*/
#include <stdio.h>
@@ -56,11 +56,11 @@ main(void)
char cmd[2048];
snprintf(cmd, sizeof cmd,
"set -e; cd %s && %s/6c -o lib_good.s lib_good.ww && "
"%s/6c -o lib_bad.s lib_bad.ww && "
"%s/6a -o lib_good.o lib_good.s && %s/6a -o lib_bad.o lib_bad.s && "
"set -e; cd %s && %s/w6c -o lib_good.s lib_good.ww && "
"%s/w6c -o lib_bad.s lib_bad.ww && "
"%s/w6a -o lib_good.o lib_good.s && %s/w6a -o lib_bad.o lib_bad.s && "
"ar rcs libfoo.a lib_good.o lib_bad.o && "
"%s/6c -o m.s m.ww && %s/6a -o m.o m.s",
"%s/w6c -o m.s m.ww && %s/w6a -o m.o m.s",
dir, bin, bin, bin, bin, bin, bin);
if (run(cmd) != 0) { fprintf(stderr, "build failed\n"); return 1; }
@@ -69,7 +69,7 @@ main(void)
snprintf(startobj, sizeof startobj, "%s/../obj/rt/start.o", bin);
snprintf(cmd, sizeof cmd,
"%s/6l -o %s/m %s/m.o %s %s/libfoo.a 2>%s/link.err",
"%s/w6l -o %s/m %s/m.o %s %s/libfoo.a 2>%s/link.err",
bin, dir, dir, startobj, dir, dir);
if (run(cmd) != 0) {
FILE *ef = fopen("/dev/null", "r");

View File

@@ -22,7 +22,7 @@ run6c(const char *bin, const char *src)
fclose(f);
char cmd[512];
snprintf(cmd, sizeof cmd, "%s/6c %s 2>&1", bin, path);
snprintf(cmd, sizeof cmd, "%s/w6c %s 2>&1", bin, path);
FILE *p = popen(cmd, "r");
size_t cap = 4096, n = 0;
char *buf = malloc(cap);
@@ -66,10 +66,10 @@ main(void)
char path[256];
snprintf(path, sizeof path, "%s/../../lib/c/libc/libc.ww", bin);
char cmd[512];
snprintf(cmd, sizeof cmd, "%s/6c %s > /dev/null 2>&1", bin, path);
snprintf(cmd, sizeof cmd, "%s/w6c %s > /dev/null 2>&1", bin, path);
int rc = system(cmd);
if (rc != 0) {
fprintf(stderr, "ffi: 6c failed on libc.ww (rc=%d)\n", rc);
fprintf(stderr, "ffi: w6c failed on libc.ww (rc=%d)\n", rc);
fail++;
}
}

View File

@@ -1,5 +1,5 @@
/*
* 810_dyn end-to-end test of 6l's dynamic linker.
* 810_dyn end-to-end test of w6l's dynamic linker.
*
* Drives `ww build -L /usr/lib -l c` over a small ww program that
* binds libc symbols via @symbol, then runs the produced binary and

View File

@@ -51,7 +51,7 @@ main(void)
for (int i = 0; modules[i]; i++, n++) {
char path[1024], cmd[2048];
snprintf(path, sizeof path, "%s/%s", cwd, modules[i]);
snprintf(cmd, sizeof cmd, "%s/6c %s > /dev/null 2>&1",
snprintf(cmd, sizeof cmd, "%s/w6c %s > /dev/null 2>&1",
bin, path);
int rc = system(cmd);
if (rc != 0) {

View File

@@ -2,7 +2,7 @@
* 990_selfhost phase-10 marker test. Three probes:
*
* 1. The selfhost stubs (mem.ww, err.ww) must parse, typecheck and
* codegen via C-side `6c`.
* codegen via C-side `w6c`.
*
* 2. selfhost/test/smoke.ww an actual ww program exercising the
* patterns the real port will use (bump arena, error union,
@@ -65,13 +65,13 @@ slurp(const char *path, char **outbuf, size_t *outlen)
return 0;
}
/* Probe 1: each file must compile through `6c`. */
/* Probe 1: each file must compile through `w6c`. */
static int
probe_codegen(const char *bin)
{
static const char *files[] = {
"selfhost/cmd/wwc/mem.ww",
"selfhost/cmd/wwc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww",
NULL,
};
char cwd[1024];
@@ -80,7 +80,7 @@ probe_codegen(const char *bin)
for (int i = 0; files[i]; i++) {
char cmd[2048];
snprintf(cmd, sizeof cmd,
"%s/6c %s/%s > /dev/null 2>&1", bin, cwd, files[i]);
"%s/w6c %s/%s > /dev/null 2>&1", bin, cwd, files[i]);
if (runwait(cmd) != 0) {
fprintf(stderr, "codegen FAIL: %s\n", files[i]);
fail++;
@@ -169,12 +169,12 @@ static int
probe_dump_diff(const char *bin)
{
const char *tok_inputs[] = {
"selfhost/cmd/wwc/mem.ww",
"selfhost/cmd/wwc/err.ww",
"selfhost/cmd/wwc/lex.ww",
"selfhost/cmd/wwc/tok.ww",
"selfhost/cmd/wwc/ast.ww",
"selfhost/cmd/wwc/parse.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/lex.ww",
"selfhost/cmd/wcc/tok.ww",
"selfhost/cmd/wcc/ast.ww",
"selfhost/cmd/wcc/parse.ww",
"selfhost/cmd/wwdump/main.ww",
"selfhost/test/smoke.ww",
NULL,
@@ -186,16 +186,16 @@ probe_dump_diff(const char *bin)
* against the C parser on every selfhost file plus the stdlib. */
const char *ast_inputs[] = {
"selfhost/test/uses.ww",
"selfhost/cmd/wwc/err.ww",
"selfhost/cmd/wwc/mem.ww",
"selfhost/cmd/wwc/lex.ww",
"selfhost/cmd/wwc/tok.ww",
"selfhost/cmd/wwc/ast.ww",
"selfhost/cmd/wwc/parse.ww",
"selfhost/cmd/wwc/typ.ww",
"selfhost/cmd/wwc/sym.ww",
"selfhost/cmd/wwc/check.ww",
"selfhost/cmd/wwc/cgen.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/lex.ww",
"selfhost/cmd/wcc/tok.ww",
"selfhost/cmd/wcc/ast.ww",
"selfhost/cmd/wcc/parse.ww",
"selfhost/cmd/wcc/typ.ww",
"selfhost/cmd/wcc/sym.ww",
"selfhost/cmd/wcc/check.ww",
"selfhost/cmd/wcc/cgen.ww",
"selfhost/cmd/wwdump/main.ww",
"selfhost/test/smoke.ww",
"lib/strconv/strconv.ww",
@@ -226,7 +226,7 @@ probe_dump_diff(const char *bin)
}
/* Probe 5: ww-side cgen (wwdump_ww -c) emits Plan 9 amd64 asm. For
* each fixture we (a) diff the ww asm against C-side 6c and (b)
* each fixture we (a) diff the ww asm against C-side w6c and (b)
* assemble + link + run the ww output and compare exit codes. Both
* must succeed. The cgen port handles literals, +/-/star/slash,
* compound assignment, idents, calls, if/else, for loops, and
@@ -349,7 +349,7 @@ probe_ww_compile(const char *bin)
/* Chained N_DOT: o.ptr_to_inner.val (read field through a
* pointer-to-struct field). Pre-fix the cgen fell through
* silently and returned the inner pointer instead of the
* dereferenced field. Surfaced porting 6l/pass.ww. */
* dereferenced field. Surfaced porting w6l/pass.ww. */
{ "@symbol(\"rt_alloc\") fn rt_alloc(n: u64) *void;\n"
"type inner = struct { val: u64 };\n"
"type outer = struct { p: *inner };\n"
@@ -384,7 +384,7 @@ probe_ww_compile(const char *bin)
fprintf(stderr, "ww-compile prog %d: wwdump_ww -c errored\n", i);
fail++; goto cleanup;
}
snprintf(cmd, sizeof cmd, "%s/6c %s > %s 2>/dev/null", bin, src, cs);
snprintf(cmd, sizeof cmd, "%s/w6c %s > %s 2>/dev/null", bin, src, cs);
runwait(cmd);
char *bw = NULL, *bc = NULL;
@@ -398,15 +398,15 @@ probe_ww_compile(const char *bin)
}
free(bw); free(bc);
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s 2>/dev/null", bin, obj, wws);
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, obj, wws);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww-compile prog %d: 6a failed\n", i);
fprintf(stderr, "ww-compile prog %d: w6a failed\n", i);
fail++; goto cleanup;
}
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s %s 2>/dev/null",
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null",
bin, exe, obj, rt);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww-compile prog %d: 6l failed\n", i);
fprintf(stderr, "ww-compile prog %d: w6l failed\n", i);
fail++; goto cleanup;
}
int rc = runwait(exe);
@@ -433,9 +433,9 @@ probe_resolve(const char *bin)
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
const char *complete[] = {
"selfhost/cmd/wwc/err.ww",
"selfhost/cmd/wwc/mem.ww",
"selfhost/cmd/wwc/tok.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/tok.ww",
"selfhost/test/smoke.ww",
NULL,
};
@@ -463,8 +463,8 @@ probe_dump_stable(const char *bin)
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
const char *inputs[] = {
"selfhost/cmd/wwc/mem.ww",
"selfhost/cmd/wwc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/test/smoke.ww",
NULL,
};
@@ -540,19 +540,19 @@ probe_bootstrap_fixed_point(const char *bin)
"%s/wwdump_ww -c %s/selfhost/cmd/wwdump/main.combined.ww > %s 2>/dev/null",
bin, cwd, ww2s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: ww1 self-compile\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s 2>/dev/null", bin, ww2o, ww2s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: 6a ww2.s\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s %s 2>/dev/null", bin, ww2e, ww2o, rt);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: 6l ww2\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, ww2o, ww2s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: w6a ww2.s\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null", bin, ww2e, ww2o, rt);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: w6l ww2\n"); fail++; goto cleanup; }
/* ww2 -> ww3 */
snprintf(cmd, sizeof cmd,
"%s -c %s/selfhost/cmd/wwdump/main.combined.ww > %s 2>/dev/null",
ww2e, cwd, ww3s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: ww2 self-compile\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s 2>/dev/null", bin, ww3o, ww3s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: 6a ww3.s\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s %s 2>/dev/null", bin, ww3e, ww3o, rt);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: 6l ww3\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, ww3o, ww3s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: w6a ww3.s\n"); fail++; goto cleanup; }
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null", bin, ww3e, ww3o, rt);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: w6l ww3\n"); fail++; goto cleanup; }
/* The fixed-point check: ww2.s == ww3.s, ww2 == ww3. */
snprintf(cmd, sizeof cmd, "cmp -s %s %s", ww2s, ww3s);
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: ww2.s != ww3.s (no fixed point)\n"); fail++; }
@@ -566,7 +566,7 @@ cleanup:
/* Probe 8: ww1 → ww2 ladder. wwdump_ww (= ww1, built by C tools)
* compiles its own concatenated source. The output assembles + links
* via 6a/6l into ww2 (a fresh ww-built compiler binary). Confirms
* via w6a/w6l into ww2 (a fresh ww-built compiler binary). Confirms
* the full ww-cgen pipeline is functionally correct end-to-end on
* the entire frontend (lex+parse+check+cgen+ast+typ+sym+mem+err+
* driver). Pre-fix-set this segfaulted at 5919 lines of asm; post-
@@ -592,18 +592,18 @@ probe_ww1_to_ww2(const char *bin)
fail++;
goto cleanup;
}
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s 2>/dev/null", bin, obj_p, asm_p);
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, obj_p, asm_p);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww1->ww2 FAIL: 6a errored on ww1 output\n");
fprintf(stderr, "ww1->ww2 FAIL: w6a errored on ww1 output\n");
fail++;
goto cleanup;
}
char rt[1024];
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s %s 2>/dev/null",
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null",
bin, exe_p, obj_p, rt);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww1->ww2 FAIL: 6l errored\n");
fprintf(stderr, "ww1->ww2 FAIL: w6l errored\n");
fail++;
goto cleanup;
}
@@ -619,8 +619,8 @@ cleanup:
}
/* Probe 7: end-to-end via wwdump_ww. Use `ww build` to produce the
* concatenated source as a side effect, then drive ww-cgen 6a
* 6l run, comparing the binary's exit code to the fixture's
* concatenated source as a side effect, then drive ww-cgen w6a
* w6l run, comparing the binary's exit code to the fixture's
* declared expectation. This is the bootstrap-grade signal: it
* doesn't require ww-cgen output to be byte-identical to C-cgen,
* only to be functionally correct. The byte-match probe above is
@@ -656,7 +656,7 @@ probe_ww_links(const char *bin)
runwait(cmd);
/* ww build to get the .combined.ww as a side effect. */
snprintf(cmd, sizeof cmd,
"cd %s && %s/ww build -I %s/selfhost/cmd/wwc %s >/dev/null 2>&1",
"cd %s && %s/ww build -I %s/selfhost/cmd/wcc %s >/dev/null 2>&1",
tmpdir, bin, cwd, tmpsrc);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww-links FAIL: ww build %s\n", fix);
@@ -676,19 +676,19 @@ probe_ww_links(const char *bin)
fail++;
goto cleanup;
}
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s 2>/dev/null",
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null",
bin, wop, wsp);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww-links FAIL: 6a %s\n", fix);
fprintf(stderr, "ww-links FAIL: w6a %s\n", fix);
fail++;
goto cleanup;
}
char rt[1024];
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s %s 2>/dev/null",
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s %s 2>/dev/null",
bin, wexep, wop, rt);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww-links FAIL: 6l %s\n", fix);
fprintf(stderr, "ww-links FAIL: w6l %s\n", fix);
fail++;
goto cleanup;
}
@@ -708,16 +708,16 @@ cleanup:
}
/* Probe 6: ww-cgen byte-matches C-cgen on every selfhost file that
* raw 6c can compile in isolation (no driver concatenation). The list
* raw w6c can compile in isolation (no driver concatenation). The list
* is the convergence set: when this stays empty, the cmp ww2 ww3
* ceiling becomes feasible. */
static int
probe_cgen_match(const char *bin)
{
const char *files[] = {
"selfhost/cmd/wwc/mem.ww",
"selfhost/cmd/wwc/err.ww",
"selfhost/cmd/wwc/tok.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/tok.ww",
"selfhost/test/smoke.ww",
NULL,
};
@@ -728,7 +728,7 @@ probe_cgen_match(const char *bin)
char a[256], b[256], cmd[2048];
snprintf(a, sizeof a, "/tmp/wwd_cm_%d_c", getpid());
snprintf(b, sizeof b, "/tmp/wwd_cm_%d_w", getpid());
snprintf(cmd, sizeof cmd, "%s/6c %s/%s > %s 2>/dev/null",
snprintf(cmd, sizeof cmd, "%s/w6c %s/%s > %s 2>/dev/null",
bin, cwd, files[i], a);
runwait(cmd);
snprintf(cmd, sizeof cmd, "%s/wwdump_ww -c %s/%s > %s 2>/dev/null",

View File

@@ -1,15 +1,15 @@
/*
* 991_6a_ww phase-10 marker for the ww-side 6a port.
* 991_w6a_ww phase-10 marker for the ww-side w6a port.
*
* Diffs the C-built `6a` against the ww-built `6a_ww` on a corpus of
* Diffs the C-built `w6a` against the ww-built `w6a_ww` on a corpus of
* .s files. Both must produce byte-identical ELF .o output. The corpus
* spans:
* - rt/X.s hand-written runtime; small, varied operands
* - generated .s from the existing selfhost cgen pipeline
* (wwdump/6a/6l main.s) - large, exercises
* every encoding path 6c emits
* (wwdump/w6a/w6l main.s) - large, exercises
* every encoding path w6c emits
*
* Any divergence is a port bug in selfhost/cmd/6a/.
* Any divergence is a port bug in selfhost/cmd/w6a/.
*/
#include <stdio.h>
#include <stdlib.h>
@@ -65,15 +65,15 @@ diff_one(const char *bin, const char *src)
snprintf(co, sizeof co, "/tmp/wwa_%d_c.o", getpid());
snprintf(wo, sizeof wo, "/tmp/wwa_%d_w.o", getpid());
snprintf(cmd, sizeof cmd, "%s/6a -o %s %s 2>/dev/null", bin, co, src);
snprintf(cmd, sizeof cmd, "%s/w6a -o %s %s 2>/dev/null", bin, co, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "6a_ww FAIL: C 6a errored on %s\n", src);
fprintf(stderr, "w6a_ww FAIL: C w6a errored on %s\n", src);
unlink(co);
return -1;
}
snprintf(cmd, sizeof cmd, "%s/6a_ww -o %s %s 2>/dev/null", bin, wo, src);
snprintf(cmd, sizeof cmd, "%s/w6a_ww -o %s %s 2>/dev/null", bin, wo, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "6a_ww FAIL: ww 6a errored on %s\n", src);
fprintf(stderr, "w6a_ww FAIL: ww w6a errored on %s\n", src);
unlink(co); unlink(wo);
return -1;
}
@@ -81,10 +81,10 @@ diff_one(const char *bin, const char *src)
size_t nc = 0, nw = 0;
int rc = 0;
if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) {
fprintf(stderr, "6a_ww FAIL: cannot read .o for %s\n", src);
fprintf(stderr, "w6a_ww FAIL: cannot read .o for %s\n", src);
rc = -1;
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
fprintf(stderr, "6a_ww FAIL: %s — C %zu vs ww %zu bytes\n",
fprintf(stderr, "w6a_ww FAIL: %s — C %zu vs ww %zu bytes\n",
src, nc, nw);
rc = -1;
}
@@ -110,11 +110,11 @@ main(void)
"rt/alloc.s",
"rt/streq.s",
/* generated .s from the existing selfhost stack — large,
* exercises every encoding 6c emits (the only way to hit
* exercises every encoding w6c emits (the only way to hit
* the long tail of operand shapes). */
"selfhost/cmd/wwdump/main.s",
"selfhost/cmd/6l/main.s",
"selfhost/cmd/6a/main.s",
"selfhost/cmd/w6l/main.s",
"selfhost/cmd/w6a/main.s",
NULL,
};
int fail = 0;
@@ -126,10 +126,10 @@ main(void)
n++;
}
if (fail) {
fprintf(stderr, "6a_ww: %d/%d diff(s) failed\n", fail, n);
fprintf(stderr, "w6a_ww: %d/%d diff(s) failed\n", fail, n);
return 1;
}
printf("6a_ww: byte-identical to C 6a on %d corpus files "
printf("w6a_ww: byte-identical to C w6a on %d corpus files "
"(rt/*.s + selfhost generated main.s)\n", n);
return 0;
}

View File

@@ -1,13 +1,13 @@
/*
* 992_6l_ww phase-10 marker for the ww-side 6l port.
* 992_w6l_ww phase-10 marker for the ww-side w6l port.
*
* Diffs the C-built `6l` against the ww-built `6l_ww` on a corpus of
* Diffs the C-built `w6l` against the ww-built `w6l_ww` on a corpus of
* link inputs. Both must produce byte-identical static ELF binaries.
* The corpus mixes:
* - a single .o input (no archive resolution)
* - a .o + libwwrt.a link, exercising the SysV `ar` two-pass loader
*
* Any divergence is a port bug in selfhost/cmd/6l/.
* Any divergence is a port bug in selfhost/cmd/w6l/.
*/
#include <stdio.h>
#include <stdlib.h>
@@ -65,15 +65,15 @@ diff_one(const char *bin, const char *label, const char *inputs)
snprintf(co, sizeof co, "/tmp/wwl_%d_c", getpid());
snprintf(wo, sizeof wo, "/tmp/wwl_%d_w", getpid());
snprintf(cmd, sizeof cmd, "%s/6l -o %s %s 2>/dev/null", bin, co, inputs);
snprintf(cmd, sizeof cmd, "%s/w6l -o %s %s 2>/dev/null", bin, co, inputs);
if (runwait(cmd) != 0) {
fprintf(stderr, "6l_ww FAIL: C 6l errored on %s\n", label);
fprintf(stderr, "w6l_ww FAIL: C w6l errored on %s\n", label);
unlink(co);
return -1;
}
snprintf(cmd, sizeof cmd, "%s/6l_ww -o %s %s 2>/dev/null", bin, wo, inputs);
snprintf(cmd, sizeof cmd, "%s/w6l_ww -o %s %s 2>/dev/null", bin, wo, inputs);
if (runwait(cmd) != 0) {
fprintf(stderr, "6l_ww FAIL: ww 6l errored on %s\n", label);
fprintf(stderr, "w6l_ww FAIL: ww w6l errored on %s\n", label);
unlink(co); unlink(wo);
return -1;
}
@@ -81,10 +81,10 @@ diff_one(const char *bin, const char *label, const char *inputs)
size_t nc = 0, nw = 0;
int rc = 0;
if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) {
fprintf(stderr, "6l_ww FAIL: cannot read output for %s\n", label);
fprintf(stderr, "w6l_ww FAIL: cannot read output for %s\n", label);
rc = -1;
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
fprintf(stderr, "6l_ww FAIL: %s — C %zu vs ww %zu bytes\n",
fprintf(stderr, "w6l_ww FAIL: %s — C %zu vs ww %zu bytes\n",
label, nc, nw);
rc = -1;
}
@@ -112,10 +112,10 @@ main(void)
* are pulled from libwwrt.a as undefs are encountered). */
{ "wwdump+libwwrt",
"%s/selfhost/cmd/wwdump/main.o %s/out/lib/libwwrt.a" },
{ "6a+libwwrt",
"%s/selfhost/cmd/6a/main.o %s/out/lib/libwwrt.a" },
{ "6l+libwwrt",
"%s/selfhost/cmd/6l/main.o %s/out/lib/libwwrt.a" },
{ "w6a+libwwrt",
"%s/selfhost/cmd/w6a/main.o %s/out/lib/libwwrt.a" },
{ "w6l+libwwrt",
"%s/selfhost/cmd/w6l/main.o %s/out/lib/libwwrt.a" },
{ NULL, NULL },
};
@@ -128,10 +128,10 @@ main(void)
n++;
}
if (fail) {
fprintf(stderr, "6l_ww: %d/%d diff(s) failed\n", fail, n);
fprintf(stderr, "w6l_ww: %d/%d diff(s) failed\n", fail, n);
return 1;
}
printf("6l_ww: byte-identical to C 6l on %d corpus links "
printf("w6l_ww: byte-identical to C w6l on %d corpus links "
"(.o + libwwrt.a archive resolution)\n", n);
return 0;
}

View File

@@ -2,7 +2,7 @@
* 993_ww_ww phase-10 marker for the ww-side driver port.
*
* Diffs the C-built `ww` against the ww-built `ww_ww`. Both drivers
* orchestrate the same 6c/6a/6l, so the resulting binaries must be
* orchestrate the same w6c/w6a/w6l, so the resulting binaries must be
* byte-identical for every program in the corpus. The corpus mixes:
* - a tiny single-file program (no -I flags)
* - a multi-import build (selfhost/cmd/wwdump/main.ww), exercising
@@ -152,7 +152,7 @@ main(void)
* regardless of the per-driver workdir. */
static char wwdump_src[2048], wwdump_inc_a[2048], wwdump_inc_b[2048];
snprintf(wwdump_src, sizeof wwdump_src, "%s/selfhost/cmd/wwdump/main.ww", cwd);
snprintf(wwdump_inc_a, sizeof wwdump_inc_a, "%s/selfhost/cmd/wwc", cwd);
snprintf(wwdump_inc_a, sizeof wwdump_inc_a, "%s/selfhost/cmd/wcc", cwd);
wwdump_inc_b[0] = '\0';
cases[1].src = wwdump_src;
cases[1].inc_a = wwdump_inc_a;

View File

@@ -1,13 +1,13 @@
/*
* 994_6c_ww phase-10 marker for the ww-side 6c port.
* 994_w6c_ww phase-10 marker for the ww-side w6c port.
*
* 6c_ww is a thin packaging of selfhost/cmd/wwc/cgen.ww: it slurps a
* w6c_ww is a thin packaging of selfhost/cmd/wcc/cgen.ww: it slurps a
* .ww file, runs lex+parse+cgen, and writes Plan 9 amd64 asm to the
* file given by -o. The same cgen is reached through `wwdump_ww -c`,
* so 6c_ww must produce byte-identical output to wwdump_ww -c on
* so w6c_ww must produce byte-identical output to wwdump_ww -c on
* every program this test pins that.
*
* (We do not diff against C-side `6c` here because the C compiler has
* (We do not diff against C-side `w6c` here because the C compiler has
* features the ww cgen has not yet ported float compare, fn-address
* @symbol, indirect call. Test 990 probe 5 covers the C-vs-ww diff on
* the subset that the ww cgen handles today.)
@@ -69,13 +69,13 @@ diff_one(const char *bin, const char *label, const char *src)
snprintf(cmd, sizeof cmd, "%s/wwdump_ww -c %s > %s 2>/dev/null",
bin, src, ws);
if (runwait(cmd) != 0) {
fprintf(stderr, "6c_ww FAIL: wwdump_ww -c errored on %s\n", label);
fprintf(stderr, "w6c_ww FAIL: wwdump_ww -c errored on %s\n", label);
unlink(ws);
return -1;
}
snprintf(cmd, sizeof cmd, "%s/6c_ww -o %s %s 2>/dev/null", bin, cs, src);
snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", bin, cs, src);
if (runwait(cmd) != 0) {
fprintf(stderr, "6c_ww FAIL: 6c_ww errored on %s\n", label);
fprintf(stderr, "w6c_ww FAIL: w6c_ww errored on %s\n", label);
unlink(ws); unlink(cs);
return -1;
}
@@ -83,10 +83,10 @@ diff_one(const char *bin, const char *label, const char *src)
size_t nw = 0, nc = 0;
int rc = 0;
if (slurp(ws, &bw, &nw) < 0 || slurp(cs, &bc, &nc) < 0) {
fprintf(stderr, "6c_ww FAIL: cannot read .s for %s\n", label);
fprintf(stderr, "w6c_ww FAIL: cannot read .s for %s\n", label);
rc = -1;
} else if (nw != nc || memcmp(bw, bc, nw) != 0) {
fprintf(stderr, "6c_ww FAIL: %s — wwdump_ww %zu vs 6c_ww %zu bytes\n",
fprintf(stderr, "w6c_ww FAIL: %s — wwdump_ww %zu vs w6c_ww %zu bytes\n",
label, nw, nc);
rc = -1;
}
@@ -115,7 +115,7 @@ main(void)
/* In-source corpus: programs the ww-side cgen handles today.
* Mirrors probe 5 in 990_selfhost without the parts that drift
* against C 6c. */
* against C w6c. */
struct { const char *label; const char *src; } progs[] = {
{ "ret42",
"fn main() i32 = { return 42; };" },
@@ -147,12 +147,12 @@ main(void)
};
/* Source-tree corpus: the same .combined.ww files the bootstrap
* fixed point chews on. Confirms 6c_ww handles realistic inputs,
* fixed point chews on. Confirms w6c_ww handles realistic inputs,
* not just hand-tailored ones. */
const char *combined_rel[] = {
"selfhost/cmd/wwdump/main.combined.ww",
"selfhost/cmd/6a/main.combined.ww",
"selfhost/cmd/6l/main.combined.ww",
"selfhost/cmd/w6a/main.combined.ww",
"selfhost/cmd/w6l/main.combined.ww",
"selfhost/cmd/ww/main.combined.ww",
NULL,
};
@@ -175,10 +175,10 @@ main(void)
}
if (fail) {
fprintf(stderr, "6c_ww: %d/%d diff(s) failed\n", fail, n);
fprintf(stderr, "w6c_ww: %d/%d diff(s) failed\n", fail, n);
return 1;
}
printf("6c_ww: byte-identical to wwdump_ww -c on %d corpus inputs "
printf("w6c_ww: byte-identical to wwdump_ww -c on %d corpus inputs "
"(in-source + selfhost combined.ww)\n", n);
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
* 995_self_rebuild the wwstage rebuilds itself.
*
* Drives ww_ww (the ww-side driver, which shells to 6c_ww/6a_ww/6l_ww)
* Drives ww_ww (the ww-side driver, which shells to w6c_ww/w6a_ww/w6l_ww)
* over each wwstage tool's source and diffs the result byte-for-byte
* against the cstage-built binary in $BIN. A green run means the
* toolchain can recompile itself without touching cc, modulo the
@@ -59,9 +59,9 @@ slurp_eq(const char *a, const char *b)
return rc;
}
/* Each tool builds via `ww_ww build -I <local> -I selfhost/cmd/wwc src`.
* Some tools have a local module dir (6a, 6l with sibling .ww files);
* wwc-only tools (6c, ww, wwdump) just need the wwc -I. inc_local is
/* Each tool builds via `ww_ww build -I <local> -I selfhost/cmd/wcc src`.
* Some tools have a local module dir (w6a, w6l with sibling .ww files);
* wwc-only tools (w6c, ww, wwdump) just need the wwc -I. inc_local is
* "" for those.
*/
static int
@@ -76,12 +76,12 @@ rebuild_one(const char *bin, const char *cwd, const char *tool,
if (inc_local && inc_local[0]) {
snprintf(cmd, sizeof cmd,
"cd %s && %s/ww_ww build -I %s/%s -I %s/selfhost/cmd/wwc "
"cd %s && %s/ww_ww build -I %s/%s -I %s/selfhost/cmd/wcc "
"%s/%s >/dev/null 2>&1",
workdir, bin, cwd, inc_local, cwd, cwd, src_rel);
} else {
snprintf(cmd, sizeof cmd,
"cd %s && %s/ww_ww build -I %s/selfhost/cmd/wwc "
"cd %s && %s/ww_ww build -I %s/selfhost/cmd/wcc "
"%s/%s >/dev/null 2>&1",
workdir, bin, cwd, cwd, src_rel);
}
@@ -121,9 +121,9 @@ main(void)
const char *src;
const char *inc_local;
} tools[] = {
{ "6c", "selfhost/cmd/6c/main.ww", "" },
{ "6a", "selfhost/cmd/6a/main.ww", "selfhost/cmd/6a" },
{ "6l", "selfhost/cmd/6l/main.ww", "selfhost/cmd/6l" },
{ "w6c", "selfhost/cmd/w6c/main.ww", "" },
{ "w6a", "selfhost/cmd/w6a/main.ww", "selfhost/cmd/w6a" },
{ "w6l", "selfhost/cmd/w6l/main.ww", "selfhost/cmd/w6l" },
{ "ww", "selfhost/cmd/ww/main.ww", "" },
{ "wwdump", "selfhost/cmd/wwdump/main.ww", "" },
{ NULL, NULL, NULL },
@@ -141,6 +141,6 @@ main(void)
return 1;
}
printf("self-rebuild: %d wwstage tool(s) round-trip byte-identical "
"through ww_ww + 6c_ww + 6a_ww + 6l_ww\n", n);
"through ww_ww + w6c_ww + w6a_ww + w6l_ww\n", n);
return 0;
}

View File

@@ -1,8 +1,8 @@
/*
* 996_dyn_ww phase-8 marker for ET_DYN linking on the ww side.
*
* Drives 6l_ww with -L/-l flags over examples/snake/snake.o and diffs
* the result against the C-built 6l on the same inputs. A green run
* Drives w6l_ww with -L/-l flags over examples/snake/snake.o and diffs
* the result against the C-built w6l on the same inputs. A green run
* means the ww-side linker emits PT_INTERP/PT_DYNAMIC binaries byte-
* for-byte identical to the C linker i.e. the dynamic linking story
* is fully ported and snake no longer depends on Cstage.
@@ -71,7 +71,7 @@ main(void)
"-l ncurses -l c >/dev/null 2>&1",
cwd, bin);
if (runwait(cmd) != 0) {
fprintf(stderr, "6l_ww-dyn FAIL: cannot build snake.o via C driver\n");
fprintf(stderr, "w6l_ww-dyn FAIL: cannot build snake.o via C driver\n");
return 1;
}
@@ -79,24 +79,24 @@ main(void)
snprintf(co, sizeof co, "/tmp/wwld_%d_c", getpid());
snprintf(wo, sizeof wo, "/tmp/wwld_%d_w", getpid());
/* C-side 6l with the dynamic flags. */
/* C-side w6l with the dynamic flags. */
snprintf(cmd, sizeof cmd,
"%s/6l -o %s %s/examples/snake/snake.o -L /usr/lib "
"%s/w6l -o %s %s/examples/snake/snake.o -L /usr/lib "
"-l ncurses -l c %s/out/lib/libwwrt.a 2>/dev/null",
bin, co, cwd, cwd);
if (runwait(cmd) != 0) {
fprintf(stderr, "6l_ww-dyn FAIL: C 6l errored\n");
fprintf(stderr, "w6l_ww-dyn FAIL: C w6l errored\n");
unlink(co);
return 1;
}
/* ww-side 6l with the same flags. */
/* ww-side w6l with the same flags. */
snprintf(cmd, sizeof cmd,
"%s/6l_ww -o %s %s/examples/snake/snake.o -L /usr/lib "
"%s/w6l_ww -o %s %s/examples/snake/snake.o -L /usr/lib "
"-l ncurses -l c %s/out/lib/libwwrt.a 2>/dev/null",
bin, wo, cwd, cwd);
if (runwait(cmd) != 0) {
fprintf(stderr, "6l_ww-dyn FAIL: ww 6l errored\n");
fprintf(stderr, "w6l_ww-dyn FAIL: ww w6l errored\n");
unlink(co); unlink(wo);
return 1;
}
@@ -105,14 +105,14 @@ main(void)
size_t nc = 0, nw = 0;
int rc = 0;
if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) {
fprintf(stderr, "6l_ww-dyn FAIL: cannot read outputs\n");
fprintf(stderr, "w6l_ww-dyn FAIL: cannot read outputs\n");
rc = 1;
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
fprintf(stderr, "6l_ww-dyn FAIL: C %zu vs ww %zu bytes\n",
fprintf(stderr, "w6l_ww-dyn FAIL: C %zu vs ww %zu bytes\n",
nc, nw);
rc = 1;
} else {
printf("6l_ww-dyn: byte-identical to C 6l on snake "
printf("w6l_ww-dyn: byte-identical to C w6l on snake "
"(PT_INTERP + PT_DYNAMIC + .rela.plt + .gnu.version_r, "
"%zu bytes)\n", nc);
}