From cf2046ec7dd4b233180377cc5b8debcf551d1fc9 Mon Sep 17 00:00:00 2001 From: "Gabriel F. T. Gomes" Date: Thu, 3 Nov 2016 12:37:08 -0200 Subject: [PATCH] float128: Add strfromf128 Add strfromf128 to stdlib when _Float128 support is enabled. * 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: Include ieee754_float128.h and ldbl-128/printf_fphex_macros.h (__printf_fphex): Add code to deal with _Float128 numbers. * 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. --- ChangeLog | 24 ++++++++++ stdio-common/printf-parsemb.c | 1 + stdio-common/printf.h | 4 +- stdio-common/printf_fp.c | 62 ++++++++++++++++++++++++-- stdio-common/printf_fphex.c | 21 +++++++++ stdio-common/printf_size.c | 8 ++++ stdio-common/vfprintf.c | 10 ++++- stdlib/fpioconst.h | 4 ++ stdlib/stdlib.h | 9 ++++ stdlib/strfrom-skeleton.c | 6 +++ sysdeps/ieee754/float128/Makefile | 2 +- sysdeps/ieee754/float128/Versions | 5 +++ sysdeps/ieee754/float128/strfromf128.c | 25 +++++++++++ 13 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 sysdeps/ieee754/float128/strfromf128.c diff --git a/ChangeLog b/ChangeLog index 9d033b5aab..88483ae3aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2017-06-07 Gabriel F. T. Gomes + + * 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: Include ieee754_float128.h and + ldbl-128/printf_fphex_macros.h + (__printf_fphex): Add code to deal with _Float128 numbers. + * 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. + 2017-06-07 Gabriel F. T. Gomes * sysdeps/ieee754/ldbl-128/printf_fphex.c: Include 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 65ee9a7937..514b698d27 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; @@ -371,6 +382,11 @@ __printf_fp_l (FILE *fp, locale_t loc, } /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + PRINTF_FP_FETCH (_Float128, fpnum.f128, float128, FLT128_MANT_DIG) + else +#endif #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) PRINTF_FP_FETCH (long double, fpnum.ldbl, long_double, LDBL_MANT_DIG) @@ -414,7 +430,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); @@ -429,7 +446,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 = FLT128_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; @@ -463,6 +488,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) @@ -603,7 +649,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 = FLT128_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 7b469c047e..004d2aa716 100644 --- a/stdio-common/printf_fphex.c +++ b/stdio-common/printf_fphex.c @@ -31,6 +31,14 @@ #include #include +#if __HAVE_DISTINCT_FLOAT128 +# include "ieee754_float128.h" +# include +# define PRINT_FPHEX_FLOAT128 \ + PRINT_FPHEX (_Float128, fpnum.flt128, ieee854_float128, \ + IEEE854_FLOAT128_BIAS) +#endif + /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */ #include @@ -94,6 +102,9 @@ __printf_fphex (FILE *fp, { union ieee754_double dbl; long double ldbl; +#if __HAVE_DISTINCT_FLOAT128 + _Float128 flt128; +#endif } fpnum; @@ -195,6 +206,11 @@ __printf_fphex (FILE *fp, } /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + PRINTF_FPHEX_FETCH (_Float128, fpnum.flt128) + else +#endif #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) PRINTF_FPHEX_FETCH (long double, fpnum.ldbl) @@ -230,6 +246,11 @@ __printf_fphex (FILE *fp, return done; } +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + PRINT_FPHEX_FLOAT128; + else +#endif 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 bc953dc53c..e20b76cf91 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; @@ -144,6 +147,11 @@ __printf_size (FILE *fp, const struct printf_info *info, } /* Fetch the argument value. */ +#if __HAVE_DISTINCT_FLOAT128 + if (info->is_binary128) + PRINTF_SIZE_FETCH (_Float128, fpnum.f128) + else +#endif #ifndef __NO_LONG_DOUBLE_MATH if (info->is_long_double && sizeof (long double) > sizeof (double)) PRINTF_SIZE_FETCH (long double, fpnum.ldbl) 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 2559d7a74c..c05f8e7bac 100644 --- a/stdlib/fpioconst.h +++ b/stdlib/fpioconst.h @@ -44,6 +44,10 @@ IBM extended precision). */ #include +#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 428ca2ef68..0a693c2b41 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -51,6 +51,9 @@ __BEGIN_DECLS # endif #endif /* X/Open or XPG7 and not included. */ +/* _FloatN API tests for enablement. */ +#include + /* Returned by `div'. */ typedef struct { @@ -175,6 +178,12 @@ extern int strfroml (char *__dest, size_t __size, const char *__format, __THROW __nonnull ((3)); #endif +#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 + #ifdef __USE_GNU /* The concept of one static locale per category is not very well 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 + . */ + +#define FLOAT _Float128 +#define STRFROM strfromf128 + +#include +#include + +#include -- 2.43.5