On 27/04/20 17:09 +0200, Matthias Kretz wrote:

From: Matthias Kretz <kr...@kde.org>

       PR libstdc++/84949
       * include/std/limits: Let is_iec559 reflect whether
       __GCC_IEC_559 says float and double support IEEE 754-2008.
       * testsuite/18_support/numeric_limits/is_iec559.cc: Test IEC559
       mandated behavior if is_iec559 is true.
       * testsuite/18_support/numeric_limits/infinity.cc: Only test inf
       behavior if is_iec559 is true, otherwise there is no guarantee
       how arithmetic on inf behaves.
       * testsuite/18_support/numeric_limits/quiet_NaN.cc: ditto for
       NaN.
       * testsuite/18_support/numeric_limits/denorm_min-1.cc: Compile
       with -ffast-math.
       * testsuite/18_support/numeric_limits/epsilon-1.cc: ditto.
       * testsuite/18_support/numeric_limits/infinity-1.cc: ditto.
       * testsuite/18_support/numeric_limits/is_iec559-1.cc: ditto.
       * testsuite/18_support/numeric_limits/quiet_NaN-1.cc: ditto.

I'm inclined to go ahead and commit this (to master only, obviously).
It certainly seems more correct to me, and we'll probably never find
out if it's "safe" to do unless we actually change it and see what
happens.

Marc, do you have an opinion?

---
libstdc++-v3/include/std/limits               |  9 ++--
.../18_support/numeric_limits/denorm_min-1.cc |  2 +
.../18_support/numeric_limits/epsilon-1.cc    |  2 +
.../18_support/numeric_limits/infinity-1.cc   |  2 +
.../18_support/numeric_limits/infinity.cc     |  4 +-
.../18_support/numeric_limits/is_iec559-1.cc  |  2 +
.../18_support/numeric_limits/is_iec559.cc    | 44 ++++++++++++++-----
.../18_support/numeric_limits/quiet_NaN-1.cc  |  2 +
.../18_support/numeric_limits/quiet_NaN.cc    |  5 ++-
9 files changed, 51 insertions(+), 21 deletions(-)
create mode 100644 libstdc++-v3/testsuite/18_support/numeric_limits/
denorm_min-1.cc
create mode 100644 libstdc++-v3/testsuite/18_support/numeric_limits/
epsilon-1.cc
create mode 100644 libstdc++-v3/testsuite/18_support/numeric_limits/
infinity-1.cc
create mode 100644 libstdc++-v3/testsuite/18_support/numeric_limits/
is_iec559-1.cc
create mode 100644 libstdc++-v3/testsuite/18_support/numeric_limits/
quiet_NaN-1.cc


diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits
index 898406f91ee..c27350c9ec4 100644
--- a/libstdc++-v3/include/std/limits
+++ b/libstdc++-v3/include/std/limits
@@ -1714,8 +1714,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      static _GLIBCXX_CONSTEXPR float
      denorm_min() _GLIBCXX_USE_NOEXCEPT { return __FLT_DENORM_MIN__; }

-      static _GLIBCXX_USE_CONSTEXPR bool is_iec559
-       = has_infinity && has_quiet_NaN && has_denorm == denorm_present;
+      static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = __GCC_IEC_559 >= 2;
      static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
      static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false;

@@ -1789,8 +1788,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      static _GLIBCXX_CONSTEXPR double
      denorm_min() _GLIBCXX_USE_NOEXCEPT { return __DBL_DENORM_MIN__; }

-      static _GLIBCXX_USE_CONSTEXPR bool is_iec559
-       = has_infinity && has_quiet_NaN && has_denorm == denorm_present;
+      static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = __GCC_IEC_559 >= 2;
      static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
      static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false;

@@ -1864,8 +1862,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      static _GLIBCXX_CONSTEXPR long double
      denorm_min() _GLIBCXX_USE_NOEXCEPT { return __LDBL_DENORM_MIN__; }

-      static _GLIBCXX_USE_CONSTEXPR bool is_iec559
-       = has_infinity && has_quiet_NaN && has_denorm == denorm_present;
+      static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = __GCC_IEC_559 >= 2;
      static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
      static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false;

diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/denorm_min-1.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/denorm_min-1.cc
new file mode 100644
index 00000000000..8ff2950d77e
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/denorm_min-1.cc
@@ -0,0 +1,2 @@
+// { dg-options "-ffast-math" }
+#include "denorm_min.cc"
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/epsilon-1.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/epsilon-1.cc
new file mode 100644
index 00000000000..34548976bea
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/epsilon-1.cc
@@ -0,0 +1,2 @@
+// { dg-options "-ffast-math" }
+#include "epsilon.cc"
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/infinity-1.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/infinity-1.cc
new file mode 100644
index 00000000000..7ff8ea81242
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/infinity-1.cc
@@ -0,0 +1,2 @@
+// { dg-options "-ffast-math" }
+#include "infinity.cc"
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/infinity.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/infinity.cc
index 3a5bce57c35..9585ab38216 100644
--- a/libstdc++-v3/testsuite/18_support/numeric_limits/infinity.cc
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/infinity.cc
@@ -33,10 +33,10 @@ test_infinity()
{
  bool test;

-  if (std::numeric_limits<T>::has_infinity)
+  if (std::numeric_limits<T>::has_infinity && 
std::numeric_limits<T>::is_iec559)
    {
      T inf = std::numeric_limits<T>::infinity();
-      test = (inf + inf == inf);
+      test  = (inf + inf == inf);
    }
  else
    test = true;
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559-1.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559-1.cc
new file mode 100644
index 00000000000..91dd8163126
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559-1.cc
@@ -0,0 +1,2 @@
+// { dg-options "-ffast-math" }
+#include "is_iec559.cc"
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559.cc
index d15ae5cae14..c71da192d1d 100644
--- a/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559.cc
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/is_iec559.cc
@@ -27,28 +27,50 @@
#include <cwchar>
#include <testsuite_hooks.h>

+// make these values "invisible" to the optimizer so that we really test the 
FPU
+template <typename T>
+T min = std::numeric_limits<T>::min();
+template <typename T>
+T denorm_min = std::numeric_limits<T>::denorm_min();
+template <typename T>
+T inf = std::numeric_limits<T>::infinity();
+template <typename T>
+T max = std::numeric_limits<T>::max();
+template <typename T>
+T qnan = std::numeric_limits<T>::quiet_NaN();
+
template<typename T>
void
test_is_iec559()
{
-  bool test;
-
  if (std::numeric_limits<T>::is_iec559)
    {
      // IEC 559 requires all of the following.
-      test = (std::numeric_limits<T>::has_infinity
-             && std::numeric_limits<T>::has_quiet_NaN
-             && std::numeric_limits<T>::has_signaling_NaN);
+      VERIFY(std::numeric_limits<T>::has_infinity &&
+            std::numeric_limits<T>::has_quiet_NaN &&
+            std::numeric_limits<T>::has_signaling_NaN);
+
+      // Test a few random IEC559 features
+      VERIFY(min<T> / 2 > T());         // min/2 is denormal, but not 0
+      VERIFY(denorm_min<T> / 3 == T()); // calculation with denormals works
+      T x = denorm_min<T>;
+      for (int i = 1; i < std::numeric_limits<T>::digits; ++i)
+       x *= 2;
+      VERIFY(x == min<T>);
+      VERIFY(inf<T> * 2 == inf<T>); // infinity saturates
+      VERIFY(max<T> * 2 == inf<T>); // max*2 saturates to infinity
+      T inf0 = inf<T> * T();        // NaN
+      VERIFY(inf0 != inf<T>);
+      VERIFY(inf0 != 0);
+      VERIFY((inf0 == inf0) == false);
+      VERIFY(qnan<T> != qnan<T>);
    }
  else
    {
-      // If we had all of the following, why didn't we set IEC 559?
-      test = (!std::numeric_limits<T>::has_infinity
-             || !std::numeric_limits<T>::has_quiet_NaN
-             || !std::numeric_limits<T>::has_signaling_NaN);
+      // We could have representations for inf, NaN, and SNaN and still not be
+      // IEC559 compliant. At this point, the meaning of operations on NaNs and
+      // infinities is unspecified.
    }
-
-  VERIFY (test);
}

// libstdc++/8949
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN-1.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN-1.cc
new file mode 100644
index 00000000000..45bef204a65
--- /dev/null
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN-1.cc
@@ -0,0 +1,2 @@
+// { dg-options "-ffast-math" }
+#include "quiet_NaN.cc"
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN.cc 
b/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN.cc
index 97406aed2b3..b17df1cc3d7 100644
--- a/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN.cc
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/quiet_NaN.cc
@@ -33,10 +33,11 @@ test_qnan()
{
  bool test;

-  if (std::numeric_limits<T>::has_quiet_NaN)
+  if (std::numeric_limits<T>::has_quiet_NaN &&
+      std::numeric_limits<T>::is_iec559)
    {
      T nan = std::numeric_limits<T>::quiet_NaN();
-      test = (nan != nan);
+      test  = (nan != nan);
    }
  else
    test = true;

Reply via email to