diff options
author | Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com> | 2016-11-03 12:37:08 -0200 |
---|---|---|
committer | Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com> | 2017-05-25 16:14:46 -0300 |
commit | b2da97305ccbfbbe16778ba3b6acb59268ab625c (patch) | |
tree | 569aed42477c529fe8741d06ffacf33603f06a1c | |
parent | fb91e22c252dbefd1b141fdf151903cf5aea7727 (diff) | |
download | glibc-b2da97305ccbfbbe16778ba3b6acb59268ab625c.tar glibc-b2da97305ccbfbbe16778ba3b6acb59268ab625c.tar.gz glibc-b2da97305ccbfbbe16778ba3b6acb59268ab625c.tar.bz2 glibc-b2da97305ccbfbbe16778ba3b6acb59268ab625c.zip |
float128: Add strfromf128
Add strfromf128 to stdlib when _Float128 support is enabled.
2016-11-07 Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com>
* NEWS: Mention the addition of strfromf128.
* include/gmp.h: Include bits/floatn.h for _Float128 support.
* stdio-common/printf-parsemb.c (__parse_one_specmb): Initialize
spec->info.is_binary128 to zero.
* stdio-common/printf.h (printf_info): Add new member is_binary128
to indicate that the number being converted to string is compatible
with the IEC 60559 binary128 format.
* stdio-common/printf_fp.c (__printf_fp_l): Add code to deal with
_Float128 numbers.
* stdio-common/printf_fphex.c (__printf_fphex): Likewise.
* stdio-common/printf_size.c (__printf_size): Likewise.
* stdio-common/vfprintf.c (process_arg): Initialize member
info.is_binary128 to zero.
* stdlib/fpioconst.h (FLT128_MAX_10_EXP_LOG): New macro.
* stdlib/stdlib.h: Include bits/floatn.h for _Float128 support.
(strfromf128): New declaration.
* stdlib/strfrom-skeleton.c (STRFROM): Set member info.is_binary128
to one.
* sysdeps/ieee754/float128/Makefile: Add strfromf128.
* sysdeps/ieee754/float128/Versions: Likewise.
* sysdeps/ieee754/float128/strfromf128.c: New file.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | include/gmp.h | 2 | ||||
-rw-r--r-- | stdio-common/printf-parsemb.c | 1 | ||||
-rw-r--r-- | stdio-common/printf.h | 4 | ||||
-rw-r--r-- | stdio-common/printf_fp.c | 103 | ||||
-rw-r--r-- | stdio-common/printf_fphex.c | 134 | ||||
-rw-r--r-- | stdio-common/printf_size.c | 29 | ||||
-rw-r--r-- | stdio-common/vfprintf.c | 10 | ||||
-rw-r--r-- | stdlib/fpioconst.h | 4 | ||||
-rw-r--r-- | stdlib/stdlib.h | 8 | ||||
-rw-r--r-- | stdlib/strfrom-skeleton.c | 6 | ||||
-rw-r--r-- | sysdeps/ieee754/float128/Makefile | 2 | ||||
-rw-r--r-- | sysdeps/ieee754/float128/Versions | 5 | ||||
-rw-r--r-- | sysdeps/ieee754/float128/strfromf128.c | 25 |
14 files changed, 328 insertions, 8 deletions
@@ -66,6 +66,9 @@ Version 2.26 * The port to Native Client running on ARMv7-A (--host=arm-nacl) has been removed. +* The function strfromf128, from ISO/IEC TS 18661-3:2015, is added to libc. + It converts a _Float128 value into string. + Security related changes: * The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes, diff --git a/include/gmp.h b/include/gmp.h index 95d6c16f14..e6f635e8d5 100644 --- a/include/gmp.h +++ b/include/gmp.h @@ -6,6 +6,8 @@ #include <stdlib/gmp.h> +#include <bits/floatn.h> + /* Now define the internal interfaces. */ extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size, int *expt, int *is_neg, diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c index edb066edf6..a42336c538 100644 --- a/stdio-common/printf-parsemb.c +++ b/stdio-common/printf-parsemb.c @@ -79,6 +79,7 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn, spec->info.extra = 0; spec->info.pad = ' '; spec->info.wide = sizeof (UCHAR_T) > 1; + spec->info.is_binary128 = 0; /* Test for positional argument. */ if (ISDIGIT (*format)) diff --git a/stdio-common/printf.h b/stdio-common/printf.h index 5d82e8d01e..6b207d2db7 100644 --- a/stdio-common/printf.h +++ b/stdio-common/printf.h @@ -47,7 +47,9 @@ struct printf_info unsigned int is_char:1; /* hh flag. */ unsigned int wide:1; /* Nonzero for wide character streams. */ unsigned int i18n:1; /* I flag. */ - unsigned int __pad:4; /* Unused so far. */ + unsigned int is_binary128:1; /* Floating-point argument is ABI-compatible + with IEC 60559 binary128. */ + unsigned int __pad:3; /* Unused so far. */ unsigned short int user; /* Bits for user-installed modifiers. */ wchar_t pad; /* Padding character. */ }; diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c index 7845d9635c..42fe7d26a8 100644 --- a/stdio-common/printf_fp.c +++ b/stdio-common/printf_fp.c @@ -218,6 +218,9 @@ __printf_fp_l (FILE *fp, locale_t loc, { double dbl; __long_double_t ldbl; +#if __HAVE_DISTINCT_FLOAT128 + _Float128 f128; +#endif } fpnum; @@ -234,9 +237,17 @@ __printf_fp_l (FILE *fp, locale_t loc, const char *special = NULL; const wchar_t *wspecial = NULL; + /* When _Float128 is enabled in the library and ABI-distinct from long + double, we need mp_limbs enough for any of them. */ +#if __HAVE_DISTINCT_FLOAT128 +# define GREATER_MANT_DIG FLT128_MANT_DIG +#else +# define GREATER_MANT_DIG LDBL_MANT_DIG +#endif /* We need just a few limbs for the input before shifting to the right position. */ - mp_limb_t fp_input[(LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB]; + mp_limb_t fp_input[(GREATER_MANT_DIG + BITS_PER_MP_LIMB - 1) + / BITS_PER_MP_LIMB]; /* We need to shift the contents of fp_input by this amount of bits. */ int to_shift = 0; @@ -328,6 +339,52 @@ __printf_fp_l (FILE *fp, locale_t loc, grouping = NULL; /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + { + fpnum.f128 = *(const _Float128 *) args[0]; + + /* Check for special values: not a number or infinity. */ + if (isnan (fpnum.f128)) + { + is_neg = signbit (fpnum.f128); + if (isupper (info->spec)) + { + special = "NAN"; + wspecial = L"NAN"; + } + else + { + special = "nan"; + wspecial = L"nan"; + } + } + else if (isinf (fpnum.f128)) + { + is_neg = signbit (fpnum.f128); + if (isupper (info->spec)) + { + special = "INF"; + wspecial = L"INF"; + } + else + { + special = "inf"; + wspecial = L"inf"; + } + } + else + { + p.fracsize = __mpn_extract_float128 (fp_input, + (sizeof (fp_input) / + sizeof (fp_input[0])), + &p.exponent, &is_neg, + fpnum.f128); + to_shift = 1 + p.fracsize * BITS_PER_MP_LIMB - FLT128_MANT_DIG; + } + } + else +#endif /* __HAVE_DISTINCT_FLOAT128 */ #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) { @@ -450,7 +507,8 @@ __printf_fp_l (FILE *fp, locale_t loc, { mp_size_t bignum_size = ((abs (p.exponent) + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB - + (LDBL_MANT_DIG / BITS_PER_MP_LIMB > 2 ? 8 : 4)) + + (GREATER_MANT_DIG / BITS_PER_MP_LIMB > 2 + ? 8 : 4)) * sizeof (mp_limb_t); p.frac = (mp_limb_t *) alloca (bignum_size); p.tmp = (mp_limb_t *) alloca (bignum_size); @@ -465,7 +523,15 @@ __printf_fp_l (FILE *fp, locale_t loc, { /* |FP| >= 8.0. */ int scaleexpo = 0; - int explog = LDBL_MAX_10_EXP_LOG; + int explog; +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + explog = FLT_MAX_10_EXP_LOG; + else + explog = LDBL_MAX_10_EXP_LOG; +#else + explog = LDBL_MAX_10_EXP_LOG; +#endif int exp10 = 0; const struct mp_power *powers = &_fpioconst_pow10[explog + 1]; int cnt_h, cnt_l, i; @@ -499,6 +565,27 @@ __printf_fp_l (FILE *fp, locale_t loc, { if (p.scalesize == 0) { +#if __HAVE_DISTINCT_FLOAT128 + if ((FLT128_MANT_DIG + > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB) + && info->is_binary128) + { +#define _FLT128_FPIO_CONST_SHIFT \ + (((FLT128_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) \ + - _FPIO_CONST_OFFSET) + /* 64bit const offset is not enough for + IEEE 854 quad long double (_Float128). */ + p.tmpsize = powers->arraysize + _FLT128_FPIO_CONST_SHIFT; + memcpy (p.tmp + _FLT128_FPIO_CONST_SHIFT, + &__tens[powers->arrayoff], + p.tmpsize * sizeof (mp_limb_t)); + MPN_ZERO (p.tmp, _FLT128_FPIO_CONST_SHIFT); + /* Adjust p.exponent, as scaleexpo will be this much + bigger too. */ + p.exponent += _FLT128_FPIO_CONST_SHIFT * BITS_PER_MP_LIMB; + } + else +#endif /* __HAVE_DISTINCT_FLOAT128 */ #ifndef __NO_LONG_DOUBLE_MATH if (LDBL_MANT_DIG > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB && info->is_long_double) @@ -639,7 +726,15 @@ __printf_fp_l (FILE *fp, locale_t loc, { /* |FP| < 1.0. */ int exp10 = 0; - int explog = LDBL_MAX_10_EXP_LOG; + int explog; +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + explog = FLT_MAX_10_EXP_LOG; + else + explog = LDBL_MAX_10_EXP_LOG; +#else + explog = LDBL_MAX_10_EXP_LOG; +#endif const struct mp_power *powers = &_fpioconst_pow10[explog + 1]; /* Now shift the input value to its right place. */ diff --git a/stdio-common/printf_fphex.c b/stdio-common/printf_fphex.c index b207e007f8..d5573b1d98 100644 --- a/stdio-common/printf_fphex.c +++ b/stdio-common/printf_fphex.c @@ -31,6 +31,10 @@ #include <stdbool.h> #include <rounding-mode.h> +#if __HAVE_DISTINCT_FLOAT128 +# include "ieee754_float128.h" +#endif + /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */ #include <assert.h> @@ -94,6 +98,9 @@ __printf_fphex (FILE *fp, { union ieee754_double dbl; long double ldbl; +#if __HAVE_DISTINCT_FLOAT128 + _Float128 flt128; +#endif } fpnum; @@ -159,6 +166,45 @@ __printf_fphex (FILE *fp, /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + { + fpnum.flt128 = *(const _Float128 *) args[0]; + + /* Check for special values: not a number or infinity. */ + if (isnan (fpnum.flt128)) + { + if (isupper (info->spec)) + { + special = "NAN"; + wspecial = L"NAN"; + } + else + { + special = "nan"; + wspecial = L"nan"; + } + } + else + { + if (isinf (fpnum.flt128)) + { + if (isupper (info->spec)) + { + special = "INF"; + wspecial = L"INF"; + } + else + { + special = "inf"; + wspecial = L"inf"; + } + } + } + negative = signbit (fpnum.flt128); + } + else +#endif /* __HAVE_DISTINCT_FLOAT128 */ #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) { @@ -260,6 +306,94 @@ __printf_fphex (FILE *fp, return done; } +#if __HAVE_DISTINCT_FLOAT128 + /* This block is copied from sysdeps/ieee754/ldbl-128/printf_fphex.c. */ + if (info->is_binary128) + { + /* We have 112 bits of mantissa plus one implicit digit. Since + 112 bits are representable without rest using hexadecimal + digits we use only the implicit digits for the number before + the decimal point. */ + unsigned long long int num0, num1; + union ieee854_float128 u; + u.d = fpnum.flt128; + + num0 = (((unsigned long long int) u.ieee.mantissa0) << 32 + | u.ieee.mantissa1); + num1 = (((unsigned long long int) u.ieee.mantissa2) << 32 + | u.ieee.mantissa3); + + zero_mantissa = (num0|num1) == 0; + + if (sizeof (unsigned long int) > 6) + { + numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, + info->spec == 'A'); + wnumstr = _itowa_word (num1, + wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), + 16, info->spec == 'A'); + } + else + { + numstr = _itoa (num1, numbuf + sizeof numbuf, 16, + info->spec == 'A'); + wnumstr = _itowa (num1, + wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), + 16, info->spec == 'A'); + } + + while (numstr > numbuf + (sizeof numbuf - 64 / 4)) + { + *--numstr = '0'; + *--wnumstr = L'0'; + } + + if (sizeof (unsigned long int) > 6) + { + numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); + wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A'); + } + else + { + numstr = _itoa (num0, numstr, 16, info->spec == 'A'); + wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A'); + } + + /* Fill with zeroes. */ + while (numstr > numbuf + (sizeof numbuf - 112 / 4)) + { + *--numstr = '0'; + *--wnumstr = L'0'; + } + + leading = u.ieee.exponent == 0 ? '0' : '1'; + + exponent = u.ieee.exponent; + + if (exponent == 0) + { + if (zero_mantissa) + expnegative = 0; + else + { + /* This is a denormalized number. */ + expnegative = 1; + exponent = IEEE854_FLOAT128_BIAS - 1; + } + } + else if (exponent >= IEEE854_FLOAT128_BIAS) + { + expnegative = 0; + exponent -= IEEE854_FLOAT128_BIAS; + } + else + { + expnegative = 1; + exponent = -(exponent - IEEE854_FLOAT128_BIAS); + } + } + else +#endif /* __HAVE_DISTINCT_FLOAT128 */ if (info->is_long_double == 0 || sizeof (double) == sizeof (long double)) { /* We have 52 bits of mantissa plus one implicit digit. Since diff --git a/stdio-common/printf_size.c b/stdio-common/printf_size.c index 9403aea07c..3449d17221 100644 --- a/stdio-common/printf_size.c +++ b/stdio-common/printf_size.c @@ -104,6 +104,9 @@ __printf_size (FILE *fp, const struct printf_info *info, { union ieee754_double dbl; long double ldbl; +#if __HAVE_DISTINCT_FLOAT128 + _Float128 f128; +#endif } fpnum; const void *ptr = &fpnum; @@ -119,6 +122,32 @@ __printf_size (FILE *fp, const struct printf_info *info, int wide = info->wide; /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + { + fpnum.f128 = *(const _Float128 *) args[0]; + + /* Check for special values: not a number or infinity. */ + if (isnan (fpnum.f128)) + { + special = "nan"; + wspecial = L"nan"; + } + else if (isinf (fpnum.f128)) + { + is_neg = signbit (fpnum.f128); + special = "inf"; + wspecial = L"inf"; + } + else + while (fpnum.f128 >= divisor && tag[1] != '\0') + { + fpnum.f128 /= divisor; + ++tag; + } + } + else +#endif /* __HAVE_DISTINCT_FLOAT128 */ #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) { diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 2cf7c8aa0b..b8c87a539f 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -770,7 +770,8 @@ static const uint8_t jump_table[] = .pad = pad, \ .extra = 0, \ .i18n = use_outdigits, \ - .wide = sizeof (CHAR_T) != 1 }; \ + .wide = sizeof (CHAR_T) != 1, \ + .is_binary128 = 0}; \ \ if (is_long_double) \ the_arg.pa_long_double = va_arg (ap, long double); \ @@ -788,6 +789,8 @@ static const uint8_t jump_table[] = fspec->data_arg_type = PA_DOUBLE; \ fspec->info.is_long_double = 0; \ } \ + /* Not supported by *printf functions. */ \ + fspec->info.is_binary128 = 0; \ \ function_done = __printf_fp (s, &fspec->info, &ptr); \ } \ @@ -827,7 +830,8 @@ static const uint8_t jump_table[] = .group = group, \ .pad = pad, \ .extra = 0, \ - .wide = sizeof (CHAR_T) != 1 }; \ + .wide = sizeof (CHAR_T) != 1, \ + .is_binary128 = 0}; \ \ if (is_long_double) \ the_arg.pa_long_double = va_arg (ap, long double); \ @@ -842,6 +846,8 @@ static const uint8_t jump_table[] = ptr = (const void *) &args_value[fspec->data_arg]; \ if (__ldbl_is_dbl) \ fspec->info.is_long_double = 0; \ + /* Not supported by *printf functions. */ \ + fspec->info.is_binary128 = 0; \ \ function_done = __printf_fphex (s, &fspec->info, &ptr); \ } \ diff --git a/stdlib/fpioconst.h b/stdlib/fpioconst.h index 7e19b0d33e..aab46d68c1 100644 --- a/stdlib/fpioconst.h +++ b/stdlib/fpioconst.h @@ -44,6 +44,10 @@ IBM extended precision). */ #include <bits/floatn.h> +#if __HAVE_DISTINCT_FLOAT128 +# define FLT128_MAX_10_EXP_LOG 12 /* = floor(log_2(FLT128_MAX_10_EXP)) */ +#endif + /* For strtold, we need powers of 10 up to floor (log_2 (LDBL_MANT_DIG - LDBL_MIN_EXP + 2)). When _Float128 is enabled in libm and it is ABI-distinct from long double (e.g. on powerpc64le), we also need powers diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h index 99125f2d23..1313aa5eb5 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -51,6 +51,9 @@ __BEGIN_DECLS # endif #endif /* X/Open or XPG7 and <sys/wait.h> not included. */ +/* _FloatN API tests for enablement. */ +#include <bits/floatn.h> + /* Returned by `div'. */ typedef struct { @@ -173,6 +176,11 @@ extern int strfromf (char *__dest, size_t __size, const char *__format, extern int strfroml (char *__dest, size_t __size, const char *__format, long double __f) __THROW __nonnull ((3)); +# if __HAVE_FLOAT128 && __GLIBC_USE (IEC_60559_TYPES_EXT) +extern int strfromf128 (char *__dest, size_t __size, const char * __format, + _Float128 __f) + __THROW __nonnull ((3)); +# endif #endif diff --git a/stdlib/strfrom-skeleton.c b/stdlib/strfrom-skeleton.c index 811a29c7d3..5841919fe4 100644 --- a/stdlib/strfrom-skeleton.c +++ b/stdlib/strfrom-skeleton.c @@ -132,6 +132,12 @@ STRFROM (char *dest, size_t size, const char *format, FLOAT f) which type of floating-point number is being passed. */ info.is_long_double = __builtin_types_compatible_p (FLOAT, long double); + /* Similarly, the function strfromf128 passes a floating-point number in + _Float128 format to printf_fp. */ +#if __HAVE_DISTINCT_FLOAT128 + info.is_binary128 = __builtin_types_compatible_p (FLOAT, _Float128); +#endif + /* Set info according to the format string. */ info.prec = precision; info.spec = specifier; diff --git a/sysdeps/ieee754/float128/Makefile b/sysdeps/ieee754/float128/Makefile index 6a7b0e0f45..c07586c1b6 100644 --- a/sysdeps/ieee754/float128/Makefile +++ b/sysdeps/ieee754/float128/Makefile @@ -1,3 +1,3 @@ ifeq ($(subdir),stdlib) -routines += float1282mpn +routines += float1282mpn strfromf128 endif diff --git a/sysdeps/ieee754/float128/Versions b/sysdeps/ieee754/float128/Versions index 9f431d920e..caf206475c 100644 --- a/sysdeps/ieee754/float128/Versions +++ b/sysdeps/ieee754/float128/Versions @@ -2,6 +2,11 @@ %ifndef FLOAT128_VERSION % error "float128-abi.h must define FLOAT128_VERSION" %endif +libc { + FLOAT128_VERSION { + strfromf128; + } +} libm { FLOAT128_VERSION { __acosf128_finite; diff --git a/sysdeps/ieee754/float128/strfromf128.c b/sysdeps/ieee754/float128/strfromf128.c new file mode 100644 index 0000000000..597c7e62f9 --- /dev/null +++ b/sysdeps/ieee754/float128/strfromf128.c @@ -0,0 +1,25 @@ +/* Definitions for strfromf128. Implementation in stdlib/strfrom-skeleton.c. + + Copyright (C) 2017 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define FLOAT _Float128 +#define STRFROM strfromf128 + +#include <bits/floatn.h> +#include <float128_private.h> + +#include <stdlib/strfrom-skeleton.c> |