summaryrefslogtreecommitdiff
path: root/gcc/real.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2002-09-17 01:28:50 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2002-09-17 01:28:50 +0000
commitb0db7939a3a9dbe5cdc3f21b65c7727a0a723fe0 (patch)
tree13b37fe93a02d7ab652503bcdc4b3b55cdb5e3d6 /gcc/real.c
parent7c4f0b1d149a7f54e531cc148616dd6838816eb2 (diff)
downloadgcc-b0db7939a3a9dbe5cdc3f21b65c7727a0a723fe0.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@57221 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/real.c')
-rw-r--r--gcc/real.c101
1 files changed, 94 insertions, 7 deletions
diff --git a/gcc/real.c b/gcc/real.c
index 61ab02ce6a9..5859f0ff878 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -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: