test: 952 add issubnormalf64 + normalizef64 runtime rows
Four cstage build+run rows for the fold-2a decompose step: issubnormalf64 across normals/zero/a constructed subnormal (f64frombits(1u64)), and normalizef64 on both the normal path (n, 0) and the subnormal multiply path (exp -52, result no longer subnormal). normalizef64's (f64, i64) return rides the #102 16B-tuple-from-call receive; tuple-field f64s are spilled to a let before any literal comparison to dodge the same gate-blind XMM mis-load that holds back frexpf64 (see 952 header + lib/math/floats.ww). Byte-id of a normalize-calling program is covered by 954's tuple-receive gate.
This commit is contained in:
@@ -1,12 +1,22 @@
|
||||
/*
|
||||
* 952_floats_run — runtime regression net for lib/math/floats fold-1
|
||||
* (f64bits, f64frombits, isnan, isinf, signf64, absf64, copysignf64,
|
||||
* ispositivef64, isnegativef64). The classify/sign/bits surface rides
|
||||
* ispositivef64, isnegativef64) plus the fold-2a decompose step
|
||||
* (issubnormalf64, normalizef64). The classify/sign/bits surface rides
|
||||
* the f64-codegen paths fixed by #96 (deref-load -> MOVSD/X0) and #97
|
||||
* (compare consults PF for NaN); both stages emit byte-identical asm, so
|
||||
* the 990-997 byte-id gates can't catch a reintroduction — only an
|
||||
* (compare consults PF for NaN); normalizef64 additionally rides the #102
|
||||
* 16B-tuple-from-call receive (its (f64, i64) return) and the f64 multiply
|
||||
* on the subnormal path. Both stages emit byte-identical asm, so the
|
||||
* 990-997 byte-id gates can't catch a reintroduction — only an
|
||||
* executed-and-checked runtime probe can. This file is that probe.
|
||||
*
|
||||
* frexpf64 is intentionally absent: its Hare-exact `n == 0f64` guard
|
||||
* miscompiles (a no-decimal f64 literal in a comparison never reaches XMM;
|
||||
* gate-blind, both stages identical). See the hold-back note in
|
||||
* lib/math/floats.ww. The normalizef64 rows below spill tuple fields to a
|
||||
* let before any f64-literal comparison, since a tuple-field f64 compared
|
||||
* directly against a literal (`r.0 == 0.0`) hits the same mis-load.
|
||||
*
|
||||
* Table-driven like 951_f64cgen_run: each row is a self-contained ww
|
||||
* program importing math; the C-side cstage `ww build -I lib` compiles
|
||||
* it, we run the binary and assert the exit code. Self-checking rows
|
||||
@@ -113,6 +123,55 @@ static const struct row rows[] = {
|
||||
"export fn main() i32 = {\n"
|
||||
" return math.absf64(-7.0): i32;\n"
|
||||
"};\n", 7 },
|
||||
/* issubnormalf64: normals and zero are not subnormal; the smallest
|
||||
* positive f64 (bits == 1, ~5e-324) is. Built via f64frombits so the
|
||||
* checker can't fold a subnormal literal (which it would flush). */
|
||||
{ "package main;\n"
|
||||
"import math;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" if (math.issubnormalf64(16.0)) { return 1; };\n"
|
||||
" if (math.issubnormalf64(0.0)) { return 2; };\n"
|
||||
" if (math.issubnormalf64(1.0)) { return 3; };\n"
|
||||
" let s: f64 = math.f64frombits(1u64);\n"
|
||||
" if (!math.issubnormalf64(s)) { return 4; };\n"
|
||||
" return 0;\n"
|
||||
"};\n", 0 },
|
||||
/* normalizef64 on a normal value returns (n, 0). The (f64, i64) tuple
|
||||
* rides the #102 16B-tuple-from-call receive; r.0 is spilled to a let
|
||||
* before comparison (see header). */
|
||||
{ "package main;\n"
|
||||
"import math;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" const r = math.normalizef64(16.0);\n"
|
||||
" const m: f64 = r.0;\n"
|
||||
" if (m != 16.0) { return 1; };\n"
|
||||
" if (r.1 != 0i64) { return 2; };\n"
|
||||
" return 0;\n"
|
||||
"};\n", 0 },
|
||||
/* normalizef64 on a subnormal multiplies by 2^52 (f64 multiply inside a
|
||||
* tuple return) and returns exp -52; the result is no longer subnormal
|
||||
* and is nonzero. */
|
||||
{ "package main;\n"
|
||||
"import math;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let s: f64 = math.f64frombits(1u64);\n"
|
||||
" const r = math.normalizef64(s);\n"
|
||||
" if (r.1 != -52i64) { return 1; };\n"
|
||||
" const m: f64 = r.0;\n"
|
||||
" if (math.issubnormalf64(m)) { return 2; };\n"
|
||||
" if (m == 0.0) { return 3; };\n"
|
||||
" return 0;\n"
|
||||
"};\n", 0 },
|
||||
/* normalizef64 value propagation: normal-path .0 truncated to i32
|
||||
* (spilled to a let to dodge the tuple-field-compare mis-load; the
|
||||
* cast itself reads the field fine). */
|
||||
{ "package main;\n"
|
||||
"import math;\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" const r = math.normalizef64(42.0);\n"
|
||||
" const m: f64 = r.0;\n"
|
||||
" return m: i32;\n"
|
||||
"};\n", 42 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user