/* * 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 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; const char *files[] = { /* hand-written runtime — small, covers MOVQ/LEAQ/CALL/SYSCALL/RET. */ "rt/start.s", "rt/syscall.s", "rt/abort.s", "rt/alloc.s", "rt/streq.s", /* generated .s from the existing selfhost stack — large, * exercises every encoding w6c emits (the only way to hit * the long tail of operand shapes). */ "selfhost/cmd/wwdump/main.s", "selfhost/cmd/w6l/main.s", "selfhost/cmd/w6a/main.s", NULL, }; int fail = 0; int n = 0; for (int i = 0; files[i]; i++) { char p[2048]; snprintf(p, sizeof p, "%s/%s", cwd, files[i]); if (diff_one(bin, p) != 0) fail++; n++; } 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 generated main.s)\n", n); return 0; }