/* * 991_w6a_ww — phase-10 marker for the ww-side w6a port. * * 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/w6a/w6l main.s) - large, exercises * every encoding path w6c emits * * Any divergence is a port bug in selfhost/cmd/w6a/. */ #include #include #include #include #include #include static int runwait(const char *cmd) { int rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return 1; } static const char * absbin(void) { const char *b = getenv("BIN"); if (!b) b = "out/bin"; if (b[0] == '/') return b; static char buf[2048]; char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return NULL; snprintf(buf, sizeof buf, "%s/%s", cwd, b); return buf; } static int slurp(const char *path, char **outbuf, size_t *outlen) { FILE *f = fopen(path, "rb"); if (!f) return -1; fseek(f, 0, SEEK_END); long n = ftell(f); fseek(f, 0, SEEK_SET); if (n < 0) { fclose(f); return -1; } char *b = malloc((size_t)n + 1); if (!b) { fclose(f); return -1; } if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; } b[n] = '\0'; fclose(f); *outbuf = b; *outlen = (size_t)n; return 0; } static int diff_one(const char *bin, const char *src) { char co[64], wo[64], cmd[2048]; snprintf(co, sizeof co, "/tmp/wwa_%d_c.o", getpid()); snprintf(wo, sizeof wo, "/tmp/wwa_%d_w.o", getpid()); snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a -o %s %s 2>/dev/null", bin, co, src); if (runwait(cmd) != 0) { fprintf(stderr, "w6a_ww FAIL: C w6a errored on %s\n", src); unlink(co); return -1; } snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a_ww -o %s %s 2>/dev/null", bin, wo, src); if (runwait(cmd) != 0) { fprintf(stderr, "w6a_ww FAIL: ww w6a errored on %s\n", src); unlink(co); unlink(wo); return -1; } char *bc = NULL, *bw = NULL; size_t nc = 0, nw = 0; int rc = 0; if (slurp(co, &bc, &nc) < 0 || slurp(wo, &bw, &nw) < 0) { 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, "w6a_ww FAIL: %s — C %zu vs ww %zu bytes\n", src, nc, nw); rc = -1; } free(bc); free(bw); unlink(co); unlink(wo); return rc; } int main(void) { const char *bin = absbin(); if (!bin) return 1; char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; /* #93 sep layout: the selfhost tools no longer leave a single * next-to-source main.s. Self-build one real tool via `ww build * --sep` into /tmp and feed EVERY emitted .sepwork/.s as * the generated-asm corpus — the root tool code plus each dep * package's .s (richer than the old 3 monolithic main.s). Flip- * invariant: --sep is live on trunk, default post-flip. */ char stem[256], cmd[4096]; snprintf(stem, sizeof stem, "/tmp/wwa_%d_sh", getpid()); snprintf(cmd, sizeof cmd, "WW_PKGCACHE=%s.pkgc timeout 400 %s/ww build --sep -o %s " "%s/selfhost/cmd/w6a >/dev/null 2>&1", stem, bin, stem, cwd); if (runwait(cmd) != 0) { fprintf(stderr, "w6a_ww FAIL: cannot sep-build selfhost/cmd/w6a\n"); return 1; } /* hand-written runtime — small, covers MOVQ/LEAQ/CALL/SYSCALL/RET; * exists in-tree regardless of layout (not a casualty). */ const char *rtfiles[] = { "rt/start.s", "rt/syscall.s", "rt/abort.s", "rt/alloc.s", "rt/streq.s", NULL, }; int fail = 0; int n = 0; for (int i = 0; rtfiles[i]; i++) { char p[2048]; snprintf(p, sizeof p, "%s/%s", cwd, rtfiles[i]); if (diff_one(bin, p) != 0) fail++; n++; } /* generated .s from the real tool's sep build — large, exercises * every encoding w6c emits (the long tail of operand shapes). */ glob_t g; char pat[320]; snprintf(pat, sizeof pat, "%s.sepwork/*.s", stem); if (glob(pat, 0, NULL, &g) == 0) { for (size_t i = 0; i < g.gl_pathc; i++) { /* skip empty units (e.g. an import-only rt.s). */ FILE *f = fopen(g.gl_pathv[i], "rb"); long sz = -1; if (f) { fseek(f, 0, SEEK_END); sz = ftell(f); fclose(f); } if (sz <= 0) continue; if (diff_one(bin, g.gl_pathv[i]) != 0) fail++; n++; } globfree(&g); } snprintf(cmd, sizeof cmd, "rm -rf %s.sepwork %s.pkgc %s", stem, stem, stem); if (system(cmd)) {} if (fail) { fprintf(stderr, "w6a_ww: %d/%d diff(s) failed\n", fail, n); return 1; } printf("w6a_ww: byte-identical to C w6a on %d corpus files " "(rt/*.s + selfhost/cmd/w6a sep-built .s)\n", n); return 0; }