summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog24
-rw-r--r--stdio-common/printf-parsemb.c1
-rw-r--r--stdio-common/printf.h4
-rw-r--r--stdio-common/printf_fp.c62
-rw-r--r--stdio-common/printf_fphex.c21
-rw-r--r--stdio-common/printf_size.c8
-rw-r--r--stdio-common/vfprintf.c10
-rw-r--r--stdlib/fpioconst.h4
-rw-r--r--stdlib/stdlib.h9
-rw-r--r--stdlib/strfrom-skeleton.c6
-rw-r--r--sysdeps/ieee754/float128/Makefile2
-rw-r--r--sysdeps/ieee754/float128/Versions5
-rw-r--r--sysdeps/ieee754/float128/strfromf128.c25
13 files changed, 173 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 9d033b5aab..88483ae3aa 100644
--- 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.
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 <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
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 <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 428ca2ef68..0a693c2b41 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
   {
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#define	FLOAT		_Float128
+#define STRFROM		strfromf128
+
+#include <bits/floatn.h>
+#include <float128_private.h>
+
+#include <stdlib/strfrom-skeleton.c>