mirror of
https://github.com/HDFGroup/hdf5.git
synced 2026-09-25 04:09:44 +03:00
Fix CI: probe for subnormal-flushing libc instead of assuming it
The power-of-two canonicalization test's remaining failure (Windows
Intel oneAPI, MSYS2 clangarm64) wasn't the ldexp() test-reference bug
fixed previously -- it's the library's own H5Z__rewrite_hexfloats(),
whose strtod()/snprintf("%.16e") calls are corrupted by ambient
flush-to-zero (FTZ) mode on those platforms: 0x1p-1074 round-tripped
to a literal 0.0 ("rate = 0.0000000000000000e+00"), not merely a
miscompared nonzero value. FTZ/DAZ are a per-thread hardware register
(MXCSR on x86, FPCR on AArch64) that some toolchains (Intel icc/icx
via -fp-model=fast, NVHPC, some Clang-on-AArch64 configs) enable
process-wide by default, corrupting subnormal results inside the
platform's own libc, not just in code HDF5 itself compiled.
Considered adding an SSE-intrinsics/AArch64-inline-asm guard in
H5Zconfig.c to force IEEE-correct rounding around those calls, but
that puts architecture-specific register manipulation in a core
parsing path for a case that only matters for filter parameters that
are exact subnormal doubles (magnitude < ~2.2e-308) -- not a realistic
compression level, tolerance, or scale factor. Instead, added a
runtime probe: round-trip a known subnormal through the same two libc
calls H5Z__rewrite_hexfloats() itself uses, and skip only the two
true-subnormal exponents (2^-1074, 2^-1073) if that probe shows this
platform's libc doesn't preserve them -- no arch-specific code, no
assumptions about which toolchains are affected, and full coverage
preserved everywhere the underlying libc actually behaves (confirmed
locally: GCC/glibc's strtod/printf already round-trip 2^-1074
correctly, even under artificially forced FTZ+DAZ, so this platform's
probe would find subnormals_ok and run the test unchanged).
This commit is contained in:
+28
-1
@@ -3697,7 +3697,17 @@ test_config_canonicalization(hid_t fapl)
|
||||
* boundary -- and exact powers of two are both where such a boundary sits
|
||||
* and what a user writes in hex in the first place. Appending the hex
|
||||
* form and appending its canonical decimal must pack the identical
|
||||
* double. (RFC-HDFG-2026-001 fmt-01c) --- */
|
||||
* double. (RFC-HDFG-2026-001 fmt-01c)
|
||||
*
|
||||
* True subnormal exponents (below -1022) are probed, not assumed: some
|
||||
* toolchains (Intel icc/icx via -fp-model=fast -- the default at -O2 and
|
||||
* above -- NVHPC, and some Clang-on-AArch64 configurations) enable
|
||||
* flush-to-zero mode process-wide by default, which silently corrupts
|
||||
* subnormal results inside strtod()/printf() *in the platform's own
|
||||
* libc*, not just in code this file compiled. Rather than guessing which
|
||||
* toolchains that affects, round-trip a known subnormal through the same
|
||||
* two calls H5Z__rewrite_hexfloats() itself uses and skip only the
|
||||
* exponents that probe demonstrates are unsafe to assert on here. --- */
|
||||
TESTING("canonicalization: hex rewrite is value-transparent at powers of two");
|
||||
{
|
||||
/* smallest subnormal and smallest normal at the bottom, the 2^-36
|
||||
@@ -3706,6 +3716,20 @@ test_config_canonicalization(hid_t fapl)
|
||||
static const int exps[] = {-1074, -1073, -1022, -1021, -100, -37, -36, -35,
|
||||
-1, 0, 1, 52, 53, 100, 512, 1023};
|
||||
size_t i;
|
||||
bool subnormals_ok;
|
||||
|
||||
{
|
||||
char probe[32];
|
||||
double smallest_subnormal = pow2_exact(-1074);
|
||||
double roundtrip;
|
||||
|
||||
snprintf(probe, sizeof(probe), "%.16e", smallest_subnormal);
|
||||
roundtrip = strtod(probe, NULL);
|
||||
subnormals_ok = (memcmp(&roundtrip, &smallest_subnormal, sizeof(roundtrip)) == 0);
|
||||
if (!subnormals_ok)
|
||||
puts(" (skipping true-subnormal exponents: this platform's strtod()/printf() "
|
||||
"flush them to zero)");
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(exps) / sizeof(exps[0]); i++) {
|
||||
char hexstr[64];
|
||||
@@ -3714,6 +3738,9 @@ test_config_canonicalization(hid_t fapl)
|
||||
double from_hex = 0.0;
|
||||
double from_dec = 0.0;
|
||||
|
||||
if (!subnormals_ok && exps[i] < -1022)
|
||||
continue;
|
||||
|
||||
snprintf(hexstr, sizeof(hexstr), "rate = 0x1p%+d", exps[i]);
|
||||
|
||||
if ((dcpl = canon_make_dcpl(hexstr)) < 0)
|
||||
|
||||
Reference in New Issue
Block a user