diff mbox

[5/8] float128: Add public _Float128 declarations to libm.

Message ID 1478716859-3246-6-git-send-email-gftg@linux.vnet.ibm.com
State New
Headers show

Commit Message

Gabriel F. T. Gomes Nov. 9, 2016, 6:40 p.m. UTC
From: "Paul E. Murphy" <murphyp@linux.vnet.ibm.com>

This introduces the machine-dependent bits/floatn.h to control
the inclusion of _Float128 ABI.

This leverages the _Generic feature of C11 as __USE_FLOAT128
must imply a test for __STDC_WANT_IEC_60559_TYPES_EXT__
which requires C11 to prevent increasingly complex math
macros for the sake of old (and unsupported?) GCC toolchains.

	* bits/floatn.h: New file.
	* bits/huge_val_flt128.h: New file.
	* math/Makefile (headers): Install bits/floatn.h

	* math/math.h: Define and undefine __FLOATN_TYPE as
	needed for _FloatN types. Add prototypes for _Float128
	if __USE_FLOAT128.

	[__GNUC_PREREQ(6,2)] (signbit): Define as type-generic macro.
	[__USE_FLOAT128] (fpclassify): Use _Generic macro selection when
	a non-GCC compiler is used.
	[__USE_FLOAT128] (signbit): Likewise.
	[__USE_FLOAT128] (isfinite): Likewise.
	[__USE_FLOAT128] (isnan): Likewise.
	[__USE_FLOAT128] (issignaling): Likewise.

	[__USE_FLOAT128] (isinf): This builtin is broken on GCC.
	Explicitly call __isinff128 for _Float128 types, otherwise
	use the builtin.

	[__USE_FLOAT128] (__f128): New macro to apply proper _Float128
	literal suffix depending on compiler version for __USE_GNU
	enabled constants.
	[__USE_FLOAT128] (M_Ef128): New _GNU_SOURCE enabled macro.
	[__USE_FLOAT128] (M_LOG2Ef128): Likewise.
	[__USE_FLOAT128] (M_LOG10Ef128): Likewise.
	[__USE_FLOAT128] (M_LN2f128): Likewise.
	[__USE_FLOAT128] (M_LN10f128): Likewise.
	[__USE_FLOAT128] (M_PIf128): Likewise.
	[__USE_FLOAT128] (M_PI_2f128): Likewise.
	[__USE_FLOAT128] (M_PI_4f128): Likewise.
	[__USE_FLOAT128] (M_1_PIf128): Likewise.
	[__USE_FLOAT128] (M_2_PIf128): Likewise.
	[__USE_FLOAT128] (M_SQRT2f128): Likewise.
	[__USE_FLOAT128] (M_SQRT1_2f128): Likewise.

	* math/mathcalls.h (drem): Only define if __FLOATN_TYPE
	not defined.
	(gamma): Likewise.
	(nexttoward): Likewise.
	(significand): Likewise.
	(pow10): Likewise.
	(scalb): Likewise.
	(finite): Likewise.
	(isinf): Likewise.
	(isnan): Likewise.
---
 bits/floatn.h          |  27 +++++++++++++
 bits/huge_val_flt128.h |  29 ++++++++++++++
 math/Makefile          |   4 +-
 math/bits/cmathcalls.h |   4 +-
 math/bits/mathcalls.h  |  30 +++++++++-----
 math/complex.h         |  27 ++++++++++++-
 math/math.h            | 107 ++++++++++++++++++++++++++++++++++++++++++++++++-
 7 files changed, 213 insertions(+), 15 deletions(-)
 create mode 100644 bits/floatn.h
 create mode 100644 bits/huge_val_flt128.h

Comments

Joseph Myers Nov. 9, 2016, 10:03 p.m. UTC | #1
On Wed, 9 Nov 2016, Gabriel F. T. Gomes wrote:

> This introduces the machine-dependent bits/floatn.h to control
> the inclusion of _Float128 ABI.
> 
> This leverages the _Generic feature of C11 as __USE_FLOAT128
> must imply a test for __STDC_WANT_IEC_60559_TYPES_EXT__
> which requires C11 to prevent increasingly complex math
> macros for the sake of old (and unsupported?) GCC toolchains.

Older tools are supported for compiling code using glibc.  4.7 and later 
are supported for building glibc (I'd hope we can add float128 support on 
x86-64 / x86 without needing to increase the minimum GCC version for 
building glibc there).

> +/* Defined if the compiler supports the _Float128 (and __float128) type.  */
> +#define __USE_FLOAT128 0

Support for _Float128 and __float128 are distinct things.  GCC 7 supports 
_Float128 on lots of platforms where long double has that format, but not 
__float128.

> +/* Defined if the runtime supports _Float128.  */
> +#define __HAVE_FLOAT128 0

You appear to be using __USE_FLOAT128 conditionals on things assuming 
library facilities to be present.

You need to be very careful in designing exactly what macros are needed to 
specify the available types and their properties, and in writing the 
comments documenting the design.

> +#if __GNUC_PREREQ (7, 0)
> +# define HUGE_VAL_F128	(__builtin_huge_valf128 ())
> +#elif __GNUC_PREREQ (6,2)

Missing space after comma.

> +# define HUGE_VAL_F128	(__builtin_huge_valq ())

My inclination would be to localize the workarounds for old compilers to 
one place, that defines __builtin_huge_valf128 as a macro.  And the choice 
of 6.2 as version here is questionable.  A generic header here should not 
have architecture-specific version conditionals.  For x86, GCC supports 
__builtin_huge_valq long before 6.2 - but even 6.2 doesn't support it in 
static initializers for x86.  So the definition casting HUGE_VAL is safer 
for old compilers.  That is, a bits/floatn-compat.h header could do

#if !__GNUC_PREREQ (7, 0)
# define __builtin_huge_valf128() ((_Float128) __builtin_huge_val ())
#endif

and similarly for defining _Float128 to __float128 and defining other 
__builtin_* macros as needed.  Of course that header would only be needed 
for certain architectures.

> @@ -55,6 +59,10 @@ __BEGIN_DECLS
>  # define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
>  #endif
>  
> +#if __USE_FLOAT128
> +# define CMPLXF128(x, y) __builtin_complex ((__float128) (x), (__float128) (y))
> +#endif

CMPLXF128 is only reserved when TS 18661-3 names are defined.  That is, 
all function or macro definitions for the new types need to be conditional 
on an __GLIBC_USE conditional for TS 18661-3 *and* on the particular type 
in question being supported.  Whereas type-generic macros in <math.h>, as 
opposed to those in <tgmath.h>, should support the new types even if the 
__GLIBC_USE conditional for TS 18661-3 is false (meaning you might need to 
split <bits/mathcalls.h> so you can declare e.g. __signbitf128 when not 
declaring sinf128).

> +#if __USE_FLOAT128
> +# ifndef _Mfloat128_
> +#  define _Mfloat128_		_Float128
> +# endif
> +/* GCC < 7 requires extra convincing to expose a complex float128 type.  */
> +# ifdef __CFLOAT128
> +#  undef _Mdouble_complex_
> +#  define _Mdouble_complex_	__CFLOAT128
> +# endif
> +# define _Mdouble_ 		_Mfloat128_
> +# define __MATH_PRECNAME(name)	name##f128
> +# include <bits/cmathcalls.h>

Likewise.

> +#if __USE_FLOAT128
> +# include <bits/huge_val_flt128.h>
> +#endif

Likewise.

> +/* Include the file of declarations again, this time using `_Float128'
> +   instead of `double' and appending f128 to each function name.  */
> +
> +#if __USE_FLOAT128
> +#ifndef _Mfloat128_
> +# define _Mfloat128_		_Float128
> +#endif
> +#define __FLOATN_TYPE		1
> +#define _Mdouble_		_Mfloat128_
> +#define __MATH_PRECNAME(name,r) name##f128##r
> +#define __MATH_DECLARING_DOUBLE  0
> +#define _Mdouble_BEGIN_NAMESPACE __BEGIN_NAMESPACE_C99
> +#define _Mdouble_END_NAMESPACE   __END_NAMESPACE_C99
> +#include <bits/mathcalls.h>

Likewise.

>  /* Return nonzero value if sign of X is negative.  */
> -# if __GNUC_PREREQ (4,0)
> +# if __GNUC_PREREQ (6,2)
> +#  define signbit(x) __builtin_signbit (x)

6.2 isn't the right version.  __builtin_signbit is type-generic in GCC 
from before GCC 6 branched, so use 6.0.

> @@ -299,8 +363,20 @@ enum
>  # endif
>  
>  /* Return nonzero value if X is positive or negative infinity.  */
> -# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
> +# if __USE_FLOAT128 && !defined __SUPPORT_SNAN__ && defined __GNUC__
> +/* __builtin_isinf_sign is broken for float128.  */

Only broken before GCC 7.

> +#if __USE_FLOAT128

__USE_GNU conditional needed as well.
diff mbox

Patch

diff --git a/bits/floatn.h b/bits/floatn.h
new file mode 100644
index 0000000..57db3a6
--- /dev/null
+++ b/bits/floatn.h
@@ -0,0 +1,27 @@ 
+/* Macros to control TS 18661-3 glibc features.
+   Copyright (C) 2016 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Defined if the compiler supports the _Float128 (and __float128) type.  */
+#define __USE_FLOAT128 0
+
+/* Defined if the runtime supports _Float128.  */
+#define __HAVE_FLOAT128 0
+
+/* Defined for GCC versions which support the __float128 type, but not
+   _Complex __float128.  This resolves to a complex binary128 type.  */
+#undef __CFLOAT128
diff --git a/bits/huge_val_flt128.h b/bits/huge_val_flt128.h
new file mode 100644
index 0000000..562d026
--- /dev/null
+++ b/bits/huge_val_flt128.h
@@ -0,0 +1,29 @@ 
+/* Default `HUGE_VAL_F128' constant.
+   Copyright (C) 2016 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _MATH_H
+# error "Never use <bits/huge_val_flt128.h> directly; include <math.h> instead."
+#endif
+
+#if __GNUC_PREREQ (7, 0)
+# define HUGE_VAL_F128	(__builtin_huge_valf128 ())
+#elif __GNUC_PREREQ (6,2)
+# define HUGE_VAL_F128	(__builtin_huge_valq ())
+#else
+# define HUGE_VAL_F128	((_Float128) HUGE_VAL)
+#endif
diff --git a/math/Makefile b/math/Makefile
index 37e7ea0..f6adf09 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -27,7 +27,9 @@  headers		:= math.h bits/mathcalls.h bits/mathinline.h bits/huge_val.h \
 		   fpu_control.h complex.h bits/cmathcalls.h fenv.h \
 		   bits/fenv.h bits/fenvinline.h bits/mathdef.h tgmath.h \
 		   bits/math-finite.h bits/math-vector.h \
-		   bits/libm-simd-decl-stubs.h bits/iscanonical.h
+		   bits/libm-simd-decl-stubs.h bits/iscanonical.h \
+		   bits/huge_val_flt128.h \
+		   bits/floatn.h
 
 # FPU support code.
 aux		:= setfpucw fpu_control
diff --git a/math/bits/cmathcalls.h b/math/bits/cmathcalls.h
index e02707e..c94976b 100644
--- a/math/bits/cmathcalls.h
+++ b/math/bits/cmathcalls.h
@@ -44,7 +44,9 @@ 
 #error "Never use <bits/cmathcalls.h> directly; include <complex.h> instead."
 #endif
 
-#define _Mdouble_complex_ _Mdouble_ _Complex
+#ifndef _Mdouble_complex_
+# define _Mdouble_complex_ _Mdouble_ _Complex
+#endif
 
 
 /* Trigonometric functions.  */
diff --git a/math/bits/mathcalls.h b/math/bits/mathcalls.h
index 2fd1d28..8a31aea 100644
--- a/math/bits/mathcalls.h
+++ b/math/bits/mathcalls.h
@@ -121,7 +121,9 @@  __MATHCALL (exp10,, (_Mdouble_ __x));
 #endif
 #ifdef __USE_GNU
 /* Another name occasionally used.  */
+# ifndef __FLOATN_TYPE
 __MATHCALL (pow10,, (_Mdouble_ __x));
+# endif
 #endif
 
 #if defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
@@ -198,14 +200,16 @@  __MATHDECL_1 (int,__finite,, (_Mdouble_ __value)) __attribute__ ((__const__));
 _Mdouble_END_NAMESPACE
 
 #ifdef __USE_MISC
-# if (!defined __cplusplus \
-      || __cplusplus < 201103L /* isinf conflicts with C++11.  */ \
-      || __MATH_DECLARING_DOUBLE == 0) /* isinff or isinfl don't.  */
+# if ((!defined __cplusplus \
+       || __cplusplus < 201103L /* isinf conflicts with C++11.  */ \
+       || __MATH_DECLARING_DOUBLE == 0)) /* isinff or isinfl don't.  */ \
+      && !defined __FLOATN_TYPE
 /* Return 0 if VALUE is finite or NaN, +1 if it
    is +Infinity, -1 if it is -Infinity.  */
 __MATHDECL_1 (int,isinf,, (_Mdouble_ __value)) __attribute__ ((__const__));
 # endif
 
+# ifndef __FLOATN_TYPE
 /* Return nonzero if VALUE is finite and not NaN.  */
 __MATHDECL_1 (int,finite,, (_Mdouble_ __value)) __attribute__ ((__const__));
 
@@ -215,6 +219,8 @@  __MATHCALL (drem,, (_Mdouble_ __x, _Mdouble_ __y));
 
 /* Return the fractional part of X after dividing out `ilogb (X)'.  */
 __MATHCALL (significand,, (_Mdouble_ __x));
+# endif
+
 #endif /* Use misc.  */
 
 #ifdef __USE_ISOC99
@@ -236,9 +242,10 @@  __END_NAMESPACE_C99
 __MATHDECL_1 (int,__isnan,, (_Mdouble_ __value)) __attribute__ ((__const__));
 
 #if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
-# if (!defined __cplusplus \
-      || __cplusplus < 201103L /* isnan conflicts with C++11.  */ \
-      || __MATH_DECLARING_DOUBLE == 0) /* isnanf or isnanl don't.  */
+# if ((!defined __cplusplus \
+       || __cplusplus < 201103L /* isnan conflicts with C++11.  */ \
+       || __MATH_DECLARING_DOUBLE == 0)) /* isnanf or isnanl don't.  */ \
+      && !defined __FLOATN_TYPE
 /* Return nonzero if VALUE is not a number.  */
 __MATHDECL_1 (int,isnan,, (_Mdouble_ __value)) __attribute__ ((__const__));
 # endif
@@ -272,8 +279,10 @@  __END_NAMESPACE_C99
 #endif
 
 #if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
+# ifndef __FLOATN_TYPE
 /* Obsolete alias for `lgamma'.  */
 __MATHCALL (gamma,, (_Mdouble_));
+# endif
 #endif
 
 #ifdef __USE_MISC
@@ -292,7 +301,7 @@  __MATHCALL (rint,, (_Mdouble_ __x));
 
 /* Return X + epsilon if X < Y, X - epsilon if X > Y.  */
 __MATHCALLX (nextafter,, (_Mdouble_ __x, _Mdouble_ __y), (__const__));
-# if defined __USE_ISOC99 && !defined __LDBL_COMPAT
+# if defined __USE_ISOC99 && !defined __LDBL_COMPAT && !defined __FLOATN_TYPE
 __MATHCALLX (nexttoward,, (_Mdouble_ __x, long double __y), (__const__));
 # endif
 
@@ -402,9 +411,10 @@  __MATHDECL_1 (int, canonicalize,, (_Mdouble_ *__cx, const _Mdouble_ *__x));
 __MATHCALL (getpayload,, (const _Mdouble_ *__x));
 #endif
 
-#if defined __USE_MISC || (defined __USE_XOPEN_EXTENDED \
-			   && __MATH_DECLARING_DOUBLE	\
-			   && !defined __USE_XOPEN2K8)
+#if (defined __USE_MISC || (defined __USE_XOPEN_EXTENDED \
+			    && __MATH_DECLARING_DOUBLE	  \
+			    && !defined __USE_XOPEN2K8))  \
+     && !defined __FLOATN_TYPE
 /* Return X times (2 to the Nth power).  */
 __MATHCALL (scalb,, (_Mdouble_ __x, _Mdouble_ __n));
 #endif
diff --git a/math/complex.h b/math/complex.h
index 331975e..4adc742 100644
--- a/math/complex.h
+++ b/math/complex.h
@@ -22,11 +22,15 @@ 
 #ifndef _COMPLEX_H
 #define _COMPLEX_H	1
 
-#include <features.h>
+#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION
+#include <bits/libc-header-start.h>
 
 /* Get general and ISO C99 specific information.  */
 #include <bits/mathdef.h>
 
+/* Gather machine-dependent _FloatN type support.  */
+#include <bits/floatn.h>
+
 __BEGIN_DECLS
 
 /* We might need to add support for more compilers here.  But since ISO
@@ -55,6 +59,10 @@  __BEGIN_DECLS
 # define CMPLXL(x, y) __builtin_complex ((long double) (x), (long double) (y))
 #endif
 
+#if __USE_FLOAT128
+# define CMPLXF128(x, y) __builtin_complex ((__float128) (x), (__float128) (y))
+#endif
+
 /* The file <bits/cmathcalls.h> contains the prototypes for all the
    actual math functions.  These macros are used for those prototypes,
    so we can easily declare each function as both `name' and `__name',
@@ -84,6 +92,23 @@  __BEGIN_DECLS
 #undef	_Mdouble_
 #undef	__MATH_PRECNAME
 
+#if __USE_FLOAT128
+# ifndef _Mfloat128_
+#  define _Mfloat128_		_Float128
+# endif
+/* GCC < 7 requires extra convincing to expose a complex float128 type.  */
+# ifdef __CFLOAT128
+#  undef _Mdouble_complex_
+#  define _Mdouble_complex_	__CFLOAT128
+# endif
+# define _Mdouble_ 		_Mfloat128_
+# define __MATH_PRECNAME(name)	name##f128
+# include <bits/cmathcalls.h>
+# undef	_Mdouble_
+# undef	__MATH_PRECNAME
+# undef	_Mdouble_complex_
+#endif
+
 /* And the long double versions.  It is non-critical to define them
    here unconditionally since `long double' is required in ISO C99.  */
 #if !(defined __NO_LONG_DOUBLE_MATH && defined _LIBC)	\
diff --git a/math/math.h b/math/math.h
index 70d9b86..87eb19d 100644
--- a/math/math.h
+++ b/math/math.h
@@ -31,9 +31,17 @@  __BEGIN_DECLS
 /* Get machine-dependent vector math functions declarations.  */
 #include <bits/math-vector.h>
 
+/* Gather machine dependent type support.  */
+#include <bits/floatn.h>
+
 /* Get machine-dependent HUGE_VAL value (returned on overflow).
    On all IEEE754 machines, this is +Infinity.  */
 #include <bits/huge_val.h>
+
+#if __USE_FLOAT128
+# include <bits/huge_val_flt128.h>
+#endif
+
 #ifdef __USE_ISOC99
 # include <bits/huge_valf.h>
 # include <bits/huge_vall.h>
@@ -106,6 +114,7 @@  __BEGIN_DECLS
   extern type __MATH_PRECNAME(function,suffix) args __THROW
 
 #define _Mdouble_		double
+#undef __FLOATN_TYPE
 #define __MATH_PRECNAME(name,r)	__CONCAT(name,r)
 #define __MATH_DECLARING_DOUBLE  1
 #define _Mdouble_BEGIN_NAMESPACE __BEGIN_NAMESPACE_STD
@@ -126,6 +135,7 @@  __BEGIN_DECLS
 # ifndef _Mfloat_
 #  define _Mfloat_		float
 # endif
+# undef __FLOATN_TYPE
 # define _Mdouble_		_Mfloat_
 # define __MATH_PRECNAME(name,r) name##f##r
 # define __MATH_DECLARING_DOUBLE  0
@@ -172,6 +182,7 @@  extern long double __REDIRECT_NTH (nexttowardl,
 #  ifndef _Mlong_double_
 #   define _Mlong_double_	long double
 #  endif
+#  undef __FLOATN_TYPE
 #  define _Mdouble_		_Mlong_double_
 #  define __MATH_PRECNAME(name,r) name##l##r
 #  define __MATH_DECLARING_DOUBLE  0
@@ -188,6 +199,29 @@  extern long double __REDIRECT_NTH (nexttowardl,
 # endif /* !(__NO_LONG_DOUBLE_MATH && _LIBC) || __LDBL_COMPAT */
 
 #endif	/* Use ISO C99.  */
+
+/* Include the file of declarations again, this time using `_Float128'
+   instead of `double' and appending f128 to each function name.  */
+
+#if __USE_FLOAT128
+#ifndef _Mfloat128_
+# define _Mfloat128_		_Float128
+#endif
+#define __FLOATN_TYPE		1
+#define _Mdouble_		_Mfloat128_
+#define __MATH_PRECNAME(name,r) name##f128##r
+#define __MATH_DECLARING_DOUBLE  0
+#define _Mdouble_BEGIN_NAMESPACE __BEGIN_NAMESPACE_C99
+#define _Mdouble_END_NAMESPACE   __END_NAMESPACE_C99
+#include <bits/mathcalls.h>
+#undef __FLOATN_TYPE
+#undef	_Mdouble_
+#undef _Mdouble_BEGIN_NAMESPACE
+#undef _Mdouble_END_NAMESPACE
+#undef	__MATH_PRECNAME
+#undef __MATH_DECLARING_DOUBLE
+#endif /* Use _Float128.  */
+
 #undef	__MATHDECL_1
 #undef	__MATHDECL
 #undef	__MATHCALL
@@ -231,6 +265,13 @@  enum
      && !defined __OPTIMIZE_SIZE__
 #  define fpclassify(x) __builtin_fpclassify (FP_NAN, FP_INFINITE,	      \
      FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x)
+# elif __USE_FLOAT128
+#  define fpclassify(x)		      \
+    _Generic ((x),		      \
+	_Float128: __fpclassifyf128,  \
+	long double: __fpclassifyl,   \
+	float: __fpclassifyf,	      \
+	default: __fpclassify)(x)
 # elif defined __NO_LONG_DOUBLE_MATH
 #  define fpclassify(x) \
      (sizeof (x) == sizeof (float) ? __fpclassifyf (x) : __fpclassify (x))
@@ -243,7 +284,16 @@  enum
 # endif
 
 /* Return nonzero value if sign of X is negative.  */
-# if __GNUC_PREREQ (4,0)
+# if __GNUC_PREREQ (6,2)
+#  define signbit(x) __builtin_signbit (x)
+# elif __USE_FLOAT128
+#  define signbit(x)		  \
+    _Generic ((x),		  \
+	_Float128: __signbitf128, \
+	long double: __signbitl,  \
+	float: __signbitf,	  \
+	default: __signbit)(x)
+# elif __GNUC_PREREQ (4,0)
 #  define signbit(x) \
      (sizeof (x) == sizeof (float)                                            \
       ? __builtin_signbitf (x)                                                        \
@@ -265,6 +315,13 @@  enum
 /* Return nonzero value if X is not +-Inf or NaN.  */
 # if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
 #  define isfinite(x) __builtin_isfinite (x)
+# elif __USE_FLOAT128
+#  define isfinite(x)		  \
+    _Generic ((x),		  \
+	_Float128: __finitef128,  \
+	long double: __finitel,	  \
+	float: __finitef,	  \
+	default: __finite) (x)
 # elif defined __NO_LONG_DOUBLE_MATH
 #  define isfinite(x) \
      (sizeof (x) == sizeof (float) ? __finitef (x) : __finite (x))
@@ -287,6 +344,13 @@  enum
    we already have this functions `__isnan' and it is faster.  */
 # if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
 #  define isnan(x) __builtin_isnan (x)
+# elif __USE_FLOAT128
+#  define isnan(x)		  \
+    _Generic ((x),		  \
+	_Float128: __isnanf128,	  \
+	long double: __isnanl,	  \
+	float: __isnanf,	  \
+	default: __isnan) (x)
 # elif defined __NO_LONG_DOUBLE_MATH
 #  define isnan(x) \
      (sizeof (x) == sizeof (float) ? __isnanf (x) : __isnan (x))
@@ -299,8 +363,20 @@  enum
 # endif
 
 /* Return nonzero value if X is positive or negative infinity.  */
-# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
+# if __USE_FLOAT128 && !defined __SUPPORT_SNAN__ && defined __GNUC__
+/* __builtin_isinf_sign is broken for float128.  */
+#  define isinf(x) \
+     (__builtin_types_compatible_p (typeof (x), _Float128) \
+      ? __isinff128 (x) : __builtin_isinf_sign (x))
+# elif __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__
 #  define isinf(x) __builtin_isinf_sign (x)
+# elif __USE_FLOAT128
+#  define isinf(x)		  \
+    _Generic ((x),		  \
+	_Float128: __isinff128,	  \
+	long double: __isinfl,	  \
+	float: __isinff,	  \
+	default: __isinf) (x)
 # elif defined __NO_LONG_DOUBLE_MATH
 #  define isinf(x) \
      (sizeof (x) == sizeof (float) ? __isinff (x) : __isinf (x))
@@ -332,6 +408,13 @@  enum
 # ifdef __NO_LONG_DOUBLE_MATH
 #  define issignaling(x) \
      (sizeof (x) == sizeof (float) ? __issignalingf (x) : __issignaling (x))
+# elif __USE_FLOAT128
+#  define issignaling(x) \
+    _Generic((x),			\
+	_Float128: __issignalingf128,	\
+	long double: __issignalingl,	\
+	float: __issignalingf,		\
+	default: __issignaling)(x)
 # else
 #  define issignaling(x) \
      (sizeof (x) == sizeof (float)					      \
@@ -467,6 +550,26 @@  extern int matherr (struct exception *__exc);
 # define M_SQRT1_2l	0.707106781186547524400844362104849039L /* 1/sqrt(2) */
 #endif
 
+#if __USE_FLOAT128
+# if defined __GNUC__ && !__GNUC_PREREQ (7,0)
+#  define __f128(x) x ## q
+# else
+#  define __f128(x) x ## f128
+# endif
+# define M_Ef128	__f128 (2.718281828459045235360287471352662498) /* e */
+# define M_LOG2Ef128	__f128 (1.442695040888963407359924681001892137) /* log_2 e */
+# define M_LOG10Ef128	__f128 (0.434294481903251827651128918916605082) /* log_10 e */
+# define M_LN2f128	__f128 (0.693147180559945309417232121458176568) /* log_e 2 */
+# define M_LN10f128	__f128 (2.302585092994045684017991454684364208) /* log_e 10 */
+# define M_PIf128	__f128 (3.141592653589793238462643383279502884) /* pi */
+# define M_PI_2f128	__f128 (1.570796326794896619231321691639751442) /* pi/2 */
+# define M_PI_4f128	__f128 (0.785398163397448309615660845819875721) /* pi/4 */
+# define M_1_PIf128	__f128 (0.318309886183790671537767526745028724) /* 1/pi */
+# define M_2_PIf128	__f128 (0.636619772367581343075535053490057448) /* 2/pi */
+# define M_2_SQRTPIf128	__f128 (1.128379167095512573896158903121545172) /* 2/sqrt(pi) */
+# define M_SQRT2f128	__f128 (1.414213562373095048801688724209698079) /* sqrt(2) */
+# define M_SQRT1_2f128	__f128 (0.707106781186547524400844362104849039) /* 1/sqrt(2) */
+#endif
 
 /* When compiling in strict ISO C compatible mode we must not use the
    inline functions since they, among other things, do not set the