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




Reply via email to