[libstdc++] NaNs via builtins

Richard Henderson rth@redhat.com
Mon Sep 16 18:32:00 GMT 2002


Implements __builtin_nan and friends.  I also added some test cases
for the other std::numeric_limits changes I'd been making.


r~


gcc/
        * builtin-types.def (BT_FN_FLOAT_CONST_STRING): New.
        (BT_FN_DOUBLE_CONST_STRING, BT_FN_LONG_DOUBLE_CONST_STRING): New.
        * builtins.def (__builtin_nan, __builtin_nanf, __builtin_nanl): New.
        (__builtin_nans, __builtin_nansf, __builtin_nansl): New.
        * builtins.c (fold_builtin_nan): New.
        (fold_builtin): Call it.
        * real.c (real_nan): Parse a non-empty string.
        (round_for_format): Fix NaN significand truncation.
        * real.h (real_nan): Return bool.
        * doc/extend.texi: Document new builtins.

libstdc++/
        * include/std/std_limits.h (__glibcpp_f32_QNaN_bytes,
        __glibcpp_f32_has_QNaN, __glibcpp_f32_SNaN_bytes,
        __glibcpp_f32_has_SNaN, __glibcpp_f64_QNaN_bytes,
        __glibcpp_f64_has_QNaN, __glibcpp_f64_SNaN_bytes,
        __glibcpp_f64_has_SNaN, __glibcpp_f80_QNaN_bytes,
        __glibcpp_f80_has_QNaN, __glibcpp_f80_SNaN_bytes,
        __glibcpp_f80_has_SNaN, __glibcpp_f96_QNaN_bytes,
        __glibcpp_f96_has_QNaN, __glibcpp_f96_SNaN_bytes,
        __glibcpp_f96_has_SNaN, __glibcpp_f128_QNaN_bytes,
        __glibcpp_f128_has_QNaN, __glibcpp_f128_SNaN_bytes,
        __glibcpp_f128_has_SNaN, __glibcpp_float_QNaN_bytes,
        __glibcpp_float_has_QNaN, __glibcpp_float_SNaN_bytes,
        __glibcpp_float_has_SNaN, __glibcpp_double_QNaN_bytes,
        __glibcpp_double_has_QNaN, __glibcpp_double_SNaN_bytes,
        __glibcpp_double_has_SNaN, __glibcpp_long_double_QNaN_bytes,
        __glibcpp_long_double_has_QNaN, __glibcpp_long_double_SNaN_bytes,
        __glibcpp_long_double_has_SNaN): Remove.
        (__glibcpp_f128_is_iec559): True if IEEE.
        (__glibcpp_float_QNaN, __glibcpp_float_SNaN): Remove.
        (__glibcpp_double_QNaN, __glibcpp_double_SNaN): Remove.
        (__glibcpp_long_double_QNaN, __glibcpp_long_double_SNaN): Remove.
        (std::numeric_limits<float>::has_quiet_NaN): Use __builtin_nanf.
        (std::numeric_limits<float>::has_signaling_NaN): Mirror has_quiet_NaN.
        (std::numeric_limits<float>::quiet_NaN): Use __builtin_nanf.
        (std::numeric_limits<float>::signaling_NaN): Use __builtin_nansf.
        (std::numeric_limits<double>): Similarly.
        (std::numeric_limits<long double>): Similarly.
        * src/limits.cc (__glibcpp_float_QNaN, __glibcpp_float_SNaN): Remove.
        (__glibcpp_double_QNaN, __glibcpp_double_SNaN): Remove.
        (__glibcpp_long_double_QNaN, __glibcpp_long_double_SNaN): Remove.

        * testsuite/18_support/numeric_limits.cc (test_infinity): New.
        (test_denorm_min, test_qnan, test_is_iec559): New.


Index: gcc/builtin-types.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtin-types.def,v
retrieving revision 1.8
diff -c -p -d -u -r1.8 builtin-types.def
--- gcc/builtin-types.def	4 Sep 2002 23:21:27 -0000	1.8
+++ gcc/builtin-types.def	17 Sep 2002 01:12:29 -0000
@@ -117,6 +117,10 @@ DEF_FUNCTION_TYPE_1 (BT_FN_INT_CONST_STR
 DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR)
 DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VALIST_REF, BT_VOID, BT_VALIST_REF)
 DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT_CONST_STRING, BT_FLOAT, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_DOUBLE_CONST_STRING, BT_DOUBLE, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_LONG_DOUBLE_CONST_STRING,
+		     BT_LONG_DOUBLE, BT_CONST_STRING)
 
 DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_INT, BT_VOID, BT_PTR, BT_INT)
 DEF_FUNCTION_TYPE_2 (BT_FN_STRING_STRING_CONST_STRING, 
Index: gcc/builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.162
diff -c -p -d -u -r1.162 builtins.c
--- gcc/builtins.c	16 Sep 2002 16:36:31 -0000	1.162
+++ gcc/builtins.c	17 Sep 2002 01:12:29 -0000
@@ -149,6 +149,7 @@ static rtx expand_builtin_expect	PARAMS 
 static tree fold_builtin_constant_p	PARAMS ((tree));
 static tree fold_builtin_classify_type	PARAMS ((tree));
 static tree fold_builtin_inf		PARAMS ((tree, int));
+static tree fold_builtin_nan		PARAMS ((tree, tree, int));
 static tree build_function_call_expr	PARAMS ((tree, tree));
 static int validate_arglist		PARAMS ((tree, ...));
 
@@ -4149,6 +4150,28 @@ fold_builtin_inf (type, warn)
   return build_real (type, real);
 }
 
+/* Fold a call to __builtin_nan or __builtin_nans.  */
+
+static tree
+fold_builtin_nan (arglist, type, quiet)
+     tree arglist, type;
+     int quiet;
+{
+  REAL_VALUE_TYPE real;
+  const char *str;
+
+  if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
+    return 0;
+  str = c_getstr (TREE_VALUE (arglist));
+  if (!str)
+    return 0;
+
+  if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
+    return 0;
+
+  return build_real (type, real);
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
@@ -4189,6 +4212,16 @@ fold_builtin (exp)
     case BUILT_IN_HUGE_VALF:
     case BUILT_IN_HUGE_VALL:
       return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), false);
+
+    case BUILT_IN_NAN:
+    case BUILT_IN_NANF:
+    case BUILT_IN_NANL:
+      return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), true);
+
+    case BUILT_IN_NANS:
+    case BUILT_IN_NANSF:
+    case BUILT_IN_NANSL:
+      return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), false);
 
     default:
       break;
Index: gcc/builtins.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.def,v
retrieving revision 1.36
diff -c -p -d -u -r1.36 builtins.def
--- gcc/builtins.def	8 Sep 2002 03:16:46 -0000	1.36
+++ gcc/builtins.def	17 Sep 2002 01:12:29 -0000
@@ -427,6 +427,32 @@ DEF_GCC_BUILTIN(BUILT_IN_HUGE_VALL,
 		BT_FN_LONG_DOUBLE,
 		ATTR_CONST_NOTHROW_LIST)
 
+DEF_LIB_BUILTIN(BUILT_IN_NAN,
+		"__builtin_nan",
+		BT_FN_DOUBLE_CONST_STRING,
+		ATTR_CONST_NOTHROW_LIST)
+DEF_LIB_BUILTIN(BUILT_IN_NANF,
+		"__builtin_nanf",
+		BT_FN_FLOAT_CONST_STRING,
+		ATTR_CONST_NOTHROW_LIST)
+DEF_LIB_BUILTIN(BUILT_IN_NANL,
+		"__builtin_nanl",
+		BT_FN_LONG_DOUBLE_CONST_STRING,
+		ATTR_CONST_NOTHROW_LIST)
+
+DEF_LIB_BUILTIN(BUILT_IN_NANS,
+		"__builtin_nans",
+		BT_FN_DOUBLE_CONST_STRING,
+		ATTR_CONST_NOTHROW_LIST)
+DEF_LIB_BUILTIN(BUILT_IN_NANSF,
+		"__builtin_nansf",
+		BT_FN_FLOAT_CONST_STRING,
+		ATTR_CONST_NOTHROW_LIST)
+DEF_LIB_BUILTIN(BUILT_IN_NANSL,
+		"__builtin_nansl",
+		BT_FN_LONG_DOUBLE_CONST_STRING,
+		ATTR_CONST_NOTHROW_LIST)
+
 DEF_GCC_BUILTIN(BUILT_IN_SAVEREGS,
 		"__builtin_saveregs",
 		BT_FN_PTR_VAR,
Index: gcc/real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.82
diff -c -p -d -u -r1.82 real.c
--- gcc/real.c	16 Sep 2002 16:36:33 -0000	1.82
+++ gcc/real.c	17 Sep 2002 01:12:29 -0000
@@ -1946,16 +1946,22 @@ real_inf (tr)
 
 /* Fills R with a NaN whose significand is described by STR.  If QUIET,
    we force a QNaN, else we force an SNaN.  The string, if not empty,
-   is parsed as a number and placed in the significand.  */
+   is parsed as a number and placed in the significand.  Return true
+   if the string was successfully parsed.  */
 
-void
+bool
 real_nan (tr, str, quiet, mode)
      REAL_VALUE_TYPE *tr;
      const char *str;
      int quiet;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
 {
   struct real_value *r = (struct real_value *) tr;
+  const struct real_format *fmt;
+
+  fmt = fmt_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    abort ();
 
   if (*str == 0)
     {
@@ -1965,8 +1971,89 @@ real_nan (tr, str, quiet, mode)
 	get_canonical_snan (r, 0);
     }
   else
-    /* FIXME */
-    abort ();
+    {
+      int base = 10, d;
+      bool neg = false;
+
+      memset (r, 0, sizeof (*r));
+      r->class = rvc_nan;
+
+      /* Parse akin to strtol into the significand of R.  */
+
+      while (ISSPACE (*str))
+	str++;
+      if (*str == '-')
+	str++, neg = true;
+      else if (*str == '+')
+	str++;
+      if (*str == '0')
+	{
+	  if (*++str == 'x')
+	    str++, base = 16;
+	  else
+	    base = 8;
+	}
+
+      while ((d = hex_value (*str)) < base)
+	{
+	  struct real_value u;
+
+	  switch (base)
+	    {
+	    case 8:
+	      lshift_significand (r, r, 3);
+	      break;
+	    case 16:
+	      lshift_significand (r, r, 4);
+	      break;
+	    case 10:
+	      lshift_significand_1 (&u, r);
+	      lshift_significand (r, r, 3);
+	      add_significands (r, r, &u);
+	      break;
+	    default:
+	      abort ();
+	    }
+
+	  get_zero (&u, 0);
+	  u.sig[0] = d;
+	  add_significands (r, r, &u);
+
+	  str++;
+	}
+
+      /* Must have consumed the entire string for success.  */
+      if (*str != 0)
+	return false;
+
+      /* Shift the significand into place such that the bits
+	 are in the most significant bits for the format.  */
+      lshift_significand (r, r, SIGNIFICAND_BITS - fmt->p);
+
+      /* Our MSB is always unset for NaNs.  */
+      r->sig[SIGSZ-1] &= ~SIG_MSB;
+
+      /* Force quiet or signalling NaN.  */
+      if (quiet)
+	r->sig[SIGSZ-1] |= SIG_MSB >> 1;
+      else
+	r->sig[SIGSZ-1] &= ~(SIG_MSB >> 1);
+
+      /* Force at least one bit of the significand set.  */
+      for (d = 0; d < SIGSZ; ++d)
+	if (r->sig[d])
+	  break;
+      if (d == SIGSZ)
+	r->sig[SIGSZ-1] |= SIG_MSB >> 2;
+
+      /* Our intermediate format forces QNaNs to have MSB-1 set.
+	 If the target format has QNaNs with the top bit unset,
+	 mirror the output routines and invert the top two bits.  */
+      if (!fmt->qnan_msb_set)
+	r->sig[SIGSZ-1] ^= (SIG_MSB >> 1) | (SIG_MSB >> 2);
+    }
+
+  return true;
 }
 
 /* Fills R with 2**N.  */
@@ -2023,7 +2110,7 @@ round_for_format (fmt, r)
       return;
 
     case rvc_nan:
-      clear_significand_below (r, np2 + 1);
+      clear_significand_below (r, np2);
 
       /* If we've cleared the entire significand, we need one bit
 	 set for this to continue to be a NaN.  */
@@ -2031,7 +2118,7 @@ round_for_format (fmt, r)
 	if (r->sig[i])
 	  break;
       if (i == SIGSZ)
-	r->sig[SIGSZ-1] = SIG_MSB >> 1;
+	r->sig[SIGSZ-1] = SIG_MSB >> 2;
       return;
 
     case rvc_normal:
Index: gcc/real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.47
diff -c -p -d -u -r1.47 real.h
--- gcc/real.h	16 Sep 2002 16:36:33 -0000	1.47
+++ gcc/real.h	17 Sep 2002 01:12:29 -0000
@@ -143,7 +143,7 @@ extern void real_from_target	PARAMS ((RE
 
 extern void real_inf		PARAMS ((REAL_VALUE_TYPE *));
 
-extern void real_nan		PARAMS ((REAL_VALUE_TYPE *, const char *,
+extern bool real_nan		PARAMS ((REAL_VALUE_TYPE *, const char *,
 					 int, enum machine_mode));
 
 extern void real_2expN		PARAMS ((REAL_VALUE_TYPE *, int));
Index: gcc/doc/extend.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v
retrieving revision 1.100
diff -c -p -d -u -r1.100 extend.texi
--- gcc/doc/extend.texi	15 Sep 2002 22:48:04 -0000	1.100
+++ gcc/doc/extend.texi	17 Sep 2002 01:12:31 -0000
@@ -4863,6 +4863,44 @@ Similar to @code{__builtin_inf}, except 
 type is @code{long double}.
 @end deftypefn
 
+@deftypefn {Built-in Function} double __builtin_nan (const char *str)
+This is an implementation of the ISO C99 function @code{nan}.
+
+Since ISO C99 defines this function in terms of @code{strtod}, which we
+do not implement, a desription of the parsing is in order.  The string
+is parsed as by @code{strtol}; that is, the base is recognized by
+leading @samp{0} or @samp{0x} prefixes.  The number parsed is placed
+in the significand such that the least significant bit of the number
+is at the least significant bit of the significand.  The number is 
+truncated to fit the significand field provided.  The significand is
+forced to be a quiet NaN.
+
+This function, if given a string literal, is evaluated early enough
+that it is considered a compile-time constant.
+@end deftypefn
+
+@deftypefn {Built-in Function} float __builtin_nanf (const char *str)
+Similar to @code{__builtin_nan}, except the return type is @code{float}.
+@end deftypefn
+
+@deftypefn {Built-in Function} long double __builtin_nanl (const char *str)
+Similar to @code{__builtin_nan}, except the return type is @code{long double}.
+@end deftypefn
+
+@deftypefn {Built-in Function} double __builtin_nans (const char *str)
+Similar to @code{__builtin_nan}, except the significand is forced 
+to be a signaling NaN.  The @code{nans} function is proposed by
+@uref{http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/n965.htm,,WG14 N956}.
+@end deftypefn
+
+@deftypefn {Built-in Function} float __builtin_nansf (const char *str)
+Similar to @code{__builtin_nans}, except the return type is @code{float}.
+@end deftypefn
+
+@deftypefn {Built-in Function} long double __builtin_nansl (const char *str)
+Similar to @code{__builtin_nans}, except the return type is @code{long double}.
+@end deftypefn
+
 @node Target Builtins
 @section Built-in Functions Specific to Particular Target Machines
 
Index: libstdc++-v3/include/std/std_limits.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/std/std_limits.h,v
retrieving revision 1.11
diff -c -p -d -u -r1.11 std_limits.h
--- libstdc++-v3/include/std/std_limits.h	16 Sep 2002 16:58:42 -0000	1.11
+++ libstdc++-v3/include/std/std_limits.h	17 Sep 2002 01:12:41 -0000
@@ -152,115 +152,32 @@
 
 #define __glibcpp_f32_round_error 1.0F
 #if __GCC_FLOAT_FORMAT__ == __IEEE_FORMAT__
-#  define __glibcpp_f32_QNaN_bytes { 0x7fc00000 }
-#  define __glibcpp_f32_has_QNaN true
-#  define __glibcpp_f32_SNaN_bytes { 0x7f800001 }
-#  define __glibcpp_f32_has_SNaN true
 #  define __glibcpp_f32_is_iec559  true
 #endif
-#ifndef __glibcpp_f32_QNaN_bytes
-#  define __glibcpp_f32_QNaN_bytes { }
-#  define __glibcpp_f32_has_QNaN false
-#endif
-#ifndef __glibcpp_f32_SNaN_bytes
-#  define __glibcpp_f32_SNaN_bytes { }
-#  define __glibcpp_f32_has_SNaN false
-#endif
 #ifndef __glibcpp_f32_is_iec559
 #  define __glibcpp_f32_is_iec559 false
 #endif 
 #define __glibcpp_f64_round_error 1.0
 #if __GCC_FLOAT_FORMAT__ == __IEEE_FORMAT__
-#  if __TARGET_FLOAT_WORDS_ORDER__ == __GCC_BIG_ENDIAN__
-#    define __glibcpp_f64_QNaN_bytes { 0x7ff80000, 0x0 }
-#    define __glibcpp_f64_SNaN_bytes { 0x7ff00000, 0x1 }
-#  else
-#    define __glibcpp_f64_QNaN_bytes { 0x0, 0x7ff80000 }
-#    define __glibcpp_f64_SNaN_bytes { 0x1, 0x7ff00000 }
-#  endif
-#  define __glibcpp_f64_has_QNaN true
-#  define __glibcpp_f64_has_SNaN true
 #  define __glibcpp_f64_is_iec559 true
 #endif
-#ifndef __glibcpp_f64_QNaN_bytes
-#  define __glibcpp_f64_QNaN_bytes { }
-#  define __glibcpp_f64_has_QNaN false
-#endif
-#ifndef __glibcpp_f64_SNaN_bytes
-#  define __glibcpp_f64_SNaN_bytes { }
-#  define __glibcpp_f64_has_SNaN false
-#endif
 #ifndef __glibcpp_f64_is_iec559
 #  define __glibcpp_f64_is_iec559 false
 #endif 
 #define __glibcpp_f80_round_error 1.0L
 #if __GCC_FLOAT_FORMAT__ == __IEEE_FORMAT__
-#  if __TARGET_BYTES_ORDER__ == __GCC_BIG_ENDIAN__
-#    define __glibcpp_f80_QNaN_bytes       \
-       { 0x7f, 0xff, 0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
-#    define __glibcpp_f80_SNaN_bytes       \
-       { 0x7f, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 }
-#  else
-#    define __glibcpp_f80_QNaN_bytes       \
-       { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC0, 0xff, 0x7f }
-#    define __glibcpp_f80_SNaN_bytes       \
-       { 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xff, 0x7f }
-#  endif
-#  define __glibcpp_f80_has_QNaN true
-#  define __glibcpp_f80_has_SNaN true
 #  define __glibcpp_f80_is_iec559 true
 #endif
-#ifndef __glibcpp_f80_QNaN_bytes
-#  define __glibcpp_f80_QNaN_bytes { }
-#  define __glibcpp_f80_has_QNaN false
-#endif
-#ifndef __glibcpp_f80_SNaN_bytes
-#  define __glibcpp_f80_SNaN_bytes { }
-#  define __glibcpp_f80_has_SNaN false
-#endif
 #ifndef __glibcpp_f80_is_iec559
 #  define __glibcpp_f80_is_iec559 false
 #endif 
 #define __glibcpp_f96_round_error 1.0L
 #if __GCC_FLOAT_FORMAT__ == __IEEE_FORMAT__
-#  if __TARGET_BYTES_ORDER__ == __GCC_BIG_ENDIAN__
-#    define __glibcpp_f96_QNaN_bytes { 0x7ff80000, 0x0, 0x0 }
-#    define __glibcpp_f96_SNaN_bytes { 0x7ff00000, 0x0, 0x1 }
-#  else
-#    define __glibcpp_f96_QNaN_bytes { 0x0, 0x0, 0x7ff80000 }
-#    define __glibcpp_f96_SNaN_bytes { 0x1, 0x0, 0x7ff00000 }
-#  endif
-#  define __glibcpp_f96_has_QNaN true
-#  define __glibcpp_f96_has_SNaN true
 #  define __glibcpp_f96_is_iec559 true
 #endif
-#ifndef __glibcpp_f96_QNaN_bytes
-#  define __glibcpp_f96_QNaN_bytes { }
-#  define __glibcpp_f96_has_QNaN false
-#endif
-#ifndef __glibcpp_f96_SNaN_bytes
-#  define __glibcpp_f96_SNaN_bytes { }
-#  define __glibcpp_f96_has_SNaN false
-#endif
 #define __glibcpp_f128_round_error 1.0L
 #if __GCC_FLOAT_FORMAT__ == __IEEE_FORMAT__
-#  if __TARGET_FLOAT_WORDS_ORDER__ == __GCC_BIG_ENDIAN__
-#    define __glibcpp_f128_QNaN_bytes { 0x7fff0800, 0x0, 0x0, 0x0 }
-#    define __glibcpp_f128_SNaN_bytes { 0x7fff0000, 0x0, 0x0, 0x1 }
-#  else
-#    define __glibcpp_f128_QNaN_bytes { 0x0, 0x0, 0x0, 0x7fff0800 }
-#    define __glibcpp_f128_SNaN_bytes { 0x1, 0x0, 0x0, 0x7fff0000 }
-#  endif
-#  define __glibcpp_f128_has_QNaN true
-#  define __glibcpp_f128_has_SNaN true
-#endif
-#ifndef __glibcpp_f128_QNaN_bytes
-#  define __glibcpp_f128_QNaN_bytes { }
-#  define __glibcpp_f128_has_QNaN false
-#endif
-#ifndef __glibcpp_f128_SNaN_bytes
-#  define __glibcpp_f128_SNaN_bytes { }
-#  define __glibcpp_f128_has_SNaN false
+#  define __glibcpp_f128_is_iec559 true
 #endif
 #ifndef __glibcpp_f128_is_iec559
 #  define __glibcpp_f128_is_iec559 false
@@ -587,24 +504,12 @@
 
 #if __FLOAT_BIT__ == 32
 #  define __glibcpp_float_round_error __glibcpp_f32_round_error
-#  define __glibcpp_float_QNaN_bytes  __glibcpp_f32_QNaN_bytes
-#  define __glibcpp_float_SNaN_bytes  __glibcpp_f32_SNaN_bytes
-#  define __glibcpp_float_has_QNaN __glibcpp_f32_has_QNaN
-#  define __glibcpp_float_has_SNaN __glibcpp_f32_has_SNaN
 #  define __glibcpp_float_is_iec559 __glibcpp_f32_is_iec559
 #elif __FLOAT_BIT__ == 64
 #  define __glibcpp_float_round_error __glibcpp_f64_round_error
-#  define __glibcpp_float_QNaN_bytes  __glibcpp_f64_QNaN_bytes
-#  define __glibcpp_float_SNaN_bytes  __glibcpp_f64_SNaN_bytes
-#  define __glibcpp_float_has_QNaN __glibcpp_f64_has_QNaN
-#  define __glibcpp_float_has_SNaN __glibcpp_f64_has_SNaN
 #  define __glibcpp_float_is_iec559 __glibcpp_f64_is_iec559
 #elif __FLOAT_BIT__ == 80
 #  define __glibcpp_float_round_error __glibcpp_f80_round_error
-#  define __glibcpp_float_QNaN_bytes  __glibcpp_f80_QNaN_bytes
-#  define __glibcpp_float_SNaN_bytes  __glibcpp_f80_SNaN_bytes
-#  define __glibcpp_float_has_QNaN __glibcpp_f80_has_QNaN
-#  define __glibcpp_float_has_SNaN __glibcpp_f80_has_SNaN
 #  define __glibcpp_float_is_iec559 __glibcpp_f80_is_iec559
 #else
 // You must define these macros in the configuration file.
@@ -612,16 +517,6 @@
 
 // Default values.  Should be overriden in configuration files if necessary.
 
-#ifndef __glibcpp_float_QNaN_bytes
-#  define __glibcpp_float_QNaN_bytes { }
-#  define __glibcpp_float_has_QNaN false
-#endif
-
-#ifndef __glibcpp_float_SNaN_bytes
-#  define __glibcpp_float_SNaN_bytes { }
-#  define __glibcpp_float_has_SNaN false
-#endif
-
 #ifndef __glibcpp_float_has_denorm_loss
 #  define __glibcpp_float_has_denorm_loss false
 #endif
@@ -654,24 +549,12 @@
 
 #if __DOUBLE_BIT__ == 32
 #  define __glibcpp_double_round_error __glibcpp_f32_round_error
-#  define __glibcpp_double_QNaN_bytes __glibcpp_f32_QNaN_bytes
-#  define __glibcpp_double_SNaN_bytes __glibcpp_f32_SNaN_bytes
-#  define __glibcpp_double_has_QNaN __glibcpp_f32_has_QNaN
-#  define __glibcpp_double_has_SNaN __glibcpp_f32_has_SNaN
 #  define __glibcpp_double_is_iec559 __glibcpp_f32_is_iec559
 #elif __DOUBLE_BIT__ == 64
 #  define __glibcpp_double_round_error __glibcpp_f64_round_error
-#  define __glibcpp_double_QNaN_bytes __glibcpp_f64_QNaN_bytes
-#  define __glibcpp_double_SNaN_bytes __glibcpp_f64_SNaN_bytes
-#  define __glibcpp_double_has_QNaN __glibcpp_f64_has_QNaN
-#  define __glibcpp_double_has_SNaN __glibcpp_f64_has_SNaN
 #  define __glibcpp_double_is_iec559 __glibcpp_f64_is_iec559
 #elif __DOUBLE_BIT__ == 80
 #  define __glibcpp_double_round_error __glibcpp_f80_round_error
-#  define __glibcpp_double_QNaN_bytes __glibcpp_f80_QNaN_bytes
-#  define __glibcpp_double_SNaN_bytes __glibcpp_f80_SNaN_bytes
-#  define __glibcpp_double_has_QNaN __glibcpp_f80_has_QNaN
-#  define __glibcpp_double_has_SNaN __glibcpp_f80_has_SNaN
 #  define __glibcpp_double_is_iec559 __glibcpp_f80_is_iec559
 #else
 // You must define these macros in the configuration file.
@@ -679,16 +562,6 @@
 
 // Default values.  Should be overriden in configuration files if necessary.
 
-#ifndef __glibcpp_double_QNaN_bytes
-#  define __glibcpp_double_QNaN_bytes { }
-#  define __glibcpp_double_has_QNaN false
-#endif
-
-#ifndef __glibcpp_double_SNaN_bytes
-#  define __glibcpp_double_SNaN_bytes { }
-#  define __glibcpp_double_has_SNaN false
-#endif
-
 #ifndef __glibcpp_double_has_denorm_loss
 #  define __glibcpp_double_has_denorm_loss false
 #endif
@@ -721,38 +594,18 @@
 
 #if __LONG_DOUBLE_BIT__ == 32
 #  define __glibcpp_long_double_round_error __glibcpp_f32_round_error
-#  define __glibcpp_long_double_QNaN_bytes __glibcpp_f32_QNaN_bytes
-#  define __glibcpp_long_double_SNaN_bytes __glibcpp_f32_SNaN_bytes
-#  define __glibcpp_long_double_has_QNaN __glibcpp_f32_has_QNaN
-#  define __glibcpp_long_double_has_SNaN __glibcpp_f32_has_SNaN
 #  define __glibcpp_long_double_is_iec559 __glibcpp_f32_is_iec559
 #elif __LONG_DOUBLE_BIT__ == 64
 #  define __glibcpp_long_double_round_error __glibcpp_f64_round_error
-#  define __glibcpp_long_double_QNaN_bytes __glibcpp_f64_QNaN_bytes
-#  define __glibcpp_long_double_SNaN_bytes __glibcpp_f64_SNaN_bytes
-#  define __glibcpp_long_double_has_QNaN __glibcpp_f64_has_QNaN
-#  define __glibcpp_long_double_has_SNaN __glibcpp_f64_has_SNaN
 #  define __glibcpp_long_double_is_iec559 __glibcpp_f64_is_iec559
 #elif __LONG_DOUBLE_BIT__ == 80
 #  define __glibcpp_long_double_round_error __glibcpp_f80_round_error
-#  define __glibcpp_long_double_QNaN_bytes __glibcpp_f80_QNaN_bytes
-#  define __glibcpp_long_double_SNaN_bytes __glibcpp_f80_SNaN_bytes
-#  define __glibcpp_long_double_has_QNaN __glibcpp_f80_has_QNaN
-#  define __glibcpp_long_double_has_SNaN __glibcpp_f80_has_SNaN
 #  define __glibcpp_long_double_is_iec559 __glibcpp_f80_is_iec559
 #elif __LONG_DOUBLE_BIT__ == 96
 #  define __glibcpp_long_double_round_error __glibcpp_f96_round_error
-#  define __glibcpp_long_double_QNaN_bytes __glibcpp_f96_QNaN_bytes
-#  define __glibcpp_long_double_SNaN_bytes __glibcpp_f96_SNaN_bytes
-#  define __glibcpp_long_double_has_QNaN __glibcpp_f96_has_QNaN
-#  define __glibcpp_long_double_has_SNaN __glibcpp_f96_has_SNaN
 #  define __glibcpp_long_double_is_iec559 __glibcpp_f96_is_iec559
 #elif __LONG_DOUBLE_BIT__ == 128
 #  define __glibcpp_long_double_round_error __glibcpp_f128_round_error
-#  define __glibcpp_long_double_QNaN_bytes __glibcpp_f128_QNaN_bytes
-#  define __glibcpp_long_double_SNaN_bytes __glibcpp_f128_SNaN_bytes
-#  define __glibcpp_long_double_has_QNaN __glibcpp_f128_has_QNaN
-#  define __glibcpp_long_double_has_SNaN __glibcpp_f128_has_SNaN
 #  define __glibcpp_long_double_is_iec559 __glibcpp_f128_is_iec559
 #else
 // You must define these macros in the configuration file.
@@ -760,16 +613,6 @@
 
 // Default values.  Should be overriden in configuration files if necessary.
 
-#ifndef __glibcpp_long_double_QNaN_bytes
-#  define __glibcpp_long_double_QNaN_bytes { }
-#  define __glibcpp_long_double_has_QNaN false
-#endif
-
-#ifndef __glibcpp_long_double_SNaN_bytes
-#  define __glibcpp_long_double_SNaN_bytes { }
-#  define __glibcpp_long_double_has_SNaN false
-#endif
-
 #ifndef __glibcpp_long_double_has_denorm_loss
 #  define __glibcpp_long_double_has_denorm_loss false
 #endif
@@ -843,15 +686,6 @@ namespace std
 #endif  
     __attribute__((__aligned__(__alignof__(long double))));
 
-  extern const __float_storage __glibcpp_float_QNaN;
-  extern const __float_storage __glibcpp_float_SNaN;
-  
-  extern const __double_storage __glibcpp_double_QNaN;
-  extern const __double_storage __glibcpp_double_SNaN;
-
-  extern const __long_double_storage __glibcpp_long_double_QNaN;
-  extern const __long_double_storage __glibcpp_long_double_SNaN;
-  
   enum float_round_style 
   {
     round_indeterminate       = -1,
@@ -1680,8 +1514,9 @@ namespace std
 
       static const bool has_infinity
 	= __builtin_huge_valf () / 2 == __builtin_huge_valf ();
-      static const bool has_quiet_NaN = __glibcpp_float_has_QNaN;
-      static const bool has_signaling_NaN = __glibcpp_float_has_SNaN;
+      static const bool has_quiet_NaN
+	= __builtin_nanf ("") != __builtin_nanf ("");
+      static const bool has_signaling_NaN = has_quiet_NaN;
       static const float_denorm_style has_denorm
 	= __FLT_DENORM_MIN__ ? denorm_present : denorm_absent;
       static const bool has_denorm_loss = __glibcpp_float_has_denorm_loss;
@@ -1689,9 +1524,9 @@ namespace std
       static float infinity() throw()
       { return __builtin_huge_valf (); }
       static float quiet_NaN() throw()
-      { return *reinterpret_cast<const float*>(__glibcpp_float_QNaN); }
+      { return __builtin_nanf (""); }
       static float signaling_NaN() throw()
-      { return *reinterpret_cast<const float*>(__glibcpp_float_SNaN); }
+      { return __builtin_nansf (""); }
       static float denorm_min() throw()
       { return __FLT_DENORM_MIN__; }
 
@@ -1705,8 +1540,6 @@ namespace std
     };
 
 #undef __glibcpp_float_round_error
-#undef __glibcpp_float_has_QNaN
-#undef __glibcpp_float_has_SNaN
 #undef __glibcpp_float_has_denorm_loss
 #undef __glibcpp_float_is_iec559
 #undef __glibcpp_float_is_bounded
@@ -1743,8 +1576,9 @@ namespace std
 
       static const bool has_infinity
 	= __builtin_huge_val () / 2 == __builtin_huge_val ();
-      static const bool has_quiet_NaN = __glibcpp_double_has_QNaN;
-      static const bool has_signaling_NaN = __glibcpp_double_has_SNaN;
+      static const bool has_quiet_NaN
+	= __builtin_nan ("") != __builtin_nan ("");
+      static const bool has_signaling_NaN = has_quiet_NaN;
       static const float_denorm_style has_denorm
 	= __DBL_DENORM_MIN__ ? denorm_present : denorm_absent;
       static const bool has_denorm_loss = __glibcpp_double_has_denorm_loss;
@@ -1752,9 +1586,9 @@ namespace std
       static double infinity() throw()
       { return __builtin_huge_val(); }
       static double quiet_NaN() throw()
-      { return *reinterpret_cast<const double*>(__glibcpp_double_QNaN); }
+      { return __builtin_nan (""); }
       static double signaling_NaN() throw()
-      { return *reinterpret_cast<const double*>(__glibcpp_double_SNaN); }
+      { return __builtin_nans (""); }
       static double denorm_min() throw()
       { return __DBL_DENORM_MIN__; }
 
@@ -1769,8 +1603,6 @@ namespace std
     };
 
 #undef __glibcpp_double_round_error
-#undef __glibcpp_double_has_QNaN
-#undef __glibcpp_double_has_SNaN
 #undef __glibcpp_double_has_denorm_loss
 #undef __glibcpp_double_is_iec559
 #undef __glibcpp_double_is_bounded
@@ -1808,8 +1640,9 @@ namespace std
 
       static const bool has_infinity
 	= __builtin_huge_vall () / 2 == __builtin_huge_vall ();
-      static const bool has_quiet_NaN = __glibcpp_long_double_has_SNaN;
-      static const bool has_signaling_NaN = __glibcpp_long_double_has_SNaN;
+      static const bool has_quiet_NaN
+	= __builtin_nanl ("") != __builtin_nanl ("");
+      static const bool has_signaling_NaN = has_quiet_NaN;
       static const float_denorm_style has_denorm
 	= __LDBL_DENORM_MIN__ ? denorm_present : denorm_absent;
       static const bool has_denorm_loss
@@ -1817,19 +1650,10 @@ namespace std
 
       static long double infinity() throw()
       { return __builtin_huge_vall (); } 
-
       static long double quiet_NaN() throw()
-      {
-        return *reinterpret_cast<const long double*>
-          (__glibcpp_long_double_QNaN);
-      }
-
+      { return __builtin_nanl (""); }
       static long double signaling_NaN() throw()
-      {
-        return *reinterpret_cast<const long double*>
-          (__glibcpp_long_double_SNaN);
-      }
-      
+      { return __builtin_nansl (""); }
       static long double denorm_min() throw()
       { return __LDBL_DENORM_MIN__; }
 
@@ -1844,8 +1668,6 @@ namespace std
     };
 
 #undef __glibcpp_long_double_round_error
-#undef __glibcpp_long_double_has_QNaN
-#undef __glibcpp_long_double_has_SNaN
 #undef __glibcpp_long_double_has_denorm_loss
 #undef __glibcpp_long_double_is_iec559
 #undef __glibcpp_long_double_is_bounded
Index: libstdc++-v3/src/limits.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/src/limits.cc,v
retrieving revision 1.8
diff -c -p -d -u -r1.8 limits.cc
--- libstdc++-v3/src/limits.cc	16 Sep 2002 16:58:42 -0000	1.8
+++ libstdc++-v3/src/limits.cc	17 Sep 2002 01:12:41 -0000
@@ -38,17 +38,6 @@
 
 namespace std 
 {
-  const __float_storage __glibcpp_float_QNaN = __glibcpp_float_QNaN_bytes;
-  const __float_storage __glibcpp_float_SNaN = __glibcpp_float_SNaN_bytes;
-
-  const __double_storage __glibcpp_double_QNaN = __glibcpp_double_QNaN_bytes;
-  const __double_storage __glibcpp_double_SNaN = __glibcpp_double_SNaN_bytes;
-
-  const __long_double_storage __glibcpp_long_double_QNaN =
-    __glibcpp_long_double_QNaN_bytes;
-  const __long_double_storage __glibcpp_long_double_SNaN =
-    __glibcpp_long_double_SNaN_bytes;
-
   const bool __numeric_limits_base::is_specialized;
   const int  __numeric_limits_base::digits;
   const int  __numeric_limits_base::digits10;
Index: libstdc++-v3/testsuite/18_support/numeric_limits.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/18_support/numeric_limits.cc,v
retrieving revision 1.12
diff -c -p -d -u -r1.12 numeric_limits.cc
--- libstdc++-v3/testsuite/18_support/numeric_limits.cc	29 Mar 2002 06:34:04 -0000	1.12
+++ libstdc++-v3/testsuite/18_support/numeric_limits.cc	17 Sep 2002 01:12:41 -0000
@@ -117,6 +117,83 @@ void test_sign()
 
 
 template<typename T>
+void
+test_infinity()
+{
+  bool test;
+
+  if (std::numeric_limits<T>::has_infinity)
+    {
+      T inf = std::numeric_limits<T>::infinity();
+      test = (inf + inf == inf);
+    }
+  else
+    test = true;
+
+  VERIFY (test);
+}
+
+template<typename T>
+void
+test_denorm_min()
+{
+  bool test;
+
+  if (std::numeric_limits<T>::has_denorm == std::denorm_present)
+    {
+      T denorm = std::numeric_limits<T>::denorm_min();
+      test = (denorm > 0);
+    }
+  else
+    test = true;
+
+  VERIFY (test);
+}
+
+template<typename T>
+void
+test_qnan()
+{
+  bool test;
+
+  if (std::numeric_limits<T>::has_quiet_NaN)
+    {
+      T nan = std::numeric_limits<T>::quiet_NaN();
+      test = (nan != nan);
+    }
+  else
+    test = true;
+
+  VERIFY (test);
+}
+
+
+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);
+    }
+  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);
+    }
+
+  VERIFY (test);
+}
+
+
+template<typename T>
   struct A 
   {
     int key;
@@ -237,5 +314,25 @@ int main()
 
   test_sign();
 
-    return 0;
+  test_infinity<float>();
+  test_infinity<double>();
+  test_infinity<long double>();
+
+  test_denorm_min<float>();
+  test_denorm_min<double>();
+  test_denorm_min<long double>();
+
+  test_qnan<float>();
+  test_qnan<double>();
+  test_qnan<long double>();
+
+  // ??? How to test SNaN?  We'd perhaps have to be prepared
+  // to catch SIGFPE.  Can't rely on a signal getting through
+  // since the exception can be disabled in the FPU.
+
+  test_is_iec559<float>();
+  test_is_iec559<double>();
+  test_is_iec559<long double>();
+
+  return 0;
 }



More information about the Libstdc++ mailing list