Commit 1472e41c by Richard Henderson Committed by Richard Henderson

builtin-types.def (BT_FN_FLOAT_CONST_STRING): New.

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.

From-SVN: r57221
parent f354b828
2002-09-16 Richard Henderson <rth@redhat.com>
* 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.
2002-09-16 Jason Merrill <jason@redhat.com>
Danny Smith <dannysmith@users.sourceforge.net>
......
......@@ -117,6 +117,10 @@ DEF_FUNCTION_TYPE_1 (BT_FN_INT_CONST_STRING, BT_INT, BT_CONST_STRING)
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,
......
......@@ -149,6 +149,7 @@ static rtx expand_builtin_expect PARAMS ((tree, rtx));
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. */
......@@ -4190,6 +4213,16 @@ fold_builtin (exp)
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;
}
......
......@@ -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,
......
......@@ -4863,6 +4863,44 @@ Similar to @code{__builtin_inf}, except the return
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
......
......@@ -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:
......
......@@ -143,7 +143,7 @@ extern void real_from_target PARAMS ((REAL_VALUE_TYPE *, const long *,
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));
......
2002-09-16 Richard Henderson <rth@redhat.com>
* 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.
2002-09-16 Phil Edwards <pme@gcc.gnu.org>
* testsuite/abi_check.cc: Pull shell fragments out into...
......
......@@ -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;
......
......@@ -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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment