While porting the fenv* modules to OpenBSD/mips64, I noticed some test failures in the 'nan' and 'snan' tests:
FAIL: test-nan-1 ================ ../../gltests/test-nan-1.c:65: assertion '!fetestexcept (FE_INVALID)' failed Abort trap (core dumped) FAIL test-nan-1 (exit status: 134) FAIL: test-nan-2 ================ Floating point exception (core dumped) FAIL test-nan-2 (exit status: 136) FAIL: test-snan-1 ================= ../../gltests/test-snan-1.c:75: assertion 'fetestexcept (FE_INVALID)' failed Abort trap (core dumped) FAIL test-snan-1 (exit status: 134) FAIL: test-snan-2.sh ==================== Use of SNaNf() did not signal. FAIL test-snan-2.sh (exit status: 1) So, we need to understand the quiet NaN vs. signalling NaN business on mips better. With the patch below, the configuration prints some insights: checking whether the NaN float encoding is IEEE 754-2008 compliant... no checking whether the NaN double encoding is IEEE 754-2008 compliant... no checking whether the NaN long double encoding is IEEE 754-2008 compliant... yes This is surprising, but the explanation is that the 'long double' operations are implemented by a software library, not by the hardware. 2023-11-06 Bruno Haible <br...@clisp.org> snan: Add more info for mips-based platforms. * m4/nan-mips.m4: New file. * lib/snan.h: Add comments regarding mips. * modules/snan (Files): Add m4/nan-mips.m4. (configure.ac): Invoke gl_NAN_MIPS. * m4/snan.m4: Update comment. diff --git a/lib/snan.h b/lib/snan.h index b89f13a8de..8b4de127c4 100644 --- a/lib/snan.h +++ b/lib/snan.h @@ -32,13 +32,27 @@ This bit is * == 0 to indicate a quiet NaN or Infinity, == 1 to indicate a signalling NaN, - on these CPUs: hppa, mips, sh4. + on these CPUs: hppa, mips (*), sh4. * == 1 to indicate a quiet NaN, == 0 to indicate a signalling NaN or Infinity, on all other CPUs. On these platforms, additionally a signalling NaN must have some other mantissa bit == 1, because when all exponent bits are == 1 and all - mantissa bits are == 0, the number denotes ±Infinity. */ + mantissa bits are == 0, the number denotes ±Infinity. + This NaN encoding is specified by IEEE 754-2008 § 6.2.1. + + (*) On mips CPUs, it depends on the CPU model. The classical behaviour is + as indicated above. On some newer models, it's like on the other CPUs. + On some (but not all!) models this meta-info can be determined from two + special CPU registers: If the "Floating Point Implementation Register" (fir) + bit 23, also known as Has2008 bit, is set, the "Floating Point Control and + Status Register" (fcsr) bit 18, also known as the NAN2008 bit, has the value + - 0 for the classical behaviour, + - 1 for like on the other CPUs. + Both of these bits are read-only. + This module has determined the behaviour at configure time and defines the + C macros MIPS_NAN2008_FLOAT, MIPS_NAN2008_DOUBLE, MIPS_NAN2008_LONG_DOUBLE + accordingly. */ /* 'float' = IEEE 754 single-precision diff --git a/m4/nan-mips.m4 b/m4/nan-mips.m4 new file mode 100644 index 0000000000..5a40f189fa --- /dev/null +++ b/m4/nan-mips.m4 @@ -0,0 +1,89 @@ +# nan-mips.m4 serial 1 +dnl Copyright (C) 2023 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Extra meta-info mentioned by lib/snan.h. +AC_DEFUN_ONCE([gl_NAN_MIPS], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_cpu" in + mips*) + AC_CACHE_CHECK([whether the NaN float encoding is IEEE 754-2008 compliant], + [gl_cv_nan2008_f], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ + float volatile zero; + /* Assume 'float' has 32 bits, i.e. IEEE single-float. */ + union { float value; unsigned int word; } qnan; + ]], + [[qnan.value = zero / zero; + return !((qnan.word >> 22) & 1); + ]]) + ], + [gl_cv_nan2008_f=yes], + [gl_cv_nan2008_f=no], + [gl_cv_nan2008_f="guessing no"]) + ]) + case "$gl_cv_nan2008_f" in + *yes) gl_mips_nan2008_f=1 ;; + *) gl_mips_nan2008_f=0 ;; + esac + AC_DEFINE_UNQUOTED([MIPS_NAN2008_FLOAT], [$gl_mips_nan2008_f], + [Define to 1 if the encoding of NaN 'float's is as in IEEE 754-2008 § 6.2.1.]) + + AC_CACHE_CHECK([whether the NaN double encoding is IEEE 754-2008 compliant], + [gl_cv_nan2008_d], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ + double volatile zero; + /* Assume 'double' has 64 bits, i.e. IEEE double-float. */ + union { double value; unsigned long long word; } qnan; + ]], + [[qnan.value = zero / zero; + return !((qnan.word >> 51) & 1); + ]]) + ], + [gl_cv_nan2008_d=yes], + [gl_cv_nan2008_d=no], + [gl_cv_nan2008_d="guessing no"]) + ]) + case "$gl_cv_nan2008_d" in + *yes) gl_mips_nan2008_d=1 ;; + *) gl_mips_nan2008_d=0 ;; + esac + AC_DEFINE_UNQUOTED([MIPS_NAN2008_DOUBLE], [$gl_mips_nan2008_d], + [Define to 1 if the encoding of NaN 'double's is as in IEEE 754-2008 § 6.2.1.]) + + AC_CACHE_CHECK([whether the NaN long double encoding is IEEE 754-2008 compliant], + [gl_cv_nan2008_l], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ + #include <float.h> + long double volatile zero; + #define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + union { long double value; unsigned int word[NWORDS]; } qnan; + ]], + [[qnan.value = zero / zero; + #if defined _MIPSEB /* equivalent: __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */ + return !((qnan.word[0] >> ((LDBL_MANT_DIG - 2) % 32)) & 1); + #else + return !((qnan.word[NWORDS - 1] >> ((LDBL_MANT_DIG - 2) % 32)) & 1); + #endif + ]]) + ], + [gl_cv_nan2008_l=yes], + [gl_cv_nan2008_l=no], + [gl_cv_nan2008_l="guessing no"]) + ]) + case "$gl_cv_nan2008_l" in + *yes) gl_mips_nan2008_l=1 ;; + *) gl_mips_nan2008_l=0 ;; + esac + AC_DEFINE_UNQUOTED([MIPS_NAN2008_LONG_DOUBLE], [$gl_mips_nan2008_l], + [Define to 1 if the encoding of NaN 'long double's is as in IEEE 754-2008 § 6.2.1.]) + ;; + esac +]) diff --git a/m4/snan.m4 b/m4/snan.m4 index 2b072dcb26..21dfb9921b 100644 --- a/m4/snan.m4 +++ b/m4/snan.m4 @@ -1,10 +1,10 @@ -# snan.m4 serial 2 +# snan.m4 serial 3 dnl Copyright (C) 2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. -# Prerequisites for tests/snan.h. +# Prerequisites for lib/snan.h. AC_DEFUN_ONCE([gl_SNAN], [ gl_FLOAT_EXPONENT_LOCATION diff --git a/modules/snan b/modules/snan index 26988bec33..ed2f3f3219 100644 --- a/modules/snan +++ b/modules/snan @@ -8,12 +8,14 @@ m4/exponentf.m4 m4/exponentd.m4 m4/exponentl.m4 m4/math_h.m4 +m4/nan-mips.m4 Depends-on: nan configure.ac: gl_SNAN +gl_NAN_MIPS Makefile.am: lib_SOURCES += snan.h