build+test: -j/ccache build, drop 990 dup compile, add make smoke (#19)

Test-speed "immediate wins" from task #19 (build/test-infra only, no
compiler/cgen change — byte-id-neutral; all 237 pass, 950/990-997 +
combined_ww_fresh unchanged).

#1 Parallel build + ccache. MAKEFLAGS += -j$(NPROC) by default: the
C-compile DAG and the five wwstage builds write disjoint outputs (each
.o distinct; each wwstage tool's side files land at its own
selfhost/cmd/<tool>/main.* stem), so -j is order-independent.
test/run's Phase-2 byte-id gates are a single serial recipe that -j
does not reach. CC is wrapped with ccache when present (content-
addressed, byte-identical to plain cc); falls back to bare $(CC).

#2 Kill 990's duplicate ww1->ww2 compile. probe_ww1_to_ww2 recompiled
main.combined.ww (~70s) to assert the ww2 binary is executable — but
probe_bootstrap_fixed_point already compiles ww1->ww2, assembles,
links, and *runs* ww2 to produce ww3, so executability is proven and
the byte-id assertions (ww2.s==ww3.s, ww2==ww3) are untouched. Drop
the redundant probe. make test ~8:30 -> 7:39.

Add `make smoke [FIXTURE=x.ww]`: inner-loop cross-stage byte-id check
(cstage w6c vs wwstage w6c_ww .s diff) on a small self-contained
fixture, seconds. Catches cs!=ww emission divergence per fold; NOT a
substitute for the full 990-997 gate before landing a cgen/ABI fold.
This commit is contained in:
2026-06-01 14:05:32 +09:00
parent a937d67377
commit befb042647
2 changed files with 38 additions and 56 deletions

View File

@@ -709,60 +709,6 @@ cleanup:
return fail ? -1 : 0;
}
/* Probe 8: ww1 → ww2 ladder. wwdump_ww (= ww1, built by C tools)
* compiles its own concatenated source. The output assembles + links
* 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-
* fix-set it produces 43K+ lines that assemble/link cleanly. */
static int
probe_ww1_to_ww2(const char *bin)
{
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
char tmpdir[64];
snprintf(tmpdir, sizeof tmpdir, "/tmp/ww12_%d", getpid());
mkdir(tmpdir, 0755);
char asm_p[512], obj_p[512], exe_p[512], cmd[4096];
snprintf(asm_p, sizeof asm_p, "%s/ww2.s", tmpdir);
snprintf(obj_p, sizeof obj_p, "%s/ww2.o", tmpdir);
snprintf(exe_p, sizeof exe_p, "%s/ww2", tmpdir);
int fail = 0;
snprintf(cmd, sizeof cmd,
"timeout 180 %s/wwdump_ww -c %s/selfhost/cmd/wwdump/main.combined.ww > %s 2>/dev/null",
bin, cwd, asm_p);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww1->ww2 FAIL: wwdump_ww segfaulted on its own source\n");
fail++;
goto cleanup;
}
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a -o %s %s 2>/dev/null", bin, obj_p, asm_p);
if (runwait(cmd) != 0) {
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, "timeout 180 %s/w6l -o %s %s %s 2>/dev/null",
bin, exe_p, obj_p, rt);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww1->ww2 FAIL: w6l errored\n");
fail++;
goto cleanup;
}
struct stat st;
if (stat(exe_p, &st) != 0 || !(st.st_mode & 0111)) {
fprintf(stderr, "ww1->ww2 FAIL: ww2 binary not executable\n");
fail++;
}
cleanup:
snprintf(cmd, sizeof cmd, "rm -rf %s", tmpdir);
runwait(cmd);
return fail ? -1 : 0;
}
/* Probe 7: end-to-end via wwdump_ww. Use `ww build` to produce the
* concatenated source as a side effect, then drive ww-cgen → w6a →
* w6l → run, comparing the binary's exit code to the fixture's
@@ -930,7 +876,6 @@ main(void)
if (probe_ww_compile(bin) != 0) fail++;
if (probe_cgen_match(bin) != 0) fail++;
if (probe_ww_links(bin) != 0) fail++;
if (probe_ww1_to_ww2(bin) != 0) fail++;
if (probe_bootstrap_fixed_point(bin) != 0) fail++;
if (fail) {