PATCH: Add __float128 I/O support

H. J. Lu hjl@lucon.org
Thu May 6 19:36:00 GMT 2004


__float128 is added to gcc 3.4.0. This patch adds the __float128 I/0
support to glibc with a new length modifier "lL" for fprintf and a new
conversion flag "lL" for fscanf. I tested it on ia64 and x86_64 with
gcc 3.4.0. I also tested it on ia32, ia64 and x86_64 with gcc 3.2.
Everything looks OK.


H.J.
-------------- next part --------------
2004-05-06  H.J. Lu  <hongjiu.lu@intel.com>

	* config.h.in: Add HAVE_FLOAT128.

	* configure.in: Test __float128. Add sysdeps/ieee754/quad to
	directory list and set HAVE_FLOAT128 if __float128 is supported.
	* configure: Regenerated.

	* include/gmp.h (__mpn_extract_float128): Add if HAVE_FLOAT128
	is defined.
	(__mpn_construct_float128): Likewise.
	* include/math.h (__isinfq): Likewise.
	* include/math.h (__isnanq): Likewise.
	* include/math.h (__signbitq): Likewise.
	* include/stdlib.h (__strtoqd_internal): Likewise.
	* include/stdlib.h (strtoqd): Likewise.
	* include/stdlib.h (strtoqd_l): Likewise.
	* include/stdlib.h (__strtoqd_l): Likewise.
	* include/stdlib.h (__strtoqd_internal): Likewise.
	* include/stdlib.h (____strtoqd_l_internal): Likewise.
	* include/wchar.h (wcstoqd): Likewise.
	* include/wchar.h (__wcstoqd_internal): Likewise.
	* include/wchar.h (wcstoqd_l): Likewise.
	* include/wchar.h (__wcstoqd_l): Likewise.
	* include/wchar.h (____wcstoqd_l_internal): Likewise.

	* include/printf.h: Include next <printf.h> instead of
	<stdio-common/printf.h>.

	* math/math_private.h: Include <math_quad.h> if HAVE_FLOAT128
	is defined.

	* stdio-common/printf-parse.h (printf_arg): Add pa_float128
	if HAVE_FLOAT128 is defined.

	* stdio-common/printf-parsemb.c (__parse_one_specmb): Support
	__float128 if HAVE_FLOAT128 is defined.
	* stdio-common/printf_fp.c (__printf_fp): Likewise.
	* stdio-common/printf_size.c (printf_size): Likewise.
	* stdio-common/printf_size.c (printf_size_info): Likewise.
	* stdio-common/vfprintf.c (vfprintf): Likewise.
	* stdio-common/vfscanf.c (_IO_vfscanf): Likewise.
	* stdlib/strfmon_l.c (__vstrfmon_l): Likewise.
	* sysdeps/generic/printf_fphex.c (__printf_fphex): Likewise.

	* stdio-common/printf_size.c: Include <ieee754-quad.h> if
	HAVE_FLOAT128 is defined.
	* stdio-common/vfscanf.c: Likewise.
	* sysdeps/generic/printf_fphex.c: Likewise.

	* stdio-common/printf_fp.c (__mpn_extract_double): Removed.
	(__mpn_extract_long_double): Likewise.

	* stdio-common/printf.h: Moved to ...
	* sysdeps/generic/printf.h: Here.

	* sysdeps/ieee754/quad/Makefile: New file.
	* sysdeps/ieee754/quad/bits/huge_valq.h: Likewise.
	* sysdeps/ieee754/quad/float.h: Likewise.
	* sysdeps/ieee754/quad/ieee754-quad.h: Likewise.
	* sysdeps/ieee754/quad/math_quad.h: Likewise.
	* sysdeps/ieee754/quad/mpn2quad.c: Likewise.
	* sysdeps/ieee754/quad/printf.h: Likewise.
	* sysdeps/ieee754/quad/printf_quadfphex.h: Likewise.
	* sysdeps/ieee754/quad/quad2mpn.c: Likewise.
	* sysdeps/ieee754/quad/s_isinfq.c: Likewise.
	* sysdeps/ieee754/quad/s_isnanq.c: Likewise.
	* sysdeps/ieee754/quad/s_signbitq.c: Likewise.
	* sysdeps/ieee754/quad/strtoqd.c: Likewise.
	* sysdeps/ieee754/quad/strtoqd_l.c: Likewise.
	* sysdeps/ieee754/quad/wcstoqd.c: Likewise.
	* sysdeps/ieee754/quad/wcstoqd_l.c: Likewise.

--- libc/config.h.in.float128	2004-05-05 14:48:53.000000000 -0700
+++ libc/config.h.in	2004-05-05 14:48:54.000000000 -0700
@@ -211,6 +211,9 @@
 /* Defined of libidn is available.  */
 #undef HAVE_LIBIDN
 
+/* Defined of __float128 is supported.  */
+#undef HAVE_FLOAT128 
+
 /*
  */
 
--- libc/configure.in.float128	2004-05-05 14:48:53.000000000 -0700
+++ libc/configure.in	2004-05-05 14:48:54.000000000 -0700
@@ -448,6 +448,20 @@ if test "$base_machine" = "i386"; then
   AC_DEFINE(USE_REGPARMS)
 fi
 
+# We need to deal with __float here to include sysdeps/ieee754/quad
+# if __float128 is supported.
+AC_CACHE_CHECK(__float128 is supported,
+	       libc_cv_float128,
+	       [cat > conftest.c <<EOF
+	        __float128 x = 1;
+EOF
+		libc_cv_float128=no
+		if AC_TRY_COMMAND(${CC-cc} -Werror -S conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then
+		  libc_cv_float128=yes
+		fi
+		rm -f conftest.[cs]
+	       ])
+
 # Compute the list of sysdep directories for this configuration.
 # This can take a while to compute.
 sysdep_dir=$srcdir/sysdeps
@@ -585,10 +599,23 @@ fi
 # from each element's parent name and Implies file (if present).
 set $sysnames
 names=
+have_float128=no
 while test $# -gt 0; do
   name=$1
   shift
 
+  if test $libc_cv_float128 = yes; then
+    if test "$name" = "sysdeps/ieee754/ldbl-96"; then
+      case " $names " in *" sysdeps/ieee754/quad "*)
+	# Already in the list.
+	continue
+      esac
+      echo $ECHO_N "sysdeps/ieee754/quad $ECHO_C" >&AS_MESSAGE_FD
+      names="$names sysdeps/ieee754/quad"
+      have_float128=yes
+    fi
+  fi
+
   case " $names " in *" $name "*)
     # Already in the list.
     continue
@@ -667,6 +694,9 @@ AC_SUBST(sysnames)
 # The other names were emitted during the scan.
 AC_MSG_RESULT($default_sysnames)
 
+if test $have_float128 = yes; then
+  AC_DEFINE(HAVE_FLOAT128)
+fi
 
 ### Locate tools.
 
--- libc/include/gmp.h.float128	2003-03-19 08:15:40.000000000 -0800
+++ libc/include/gmp.h	2004-05-05 14:48:54.000000000 -0700
@@ -23,5 +23,13 @@ extern double __mpn_construct_double (mp
 extern long double __mpn_construct_long_double (mp_srcptr frac_ptr, int expt,
 						int sign);
 
+#ifdef HAVE_FLOAT128
+extern mp_size_t __mpn_extract_float128 (mp_ptr res_ptr, mp_size_t size,
+					 int *expt, int *is_neg,
+					 __float128 value);
+
+extern __float128 __mpn_construct_float128 (mp_srcptr frac_ptr,
+					       int expt, int negative); 
+#endif
 
 #endif
--- libc/include/math.h.float128	2002-09-09 17:41:44.000000000 -0700
+++ libc/include/math.h	2004-05-05 14:48:54.000000000 -0700
@@ -28,4 +28,13 @@ libm_hidden_proto (__fpclassifyl)
 libm_hidden_proto (__expm1l)
 # endif
 
+# ifdef HAVE_FLOAT128
+extern int __isinfq (__float128);
+extern int __isnanq (__float128);
+extern int __signbitq (__float128);
+
+hidden_proto (__isinfq)
+hidden_proto (__isnanq)
+# endif
+
 #endif
--- libc/include/printf.h.float128	2002-08-02 23:15:15.000000000 -0700
+++ libc/include/printf.h	2004-05-06 11:54:43.000000000 -0700
@@ -1,6 +1,6 @@
 #ifndef	_PRINTF_H
 
-#include <stdio-common/printf.h>
+#include_next <printf.h>
 
 /* Now define the internal interfaces.  */
 extern int __printf_fphex (FILE *, const struct printf_info *,
--- libc/include/stdlib.h.float128	2004-02-06 12:36:00.000000000 -0800
+++ libc/include/stdlib.h	2004-05-05 14:48:54.000000000 -0700
@@ -194,6 +194,37 @@ __strtoull_l (__const char * __restrict 
 # define __cxa_atexit(func, arg, d) INTUSE(__cxa_atexit) (func, arg, d)
 # endif
 
+#ifdef HAVE_FLOAT128
+extern __float128 __strtoqd_internal (__const char *__restrict __nptr,
+					 char **__restrict __endptr,
+					 int __group) __THROW;
+
+extern __float128 strtoqd (__const char *__restrict __nptr,
+			      char **__restrict __endptr) __THROW;
+
+extern __float128 strtoqd_l (__const char *__restrict __nptr,
+				char **__restrict __endptr,
+				__locale_t __loc) __THROW;
+
+extern __typeof (strtoqd_l) __strtoqd_l;
+
+libc_hidden_proto (__strtoqd_internal)
+
+extern __float128 ____strtoqd_l_internal (__const char *__restrict __nptr,
+					     char **__restrict __endptr,
+					     int __group, __locale_t __loc)
+     __THROW;
+
+libc_hidden_proto (____strtoqd_l_internal)
+
+extern __inline __float128
+__strtoqd_l (__const char *__restrict __nptr, char **__restrict __endptr,
+	     __locale_t __loc) __THROW
+{
+  return ____strtoqd_l_internal (__nptr, __endptr, 0, __loc);
+}
+#endif
+
 #endif
 
 extern void * __default_morecore (ptrdiff_t);
--- libc/include/wchar.h.float128	2004-03-15 12:43:44.000000000 -0800
+++ libc/include/wchar.h	2004-05-05 14:48:54.000000000 -0700
@@ -123,5 +123,28 @@ extern size_t __mbsrtowcs_l (wchar_t *ds
 #  define mbsinit(state) ((state)->__count == 0)
 #  define __mbsinit(state) ((state)->__count == 0)
 
+#  ifdef HAVE_FLOAT128
+extern __float128 wcstoqd (__const wchar_t *__restrict __nptr,
+			      wchar_t **__restrict __endptr) __THROW;
+extern __float128 __wcstoqd_internal (__const wchar_t *__restrict __nptr,
+					 wchar_t **__restrict __endptr,
+					 int __group) __THROW;
+
+
+extern __float128 wcstoqd_l (__const wchar_t *__restrict __nptr,
+				wchar_t **__restrict __endptr,
+				__locale_t __loc) __THROW;
+extern __typeof (wcstoqd_l) __wcstoqd_l;
+
+extern __float128 ____wcstoqd_l_internal (__const wchar_t *__restrict __nptr,
+					     wchar_t **__restrict __endptr,
+					     int __group,
+					     __locale_t __loc) __THROW;
+
+libc_hidden_proto (__wcstoqd_internal)
+libc_hidden_proto (____wcstoqd_l_internal)
+
+#  endif
+
 # endif
 #endif
--- libc/math/math_private.h.float128	2003-09-04 09:10:31.000000000 -0700
+++ libc/math/math_private.h	2004-05-05 14:48:54.000000000 -0700
@@ -20,6 +20,10 @@
 #include <endian.h>
 #include <sys/types.h>
 
+#ifdef HAVE_FLOAT128
+#include <math_quad.h>
+#endif
+
 /* The original fdlibm code used statements like:
 	n0 = ((*(int*)&one)>>29)^1;		* index of high word *
 	ix0 = *(n0+(int*)&x);			* high word of x *
--- libc/stdio-common/printf-parse.h.float128	2003-06-12 07:53:10.000000000 -0700
+++ libc/stdio-common/printf-parse.h	2004-05-05 14:48:54.000000000 -0700
@@ -57,6 +57,9 @@ union printf_arg
     const char *pa_string;
     const wchar_t *pa_wstring;
     void *pa_pointer;
+#ifdef HAVE_FLOAT128
+    __float128 pa_float128;
+#endif
   };
 
 
--- libc/stdio-common/printf-parsemb.c.float128	2003-06-12 08:17:00.000000000 -0700
+++ libc/stdio-common/printf-parsemb.c	2004-05-06 11:02:58.000000000 -0700
@@ -351,6 +351,11 @@ __parse_one_specmb (const UCHAR_T *forma
 	case L'G':
 	case L'a':
 	case L'A':
+#ifdef HAVE_FLOAT128
+	  if (spec->info.is_float128)
+	    spec->data_arg_type = PA_DOUBLE|PA_FLAG_FLOAT128;
+	  else
+#endif
 	  if (spec->info.is_long_double)
 	    spec->data_arg_type = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
 	  else
--- libc/stdio-common/printf.h.float128	2001-07-23 16:42:48.000000000 -0700
+++ libc/stdio-common/printf.h	2004-05-06 11:55:03.000000000 -0700
@@ -1,145 +0,0 @@
-/* Copyright (C) 1991-1993,1995-1999,2000,2001 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#ifndef	_PRINTF_H
-
-#define	_PRINTF_H	1
-#include <features.h>
-
-__BEGIN_DECLS
-
-#define	__need_FILE
-#include <stdio.h>
-#define	__need_size_t
-#define __need_wchar_t
-#include <stddef.h>
-
-
-struct printf_info
-{
-  int prec;			/* Precision.  */
-  int width;			/* Width.  */
-  wchar_t spec;			/* Format letter.  */
-  unsigned int is_long_double:1;/* L flag.  */
-  unsigned int is_short:1;	/* h flag.  */
-  unsigned int is_long:1;	/* l flag.  */
-  unsigned int alt:1;		/* # flag.  */
-  unsigned int space:1;		/* Space flag.  */
-  unsigned int left:1;		/* - flag.  */
-  unsigned int showsign:1;	/* + flag.  */
-  unsigned int group:1;		/* ' flag.  */
-  unsigned int extra:1;		/* For special use.  */
-  unsigned int is_char:1;	/* hh flag.  */
-  unsigned int wide:1;		/* Nonzero for wide character streams.  */
-  unsigned int i18n:1;		/* I flag.  */
-  wchar_t pad;			/* Padding character.  */
-};
-
-
-/* Type of a printf specifier-handler function.
-   STREAM is the FILE on which to write output.
-   INFO gives information about the format specification.
-   ARGS is a vector of pointers to the argument data;
-   the number of pointers will be the number returned
-   by the associated arginfo function for the same INFO.
-
-   The function should return the number of characters written,
-   or -1 for errors.  */
-
-typedef int printf_function (FILE *__stream,
-			     __const struct printf_info *__info,
-			     __const void *__const *__args);
-
-/* Type of a printf specifier-arginfo function.
-   INFO gives information about the format specification.
-   N, ARGTYPES, and return value are as for parse_printf_format.  */
-
-typedef int printf_arginfo_function (__const struct printf_info *__info,
-				     size_t __n, int *__argtypes);
-
-
-/* Register FUNC to be called to format SPEC specifiers; ARGINFO must be
-   specified to determine how many arguments a SPEC conversion requires and
-   what their types are.  */
-
-extern int register_printf_function (int __spec, printf_function __func,
-				     printf_arginfo_function __arginfo);
-
-
-/* Parse FMT, and fill in N elements of ARGTYPES with the
-   types needed for the conversions FMT specifies.  Returns
-   the number of arguments required by FMT.
-
-   The ARGINFO function registered with a user-defined format is passed a
-   `struct printf_info' describing the format spec being parsed.  A width
-   or precision of INT_MIN means a `*' was used to indicate that the
-   width/precision will come from an arg.  The function should fill in the
-   array it is passed with the types of the arguments it wants, and return
-   the number of arguments it wants.  */
-
-extern size_t parse_printf_format (__const char *__restrict __fmt, size_t __n,
-				   int *__restrict __argtypes) __THROW;
-
-
-/* Codes returned by `parse_printf_format' for basic types.
-
-   These values cover all the standard format specifications.
-   Users can add new values after PA_LAST for their own types.  */
-
-enum
-{				/* C type: */
-  PA_INT,			/* int */
-  PA_CHAR,			/* int, cast to char */
-  PA_WCHAR,			/* wide char */
-  PA_STRING,			/* const char *, a '\0'-terminated string */
-  PA_WSTRING,			/* const wchar_t *, wide character string */
-  PA_POINTER,			/* void * */
-  PA_FLOAT,			/* float */
-  PA_DOUBLE,			/* double */
-  PA_LAST
-};
-
-/* Flag bits that can be set in a type returned by `parse_printf_format'.  */
-#define	PA_FLAG_MASK		0xff00
-#define	PA_FLAG_LONG_LONG	(1 << 8)
-#define	PA_FLAG_LONG_DOUBLE	PA_FLAG_LONG_LONG
-#define	PA_FLAG_LONG		(1 << 9)
-#define	PA_FLAG_SHORT		(1 << 10)
-#define	PA_FLAG_PTR		(1 << 11)
-
-
-
-/* Function which can be registered as `printf'-handlers.  */
-
-/* Print floating point value using using abbreviations for the orders
-   of magnitude used for numbers ('k' for kilo, 'm' for mega etc).  If
-   the format specifier is a uppercase character powers of 1000 are
-   used.  Otherwise powers of 1024.  */
-extern int printf_size (FILE *__restrict __fp,
-			__const struct printf_info *__info,
-			__const void *__const *__restrict __args) __THROW;
-
-/* This is the appropriate argument information function for `printf_size'.  */
-extern int printf_size_info (__const struct printf_info *__restrict
-			     __info, size_t __n, int *__restrict __argtypes)
-     __THROW;
-
-
-__END_DECLS
-
-#endif /* printf.h  */
--- libc/stdio-common/printf_fp.c.float128	2004-03-26 10:57:38.000000000 -0800
+++ libc/stdio-common/printf_fp.c	2004-05-06 11:31:17.000000000 -0700
@@ -45,6 +45,14 @@
 # define CHAR_T        char
 #endif
 
+#ifdef HAVE_FLOAT128
+#define FLOAT_MANT_DIG		QUAD_MANT_DIG
+#define FLOAT_MAX_10_EXP_LOG	QUAD_MAX_10_EXP_LOG
+#else
+#define FLOAT_MANT_DIG		LDBL_MANT_DIG
+#define FLOAT_MAX_10_EXP_LOG	LDBL_MAX_10_EXP_LOG
+#endif
+
 #include "_i18n_number.h"
 
 #ifndef NDEBUG
@@ -121,12 +129,6 @@
 extern int __isinfl_internal (long double) attribute_hidden;
 extern int __isnanl_internal (long double) attribute_hidden;
 
-extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size,
-				       int *expt, int *is_neg,
-				       double value);
-extern mp_size_t __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size,
-					    int *expt, int *is_neg,
-					    long double value);
 extern unsigned int __guess_grouping (unsigned int intdig_max,
 				      const char *grouping);
 
@@ -147,6 +149,9 @@ __printf_fp (FILE *fp,
     {
       double dbl;
       __long_double_t ldbl;
+#ifdef HAVE_FLOAT128
+      __float128 flt128;
+#endif
     }
   fpnum;
 
@@ -165,7 +170,7 @@ __printf_fp (FILE *fp,
 
   /* 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[(FLOAT_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;
 
@@ -309,6 +314,52 @@ __printf_fp (FILE *fp,
     grouping = NULL;
 
   /* Fetch the argument value.	*/
+#ifdef HAVE_FLOAT128
+  if (info->is_float128)
+    {
+      fpnum.flt128 = *(const __float128 *) args[0];
+
+      /* Check for special values: not a number or infinity.  */
+      if (__isnanq (fpnum.flt128))
+	{
+	  if (isupper (info->spec))
+	    {
+	      special = "NAN";
+	      wspecial = L"NAN";
+	    }
+	    else
+	      {
+		special = "nan";
+		wspecial = L"nan";
+	      }
+	  is_neg = 0;
+	}
+      else if (__isinfq (fpnum.flt128))
+	{
+	  if (isupper (info->spec))
+	    {
+	      special = "INF";
+	      wspecial = L"INF";
+	    }
+	  else
+	    {
+	      special = "inf";
+	      wspecial = L"inf";
+	    }
+	  is_neg = __signbitq (fpnum.flt128);
+	}
+      else
+	{
+	  fracsize = __mpn_extract_float128 (fp_input,
+					     (sizeof (fp_input) /
+					      sizeof (fp_input[0])),
+					     &exponent, &is_neg,
+					     fpnum.flt128);
+	  to_shift = 1 + fracsize * BITS_PER_MP_LIMB - QUAD_MANT_DIG;
+	}
+    }
+  else
+#endif
 #ifndef __NO_LONG_DOUBLE_MATH
   if (info->is_long_double && sizeof (long double) > sizeof (double))
     {
@@ -446,7 +497,7 @@ __printf_fp (FILE *fp,
     {
       /* |FP| >= 8.0.  */
       int scaleexpo = 0;
-      int explog = LDBL_MAX_10_EXP_LOG;
+      int explog = FLOAT_MAX_10_EXP_LOG;
       int exp10 = 0;
       const struct mp_power *powers = &_fpioconst_pow10[explog + 1];
       int cnt_h, cnt_l, i;
@@ -479,10 +530,31 @@ __printf_fp (FILE *fp,
 	    {
 	      if (scalesize == 0)
 		{
+#ifdef HAVE_FLOAT128
+		  if (QUAD_MANT_DIG > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB
+		      && info->is_float128)
+		    {
+#define _FPIO_CONST_SHIFT \
+  (((QUAD_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) \
+   - _FPIO_CONST_OFFSET)
+		      /* 64bit const offset is not enough for
+			 IEEE quad long double.  */
+		      tmpsize = powers->arraysize + _FPIO_CONST_SHIFT;
+		      memcpy (tmp + _FPIO_CONST_SHIFT,
+			      &__tens[powers->arrayoff],
+			      tmpsize * sizeof (mp_limb_t));
+		      MPN_ZERO (tmp, _FPIO_CONST_SHIFT);
+		      /* Adjust exponent, as scaleexpo will be this much
+			 bigger too.  */
+		      exponent += _FPIO_CONST_SHIFT * BITS_PER_MP_LIMB;
+		    }
+		  else
+#endif
 #ifndef __NO_LONG_DOUBLE_MATH
 		  if (LDBL_MANT_DIG > _FPIO_CONST_OFFSET * BITS_PER_MP_LIMB
 		      && info->is_long_double)
 		    {
+#undef _FPIO_CONST_SHIFT
 #define _FPIO_CONST_SHIFT \
   (((LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB) \
    - _FPIO_CONST_OFFSET)
@@ -617,7 +689,7 @@ __printf_fp (FILE *fp,
     {
       /* |FP| < 1.0.  */
       int exp10 = 0;
-      int explog = LDBL_MAX_10_EXP_LOG;
+      int explog = FLOAT_MAX_10_EXP_LOG;
       const struct mp_power *powers = &_fpioconst_pow10[explog + 1];
       mp_size_t used_limbs = fracsize - 1;
 
--- libc/stdio-common/printf_size.c.float128	2004-03-19 11:19:06.000000000 -0800
+++ libc/stdio-common/printf_size.c	2004-05-06 10:57:30.000000000 -0700
@@ -25,6 +25,9 @@
 #include <printf.h>
 #include <libioP.h>
 
+#ifdef HAVE_FLOAT128
+#include <ieee754-quad.h>
+#endif
 
 /* This defines make it possible to use the same code for GNU C library and
    the GNU I/O library.	 */
@@ -104,6 +107,9 @@ printf_size (FILE *fp, const struct prin
     {
       union ieee754_double dbl;
       union ieee854_long_double ldbl;
+#ifdef HAVE_FLOAT128
+      union ieee854_float128 flt128;
+#endif
     }
   fpnum;
   const void *ptr = &fpnum;
@@ -120,6 +126,39 @@ printf_size (FILE *fp, const struct prin
 
 
   /* Fetch the argument value.	*/
+#ifdef HAVE_FLOAT128
+  if (info->is_float128)
+    {
+      fpnum.flt128.d = *(const __float128 *) args[0];
+
+      /* Check for special values: not a number or infinity.  */
+      if (__isnanq (fpnum.flt128.d))
+	{
+	  special = "nan";
+	  wspecial = L"nan";
+	  negative = 0;
+	}
+      else if (__isinfq (fpnum.flt128.d))
+	{
+	  special = "inf";
+	  wspecial = L"inf";
+
+	  negative = __signbitq (fpnum.flt128.d);
+	}
+      else
+#if 1
+	/* FIXME: The __float128 algorithm doesn't work yet.  */
+	abort ();
+#else
+	while (fpnum.flt128.d >= divisor && tag[1] != '\0')
+	  {
+	    fpnum.flt128.d /= divisor;
+	    ++tag;
+	  }
+#endif
+    }
+  else
+#endif
 #ifndef __NO_LONG_DOUBLE_MATH
   if (info->is_long_double && sizeof (long double) > sizeof (double))
     {
@@ -204,6 +243,9 @@ printf_size (FILE *fp, const struct prin
   fp_info.spec = 'f';
   fp_info.prec = info->prec < 0 ? 3 : info->prec;
   fp_info.is_long_double = info->is_long_double;
+#ifdef HAVE_FLOAT128
+  fp_info.is_float128 = info->is_float128;
+#endif
   fp_info.is_short = info->is_short;
   fp_info.is_long = info->is_long;
   fp_info.alt = info->alt;
@@ -250,7 +292,14 @@ printf_size_info (const struct printf_in
 {
   /* We need only one double or long double argument.  */
   if (n >= 1)
+#ifdef HAVE_FLOAT128
+    argtypes[0] = (PA_DOUBLE
+		   | ((info->is_long_double
+		       ? PA_FLAG_LONG_DOUBLE
+		       : (info->is_float128 ? PA_FLAG_FLOAT128 : 0))));
+#else
     argtypes[0] = PA_DOUBLE | (info->is_long_double ? PA_FLAG_LONG_DOUBLE : 0);
+#endif
 
   return 1;
 }
--- libc/stdio-common/vfprintf.c.float128	2004-03-19 11:19:06.000000000 -0800
+++ libc/stdio-common/vfprintf.c	2004-05-06 11:41:41.000000000 -0700
@@ -433,7 +433,7 @@ vfprintf (FILE *s, const CHAR_T *format,
       REF (form_unknown),	/* for '.' */				      \
       REF (form_unknown),	/* for 'h' */				      \
       REF (mod_longlong),	/* for 'l' */				      \
-      REF (form_unknown),	/* for 'L', 'q' */			      \
+      REF (mod_float128),	/* for 'L', 'q' */			      \
       REF (form_unknown),	/* for 'z', 'Z' */			      \
       REF (form_percent),	/* for '%' */				      \
       REF (form_integer),	/* for 'd', 'i' */			      \
@@ -490,6 +490,16 @@ vfprintf (FILE *s, const CHAR_T *format,
     }
 
 
+#ifdef HAVE_FLOAT128
+#define INIT_FLOAT128	.is_float128 = is_float128,
+#define	CHECK_FLOAT128	if (is_float128)				      \
+			  the_arg.pa_float128 = va_arg (ap, __float128);      \
+			else
+#else
+#define INIT_FLOAT128
+#define	CHECK_FLOAT128
+#endif
+
 #define process_arg(fspec)						      \
       /* Start real work.  We know about all flags and modifiers and	      \
 	 now process the wanted format specifier.  */			      \
@@ -767,8 +777,10 @@ vfprintf (FILE *s, const CHAR_T *format,
 					.pad = pad,			      \
 					.extra = 0,			      \
 					.i18n = use_outdigits,		      \
+					INIT_FLOAT128			      \
 					.wide = sizeof (CHAR_T) != 1 };	      \
 									      \
+	    CHECK_FLOAT128						      \
 	    if (is_long_double)						      \
 	      the_arg.pa_long_double = va_arg (ap, long double);	      \
 	    else							      \
@@ -809,6 +821,7 @@ vfprintf (FILE *s, const CHAR_T *format,
 					.is_long_double = is_long_double,     \
 					.is_short = is_short,		      \
 					.is_long = is_long,		      \
+					INIT_FLOAT128			      \
 					.alt = alt,			      \
 					.space = space,			      \
 					.left = left,			      \
@@ -818,6 +831,7 @@ vfprintf (FILE *s, const CHAR_T *format,
 					.extra = 0,			      \
 					.wide = sizeof (CHAR_T) != 1 };	      \
 									      \
+	    CHECK_FLOAT128						      \
 	    if (is_long_double)						      \
 	      the_arg.pa_long_double = va_arg (ap, long double);	      \
 	    else							      \
@@ -1293,6 +1307,9 @@ vfprintf (FILE *s, const CHAR_T *format,
       int is_short = 0;	/* Argument is short int.  */
       int is_long = 0;	/* Argument is long int.  */
       int is_char = 0;	/* Argument is promoted (unsigned) char.  */
+#ifdef HAVE_FLOAT128
+      int is_float128 = 0; /* Argument is float128.  */
+#endif
       int width = 0;	/* Width of output; 0 means none specified.  */
       int prec = -1;	/* Precision of output; -1 means none specified.  */
       /* This flag is set by the 'I' modifier and selects the use of the
@@ -1495,6 +1512,16 @@ vfprintf (FILE *s, const CHAR_T *format,
       is_long = 1;
       JUMP (*++f, step4_jumps);
 
+    LABEL (mod_float128):
+#ifdef HAVE_FLOAT128
+      if (*f != 'L')
+	goto LABEL (form_unknown);
+      is_float128 = 1;
+      JUMP (*++f, step4_jumps);
+#else
+      goto LABEL (form_unknown); 
+#endif
+
     LABEL (mod_size_t):
       is_long_double = sizeof (size_t) > sizeof (unsigned long int);
       is_long = sizeof (size_t) > sizeof (unsigned int);
@@ -1686,6 +1713,9 @@ do_positional:
 	T (PA_FLOAT, pa_double, double);	/* Promoted.  */
 	T (PA_DOUBLE, pa_double, double);
 	T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);
+#ifdef HAVE_FLOAT128
+	T (PA_DOUBLE|PA_FLAG_FLOAT128, pa_float128, __float128);
+#endif
 	T (PA_STRING, pa_string, const char *);
 	T (PA_WSTRING, pa_wstring, const wchar_t *);
 	T (PA_POINTER, pa_pointer, void *);
@@ -1728,6 +1758,9 @@ do_positional:
 	int showsign = specs[nspecs_done].info.showsign;
 	int group = specs[nspecs_done].info.group;
 	int is_long_double = specs[nspecs_done].info.is_long_double;
+#ifdef HAVE_FLOAT128
+	int is_float128 = specs[nspecs_done].info.is_float128;
+#endif
 	int is_short = specs[nspecs_done].info.is_short;
 	int is_char = specs[nspecs_done].info.is_char;
 	int is_long = specs[nspecs_done].info.is_long;
--- libc/stdio-common/vfscanf.c.float128	2004-04-21 09:36:18.000000000 -0700
+++ libc/stdio-common/vfscanf.c	2004-05-05 14:48:54.000000000 -0700
@@ -30,6 +30,10 @@
 #include <bits/libc-lock.h>
 #include <locale/localeinfo.h>
 
+#ifdef HAVE_FLOAT128
+#include <ieee754-quad.h>
+#endif
+
 #ifdef	__GNUC__
 # define HAVE_LONGLONG
 # define LONGLONG	long long
@@ -63,6 +67,7 @@
 #define MALLOC		0x100	/* a: malloc strings */
 #define CHAR		0x200	/* hh: char */
 #define I18N		0x400	/* I: use locale's digits */
+#define FLOAT128	0x800	/* lL: IEEE Quda */
 
 
 #include <locale/localeinfo.h>
@@ -95,6 +100,7 @@
 # define __strtol_internal	__wcstol_internal
 # define __strtoul_internal	__wcstoul_internal
 # define __strtold_internal	__wcstold_internal
+# define __strtoqd_internal	__wcstoqd_internal
 # define __strtod_internal	__wcstod_internal
 # define __strtof_internal	__wcstof_internal
 
@@ -491,6 +497,13 @@ _IO_vfscanf (s, format, argptr, errp)
 	      ++f;
 	      flags |= LONGDBL | LONG;
 	    }
+#ifdef HAVE_FLOAT128
+	  else if (*f == L_('L'))
+	    {
+	      ++f;
+	      flags |= FLOAT128;
+	    }
+#endif
 	  else
 	    /* ints are long ints.  */
 	    flags |= LONG;
@@ -1808,6 +1821,15 @@ _IO_vfscanf (s, format, argptr, errp)
 	scan_float:
 	  /* Convert the number.  */
 	  ADDW (L_('\0'));
+#ifdef HAVE_FLOAT128
+	  if (flags & FLOAT128)
+	    {
+	      __float128 d = __strtoqd_internal (wp, &tw, flags & GROUP);
+	      if (!(flags & SUPPRESS) && tw != wp)
+		*ARG (__float128 *) = negative ? -d : d;
+	    }
+	  else
+#endif
 	  if (flags & LONGDBL)
 	    {
 	      long double d = __strtold_internal (wp, &tw, flags & GROUP);
--- libc/stdlib/strfmon_l.c.float128	2004-03-15 12:43:46.000000000 -0800
+++ libc/stdlib/strfmon_l.c	2004-05-06 11:31:45.000000000 -0700
@@ -114,6 +114,9 @@ __vstrfmon_l (char *s, size_t maxsize, _
       {
 	double dbl;
 	__long_double_t ldbl;
+#ifdef HAVE_FLOAT128
+	__float128 flt128;
+#endif
       }
       fpnum;
       int int_format;
@@ -124,6 +127,9 @@ __vstrfmon_l (char *s, size_t maxsize, _
       int group;
       char pad;
       int is_long_double;
+#ifdef HAVE_FLOAT128
+      int is_float128;
+#endif
       int p_sign_posn;
       int n_sign_posn;
       int sign_posn;
@@ -168,6 +174,9 @@ __vstrfmon_l (char *s, size_t maxsize, _
       group = 1;			/* Print digits grouped.  */
       pad = ' ';			/* Fill character is <SP>.  */
       is_long_double = 0;		/* Double argument by default.  */
+#ifdef HAVE_FLOAT128
+      is_float128 = 0;
+#endif
       p_sign_posn = -1;			/* This indicates whether the */
       n_sign_posn = -1;			/* '(' flag is given.  */
       width = -1;			/* No width specified so far.  */
@@ -280,6 +289,13 @@ __vstrfmon_l (char *s, size_t maxsize, _
 	  ++fmt;
 	  is_long_double = 1;
 	}
+#ifdef HAVE_FLOAT128
+      else if (*fmt == 'Q')
+	{
+	  ++fmt;
+	  is_float128 = 1;
+	}
+#endif
 
       /* Handle format specifier.  */
       char int_symbol[4];
@@ -333,6 +349,16 @@ __vstrfmon_l (char *s, size_t maxsize, _
 						     MON_THOUSANDS_SEP));
 
       /* Now it's time to get the value.  */
+#ifdef HAVE_FLOAT128
+      if (is_float128 == 1)
+	{
+	  fpnum.flt128  = va_arg (ap, __float128);
+	  is_negative = __signbitq (fpnum.flt128);
+	  if (is_negative)
+	    fpnum.flt128  = -fpnum.flt128;
+	}
+      else
+#endif
       if (is_long_double == 1)
 	{
 	  fpnum.ldbl = va_arg (ap, long double);
@@ -547,6 +573,9 @@ __vstrfmon_l (char *s, size_t maxsize, _
       info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
       info.spec = 'f';
       info.is_long_double = is_long_double;
+#ifdef HAVE_FLOAT128
+      info.is_float128 = is_float128;
+#endif
       info.is_short = 0;
       info.is_long = 0;
       info.alt = 0;
--- libc/sysdeps/generic/printf.h.float128	2004-05-06 11:51:39.000000000 -0700
+++ libc/sysdeps/generic/printf.h	2001-07-23 16:42:48.000000000 -0700
@@ -0,0 +1,145 @@
+/* Copyright (C) 1991-1993,1995-1999,2000,2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef	_PRINTF_H
+
+#define	_PRINTF_H	1
+#include <features.h>
+
+__BEGIN_DECLS
+
+#define	__need_FILE
+#include <stdio.h>
+#define	__need_size_t
+#define __need_wchar_t
+#include <stddef.h>
+
+
+struct printf_info
+{
+  int prec;			/* Precision.  */
+  int width;			/* Width.  */
+  wchar_t spec;			/* Format letter.  */
+  unsigned int is_long_double:1;/* L flag.  */
+  unsigned int is_short:1;	/* h flag.  */
+  unsigned int is_long:1;	/* l flag.  */
+  unsigned int alt:1;		/* # flag.  */
+  unsigned int space:1;		/* Space flag.  */
+  unsigned int left:1;		/* - flag.  */
+  unsigned int showsign:1;	/* + flag.  */
+  unsigned int group:1;		/* ' flag.  */
+  unsigned int extra:1;		/* For special use.  */
+  unsigned int is_char:1;	/* hh flag.  */
+  unsigned int wide:1;		/* Nonzero for wide character streams.  */
+  unsigned int i18n:1;		/* I flag.  */
+  wchar_t pad;			/* Padding character.  */
+};
+
+
+/* Type of a printf specifier-handler function.
+   STREAM is the FILE on which to write output.
+   INFO gives information about the format specification.
+   ARGS is a vector of pointers to the argument data;
+   the number of pointers will be the number returned
+   by the associated arginfo function for the same INFO.
+
+   The function should return the number of characters written,
+   or -1 for errors.  */
+
+typedef int printf_function (FILE *__stream,
+			     __const struct printf_info *__info,
+			     __const void *__const *__args);
+
+/* Type of a printf specifier-arginfo function.
+   INFO gives information about the format specification.
+   N, ARGTYPES, and return value are as for parse_printf_format.  */
+
+typedef int printf_arginfo_function (__const struct printf_info *__info,
+				     size_t __n, int *__argtypes);
+
+
+/* Register FUNC to be called to format SPEC specifiers; ARGINFO must be
+   specified to determine how many arguments a SPEC conversion requires and
+   what their types are.  */
+
+extern int register_printf_function (int __spec, printf_function __func,
+				     printf_arginfo_function __arginfo);
+
+
+/* Parse FMT, and fill in N elements of ARGTYPES with the
+   types needed for the conversions FMT specifies.  Returns
+   the number of arguments required by FMT.
+
+   The ARGINFO function registered with a user-defined format is passed a
+   `struct printf_info' describing the format spec being parsed.  A width
+   or precision of INT_MIN means a `*' was used to indicate that the
+   width/precision will come from an arg.  The function should fill in the
+   array it is passed with the types of the arguments it wants, and return
+   the number of arguments it wants.  */
+
+extern size_t parse_printf_format (__const char *__restrict __fmt, size_t __n,
+				   int *__restrict __argtypes) __THROW;
+
+
+/* Codes returned by `parse_printf_format' for basic types.
+
+   These values cover all the standard format specifications.
+   Users can add new values after PA_LAST for their own types.  */
+
+enum
+{				/* C type: */
+  PA_INT,			/* int */
+  PA_CHAR,			/* int, cast to char */
+  PA_WCHAR,			/* wide char */
+  PA_STRING,			/* const char *, a '\0'-terminated string */
+  PA_WSTRING,			/* const wchar_t *, wide character string */
+  PA_POINTER,			/* void * */
+  PA_FLOAT,			/* float */
+  PA_DOUBLE,			/* double */
+  PA_LAST
+};
+
+/* Flag bits that can be set in a type returned by `parse_printf_format'.  */
+#define	PA_FLAG_MASK		0xff00
+#define	PA_FLAG_LONG_LONG	(1 << 8)
+#define	PA_FLAG_LONG_DOUBLE	PA_FLAG_LONG_LONG
+#define	PA_FLAG_LONG		(1 << 9)
+#define	PA_FLAG_SHORT		(1 << 10)
+#define	PA_FLAG_PTR		(1 << 11)
+
+
+
+/* Function which can be registered as `printf'-handlers.  */
+
+/* Print floating point value using using abbreviations for the orders
+   of magnitude used for numbers ('k' for kilo, 'm' for mega etc).  If
+   the format specifier is a uppercase character powers of 1000 are
+   used.  Otherwise powers of 1024.  */
+extern int printf_size (FILE *__restrict __fp,
+			__const struct printf_info *__info,
+			__const void *__const *__restrict __args) __THROW;
+
+/* This is the appropriate argument information function for `printf_size'.  */
+extern int printf_size_info (__const struct printf_info *__restrict
+			     __info, size_t __n, int *__restrict __argtypes)
+     __THROW;
+
+
+__END_DECLS
+
+#endif /* printf.h  */
--- libc/sysdeps/generic/printf_fphex.c.float128	2002-10-23 18:15:31.000000000 -0700
+++ libc/sysdeps/generic/printf_fphex.c	2004-05-05 14:48:55.000000000 -0700
@@ -30,6 +30,10 @@
 #include "_itowa.h"
 #include <locale/localeinfo.h>
 
+#ifdef HAVE_FLOAT128
+#include <ieee754-quad.h>
+#endif
+
 /* #define NDEBUG 1*/		/* Undefine this for debugging assertions.  */
 #include <assert.h>
 
@@ -99,6 +103,9 @@ __printf_fphex (FILE *fp,
     {
       union ieee754_double dbl;
       union ieee854_long_double ldbl;
+#ifdef HAVE_FLOAT128
+      union ieee854_float128 flt128;
+#endif
     }
   fpnum;
 
@@ -164,6 +171,47 @@ __printf_fphex (FILE *fp,
 
 
   /* Fetch the argument value.	*/
+#ifdef HAVE_FLOAT128
+  if (info->is_float128)
+    {
+      fpnum.flt128.d = *(const __float128 *) args[0];
+
+      /* Check for special values: not a number or infinity.  */
+      if (__isnanq (fpnum.flt128.d))
+	{
+	  if (isupper (info->spec))
+	    {
+	      special = "NAN";
+	      wspecial = L"NAN";
+	    }
+	  else
+	    {
+	      special = "nan";
+	      wspecial = L"nan";
+	    }
+	  negative = 0;
+	}
+      else
+	{
+	  if (__isinfq (fpnum.flt128.d))
+	    {
+	      if (isupper (info->spec))
+		{
+		  special = "INF";
+		  wspecial = L"INF";
+		}
+	      else
+		{
+		  special = "inf";
+		  wspecial = L"inf";
+		}
+	    }
+
+	  negative = __signbitq (fpnum.flt128.d);
+	}
+    }
+  else
+#endif
 #ifndef __NO_LONG_DOUBLE_MATH
   if (info->is_long_double && sizeof (long double) > sizeof (double))
     {
@@ -269,7 +317,12 @@ __printf_fphex (FILE *fp,
       return done;
     }
 
-  if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
+  if ((info->is_long_double == 0
+#ifdef HAVE_FLOAT128
+       && info->is_float128 == 0
+#endif
+      )
+      || sizeof (double) == sizeof (long double))
     {
       /* We have 52 bits of mantissa plus one implicit digit.  Since
 	 52 bits are representable without rest using hexadecimal
@@ -330,6 +383,11 @@ __printf_fphex (FILE *fp,
 	  exponent = -(exponent - IEEE754_DOUBLE_BIAS);
 	}
     }
+#ifdef HAVE_FLOAT128
+# include <printf_quadfphex.h>
+  else if (info->is_float128)
+    PRINT_FPHEX_FLOAT128;
+#endif
 #ifdef PRINT_FPHEX_LONG_DOUBLE
   else
     PRINT_FPHEX_LONG_DOUBLE;
--- libc/sysdeps/ieee754/quad/Makefile.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/Makefile	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,14 @@
+ifeq ($(subdir),stdlib)
+routines += mpn2quad quad2mpn strtoqd strtoqd_l
+endif
+
+ifeq ($(subdir),math)
+routines += s_isinfq s_isnanq s_signbitq
+endif
+
+ifeq ($(subdir),wcsmbs)
+routines += wcstoqd wcstoqd_l
+
+CFLAGS-wcstoqd.c = $(strtox-CFLAGS)
+CFLAGS-wcstoqd_l.c = $(strtox-CFLAGS)
+endif
--- libc/sysdeps/ieee754/quad/bits/huge_valq.h.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/bits/huge_valq.h	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,45 @@
+/* `HUGE_VALQ' constant for IEEE 754 machines (where it is infinity).
+   Used by <stdlib.h> and <math.h> functions for overflow.
+   Copyright (C) 2004
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _MATH_H
+# error "Never use <bits/huge_valq.h> directly; include <math.h> instead."
+#endif
+
+/* IEEE positive infinity (-HUGE_VAL is negative infinity).  */
+
+#include <endian.h>
+
+typedef union { unsigned char __c[16]; __float128 __qd; } __huge_valq_t;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define __HUGE_VALQ_bytes	{ 0x7f, 0xff, 0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
+#endif
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define __HUGE_VALQ_bytes	{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0xff, 0x7f }
+#endif
+
+#ifdef __GNUC__
+# define HUGE_VALQ	(__extension__ \
+			 ((__huge_valq_t) { __c : __HUGE_VALQ_bytes }).__qd)
+#else
+static __huge_valq_t __huge_valq = { __HUGE_VALQ_bytes };
+# define HUGE_VALQ	(__huge_valq.__qd)
+#endif 
--- libc/sysdeps/ieee754/quad/float.h.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/float.h	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,47 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include_next <float.h>
+
+#ifndef QUAD_MANT_DIG
+#define QUAD_MANT_DIG	113
+#endif
+
+#ifndef QUAD_DIG
+#define QUAD_DIG	33
+#endif
+
+#ifndef QUAD_MIN_EXP
+#define QUAD_MIN_EXP	(-16381)
+#endif
+
+#ifndef QUAD_MIN_10_EXP
+#define QUAD_MIN_10_EXP	(-4931)
+#endif
+
+#ifndef QUAD_MAX_EXP
+#define QUAD_MAX_EXP	16384
+#endif
+
+#ifndef QUAD_MAX_10_EXP
+#define QUAD_MAX_10_EXP	4932
+#endif
+
+#ifndef QUAD_MAX_10_EXP_LOG
+#define QUAD_MAX_10_EXP_LOG	12
+#endif
--- libc/sysdeps/ieee754/quad/ieee754-quad.h.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/ieee754-quad.h	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,84 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _IEEE754_QUAD_H
+
+#define _IEEE754_QUAD_H 1
+#include <features.h>
+
+#include <endian.h>
+
+__BEGIN_DECLS
+
+union ieee854_float128
+  {
+    __float128 d;
+
+    /* This is the IEEE 854 quad-precision format.  */
+    struct
+      {
+#if	__BYTE_ORDER == __BIG_ENDIAN
+	unsigned int negative:1;
+	unsigned int exponent:15;
+	/* Together these comprise the mantissa.  */
+	unsigned int mantissa0:16;
+	unsigned int mantissa1:32;
+	unsigned int mantissa2:32;
+	unsigned int mantissa3:32;
+#endif				/* Big endian.  */
+#if	__BYTE_ORDER == __LITTLE_ENDIAN
+	/* Together these comprise the mantissa.  */
+	unsigned int mantissa3:32;
+	unsigned int mantissa2:32;
+	unsigned int mantissa1:32;
+	unsigned int mantissa0:16;
+	unsigned int exponent:15;
+	unsigned int negative:1;
+#endif				/* Little endian.  */
+      } ieee;
+
+    /* This format makes it easier to see if a NaN is a signalling NaN.  */
+    struct
+      {
+#if	__BYTE_ORDER == __BIG_ENDIAN
+	unsigned int negative:1;
+	unsigned int exponent:15;
+	unsigned int quiet_nan:1;
+	/* Together these comprise the mantissa.  */
+	unsigned int mantissa0:15;
+	unsigned int mantissa1:32;
+	unsigned int mantissa2:32;
+	unsigned int mantissa3:32;
+#else
+	/* Together these comprise the mantissa.  */
+	unsigned int mantissa3:32;
+	unsigned int mantissa2:32;
+	unsigned int mantissa1:32;
+	unsigned int mantissa0:15;
+	unsigned int quiet_nan:1;
+	unsigned int exponent:15;
+	unsigned int negative:1;
+#endif
+      } ieee_nan;
+  };
+
+#define IEEE854_FLOAT128_BIAS 0x3fff /* Added to exponent.  */
+
+__END_DECLS
+
+#endif /* ieee754-quad.h */
--- libc/sysdeps/ieee754/quad/math_quad.h.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/math_quad.h	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,90 @@
+#ifndef _MATH_PRIVATE_H_
+#error "Never use <math_quad.h> directly; include <math_private.h> instead."
+#endif
+
+/* A union which permits us to convert between a long double and
+   four 32 bit ints or two 64 bit ints.  */
+
+#if __FLOAT_WORD_ORDER == BIG_ENDIAN
+
+typedef union
+{
+  __float128 value;
+  struct
+  {
+    u_int64_t msw;
+    u_int64_t lsw;
+  } parts64;
+  struct
+  {
+    u_int32_t w0, w1, w2, w3;
+  } parts32;
+} ieee854_long_double_shape_type;
+
+#endif
+
+#if __FLOAT_WORD_ORDER == LITTLE_ENDIAN
+
+typedef union
+{
+  __float128 value;
+  struct
+  {
+    u_int64_t lsw;
+    u_int64_t msw;
+  } parts64;
+  struct
+  {
+    u_int32_t w3, w2, w1, w0;
+  } parts32;
+} ieee854_long_double_shape_type;
+
+#endif
+
+/* Get two 64 bit ints from a long double.  */
+
+#define GET_LDOUBLE_WORDS64(ix0,ix1,d)				\
+do {								\
+  ieee854_long_double_shape_type qw_u;				\
+  qw_u.value = (d);						\
+  (ix0) = qw_u.parts64.msw;					\
+  (ix1) = qw_u.parts64.lsw;					\
+} while (0)
+
+/* Set a long double from two 64 bit ints.  */
+
+#define SET_LDOUBLE_WORDS64(d,ix0,ix1)				\
+do {								\
+  ieee854_long_double_shape_type qw_u;				\
+  qw_u.parts64.msw = (ix0);					\
+  qw_u.parts64.lsw = (ix1);					\
+  (d) = qw_u.value;						\
+} while (0)
+
+/* Get the more significant 64 bits of a long double mantissa.  */
+
+#define GET_LDOUBLE_MSW64(v,d)					\
+do {								\
+  ieee854_long_double_shape_type sh_u;				\
+  sh_u.value = (d);						\
+  (v) = sh_u.parts64.msw;					\
+} while (0)
+
+/* Set the more significant 64 bits of a long double mantissa from an int.  */
+
+#define SET_LDOUBLE_MSW64(d,v)					\
+do {								\
+  ieee854_long_double_shape_type sh_u;				\
+  sh_u.value = (d);						\
+  sh_u.parts64.msw = (v);					\
+  (d) = sh_u.value;						\
+} while (0)
+
+/* Get the least significant 64 bits of a long double mantissa.  */
+
+#define GET_LDOUBLE_LSW64(v,d)					\
+do {								\
+  ieee854_long_double_shape_type sh_u;				\
+  sh_u.value = (d);						\
+  (v) = sh_u.parts64.lsw;					\
+} while (0)
--- libc/sysdeps/ieee754/quad/mpn2quad.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/mpn2quad.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,54 @@
+/* Copyright (C) 2004
+	Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include <ieee754-quad.h>
+#include <float.h>
+#include <math.h>
+
+/* Convert a multi-precision integer of the needed number of bits (113 for
+   long double) and an integral power of two to a `long double' in IEEE854
+   quad-precision format.  */
+
+__float128
+__mpn_construct_float128 (mp_srcptr frac_ptr, int expt, int sign)
+{
+  union ieee854_float128 u;
+
+  u.ieee.negative = sign;
+  u.ieee.exponent = expt + IEEE854_FLOAT128_BIAS;
+#if BITS_PER_MP_LIMB == 32
+  u.ieee.mantissa3 = frac_ptr[0];
+  u.ieee.mantissa2 = frac_ptr[1];
+  u.ieee.mantissa1 = frac_ptr[2];
+  u.ieee.mantissa0 = frac_ptr[3] & (((mp_limb_t) 1
+				     << (QUAD_MANT_DIG - 96)) - 1);
+#elif BITS_PER_MP_LIMB == 64
+  u.ieee.mantissa3 = frac_ptr[0] & (((mp_limb_t) 1 << 32) - 1);
+  u.ieee.mantissa2 = frac_ptr[0] >> 32;
+  u.ieee.mantissa1 = frac_ptr[1] & (((mp_limb_t) 1 << 32) - 1);
+  u.ieee.mantissa0 = (frac_ptr[1] >> 32) & (((mp_limb_t) 1
+					     << (QUAD_MANT_DIG - 96)) - 1);
+#else
+  #error "mp_limb size " BITS_PER_MP_LIMB "not accounted for"
+#endif
+
+  return u.d;
+}
--- libc/sysdeps/ieee754/quad/printf.h.float128	2004-05-06 11:37:41.000000000 -0700
+++ libc/sysdeps/ieee754/quad/printf.h	2004-05-06 11:38:00.000000000 -0700
@@ -0,0 +1,147 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef	_PRINTF_H
+
+#define	_PRINTF_H	1
+#include <features.h>
+
+__BEGIN_DECLS
+
+#define	__need_FILE
+#include <stdio.h>
+#define	__need_size_t
+#define __need_wchar_t
+#include <stddef.h>
+
+
+struct printf_info
+{
+  int prec;			/* Precision.  */
+  int width;			/* Width.  */
+  wchar_t spec;			/* Format letter.  */
+  unsigned int is_long_double:1;/* L flag.  */
+  unsigned int is_short:1;	/* h flag.  */
+  unsigned int is_long:1;	/* l flag.  */
+  unsigned int alt:1;		/* # flag.  */
+  unsigned int space:1;		/* Space flag.  */
+  unsigned int left:1;		/* - flag.  */
+  unsigned int showsign:1;	/* + flag.  */
+  unsigned int group:1;		/* ' flag.  */
+  unsigned int extra:1;		/* For special use.  */
+  unsigned int is_char:1;	/* hh flag.  */
+  unsigned int wide:1;		/* Nonzero for wide character streams.  */
+  unsigned int i18n:1;		/* I flag.  */
+  unsigned int is_float128:1;	/* lL flag.  */
+  wchar_t pad;			/* Padding character.  */
+};
+
+
+/* Type of a printf specifier-handler function.
+   STREAM is the FILE on which to write output.
+   INFO gives information about the format specification.
+   ARGS is a vector of pointers to the argument data;
+   the number of pointers will be the number returned
+   by the associated arginfo function for the same INFO.
+
+   The function should return the number of characters written,
+   or -1 for errors.  */
+
+typedef int printf_function (FILE *__stream,
+			     __const struct printf_info *__info,
+			     __const void *__const *__args);
+
+/* Type of a printf specifier-arginfo function.
+   INFO gives information about the format specification.
+   N, ARGTYPES, and return value are as for parse_printf_format.  */
+
+typedef int printf_arginfo_function (__const struct printf_info *__info,
+				     size_t __n, int *__argtypes);
+
+
+/* Register FUNC to be called to format SPEC specifiers; ARGINFO must be
+   specified to determine how many arguments a SPEC conversion requires and
+   what their types are.  */
+
+extern int register_printf_function (int __spec, printf_function __func,
+				     printf_arginfo_function __arginfo);
+
+
+/* Parse FMT, and fill in N elements of ARGTYPES with the
+   types needed for the conversions FMT specifies.  Returns
+   the number of arguments required by FMT.
+
+   The ARGINFO function registered with a user-defined format is passed a
+   `struct printf_info' describing the format spec being parsed.  A width
+   or precision of INT_MIN means a `*' was used to indicate that the
+   width/precision will come from an arg.  The function should fill in the
+   array it is passed with the types of the arguments it wants, and return
+   the number of arguments it wants.  */
+
+extern size_t parse_printf_format (__const char *__restrict __fmt, size_t __n,
+				   int *__restrict __argtypes) __THROW;
+
+
+/* Codes returned by `parse_printf_format' for basic types.
+
+   These values cover all the standard format specifications.
+   Users can add new values after PA_LAST for their own types.  */
+
+enum
+{				/* C type: */
+  PA_INT,			/* int */
+  PA_CHAR,			/* int, cast to char */
+  PA_WCHAR,			/* wide char */
+  PA_STRING,			/* const char *, a '\0'-terminated string */
+  PA_WSTRING,			/* const wchar_t *, wide character string */
+  PA_POINTER,			/* void * */
+  PA_FLOAT,			/* float */
+  PA_DOUBLE,			/* double */
+  PA_LAST
+};
+
+/* Flag bits that can be set in a type returned by `parse_printf_format'.  */
+#define	PA_FLAG_MASK		0xff00
+#define	PA_FLAG_LONG_LONG	(1 << 8)
+#define	PA_FLAG_LONG_DOUBLE	PA_FLAG_LONG_LONG
+#define	PA_FLAG_LONG		(1 << 9)
+#define	PA_FLAG_SHORT		(1 << 10)
+#define	PA_FLAG_PTR		(1 << 11)
+#define	PA_FLAG_FLOAT128	(1 << 12)
+
+
+
+/* Function which can be registered as `printf'-handlers.  */
+
+/* Print floating point value using using abbreviations for the orders
+   of magnitude used for numbers ('k' for kilo, 'm' for mega etc).  If
+   the format specifier is a uppercase character powers of 1000 are
+   used.  Otherwise powers of 1024.  */
+extern int printf_size (FILE *__restrict __fp,
+			__const struct printf_info *__info,
+			__const void *__const *__restrict __args) __THROW;
+
+/* This is the appropriate argument information function for `printf_size'.  */
+extern int printf_size_info (__const struct printf_info *__restrict
+			     __info, size_t __n, int *__restrict __argtypes)
+     __THROW;
+
+
+__END_DECLS
+
+#endif /* printf.h  */
--- libc/sysdeps/ieee754/quad/printf_quadfphex.h.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/printf_quadfphex.h	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,102 @@
+/* Print floating point number in hexadecimal notation according to
+   ISO C99.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define PRINT_FPHEX_FLOAT128 \
+do {									      \
+      /* 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;				      \
+									      \
+      num0 = (((unsigned long long int) fpnum.flt128.ieee.mantissa0) << 32      \
+	     | fpnum.flt128.ieee.mantissa1);				      \
+      num1 = (((unsigned long long int) fpnum.flt128.ieee.mantissa2) << 32      \
+	     | fpnum.flt128.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 = fpnum.flt128.ieee.exponent == 0 ? '0' : '1';		      \
+									      \
+      exponent = fpnum.flt128.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);		      \
+	}								      \
+} while (0)
--- libc/sysdeps/ieee754/quad/quad2mpn.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/quad2mpn.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,141 @@
+/* Copyright (C) 2004
+	Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "gmp.h"
+#include "gmp-impl.h"
+#include "longlong.h"
+#include <ieee754-quad.h>
+#include <float.h>
+#include <math.h>
+#include <stdlib.h>
+
+/* Convert a `long double' in IEEE854 quad-precision format to a
+   multi-precision integer representing the significand scaled up by its
+   number of bits (113 for long double) and an integral power of two
+   (MPN frexpl). */
+
+mp_size_t
+__mpn_extract_float128 (mp_ptr res_ptr, mp_size_t size,
+			   int *expt, int *is_neg,
+			   __float128 value)
+{
+  union ieee854_float128 u;
+  u.d = value;
+
+  *is_neg = u.ieee.negative;
+  *expt = (int) u.ieee.exponent - IEEE854_FLOAT128_BIAS;
+
+#if BITS_PER_MP_LIMB == 32
+  res_ptr[0] = u.ieee.mantissa3; /* Low-order 32 bits of fraction.  */
+  res_ptr[1] = u.ieee.mantissa2;
+  res_ptr[2] = u.ieee.mantissa1;
+  res_ptr[3] = u.ieee.mantissa0; /* High-order 32 bits.  */
+  #define N 4
+#elif BITS_PER_MP_LIMB == 64
+  /* Hopefully the compiler will combine the two bitfield extracts
+     and this composition into just the original quadword extract.  */
+  res_ptr[0] = ((mp_limb_t) u.ieee.mantissa2 << 32) | u.ieee.mantissa3;
+  res_ptr[1] = ((mp_limb_t) u.ieee.mantissa0 << 32) | u.ieee.mantissa1;
+  #define N 2
+#else
+  #error "mp_limb size " BITS_PER_MP_LIMB "not accounted for"
+#endif
+/* The format does not fill the last limb.  There are some zeros.  */
+#define NUM_LEADING_ZEROS (BITS_PER_MP_LIMB \
+			   - (QUAD_MANT_DIG - ((N - 1) * BITS_PER_MP_LIMB)))
+
+  if (u.ieee.exponent == 0)
+    {
+      /* A biased exponent of zero is a special case.
+	 Either it is a zero or it is a denormal number.  */
+      if (res_ptr[0] == 0 && res_ptr[1] == 0
+          && res_ptr[N - 2] == 0 && res_ptr[N - 1] == 0) /* Assumes N<=4.  */
+	/* It's zero.  */
+	*expt = 0;
+      else
+	{
+          /* It is a denormal number, meaning it has no implicit leading
+  	     one bit, and its exponent is in fact the format minimum.  */
+	  int cnt;
+
+#if N == 2
+	  if (res_ptr[N - 1] != 0)
+	    {
+	      count_leading_zeros (cnt, res_ptr[N - 1]);
+	      cnt -= NUM_LEADING_ZEROS;
+	      res_ptr[N - 1] = res_ptr[N - 1] << cnt
+			       | (res_ptr[0] >> (BITS_PER_MP_LIMB - cnt));
+	      res_ptr[0] <<= cnt;
+	      *expt = QUAD_MIN_EXP - 1 - cnt;
+	    }
+	  else
+	    {
+	      count_leading_zeros (cnt, res_ptr[0]);
+	      if (cnt >= NUM_LEADING_ZEROS)
+		{
+		  res_ptr[N - 1] = res_ptr[0] << (cnt - NUM_LEADING_ZEROS);
+		  res_ptr[0] = 0;
+		}
+	      else
+		{
+		  res_ptr[N - 1] = res_ptr[0] >> (NUM_LEADING_ZEROS - cnt);
+		  res_ptr[0] <<= BITS_PER_MP_LIMB - (NUM_LEADING_ZEROS - cnt);
+		}
+	      *expt = QUAD_MIN_EXP - 1
+		- (BITS_PER_MP_LIMB - NUM_LEADING_ZEROS) - cnt;
+	    }
+#else
+	  int j, k, l;
+
+	  for (j = N - 1; j > 0; j--)
+	    if (res_ptr[j] != 0)
+	      break;
+
+	  count_leading_zeros (cnt, res_ptr[j]);
+	  cnt -= NUM_LEADING_ZEROS;
+	  l = N - 1 - j;
+	  if (cnt < 0)
+	    {
+	      cnt += BITS_PER_MP_LIMB;
+	      l--;
+	    }
+	  if (!cnt)
+	    for (k = N - 1; k >= l; k--)
+	      res_ptr[k] = res_ptr[k-l];
+	  else
+	    {
+	      for (k = N - 1; k > l; k--)
+		res_ptr[k] = res_ptr[k-l] << cnt
+			     | res_ptr[k-l-1] >> (BITS_PER_MP_LIMB - cnt);
+	      res_ptr[k--] = res_ptr[0] << cnt;
+	    }
+
+	  for (; k >= 0; k--)
+	    res_ptr[k] = 0;
+	  *expt = QUAD_MIN_EXP - 1 - l * BITS_PER_MP_LIMB - cnt;
+#endif
+	}
+    }
+  else
+    /* Add the implicit leading one bit for a normalized number.  */
+    res_ptr[N - 1] |= (mp_limb_t) 1 << (QUAD_MANT_DIG - 1
+					- ((N - 1) * BITS_PER_MP_LIMB));
+
+  return N;
+}
--- libc/sysdeps/ieee754/quad/s_isinfq.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/s_isinfq.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,29 @@
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>.
+ * Change for long double by Jakub Jelinek <jj@ultra.linux.cz>
+ * Public domain.
+ */
+
+#if defined(LIBM_SCCS) && !defined(lint)
+static char rcsid[] = "$NetBSD: $";
+#endif
+
+/*
+ * isinfq(x) returns 1 if x is inf, -1 if x is -inf, else 0;
+ * no branching!
+ */
+
+#include <math.h>
+#include <math_private.h>
+
+int
+__isinfq (__float128 x)
+{
+	int64_t hx,lx;
+	GET_LDOUBLE_WORDS64(hx,lx,x);
+	lx |= (hx & 0x7fffffffffffffffLL) ^ 0x7fff000000000000LL;
+	lx |= -lx;
+	return ~(lx >> 63) & (hx >> 62);
+}
+hidden_def (__isinfq)
+weak_alias (__isinfq, isinfq)
--- libc/sysdeps/ieee754/quad/s_isnanq.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/s_isnanq.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,39 @@
+/* s_isnanl.c -- long double version of s_isnan.c.
+ * Conversion to long double by Jakub Jelinek, jj@ultra.linux.cz.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#if defined(LIBM_SCCS) && !defined(lint)
+static char rcsid[] = "$NetBSD: $";
+#endif
+
+/*
+ * isnanl(x) returns 1 is x is nan, else 0;
+ * no branching!
+ */
+
+#include <math.h>
+#include <math_private.h>
+
+int
+__isnanq (__float128 x)
+{
+	int64_t hx,lx;
+	GET_LDOUBLE_WORDS64(hx,lx,x);
+	hx &= 0x7fffffffffffffffLL;
+	hx |= (u_int64_t)(lx|(-lx))>>63;
+	hx = 0x7fff000000000000LL - hx;
+	return (int)((u_int64_t)hx>>63);
+}
+hidden_def (__isnanq)
+weak_alias (__isnanq, isnanq)
--- libc/sysdeps/ieee754/quad/s_signbitq.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/s_signbitq.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,30 @@
+/* Return nonzero value if number is negative.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <math.h>
+#include <math_private.h>
+
+int
+__signbitq (__float128 x)
+{
+  int64_t e;
+
+  GET_LDOUBLE_MSW64 (e, x);
+  return e < 0;
+}
--- libc/sysdeps/ieee754/quad/strtoqd.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/strtoqd.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,28 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define	FLOAT		__float128
+#ifdef USE_WIDE_CHAR
+# define STRTOF		wcstoqd
+# define STRTOF_L	__wcstoqd_l
+#else
+# define STRTOF		strtoqd
+# define STRTOF_L	__strtoqd_l
+#endif
+
+#include <strtod.c>
--- libc/sysdeps/ieee754/quad/strtoqd_l.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/strtoqd_l.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,53 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <math.h>
+#ifdef USE_WIDE_CHAR
+# include <wchar.h>
+#endif
+#include <endian.h>
+#include <ieee754-quad.h>
+#include <bits/huge_valq.h>
+
+/* The actual implementation for all floating point sizes is in strtod.c.
+   These macros tell it to produce the `IEEE quad' version, `strtoq'.  */
+
+#define FLOAT		__float128
+#define FLT		QUAD
+#ifdef USE_WIDE_CHAR
+# define STRTOF		wcstoqd_l
+# define __STRTOF	__wcstoqd_l
+#else
+# define STRTOF		strtoqd_l
+# define __STRTOF	__strtoqd_l
+#endif
+#define MPN2FLOAT	__mpn_construct_float128
+#ifndef FLOAT_HUGE_VAL
+# define FLOAT_HUGE_VAL	HUGE_VALQ
+#endif
+#define SET_MANTISSA(flt, mant) \
+  do { union ieee854_float128 u;					      \
+       u.d = (flt);							      \
+       u.ieee.mantissa0 = 0x8000;					      \
+       u.ieee.mantissa1 = 0;						      \
+       u.ieee.mantissa2 = ((mant) >> 32);	      			      \
+       u.ieee.mantissa3 = (mant) & 0xffffffff;				      \
+       (flt) = u.d;							      \
+  } while (0)
+
+#include <stdlib/strtod_l.c>
--- libc/sysdeps/ieee754/quad/wcstoqd.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/wcstoqd.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,2 @@
+#define USE_WIDE_CHAR 1
+#include <strtoqd.c>
--- libc/sysdeps/ieee754/quad/wcstoqd_l.c.float128	2004-05-05 14:48:55.000000000 -0700
+++ libc/sysdeps/ieee754/quad/wcstoqd_l.c	2004-05-05 14:48:55.000000000 -0700
@@ -0,0 +1,11 @@
+#include <stddef.h>
+#include <xlocale.h>
+
+#define USE_WIDE_CHAR 1
+
+extern unsigned long long int ____wcstoull_l_internal (const wchar_t *,
+						       wchar_t **,
+						       int, int,
+						       __locale_t);
+
+#include <strtoqd_l.c>


More information about the Libc-alpha mailing list