]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
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>
Thu, 25 May 2017 19:14:46 +0000 (16:14 -0300)
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.

14 files changed:
NEWS
include/gmp.h
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]

diff --git a/NEWS b/NEWS
index b4ecd6201d57283d95b6c29a8ac5c78e85c39c61..8cb17cc1e6b6bbf843294ed098f75af55e7c103f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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,
index 95d6c16f14695e2f63e9ef80fce93f2e47b4e9b1..e6f635e8d5b4e47c9acd7ec7119eb1db7d2d9a18 100644 (file)
@@ -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,
index edb066edf698a6ee770926e89b3ee13f03d5cb9f..a42336c53872a2295ba2313a6cf8605637f5f8e1 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 5d82e8d01ef414b27b5c6435e883ef7861be7024..6b207d2db7072b107cad52917130e3fb86f920b9 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 7845d9635cea5bfbec8d8b820860274aaf7a70e3..42fe7d26a87e5417b6bd251d65f6c0f522c2e2ec 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;
 
@@ -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. */
index b207e007f84dfa90da64831039d54cea2e7b0541..d5573b1d98ed9c735ea2295ce820c4d220c639c0 100644 (file)
 #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
index 9403aea07c4faf0ca571b3a2b5b169714a96c232..3449d17221d5deadda9e723235190a3cc331933a 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;
@@ -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))
     {
index 2cf7c8aa0b078d5c1145324c09d8da8a356f6748..b8c87a539fe52ab1c6f872f754f8eb31d46c5acb 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 7e19b0d33e532546366591ccf2d8c16be6df09a3..aab46d68c17377ffb2b653c7fdc5ec0a436dfd59 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 99125f2d2396985a6cd00b75d6e77a3b98e00d0d..1313aa5eb586c1be6c33e3caf56af0cd70388283 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
   {
@@ -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
 
 
index 811a29c7d3ba96c829a340bc22194c102abb8876..5841919fe442ec1217ff1e54bbd80efc8522be95 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 6a7b0e0f45320d45f016f1952f59af549a6a5f84..c07586c1b6d2dcfd276871bdfd252067df3bbdc4 100644 (file)
@@ -1,3 +1,3 @@
 ifeq ($(subdir),stdlib)
-routines += float1282mpn
+routines += float1282mpn strfromf128
 endif
index 9f431d920efd8a4d0cd05cff84b8b36b4b4370c5..caf206475c17732c35aa9dc7202752ddc2cc3655 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>