test: re-point 990/994/#110 off combined.ww-input to sep-feed (M4 E4-keystone, #22)
The E3 driver flip makes build_one_sep the sole path; it writes .sepwork/*.unit.ww, not <stem>.combined.ww, so the flip stops producing combined.ww. Migrate its consumers to sep-feed first, while both build paths still exist (reversible; all 5 stage binaries stay byte-identical): - 990_selfhost: resolveunit drives `ww build --sep` and reads <stem>.sepwork/__root.unit.ww; probe_cgen_match gains err.ww (sep inlines fmt's .wwi only, so cs==ww holds); probe_ww_links re-expressed as `ww_ww build --sep`->run; probe_bootstrap_fixed_point removed (the monolith path it tested is deleted by E4 -- the self-application axis lives in `make bootstrap`, the cs==ww axis in 995). - 994_w6c_ww: drop the combined-fed emit_eq + corpus; keep the live per-package cs-sep==ww-sep oracle (cmp_sepwork + diff_one + bad[]). - #110 combined_ww_fresh gate removed (its regen-vs-committed premise dies with its producer). Non-vacuity proven: a one-line emitter mutation reddens 994's per-package cs!=ww check across 15 packages; revert restores green.
This commit is contained in:
19
test/run
19
test/run
@@ -187,25 +187,6 @@ if [ "${UNIT:-0}" != "1" ]; then
|
|||||||
done | xargs -0 -n2 -P "$JOBS" "$0" --one || true
|
done | xargs -0 -n2 -P "$JOBS" "$0" --one || true
|
||||||
p2par_end=$(date +%s.%N)
|
p2par_end=$(date +%s.%N)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# combined.ww freshness gate (#110): 990/995 above unconditionally
|
|
||||||
# regenerate every tracked combined.ww amalgamation, so a diff vs HEAD
|
|
||||||
# here means an embedded source changed without its derived artifact
|
|
||||||
# being regenerated + committed (the #28 staleness hole the per-file
|
|
||||||
# byte-id gates were blind to). git ls-files keeps new combined.ww
|
|
||||||
# auto-covered (rule-13 SSoT). Lives inside the UNIT guard because
|
|
||||||
# test-unit skips 990/995 and thus the regen.
|
|
||||||
name=combined_ww_fresh
|
|
||||||
if git diff --exit-code -- $(git ls-files '*.combined.ww') > /dev/null 2>&1; then
|
|
||||||
printf 'ok %s\n' "$name" > "$RESULTS/$name.status"
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf 'FAIL %s (stale; regen + commit the derived amalgamation)\n' "$name"
|
|
||||||
echo '--- stale combined.ww ---'
|
|
||||||
git diff --name-only -- $(git ls-files '*.combined.ww')
|
|
||||||
} > "$RESULTS/$name.status"
|
|
||||||
: > "$RESULTS/$name.fail"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fail=0
|
fail=0
|
||||||
|
|||||||
@@ -518,21 +518,21 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* resolveunit — produce <fixture>'s RESOLVED translation unit the way
|
/* resolveunit — produce <fixture>'s RESOLVED translation unit the way
|
||||||
* the driver does. `ww build` concatenates the module with its
|
* the sep driver does. `ww build --sep` composes the root package's
|
||||||
* transitive imports into <stem>.combined.ww (cmd/ww/main.c expand()),
|
* <stem>.sepwork/__root.unit.ww: the transitive deps' `.wwi` interface
|
||||||
* which is the single unit w6c/wwdump actually consume; w6c never
|
* stubs followed by the root package body — the single self-contained
|
||||||
* resolves imports itself (cmd/w6c/main.c reads one pre-concatenated
|
* unit w6c/wwdump consume for the root (the producer compiles it with no
|
||||||
* file). Feeding a raw module file therefore leaves its import refs
|
* -I; cmd/ww/main.c sep_compose_unit). Feeding a raw module file instead
|
||||||
* (os.write, fmt.errorln, strconv.i64tos …) unresolved — a partial
|
* would leave its import refs (os.write, fmt.errorln, strconv.i64tos …)
|
||||||
* unit harec's module::resolve never hands the checker, and which the
|
* unresolved — a partial unit harec's module::resolve never hands the
|
||||||
* ww-stage asserttyped invariant (check.ww) is not meant to see.
|
* checker, and which the ww-stage asserttyped invariant must not see.
|
||||||
*
|
*
|
||||||
* Built in a private /tmp dir (a copy of the fixture) so no .combined.ww
|
* Built in a private /tmp dir (a copy of the fixture) so the sepwork
|
||||||
* / .s / .o lands next to the repo source. The link step fails for an
|
* lands off the repo source tree. The link step fails for an import-only
|
||||||
* import-only module (no main), but .combined.ww is written before
|
* module (no main), but the unit is written before the link, so we detect
|
||||||
* codegen, so we detect that artifact rather than gating on the build
|
* that artifact rather than gating on the build exit. Writes the owning
|
||||||
* exit. Writes the owning tmpdir into `td` (caller rm -rf's it) and the
|
* tmpdir into `td` (caller rm -rf's it) and the unit path into `out`.
|
||||||
* combined path into `out`. Returns 0 on success, -1 otherwise. */
|
* Returns 0 on success, -1 otherwise. */
|
||||||
static int
|
static int
|
||||||
resolveunit(const char *bin, const char *cwd, const char *fixture,
|
resolveunit(const char *bin, const char *cwd, const char *fixture,
|
||||||
int idx, char *td, size_t tdsz, char *out, size_t outsz)
|
int idx, char *td, size_t tdsz, char *out, size_t outsz)
|
||||||
@@ -549,18 +549,19 @@ resolveunit(const char *bin, const char *cwd, const char *fixture,
|
|||||||
snprintf(cmd, sizeof cmd, "cp %s/%s %s", cwd, fixture, tmpsrc);
|
snprintf(cmd, sizeof cmd, "cp %s/%s %s", cwd, fixture, tmpsrc);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"cd %s && timeout 180 %s/ww build %s >/dev/null 2>&1", td, bin, base);
|
"cd %s && timeout 180 %s/ww build --sep %s >/dev/null 2>&1",
|
||||||
|
td, bin, base);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
snprintf(out, outsz, "%s", tmpsrc);
|
char stem[768];
|
||||||
char *dot = strrchr(out, '.');
|
snprintf(stem, sizeof stem, "%s", tmpsrc);
|
||||||
|
char *dot = strrchr(stem, '.');
|
||||||
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
|
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
|
||||||
size_t n = strlen(out);
|
snprintf(out, outsz, "%s.sepwork/__root.unit.ww", stem);
|
||||||
snprintf(out + n, outsz - n, ".combined.ww");
|
|
||||||
return access(out, 0) == 0 ? 0 : -1;
|
return access(out, 0) == 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe 4: ww-side checker (wwdump_ww -r) runs name resolution on each
|
/* Probe 4: ww-side checker (wwdump_ww -r) runs name resolution on each
|
||||||
* selfhost fixture's RESOLVED unit (imports concatenated — see
|
* selfhost fixture's RESOLVED unit (sep root unit — see
|
||||||
* resolveunit) and reports zero unresolved. The raw file would leave
|
* resolveunit) and reports zero unresolved. The raw file would leave
|
||||||
* its `import` refs (os/fmt/strconv/ascii members) unresolved, i.e. the
|
* its `import` refs (os/fmt/strconv/ascii members) unresolved, i.e. the
|
||||||
* partial unit the asserttyped invariant must never see (harec resolves
|
* partial unit the asserttyped invariant must never see (harec resolves
|
||||||
@@ -578,9 +579,9 @@ probe_resolve(const char *bin)
|
|||||||
};
|
};
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
for (int i = 0; fixtures[i]; i++) {
|
for (int i = 0; fixtures[i]; i++) {
|
||||||
char td[64], combined[1024], a[256], cmd[2048];
|
char td[64], unit[1024], a[256], cmd[2048];
|
||||||
if (resolveunit(bin, cwd, fixtures[i], i, td, sizeof td,
|
if (resolveunit(bin, cwd, fixtures[i], i, td, sizeof td,
|
||||||
combined, sizeof combined) != 0) {
|
unit, sizeof unit) != 0) {
|
||||||
fprintf(stderr, "resolve FAIL: %s — no resolved unit\n",
|
fprintf(stderr, "resolve FAIL: %s — no resolved unit\n",
|
||||||
fixtures[i]);
|
fixtures[i]);
|
||||||
fail++;
|
fail++;
|
||||||
@@ -588,7 +589,7 @@ probe_resolve(const char *bin)
|
|||||||
}
|
}
|
||||||
snprintf(a, sizeof a, "/tmp/wwd_r_%d", getpid());
|
snprintf(a, sizeof a, "/tmp/wwd_r_%d", getpid());
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -r %s > %s 2>/dev/null",
|
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -r %s > %s 2>/dev/null",
|
||||||
bin, combined, a);
|
bin, unit, a);
|
||||||
int rc = runwait(cmd);
|
int rc = runwait(cmd);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
fprintf(stderr, "resolve FAIL: %s exited %d (unresolved names)\n",
|
fprintf(stderr, "resolve FAIL: %s exited %d (unresolved names)\n",
|
||||||
@@ -657,72 +658,21 @@ probe_dump_stable(const char *bin)
|
|||||||
return fail ? -1 : 0;
|
return fail ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe 9: full bootstrap fixed-point. ww1 → ww2 → ww3 with
|
/* Probe 7: end-to-end via the ww driver's sep path. `ww_ww build --sep`
|
||||||
* cmp ww2.s == ww3.s and cmp ww2 == ww3 (byte-identical binaries).
|
* drives the ww-side toolchain (w6c_ww → w6a_ww → w6l_ww) over the
|
||||||
* This is the textbook self-host gate: the compiler must reach a
|
* fixture's package graph — per-package compile, archive, reverse-topo
|
||||||
* fixed point under iterated self-compilation. */
|
* link — and we run the result, comparing the exit code to the fixture's
|
||||||
static int
|
* declared expectation. This is the bootstrap-grade signal: it doesn't
|
||||||
probe_bootstrap_fixed_point(const char *bin)
|
* require byte-identity, only that the ww toolchain links the fixture's
|
||||||
{
|
* dep stack (sym/typ/ast via the syntax package, in a SEPARATE `.o`) into
|
||||||
char cwd[1024];
|
* a functionally correct binary. The single-`.s` link the combined path
|
||||||
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
* used is gone with combined-mode (the syntax symbols live in their own
|
||||||
char tmpdir[64];
|
* `.o` under --sep, not in the root unit). */
|
||||||
snprintf(tmpdir, sizeof tmpdir, "/tmp/wwfp_%d", getpid());
|
|
||||||
mkdir(tmpdir, 0755);
|
|
||||||
char ww2s[512], ww2o[512], ww2e[512];
|
|
||||||
char ww3s[512], ww3o[512], ww3e[512];
|
|
||||||
char rt[1024], cmd[4096];
|
|
||||||
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
|
||||||
snprintf(ww2s, sizeof ww2s, "%s/ww2.s", tmpdir);
|
|
||||||
snprintf(ww2o, sizeof ww2o, "%s/ww2.o", tmpdir);
|
|
||||||
snprintf(ww2e, sizeof ww2e, "%s/ww2", tmpdir);
|
|
||||||
snprintf(ww3s, sizeof ww3s, "%s/ww3.s", tmpdir);
|
|
||||||
snprintf(ww3o, sizeof ww3o, "%s/ww3.o", tmpdir);
|
|
||||||
snprintf(ww3e, sizeof ww3e, "%s/ww3", tmpdir);
|
|
||||||
int fail = 0;
|
|
||||||
/* ww1 -> ww2 */
|
|
||||||
snprintf(cmd, sizeof cmd,
|
|
||||||
"timeout 180 %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, "timeout 180 %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, "timeout 180 %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,
|
|
||||||
"timeout 180 %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, "timeout 180 %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, "timeout 180 %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++; }
|
|
||||||
snprintf(cmd, sizeof cmd, "cmp -s %s %s", ww2e, ww3e);
|
|
||||||
if (runwait(cmd) != 0) { fprintf(stderr, "fp FAIL: ww2 != ww3 binaries\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
|
|
||||||
* 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
|
|
||||||
* useful while it lasts but layout choices (slot allocation order,
|
|
||||||
* spill placement) eventually diverge between cgens; correctness is
|
|
||||||
* the test that scales. */
|
|
||||||
static int
|
static int
|
||||||
probe_ww_links(const char *bin)
|
probe_ww_links(const char *bin)
|
||||||
{
|
{
|
||||||
const char *fixtures[][2] = {
|
const char *fixtures[][2] = {
|
||||||
{ "selfhost/test/sym_link.ww", "42" }, /* sym/typ/ast/mem */
|
{ "selfhost/test/sym_link.ww", "42" }, /* sym/typ/ast via syntax */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
char cwd[1024];
|
char cwd[1024];
|
||||||
@@ -745,41 +695,18 @@ probe_ww_links(const char *bin)
|
|||||||
char cmd[4096];
|
char cmd[4096];
|
||||||
snprintf(cmd, sizeof cmd, "cp %s/%s %s", cwd, fix, tmpsrc);
|
snprintf(cmd, sizeof cmd, "cp %s/%s %s", cwd, fix, tmpsrc);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
/* ww build to get the .combined.ww as a side effect. */
|
/* Isolated WW_PKGCACHE: the default out/.pkgcache is shared with
|
||||||
snprintf(cmd, sizeof cmd,
|
* the other phase-2 gates' sep builds (perturb + race). -o + the
|
||||||
"cd %s && timeout 180 %s/ww build -I %s/lib/ww -I %s/selfhost/cmd/wcc %s >/dev/null 2>&1",
|
* absolute src/-I paths route every side file into tmpdir, so no
|
||||||
tmpdir, bin, cwd, cwd, tmpsrc);
|
* cwd dependency. */
|
||||||
if (runwait(cmd) != 0) {
|
char wexep[512];
|
||||||
fprintf(stderr, "ww-links FAIL: ww build %s\n", fix);
|
|
||||||
fail++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
/* Now compile the combined source via the ww frontend. */
|
|
||||||
char combinedp[512], wsp[512], wop[512], wexep[512];
|
|
||||||
snprintf(combinedp, sizeof combinedp, "%s.combined.ww", stem);
|
|
||||||
snprintf(wsp, sizeof wsp, "%s_w.s", stem);
|
|
||||||
snprintf(wop, sizeof wop, "%s_w.o", stem);
|
|
||||||
snprintf(wexep, sizeof wexep, "%s_w", stem);
|
snprintf(wexep, sizeof wexep, "%s_w", stem);
|
||||||
snprintf(cmd, sizeof cmd,
|
snprintf(cmd, sizeof cmd,
|
||||||
"timeout 180 %s/wwdump_ww -c %s > %s 2>/dev/null", bin, combinedp, wsp);
|
"WW_PKGCACHE='%s.cache' timeout 180 %s/ww_ww build --sep "
|
||||||
|
"-o %s -I %s/lib/ww -I %s/selfhost/cmd/wcc %s >/dev/null 2>&1",
|
||||||
|
stem, bin, wexep, cwd, cwd, tmpsrc);
|
||||||
if (runwait(cmd) != 0) {
|
if (runwait(cmd) != 0) {
|
||||||
fprintf(stderr, "ww-links FAIL: wwdump_ww -c %s\n", fix);
|
fprintf(stderr, "ww-links FAIL: ww_ww build --sep %s\n", fix);
|
||||||
fail++;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a -o %s %s 2>/dev/null",
|
|
||||||
bin, wop, wsp);
|
|
||||||
if (runwait(cmd) != 0) {
|
|
||||||
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, "timeout 180 %s/w6l -o %s %s %s 2>/dev/null",
|
|
||||||
bin, wexep, wop, rt);
|
|
||||||
if (runwait(cmd) != 0) {
|
|
||||||
fprintf(stderr, "ww-links FAIL: w6l %s\n", fix);
|
|
||||||
fail++;
|
fail++;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@@ -791,8 +718,6 @@ probe_ww_links(const char *bin)
|
|||||||
fail++;
|
fail++;
|
||||||
}
|
}
|
||||||
cleanup:
|
cleanup:
|
||||||
/* Sweep tmpdir contents, then remove. ww build also drops a
|
|
||||||
* C-built binary at <stem> — clean it too. */
|
|
||||||
snprintf(cmd, sizeof cmd, "rm -rf %s", tmpdir);
|
snprintf(cmd, sizeof cmd, "rm -rf %s", tmpdir);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
}
|
}
|
||||||
@@ -800,23 +725,20 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Probe 6: ww-cgen byte-matches C-cgen on each selfhost fixture's
|
/* Probe 6: ww-cgen byte-matches C-cgen on each selfhost fixture's
|
||||||
* RESOLVED unit (imports concatenated — see resolveunit). The driver
|
* RESOLVED unit (sep root unit — see resolveunit). The producer feeds
|
||||||
* always feeds w6c/wwdump a concatenated unit, so the byte-identity
|
* w6c/wwdump that self-contained unit, so the byte-identity gate (rule
|
||||||
* gate (rule 10) belongs on that shape rather than the raw file; the
|
* 10) belongs on that shape rather than the raw file.
|
||||||
* unit also drags in the imported stdlib (os/strconv/ascii), widening
|
|
||||||
* the convergence set. When this stays empty the cmp ww2 ww3 ceiling
|
|
||||||
* becomes feasible.
|
|
||||||
*
|
*
|
||||||
* selfhost/cmd/wcc/err.ww is exercised by probe_resolve but not here:
|
* err.ww is included now (it was excluded under combined-mode, where its
|
||||||
* its resolved unit pulls in lib/fmt, whose `formattable` match the
|
* unit inlined lib/fmt's BODY and the ww checker rejected fmt's
|
||||||
* ww-stage checker rejects (check.ww casecovers/casevariantin raise
|
* `formattable` match-exhaustiveness): the sep unit inlines only fmt's
|
||||||
* ck.errs, so wwdump -c bails before cgen) — a cs≠ww match-exhaustive-
|
* `.wwi` INTERFACE, so the fmt body never reaches the checker and err's
|
||||||
* ness divergence, latent for the bootstrap (the compiler's own
|
* root cgen converges cs==ww. */
|
||||||
* main.combined.ww imports no fmt) and tracked separately. */
|
|
||||||
static int
|
static int
|
||||||
probe_cgen_match(const char *bin)
|
probe_cgen_match(const char *bin)
|
||||||
{
|
{
|
||||||
const char *files[] = {
|
const char *files[] = {
|
||||||
|
"selfhost/cmd/wcc/err.ww",
|
||||||
"lib/ww/syntax/tok.ww",
|
"lib/ww/syntax/tok.ww",
|
||||||
"selfhost/test/smoke.ww",
|
"selfhost/test/smoke.ww",
|
||||||
NULL,
|
NULL,
|
||||||
@@ -825,9 +747,9 @@ probe_cgen_match(const char *bin)
|
|||||||
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
for (int i = 0; files[i]; i++) {
|
for (int i = 0; files[i]; i++) {
|
||||||
char td[64], combined[1024], a[256], b[256], cmd[2048];
|
char td[64], unit[1024], a[256], b[256], cmd[2048];
|
||||||
if (resolveunit(bin, cwd, files[i], i, td, sizeof td,
|
if (resolveunit(bin, cwd, files[i], i, td, sizeof td,
|
||||||
combined, sizeof combined) != 0) {
|
unit, sizeof unit) != 0) {
|
||||||
fprintf(stderr, "cgen-match FAIL: %s — no resolved unit\n",
|
fprintf(stderr, "cgen-match FAIL: %s — no resolved unit\n",
|
||||||
files[i]);
|
files[i]);
|
||||||
fail++;
|
fail++;
|
||||||
@@ -836,10 +758,10 @@ probe_cgen_match(const char *bin)
|
|||||||
snprintf(a, sizeof a, "/tmp/wwd_cm_%d_c", getpid());
|
snprintf(a, sizeof a, "/tmp/wwd_cm_%d_c", getpid());
|
||||||
snprintf(b, sizeof b, "/tmp/wwd_cm_%d_w", getpid());
|
snprintf(b, sizeof b, "/tmp/wwd_cm_%d_w", getpid());
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c %s > %s 2>/dev/null",
|
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c %s > %s 2>/dev/null",
|
||||||
bin, combined, a);
|
bin, unit, a);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -c %s > %s 2>/dev/null",
|
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -c %s > %s 2>/dev/null",
|
||||||
bin, combined, b);
|
bin, unit, b);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
char *bc = NULL, *bw = NULL;
|
char *bc = NULL, *bw = NULL;
|
||||||
size_t nc = 0, nw = 0;
|
size_t nc = 0, nw = 0;
|
||||||
@@ -876,19 +798,26 @@ main(void)
|
|||||||
if (probe_ww_compile(bin) != 0) fail++;
|
if (probe_ww_compile(bin) != 0) fail++;
|
||||||
if (probe_cgen_match(bin) != 0) fail++;
|
if (probe_cgen_match(bin) != 0) fail++;
|
||||||
if (probe_ww_links(bin) != 0) fail++;
|
if (probe_ww_links(bin) != 0) fail++;
|
||||||
if (probe_bootstrap_fixed_point(bin) != 0) fail++;
|
|
||||||
|
|
||||||
if (fail) {
|
if (fail) {
|
||||||
fprintf(stderr, "selfhost: %d probe(s) failed\n", fail);
|
fprintf(stderr, "selfhost: %d probe(s) failed\n", fail);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* The ww1->ww2->ww3 binary fixed point is no longer reproducible here:
|
||||||
|
* it self-compiled wwdump as a monolith from main.combined.ww, a model
|
||||||
|
* combined-mode provided and --sep retires (the sep root unit holds only
|
||||||
|
* the root body + dep INTERFACE stubs, not a linkable whole program). The
|
||||||
|
* two axes it covered now live elsewhere: the self-application fixed point
|
||||||
|
* (iterated self-compile converges, ww2==ww3==ww4) is `make bootstrap`'s
|
||||||
|
* sep-path gate (migrated E2-C1); the orthogonal wwstage==cstage byte
|
||||||
|
* identity is 995_self_rebuild, which drives ww_ww --sep over all five
|
||||||
|
* tools (wwdump included) and byte-compares against the cstage binaries. */
|
||||||
printf("selfhost: codegen ok; smoke=42; wwdump stable; "
|
printf("selfhost: codegen ok; smoke=42; wwdump stable; "
|
||||||
"ww lexer matches C on 8 fixtures (-t); "
|
"ww lexer matches C on 8 fixtures (-t); "
|
||||||
"ww parser matches C on 32 fixtures (-a); "
|
"ww parser matches C on 32 fixtures (-a); "
|
||||||
"ww checker resolves 3 fixtures' import-concatenated units (-r); "
|
"ww checker resolves 3 fixtures' sep root units (-r); "
|
||||||
"ww cgen compiles + runs 13 ww programs (incl. compound -= regression); "
|
"ww cgen compiles + runs 13 ww programs (incl. compound -= regression); "
|
||||||
"ww cgen byte-matches C on 2 resolved units (tok/smoke); "
|
"ww cgen byte-matches C on 3 sep root units (err/tok/smoke); "
|
||||||
"ww cgen builds runnable binaries from sym/typ/ast/mem stack; "
|
"ww toolchain sep-builds + runs the syntax dep stack (sym_link=42)\n");
|
||||||
"ww1 -> ww2 -> ww3 fixed-point reached: ww2.s == ww3.s, ww2 == ww3 byte-identical\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,41 +120,6 @@ files_eq(const char *a, const char *b)
|
|||||||
return eq ? 0 : 1;
|
return eq ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tier-C oracle helper (rob-c6-spec §2 / amendment-B): a sep-built w6c at
|
|
||||||
* `sepw6c` must EMIT byte-identical asm to the combined-built `w6c_ww` on
|
|
||||||
* `target`. (We assert OUTPUT equivalence, never `cmp` the tool binaries —
|
|
||||||
* sep vs combined differ by a constant link-layout delta.) Returns 0 on
|
|
||||||
* byte-identical .s, non-zero otherwise. */
|
|
||||||
static int
|
|
||||||
emit_eq(const char *sepw6c, const char *w6c_ww, const char *target,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
char a[64], b[64], cmd[4096];
|
|
||||||
snprintf(a, sizeof a, "/tmp/wwc6tc_%d_sep.s", getpid());
|
|
||||||
snprintf(b, sizeof b, "/tmp/wwc6tc_%d_comb.s", getpid());
|
|
||||||
snprintf(cmd, sizeof cmd, "timeout 240 %s -o %s %s 2>/dev/null",
|
|
||||||
sepw6c, a, target);
|
|
||||||
if (runwait(cmd) != 0) {
|
|
||||||
fprintf(stderr, "Tier-C FAIL: sep-w6c emit errored on %s\n", label);
|
|
||||||
unlink(a);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
snprintf(cmd, sizeof cmd, "timeout 240 %s -o %s %s 2>/dev/null",
|
|
||||||
w6c_ww, b, target);
|
|
||||||
if (runwait(cmd) != 0) {
|
|
||||||
fprintf(stderr, "Tier-C FAIL: combined-w6c_ww emit errored on %s\n",
|
|
||||||
label);
|
|
||||||
unlink(a); unlink(b);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int rc = files_eq(a, b);
|
|
||||||
if (rc != 0)
|
|
||||||
fprintf(stderr, "Tier-C FAIL: %s — sep-out != combined-out "
|
|
||||||
"(M4 output-equivalence broken)\n", label);
|
|
||||||
unlink(a); unlink(b);
|
|
||||||
return rc == 0 ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cs==ww over a sep-build's per-package artifacts: every .s/.o/.wwi the
|
/* cs==ww over a sep-build's per-package artifacts: every .s/.o/.wwi the
|
||||||
* cstage driver produced in `csdir` must be byte-identical to the wwstage
|
* cstage driver produced in `csdir` must be byte-identical to the wwstage
|
||||||
* driver's same-named file in `wwdir` (rule 10; the .wwi interface files
|
* driver's same-named file in `wwdir` (rule 10; the .wwi interface files
|
||||||
@@ -309,17 +274,6 @@ main(void)
|
|||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Source-tree corpus: the same .combined.ww files the bootstrap
|
|
||||||
* 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/w6a/main.combined.ww",
|
|
||||||
"selfhost/cmd/w6l/main.combined.ww",
|
|
||||||
"selfhost/cmd/ww/main.combined.ww",
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
int fail = 0, n = 0;
|
int fail = 0, n = 0;
|
||||||
|
|
||||||
for (int i = 0; progs[i].label; i++) {
|
for (int i = 0; progs[i].label; i++) {
|
||||||
@@ -330,12 +284,6 @@ main(void)
|
|||||||
unlink(src);
|
unlink(src);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
for (int i = 0; combined_rel[i]; i++) {
|
|
||||||
char p[2048];
|
|
||||||
snprintf(p, sizeof p, "%s/%s", cwd, combined_rel[i]);
|
|
||||||
if (diff_one(bin, combined_rel[i], p) != 0) fail++;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* #50: the check pass is wired into both wwdump_ww -c and
|
/* #50: the check pass is wired into both wwdump_ww -c and
|
||||||
* w6c_ww in front of cgen. Pre-#50, a hard type error parsed
|
* w6c_ww in front of cgen. Pre-#50, a hard type error parsed
|
||||||
@@ -376,22 +324,19 @@ main(void)
|
|||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Tier-C capstone (#46 c6, rob-c6-spec §2 / amendment-B) ----------
|
/* ---- Tier-C capstone (#46 c6, rob-c6-spec §2 / amendment-B; M4 #89) ---
|
||||||
* Fold the dual-path soak into this bootstrap oracle: a w6c built by
|
* The load-bearing M4 oracle: build w6c by SEPARATE compilation under
|
||||||
* SEPARATE compilation must EMIT byte-identical .s to the combined-built
|
* BOTH driver stages and prove they sep-produce byte-identical per-package
|
||||||
* w6c_ww on every real bootstrap input, and both driver stages must
|
* .s/.o/.wwi (cs==ww on the real tool's sep artifacts, rule 10). The
|
||||||
* sep-produce byte-identical per-package .s/.o/.wwi (cs==ww on the real
|
* combined corpus + the sep-out==combined-out leg are gone — combined-mode
|
||||||
* tool's sep artifacts). This is the load-bearing M4 proof — the
|
* is being retired (E3 flip), so combined.ww is no longer fed as compiler
|
||||||
* combined-out==sep-out leg the bootstrap fixed point alone cannot reach.
|
* INPUT; the per-pkg cs==ww comparison is the surviving live oracle. COLD
|
||||||
* We assert OBSERVABLE OUTPUT, never `cmp` the tool binaries (sep vs
|
* (pid-keyed scratch, wiped); heavy (≈ one bootstrap leg) → phase-2. */
|
||||||
* combined differ by a constant link-layout delta). COLD (pid-keyed
|
|
||||||
* scratch, wiped); heavy (≈ one bootstrap leg) → this gate is phase-2. */
|
|
||||||
{
|
{
|
||||||
char inc[4096], cmd[16384];
|
char inc[4096], cmd[16384];
|
||||||
snprintf(inc, sizeof inc,
|
snprintf(inc, sizeof inc,
|
||||||
"-I %s/lib -I %s/lib/ww -I %s/selfhost/cmd/wcc", cwd, cwd, cwd);
|
"-I %s/lib -I %s/lib/ww -I %s/selfhost/cmd/wcc", cwd, cwd, cwd);
|
||||||
char w6c_ww[2048], root[2048];
|
char root[2048];
|
||||||
snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin);
|
|
||||||
snprintf(root, sizeof root, "%s/selfhost/cmd/w6c/main.ww", cwd);
|
snprintf(root, sizeof root, "%s/selfhost/cmd/w6c/main.ww", cwd);
|
||||||
|
|
||||||
struct { const char *drv, *tag; char prog[2048]; int ok; }
|
struct { const char *drv, *tag; char prog[2048]; int ok; }
|
||||||
@@ -415,29 +360,6 @@ main(void)
|
|||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OUTPUT equivalence on every real bootstrap input: each built
|
|
||||||
* sep-w6c vs the combined w6c_ww (the M4 combined-out==sep-out bar;
|
|
||||||
* cs==ww follows since both sep stages match the same reference). */
|
|
||||||
const char *targ[] = {
|
|
||||||
"selfhost/cmd/w6c/main.combined.ww",
|
|
||||||
"selfhost/cmd/wwdump/main.combined.ww",
|
|
||||||
"selfhost/cmd/w6a/main.combined.ww",
|
|
||||||
"selfhost/cmd/w6l/main.combined.ww",
|
|
||||||
"selfhost/cmd/ww/main.combined.ww",
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
for (int s = 0; s < 2; s++) {
|
|
||||||
if (!stg[s].ok) continue;
|
|
||||||
for (int i = 0; targ[i]; i++) {
|
|
||||||
char t[2048], label[256];
|
|
||||||
snprintf(t, sizeof t, "%s/%s", cwd, targ[i]);
|
|
||||||
snprintf(label, sizeof label, "sep-%s emit %s",
|
|
||||||
stg[s].tag, targ[i]);
|
|
||||||
if (emit_eq(stg[s].prog, w6c_ww, t, label) != 0) fail++;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cs==ww on the real tool's sep .s/.o/.wwi (rule 10). */
|
/* cs==ww on the real tool's sep .s/.o/.wwi (rule 10). */
|
||||||
if (stg[0].ok && stg[1].ok) {
|
if (stg[0].ok && stg[1].ok) {
|
||||||
char csdir[2176], wwdir[2176];
|
char csdir[2176], wwdir[2176];
|
||||||
@@ -458,9 +380,8 @@ main(void)
|
|||||||
fprintf(stderr, "w6c_ww: %d/%d diff(s) failed\n", fail, n);
|
fprintf(stderr, "w6c_ww: %d/%d diff(s) failed\n", fail, n);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("w6c_ww: byte-identical to wwdump_ww -c on %d corpus inputs "
|
printf("w6c_ww: byte-identical to wwdump_ww -c on %d in-source corpus "
|
||||||
"(in-source + selfhost combined.ww) + Tier-C: sep-built w6c emits "
|
"inputs + Tier-C: cs==ww sep .s/.o/.wwi on the real w6c build\n",
|
||||||
"== combined w6c_ww on all bootstrap inputs, cs==ww sep .s/.o/.wwi\n",
|
|
||||||
n);
|
n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user