float128: Add strfromf128
authorGabriel F. T. Gomes <gftg@linux.vnet.ibm.com>
Thu, 3 Nov 2016 14:37:08 +0000 (12:37 -0200)
committerGabriel F. T. Gomes <gftg@linux.vnet.ibm.com>
Wed, 7 Jun 2017 20:08:21 +0000 (17:08 -0300)
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.

13 files changed:
ChangeLog
stdio-common/printf-parsemb.c
stdio-common/printf.h
stdio-common/printf_fp.c
stdio-common/printf_fphex.c
stdio-common/printf_size.c
stdio-common/vfprintf.c
stdlib/fpioconst.h
stdlib/stdlib.h
stdlib/strfrom-skeleton.c
sysdeps/ieee754/float128/Makefile
sysdeps/ieee754/float128/Versions
sysdeps/ieee754/float128/strfromf128.c [new file with mode: 0644]

index 9d033b5..88483ae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
 2017-06-07  Gabriel F. T. Gomes  <gftg@linux.vnet.ibm.com>
 
+       * 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  <gftg@linux.vnet.ibm.com>
+
        * sysdeps/ieee754/ldbl-128/printf_fphex.c: Include
        ldbl-128/printf_fphex_macros.h for the definition of PRINT_FPHEX.
        (PRINT_FPHEX_LONG_DOUBLE): Define based on PRINT_FPHEX.
index edb066e..a42336c 100644 (file)
@@ -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))
index 5d82e8d..6b207d2 100644 (file)
@@ -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.  */
 };
index 65ee9a7..514b698 100644 (file)
@@ -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. */
index 7b469c0..004d2aa 100644 (file)
 #include <stdbool.h>
 #include <rounding-mode.h>
 
+#if __HAVE_DISTINCT_FLOAT128
+# include "ieee754_float128.h"
+# include <ldbl-128/printf_fphex_macros.h>
+# define PRINT_FPHEX_FLOAT128 \
+   PRINT_FPHEX (_Float128, fpnum.flt128, ieee854_float128, \
+               IEEE854_FLOAT128_BIAS)
+#endif
+
 /* #define NDEBUG 1*/          /* Undefine this for debugging assertions.  */
 #include <assert.h>
 
@@ -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
index bc953dc..e20b76c 100644 (file)
@@ -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)
index 2cf7c8a..b8c87a5 100644 (file)
@@ -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);           \
          }                                                                   \
index 2559d7a..c05f8e7 100644 (file)
    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
index 428ca2e..0a693c2 100644 (file)
@@ -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
   {
@@ -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
index 811a29c..5841919 100644 (file)
@@ -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;
index 6a7b0e0..c07586c 100644 (file)
@@ -1,3 +1,3 @@
 ifeq ($(subdir),stdlib)
-routines += float1282mpn
+routines += float1282mpn strfromf128
 endif
index 9f431d9..caf2064 100644 (file)
@@ -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 (file)
index 0000000..597c7e6
--- /dev/null
@@ -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>