/* * 989_floatlit_run — runtime + byte-id net for #62: the two stages * folded float LITERALS differently. cstage folds via strtod * (correctly rounded); the wwstage lexer used a pow-10 accumulation * fold that was 1-2 ULP off on decimal fractions, overflowed its i64 * accumulator past 19 mantissa digits, and missed DBL_MIN/DBL_MAX by * up to 2 ULP — a pinned cs≠ww DATA divergence (989 ratchet #59.10). * Fix: lexnum folds through strconv.stof64 (the Hare-ported * correctly-rounded decimal engine). * * Fixture 1 (vectors): each row reads back a literal's IEEE bits via * a *u64 reinterpret and compares against the C-strtod-oracle bit * pattern; the exit code pinpoints the failing row. Carries (a) * cstage `ww build` + run asserting exit 0 (rule-10: convergence * targets the runtime-CORRECT side) and (b) w6c vs w6c_ww `.s` cmp * (byte-id — the wwstage fold itself). * * Fixture 2 (overflow): 1.7976931348623159e308 rounds above DBL_MAX — * strtod sets ERANGE so cstage rejects; wwstage must reject too * (stof64 overflow → errat). Both compilers must exit non-zero. * * Retained divergence (task #21): a SUBNORMAL literal (e.g. * 2.2250738585072011e-308) is rejected by cstage (glibc strtod flags * partial underflow with ERANGE) but accepted correctly-rounded by * wwstage (Hare stof semantics) — accept-set asymmetry only, not a * bits divergence; pre-existing on master (old parsef64 accepted it * with garbage bits). * * 9xx is full; shares the 989 prefix per the 989_sha256 precedent. */ #include #include #include #include #include static const char *vectors_src = "package main;\n" "fn bits(v: f64) u64 = {\n" " let x: f64 = v;\n" " let p: *u64 = (&x): *u64;\n" " return *p;\n" "};\n" "export fn main() i32 = {\n" " if (bits(1.0000000000000002) != 0x3FF0000000000001u64) { return 1; };\n" " if (bits(9007199254740993.0) != 0x4340000000000000u64) { return 2; };\n" " if (bits(1.2345e67) != 0x4DDD4E421712C0B7u64) { return 3; };\n" " if (bits(0.1) != 0x3FB999999999999Au64) { return 4; };\n" " if (bits(1.1) != 0x3FF199999999999Au64) { return 5; };\n" " if (bits(123456789012345678901234567890.0) != 0x45F8EE90FF6C373Eu64) { return 6; };\n" " if (bits(2.2250738585072014e-308) != 0x0010000000000000u64) { return 7; };\n" " if (bits(0.3) != 0x3FD3333333333333u64) { return 8; };\n" " if (bits(3.141592653589793) != 0x400921FB54442D18u64) { return 9; };\n" " if (bits(1.7976931348623157e308) != 0x7FEFFFFFFFFFFFFFu64) { return 10; };\n" " if (bits(1.7976931348623158e308) != 0x7FEFFFFFFFFFFFFFu64) { return 11; };\n" " if (bits(7.2057594037927933e16) != 0x4370000000000000u64) { return 12; };\n" " if (bits(1000000000000000000000.0) != 0x444B1AE4D6E2EF50u64) { return 13; };\n" " if (bits(1_000.5) != 0x408F440000000000u64) { return 14; };\n" " if (bits(1.00000000000000011102230246251565404236316680908203125) != 0x3FF0000000000000u64) { return 15; };\n" " if (bits(1.00000000000000011102230246251565404236316680908203126) != 0x3FF0000000000001u64) { return 16; };\n" " if (bits(4503599627370497.5) != 0x4330000000000002u64) { return 17; };\n" " if (bits(0.5) != 0x3FE0000000000000u64) { return 18; };\n" " if (bits(1.0e308) != 0x7FE1CCF385EBC8A0u64) { return 19; };\n" " if (bits(2.225073858507202e-308) != 0x0010000000000001u64) { return 20; };\n" " return 0;\n" "};\n"; static const char *overflow_src = "package main;\n" "export fn main() i32 = {\n" " let a: f64 = 1.7976931348623159e308;\n" " return 0;\n" "};\n"; static int runwait(const char *cmd) { int rc = system(cmd); if (rc == -1) return -1; if (WIFEXITED(rc)) return WEXITSTATUS(rc); return -1; } static int slurp_eq(const char *a, const char *b) { FILE *fa = fopen(a, "rb"); FILE *fb = fopen(b, "rb"); if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } int rc = 0; for (;;) { int ca = fgetc(fa); int cb = fgetc(fb); if (ca != cb) { rc = -1; break; } if (ca == EOF) break; } fclose(fa); fclose(fb); return rc; } static int writesrc(const char *path, const char *src) { FILE *f = fopen(path, "wb"); if (f == NULL) return -1; fputs(src, f); fclose(f); return 0; } int main(void) { const char *bin = getenv("BIN"); if (!bin) bin = "out/bin"; char absbin[1024]; if (bin[0] != '/') { char cwd[1024]; if (getcwd(cwd, sizeof cwd) == NULL) return 1; snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); bin = absbin; } char w6c[1100], w6c_ww[1100]; snprintf(w6c, sizeof w6c, "%s/w6c", bin); snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); if (access(w6c_ww, X_OK) != 0) { fprintf(stderr, "floatlit: w6c_ww missing — cannot run " "the cs==ww byte-id gate (the whole point of this test)\n"); return 1; } int fail = 0; char src[128], outbin[128], cs_s[128], ws_s[128], cmd[2048]; char tmpdir[64], rmcmd[160]; snprintf(tmpdir, sizeof tmpdir, "/tmp/wwflit_%d_d", getpid()); mkdir(tmpdir, 0755); snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); /* fixture 1: vectors — cstage build+run, then byte-id */ snprintf(src, sizeof src, "%s/wwflit_%d.ww", tmpdir, getpid()); if (writesrc(src, vectors_src) != 0) { runwait(rmcmd); return 1; } snprintf(outbin, sizeof outbin, "%s/wwflit_%d", tmpdir, getpid()); snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", bin, outbin, src); if (runwait(cmd) != 0) { fprintf(stderr, "floatlit: cstage build failed\n"); fail++; } else { int got = runwait(outbin); if (got != 0) { fprintf(stderr, "floatlit: vector row %d has wrong " "bits at runtime (cstage)\n", got); fail++; } } snprintf(cs_s, sizeof cs_s, "%s/wwflit_%d_cs.s", tmpdir, getpid()); snprintf(ws_s, sizeof ws_s, "%s/wwflit_%d_ww.s", tmpdir, getpid()); snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, cs_s, src); if (runwait(cmd) != 0) { fprintf(stderr, "floatlit: w6c failed on vectors\n"); fail++; } else { snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c_ww, ws_s, src); if (runwait(cmd) != 0) { fprintf(stderr, "floatlit: w6c_ww failed on vectors\n"); fail++; } else if (slurp_eq(cs_s, ws_s) != 0) { fprintf(stderr, "floatlit: cstage/wwstage .s DIFFER " "(rule-10 byte-id violation)\n"); fail++; } } /* fixture 2: overflow literal — BOTH stages must reject */ snprintf(src, sizeof src, "%s/wwflit_%d_ovf.ww", tmpdir, getpid()); if (writesrc(src, overflow_src) != 0) { runwait(rmcmd); return 1; } snprintf(cmd, sizeof cmd, "%s %s >/dev/null 2>&1", w6c, src); if (runwait(cmd) == 0) { fprintf(stderr, "floatlit: w6c ACCEPTED overflow literal\n"); fail++; } snprintf(cmd, sizeof cmd, "%s %s >/dev/null 2>&1", w6c_ww, src); if (runwait(cmd) == 0) { fprintf(stderr, "floatlit: w6c_ww ACCEPTED overflow literal\n"); fail++; } runwait(rmcmd); if (fail) { fprintf(stderr, "floatlit: %d check(s) failed\n", fail); return 1; } printf("floatlit: vectors byte-id + runtime-correct, " "overflow rejected by both stages\n"); return 0; }