diff mbox

[rs6000] Add minimum __float128 built-in support required for glibc

Message ID alpine.DEB.2.20.1606222315140.22324@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers June 22, 2016, 11:27 p.m. UTC
On Wed, 22 Jun 2016, Bill Schmidt wrote:

> Hi Joseph,
> 
> That's indeed preferable for the long term -- given how close we are to the 
> cutoff for 6.2, though, I'm worried about adding any new dependencies for 
> getting this upstream.  I'd suggest that we go ahead with reviewing this 
> patch in the short term, and I'll be happy to work with you later on getting
> the impedance matching right when they become arch-neutral.

The architecture-independent built-in functions really aren't hard.  See 
this patch, on top of my main _FloatN / _FloatNx patch.  (Not written up 
or fully regression-tested, and I want to add more test coverage, but it 
seems to work.)  To keep this patch minimal I didn't include updates to a 
few case statements only needed for optimization, e.g. in 
tree_call_nonnegative_warnv_p, but when those are changed you get 
optimizations automatically for these functions that would be harder to 
get with anything architecture-specific.

Regarding your patch:

(a) for GCC 6 (supposing my patch is used for trunk), it's missing 
documentation for the new functions (this patch has documentation for the 
architecture-independent functions);

(b) for trunk, having an insn pattern infkf1 for a built-in function that 
loads a constant is not appropriate (other insn patterns to optimize the 
architecture-independent built-in functions may well be appropriate).  
Rather, if there is a particularly efficient way of generating code to 
load a certain constant, the back end should be set up to use that way 
whenever that constant occurs (more generally, whenever any constant to 
which that efficient way applies occurs) - including for example when it 
occurs from folding arithmetic, say (__float128) __builtin_inff (), not 
just from __builtin_inff128 ().

Comments

Bill Schmidt June 23, 2016, 1:10 a.m. UTC | #1
> On Jun 22, 2016, at 6:27 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> On Wed, 22 Jun 2016, Bill Schmidt wrote:
> 
>> Hi Joseph,
>> 
>> That's indeed preferable for the long term -- given how close we are to the 
>> cutoff for 6.2, though, I'm worried about adding any new dependencies for 
>> getting this upstream.  I'd suggest that we go ahead with reviewing this 
>> patch in the short term, and I'll be happy to work with you later on getting
>> the impedance matching right when they become arch-neutral.
> 
> The architecture-independent built-in functions really aren't hard.  See 
> this patch, on top of my main _FloatN / _FloatNx patch.  (Not written up 
> or fully regression-tested, and I want to add more test coverage, but it 
> seems to work.)  To keep this patch minimal I didn't include updates to a 
> few case statements only needed for optimization, e.g. in 
> tree_call_nonnegative_warnv_p, but when those are changed you get 
> optimizations automatically for these functions that would be harder to 
> get with anything architecture-specific.

I understand that this is what we want for GCC 7.  My current concern is to
get my patch included in GCC 6.2, where I can't be polluting common code.
To get it accepted there, I first need this code approved in mainline.  So I
am quite willing to move to the architecture-independent ones later, but
for now I don't see that I have any choice but to seek approval for the
purely arch-dependent one.

> 
> Regarding your patch:
> 
> (a) for GCC 6 (supposing my patch is used for trunk), it's missing 
> documentation for the new functions (this patch has documentation for the 
> architecture-independent functions);

A very good point -- I totally forgot about this, and will have to add it.

> 
> (b) for trunk, having an insn pattern infkf1 for a built-in function that 
> loads a constant is not appropriate (other insn patterns to optimize the 
> architecture-independent built-in functions may well be appropriate).  
> Rather, if there is a particularly efficient way of generating code to 
> load a certain constant, the back end should be set up to use that way 
> whenever that constant occurs (more generally, whenever any constant to 
> which that efficient way applies occurs) - including for example when it 
> occurs from folding arithmetic, say (__float128) __builtin_inff (), not 
> just from __builtin_inff128 ().

The fact that I hook this built-in directly to a pattern named infkf1
doesn't seem to preclude anything you suggest.  I named it this way
on the off-chance that inf<m>1 becomes a standard pattern in the
future, in which case I want to generate this constant.  We can 
always use gen_infkf1 to reuse this code in any other context.  I'm
not understanding your objection.

Thanks,
Bill
Joseph Myers June 23, 2016, 11:44 a.m. UTC | #2
On Wed, 22 Jun 2016, Bill Schmidt wrote:

> I understand that this is what we want for GCC 7.  My current concern is to
> get my patch included in GCC 6.2, where I can't be polluting common code.
> To get it accepted there, I first need this code approved in mainline.  So I
> am quite willing to move to the architecture-independent ones later, but
> for now I don't see that I have any choice but to seek approval for the
> purely arch-dependent one.

I don't think it's sensible to choose implementation approaches on 
mainline based on possible backports.

It seems clear to me that the architecture-independent approach is the 
right one for mainline.  This may mean the backport has some 
architecture-specific code that's not on mainline (along with code, to 
optimize copysign/fabs expansion, that may be relevant in both places), 
but that shouldn't influence the choice of how to do things on mainline.

It looks rather like this proposed code would not in fact result in 
__builtin_inff128 or __builtin_huge_valf128 suitable for glibc use - 
there's no folding support for them so they wouldn't be usable in static 
initializers.  (This can be worked around, as would be necessary anyway 
for __float128 support in glibc for x86_64 with existing GCC releases - 
some internal header would define __builtin_inff128() to ((__float128) 
__builtin_inf ()) for older compilers.)

Until the glibc support is actually tested, reviewed and fully functional, 
it would not surprise me at all if there are other back-end bugs in GCC 6 
that need fixing for it to be usable to build or use such support in 
glibc, or other features needed that we haven't realised are needed.

> The fact that I hook this built-in directly to a pattern named infkf1
> doesn't seem to preclude anything you suggest.  I named it this way
> on the off-chance that inf<m>1 becomes a standard pattern in the
> future, in which case I want to generate this constant.  We can 
> always use gen_infkf1 to reuse this code in any other context.  I'm
> not understanding your objection.

That expander pattern is not useful given a target-independent built-in 
__builtin_inff128, since it will never be used except by a built-in 
function specifically associated with it.

I don't know what code will be generated for a use of _Float128 infinity, 
from the target-independent code - or, right now, for a use of 
(__float128) __builtin_inf ().  But if it's not the code you want, any 
reasonable fix would not be restricted to the case where __builtin_inff128 
() is used - it would work equally well for any case where that constant 
bit-pattern is wanted in VSX registers.
Bill Schmidt June 23, 2016, 12:48 p.m. UTC | #3
> On Jun 22, 2016, at 8:10 PM, Bill Schmidt <wschmidt@linux.vnet.ibm.com> wrote:
> 
>> On Jun 22, 2016, at 6:27 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>> 
>> (b) for trunk, having an insn pattern infkf1 for a built-in function that 
>> loads a constant is not appropriate (other insn patterns to optimize the 
>> architecture-independent built-in functions may well be appropriate).  
>> Rather, if there is a particularly efficient way of generating code to 
>> load a certain constant, the back end should be set up to use that way 
>> whenever that constant occurs (more generally, whenever any constant to 
>> which that efficient way applies occurs) - including for example when it 
>> occurs from folding arithmetic, say (__float128) __builtin_inff (), not 
>> just from __builtin_inff128 ().
> 
> The fact that I hook this built-in directly to a pattern named infkf1
> doesn't seem to preclude anything you suggest.  I named it this way
> on the off-chance that inf<m>1 becomes a standard pattern in the
> future, in which case I want to generate this constant.  We can 
> always use gen_infkf1 to reuse this code in any other context.  I'm
> not understanding your objection.

Though perhaps your point is the specific use of KF here, which is
inconsistent and should be fixed.  The mode should be "whichever of
TF and KF is IEEE-128" as elsewhere.  I'll fix that.  Probably this
pattern should be moved over to rs6000.md also, where the fabs and
copysign support are.

Bill

> 
> Thanks,
> Bill
Richard Sandiford June 27, 2016, 5:41 p.m. UTC | #4
Joseph Myers <joseph@codesourcery.com> writes:
> On Wed, 22 Jun 2016, Bill Schmidt wrote:
>> The fact that I hook this built-in directly to a pattern named infkf1
>> doesn't seem to preclude anything you suggest.  I named it this way
>> on the off-chance that inf<m>1 becomes a standard pattern in the
>> future, in which case I want to generate this constant.  We can 
>> always use gen_infkf1 to reuse this code in any other context.  I'm
>> not understanding your objection.
>
> That expander pattern is not useful given a target-independent built-in 
> __builtin_inff128, since it will never be used except by a built-in 
> function specifically associated with it.
>
> I don't know what code will be generated for a use of _Float128 infinity, 
> from the target-independent code - or, right now, for a use of 
> (__float128) __builtin_inf ().  But if it's not the code you want, any 
> reasonable fix would not be restricted to the case where __builtin_inff128 
> () is used - it would work equally well for any case where that constant 
> bit-pattern is wanted in VSX registers.

Yeah, I don't think we should have named patterns to generate constants.
We should send the constant through the normal move patterns and make
the expander or move define_insns handle them appropriately.

Thanks,
Richard
Bill Schmidt June 27, 2016, 5:42 p.m. UTC | #5
> On Jun 27, 2016, at 12:41 PM, Richard Sandiford <rdsandiford@googlemail.com> wrote:
> 
> Joseph Myers <joseph@codesourcery.com> writes:
>> On Wed, 22 Jun 2016, Bill Schmidt wrote:
>>> The fact that I hook this built-in directly to a pattern named infkf1
>>> doesn't seem to preclude anything you suggest.  I named it this way
>>> on the off-chance that inf<m>1 becomes a standard pattern in the
>>> future, in which case I want to generate this constant.  We can 
>>> always use gen_infkf1 to reuse this code in any other context.  I'm
>>> not understanding your objection.
>> 
>> That expander pattern is not useful given a target-independent built-in 
>> __builtin_inff128, since it will never be used except by a built-in 
>> function specifically associated with it.
>> 
>> I don't know what code will be generated for a use of _Float128 infinity, 
>> from the target-independent code - or, right now, for a use of 
>> (__float128) __builtin_inf ().  But if it's not the code you want, any 
>> reasonable fix would not be restricted to the case where __builtin_inff128 
>> () is used - it would work equally well for any case where that constant 
>> bit-pattern is wanted in VSX registers.
> 
> Yeah, I don't think we should have named patterns to generate constants.
> We should send the constant through the normal move patterns and make
> the expander or move define_insns handle them appropriately.

Agreed.  We'll plan on working the various interesting constants into the handling of the move insns.

Bill

> 
> Thanks,
> Richard
>
diff mbox

Patch

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index 7fab9f8..468313c4 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -76,6 +76,27 @@  DEF_PRIMITIVE_TYPE (BT_UNWINDWORD, (*lang_hooks.types.type_for_mode)
 DEF_PRIMITIVE_TYPE (BT_FLOAT, float_type_node)
 DEF_PRIMITIVE_TYPE (BT_DOUBLE, double_type_node)
 DEF_PRIMITIVE_TYPE (BT_LONGDOUBLE, long_double_type_node)
+DEF_PRIMITIVE_TYPE (BT_FLOAT16, (float16_type_node
+				 ? float16_type_node
+				 : error_mark_node))
+DEF_PRIMITIVE_TYPE (BT_FLOAT32, (float32_type_node
+				 ? float32_type_node
+				 : error_mark_node))
+DEF_PRIMITIVE_TYPE (BT_FLOAT64, (float64_type_node
+				 ? float64_type_node
+				 : error_mark_node))
+DEF_PRIMITIVE_TYPE (BT_FLOAT128, (float128_type_node
+				  ? float128_type_node
+				  : error_mark_node))
+DEF_PRIMITIVE_TYPE (BT_FLOAT32X, (float32x_type_node
+				  ? float32x_type_node
+				  : error_mark_node))
+DEF_PRIMITIVE_TYPE (BT_FLOAT64X, (float64x_type_node
+				  ? float64x_type_node
+				  : error_mark_node))
+DEF_PRIMITIVE_TYPE (BT_FLOAT128X, (float128x_type_node
+				   ? float128x_type_node
+				   : error_mark_node))
 DEF_PRIMITIVE_TYPE (BT_COMPLEX_FLOAT, complex_float_type_node)
 DEF_PRIMITIVE_TYPE (BT_COMPLEX_DOUBLE, complex_double_type_node)
 DEF_PRIMITIVE_TYPE (BT_COMPLEX_LONGDOUBLE, complex_long_double_type_node)
@@ -146,6 +167,13 @@  DEF_FUNCTION_TYPE_0 (BT_FN_DOUBLE, BT_DOUBLE)
    distinguish it from two types in sequence, "long" followed by
    "double".  */
 DEF_FUNCTION_TYPE_0 (BT_FN_LONGDOUBLE, BT_LONGDOUBLE)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT16, BT_FLOAT16)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT32, BT_FLOAT32)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT64, BT_FLOAT64)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT128, BT_FLOAT128)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT32X, BT_FLOAT32X)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT64X, BT_FLOAT64X)
+DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT128X, BT_FLOAT128X)
 DEF_FUNCTION_TYPE_0 (BT_FN_DFLOAT32, BT_DFLOAT32)
 DEF_FUNCTION_TYPE_0 (BT_FN_DFLOAT64, BT_DFLOAT64)
 DEF_FUNCTION_TYPE_0 (BT_FN_DFLOAT128, BT_DFLOAT128)
@@ -157,6 +185,13 @@  DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT_FLOAT, BT_FLOAT, BT_FLOAT)
 DEF_FUNCTION_TYPE_1 (BT_FN_DOUBLE_DOUBLE, BT_DOUBLE, BT_DOUBLE)
 DEF_FUNCTION_TYPE_1 (BT_FN_LONGDOUBLE_LONGDOUBLE,
 		     BT_LONGDOUBLE, BT_LONGDOUBLE)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT16_FLOAT16, BT_FLOAT16, BT_FLOAT16)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT32_FLOAT32, BT_FLOAT32, BT_FLOAT32)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT64_FLOAT64, BT_FLOAT64, BT_FLOAT64)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT128_FLOAT128, BT_FLOAT128, BT_FLOAT128)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT32X_FLOAT32X, BT_FLOAT32X, BT_FLOAT32X)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT64X_FLOAT64X, BT_FLOAT64X, BT_FLOAT64X)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT128X_FLOAT128X, BT_FLOAT128X, BT_FLOAT128X)
 DEF_FUNCTION_TYPE_1 (BT_FN_COMPLEX_FLOAT_COMPLEX_FLOAT,
 		     BT_COMPLEX_FLOAT, BT_COMPLEX_FLOAT)
 DEF_FUNCTION_TYPE_1 (BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE,
@@ -208,6 +243,13 @@  DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT_CONST_STRING, BT_FLOAT, BT_CONST_STRING)
 DEF_FUNCTION_TYPE_1 (BT_FN_DOUBLE_CONST_STRING, BT_DOUBLE, BT_CONST_STRING)
 DEF_FUNCTION_TYPE_1 (BT_FN_LONGDOUBLE_CONST_STRING,
 		     BT_LONGDOUBLE, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT16_CONST_STRING, BT_FLOAT16, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT32_CONST_STRING, BT_FLOAT32, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT64_CONST_STRING, BT_FLOAT64, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT128_CONST_STRING, BT_FLOAT128, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT32X_CONST_STRING, BT_FLOAT32X, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT64X_CONST_STRING, BT_FLOAT64X, BT_CONST_STRING)
+DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT128X_CONST_STRING, BT_FLOAT128X, BT_CONST_STRING)
 DEF_FUNCTION_TYPE_1 (BT_FN_DFLOAT32_CONST_STRING, BT_DFLOAT32, BT_CONST_STRING)
 DEF_FUNCTION_TYPE_1 (BT_FN_DFLOAT64_CONST_STRING, BT_DFLOAT64, BT_CONST_STRING)
 DEF_FUNCTION_TYPE_1 (BT_FN_DFLOAT128_CONST_STRING,
@@ -271,6 +313,20 @@  DEF_FUNCTION_TYPE_2 (BT_FN_DOUBLE_DOUBLE_DOUBLE,
 		     BT_DOUBLE, BT_DOUBLE, BT_DOUBLE)
 DEF_FUNCTION_TYPE_2 (BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE,
 		     BT_LONGDOUBLE, BT_LONGDOUBLE, BT_LONGDOUBLE)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT16_FLOAT16_FLOAT16,
+		     BT_FLOAT16, BT_FLOAT16, BT_FLOAT16)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT32_FLOAT32_FLOAT32,
+		     BT_FLOAT32, BT_FLOAT32, BT_FLOAT32)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT64_FLOAT64_FLOAT64,
+		     BT_FLOAT64, BT_FLOAT64, BT_FLOAT64)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT128_FLOAT128_FLOAT128,
+		     BT_FLOAT128, BT_FLOAT128, BT_FLOAT128)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT32X_FLOAT32X_FLOAT32X,
+		     BT_FLOAT32X, BT_FLOAT32X, BT_FLOAT32X)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT64X_FLOAT64X_FLOAT64X,
+		     BT_FLOAT64X, BT_FLOAT64X, BT_FLOAT64X)
+DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT128X_FLOAT128X_FLOAT128X,
+		     BT_FLOAT128X, BT_FLOAT128X, BT_FLOAT128X)
 DEF_FUNCTION_TYPE_2 (BT_FN_FLOAT_FLOAT_FLOATPTR,
 		     BT_FLOAT, BT_FLOAT, BT_FLOAT_PTR)
 DEF_FUNCTION_TYPE_2 (BT_FN_DOUBLE_DOUBLE_DOUBLEPTR,
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5d234a5..f8ec9cf 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5761,6 +5761,7 @@  expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
   switch (fcode)
     {
     CASE_FLT_FN (BUILT_IN_FABS):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
     case BUILT_IN_FABSD32:
     case BUILT_IN_FABSD64:
     case BUILT_IN_FABSD128:
@@ -5770,6 +5771,7 @@  expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_COPYSIGN):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN):
       target = expand_builtin_copysign (exp, target, subtarget);
       if (target)
 	return target;
@@ -8094,12 +8096,14 @@  fold_builtin_0 (location_t loc, tree fndecl)
       return fold_builtin_LINE (loc, type);
 
     CASE_FLT_FN (BUILT_IN_INF):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_INF):
     case BUILT_IN_INFD32:
     case BUILT_IN_INFD64:
     case BUILT_IN_INFD128:
       return fold_builtin_inf (loc, type, true);
 
     CASE_FLT_FN (BUILT_IN_HUGE_VAL):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_HUGE_VAL):
       return fold_builtin_inf (loc, type, false);
 
     case BUILT_IN_CLASSIFY_TYPE:
@@ -8148,6 +8152,7 @@  fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
       return fold_builtin_strlen (loc, type, arg0);
 
     CASE_FLT_FN (BUILT_IN_FABS):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
     case BUILT_IN_FABSD32:
     case BUILT_IN_FABSD64:
     case BUILT_IN_FABSD128:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 33a7626..814ca15 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -87,6 +87,19 @@  along with GCC; see the file COPYING3.  If not see
   DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, TYPE, BT_LAST,	\
 	       false, false, false, ATTRS, true, true)
 
+/* A set of GCC builtins for _FloatN and _FloatNx types.  TYPE_MACRO
+   is called with an argument such as FLOAT32 to produce the enum
+   value for the type.  */
+#undef DEF_GCC_FLOATN_NX_BUILTINS
+#define DEF_GCC_FLOATN_NX_BUILTINS(ENUM, NAME, TYPE_MACRO, ATTRS)	\
+  DEF_GCC_BUILTIN (ENUM ## F16, NAME "f16", TYPE_MACRO (FLOAT16), ATTRS) \
+  DEF_GCC_BUILTIN (ENUM ## F32, NAME "f32", TYPE_MACRO (FLOAT32), ATTRS) \
+  DEF_GCC_BUILTIN (ENUM ## F64, NAME "f64", TYPE_MACRO (FLOAT64), ATTRS) \
+  DEF_GCC_BUILTIN (ENUM ## F128, NAME "f128", TYPE_MACRO (FLOAT128), ATTRS) \
+  DEF_GCC_BUILTIN (ENUM ## F32X, NAME "f32x", TYPE_MACRO (FLOAT32X), ATTRS) \
+  DEF_GCC_BUILTIN (ENUM ## F64X, NAME "f64x", TYPE_MACRO (FLOAT64X), ATTRS) \
+  DEF_GCC_BUILTIN (ENUM ## F128X, NAME "f128x", TYPE_MACRO (FLOAT128X), ATTRS)
+
 /* A library builtin (like __builtin_strchr) is a builtin equivalent
    of an ANSI/ISO standard library function.  In addition to the
    `__builtin' version, we will create an ordinary version (e.g,
@@ -296,6 +309,9 @@  DEF_C99_C90RES_BUILTIN (BUILT_IN_CEILL, "ceill", BT_FN_LONGDOUBLE_LONGDOUBLE, AT
 DEF_C99_BUILTIN        (BUILT_IN_COPYSIGN, "copysign", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_COPYSIGNF, "copysignf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_COPYSIGNL, "copysignl", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#define COPYSIGN_TYPE(F) BT_FN_##F##_##F##_##F
+DEF_GCC_FLOATN_NX_BUILTINS (BUILT_IN_COPYSIGN, "copysign", COPYSIGN_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#undef COPYSIGN_TYPE
 DEF_LIB_BUILTIN        (BUILT_IN_COS, "cos", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_COSF, "cosf", BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING)
 DEF_LIB_BUILTIN        (BUILT_IN_COSH, "cosh", BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
@@ -326,6 +342,9 @@  DEF_C99_BUILTIN        (BUILT_IN_EXPM1L, "expm1l", BT_FN_LONGDOUBLE_LONGDOUBLE,
 DEF_LIB_BUILTIN        (BUILT_IN_FABS, "fabs", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_FABSF, "fabsf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_FABSL, "fabsl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#define FABS_TYPE(F) BT_FN_##F##_##F
+DEF_GCC_FLOATN_NX_BUILTINS (BUILT_IN_FABS, "fabs", FABS_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#undef FABS_TYPE
 DEF_GCC_BUILTIN        (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_FABSD128, "fabsd128", BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -359,6 +378,8 @@  DEF_EXT_LIB_BUILTIN    (BUILT_IN_GAMMAL_R, "gammal_r", BT_FN_LONGDOUBLE_LONGDOUB
 DEF_GCC_BUILTIN        (BUILT_IN_HUGE_VAL, "huge_val", BT_FN_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_HUGE_VALF, "huge_valf", BT_FN_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_HUGE_VALL, "huge_vall", BT_FN_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#define INF_TYPE(F) BT_FN_##F
+DEF_GCC_FLOATN_NX_BUILTINS (BUILT_IN_HUGE_VAL, "huge_val", INF_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_HYPOT, "hypot", BT_FN_DOUBLE_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_HYPOTF, "hypotf", BT_FN_FLOAT_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_HYPOTL, "hypotl", BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
@@ -374,6 +395,8 @@  DEF_C99_BUILTIN        (BUILT_IN_ILOGBL, "ilogbl", BT_FN_INT_LONGDOUBLE, ATTR_MA
 DEF_GCC_BUILTIN        (BUILT_IN_INF, "inf", BT_FN_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_INFF, "inff", BT_FN_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_INFL, "infl", BT_FN_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_FLOATN_NX_BUILTINS (BUILT_IN_INF, "inf", INF_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#undef INF_TYPE
 DEF_GCC_BUILTIN	       (BUILT_IN_INFD32, "infd32", BT_FN_DFLOAT32, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_INFD64, "infd64", BT_FN_DFLOAT64, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_INFD128, "infd128", BT_FN_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -446,12 +469,16 @@  DEF_C99_C90RES_BUILTIN (BUILT_IN_MODFL, "modfl", BT_FN_LONGDOUBLE_LONGDOUBLE_LON
 DEF_C99_BUILTIN        (BUILT_IN_NAN, "nan", BT_FN_DOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_C99_BUILTIN        (BUILT_IN_NANF, "nanf", BT_FN_FLOAT_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_C99_BUILTIN        (BUILT_IN_NANL, "nanl", BT_FN_LONGDOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
+#define NAN_TYPE(F) BT_FN_##F##_CONST_STRING
+DEF_GCC_FLOATN_NX_BUILTINS (BUILT_IN_NAN, "nan", NAN_TYPE, ATTR_CONST_NOTHROW_NONNULL)
 DEF_GCC_BUILTIN        (BUILT_IN_NAND32, "nand32", BT_FN_DFLOAT32_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_GCC_BUILTIN        (BUILT_IN_NAND64, "nand64", BT_FN_DFLOAT64_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_GCC_BUILTIN        (BUILT_IN_NAND128, "nand128", BT_FN_DFLOAT128_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_GCC_BUILTIN        (BUILT_IN_NANS, "nans", BT_FN_DOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_GCC_BUILTIN        (BUILT_IN_NANSF, "nansf", BT_FN_FLOAT_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
 DEF_GCC_BUILTIN        (BUILT_IN_NANSL, "nansl", BT_FN_LONGDOUBLE_CONST_STRING, ATTR_CONST_NOTHROW_NONNULL)
+DEF_GCC_FLOATN_NX_BUILTINS (BUILT_IN_NANS, "nans", NAN_TYPE, ATTR_CONST_NOTHROW_NONNULL)
+#undef NAN_TYPE
 DEF_C99_BUILTIN        (BUILT_IN_NEARBYINT, "nearbyint", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_NEARBYINTF, "nearbyintf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_NEARBYINTL, "nearbyintl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index c61ece9..0cd7b1e 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10811,6 +10811,13 @@  that are recognized in any mode since ISO C90 reserves these names for
 the purpose to which ISO C99 puts them.  All these functions have
 corresponding versions prefixed with @code{__builtin_}.
 
+There are also built-in functions @code{__builtin_fabsf@var{n}},
+@code{__builtin_fabsf@var{n}x}, @code{__builtin_copysignf@var{n}} and
+@code{__builtin_copysignf@var{n}x}, corresponding to the TS 18661-3
+functions @code{fabsf@var{n}}, @code{fabsf@var{n}x},
+@code{copysignf@var{n}} and @code{copysignf@var{n}x}, for supported
+types @code{_Float@var{n}} and @code{_Float@var{n}x}.
+
 There are also GNU extension functions @code{clog10}, @code{clog10f} and
 @code{clog10l} which names are reserved by ISO C99 for future use.
 All these functions have versions prefixed with @code{__builtin_}.
@@ -11349,6 +11356,16 @@  Similar to @code{__builtin_huge_val}, except the return
 type is @code{long double}.
 @end deftypefn
 
+@deftypefn {Built-in Function} _Float@var{n} __builtin_huge_valf@var{n} (void)
+Similar to @code{__builtin_huge_val}, except the return type is
+@code{_Float@var{n}}.
+@end deftypefn
+
+@deftypefn {Built-in Function} _Float@var{n}x __builtin_huge_valf@var{n}x (void)
+Similar to @code{__builtin_huge_val}, except the return type is
+@code{_Float@var{n}x}.
+@end deftypefn
+
 @deftypefn {Built-in Function} int __builtin_fpclassify (int, int, int, int, int, ...)
 This built-in implements the C99 fpclassify functionality.  The first
 five int arguments should be the target library's notion of the
@@ -11387,6 +11404,16 @@  Similar to @code{__builtin_inf}, except the return
 type is @code{long double}.
 @end deftypefn
 
+@deftypefn {Built-in Function} _Float@var{n} __builtin_inff@var{n} (void)
+Similar to @code{__builtin_inf}, except the return
+type is @code{_Float@var{n}}.
+@end deftypefn
+
+@deftypefn {Built-in Function} _Float@var{n} __builtin_inff@var{n}x (void)
+Similar to @code{__builtin_inf}, except the return
+type is @code{_Float@var{n}x}.
+@end deftypefn
+
 @deftypefn {Built-in Function} int __builtin_isinf_sign (...)
 Similar to @code{isinf}, except the return value is -1 for
 an argument of @code{-Inf} and 1 for an argument of @code{+Inf}.
@@ -11433,6 +11460,16 @@  Similar to @code{__builtin_nan}, except the return type is @code{float}.
 Similar to @code{__builtin_nan}, except the return type is @code{long double}.
 @end deftypefn
 
+@deftypefn {Built-in Function} _Float@var{n} __builtin_nanf@var{n} (const char *str)
+Similar to @code{__builtin_nan}, except the return type is
+@code{_Float@var{n}}.
+@end deftypefn
+
+@deftypefn {Built-in Function} _Float@var{n}x __builtin_nanf@var{n}x (const char *str)
+Similar to @code{__builtin_nan}, except the return type is
+@code{_Float@var{n}x}.
+@end deftypefn
+
 @deftypefn {Built-in Function} double __builtin_nans (const char *str)
 Similar to @code{__builtin_nan}, except the significand is forced
 to be a signaling NaN@.  The @code{nans} function is proposed by
@@ -11447,6 +11484,16 @@  Similar to @code{__builtin_nans}, except the return type is @code{float}.
 Similar to @code{__builtin_nans}, except the return type is @code{long double}.
 @end deftypefn
 
+@deftypefn {Built-in Function} _Float@var{n} __builtin_nansf@var{n} (const char *str)
+Similar to @code{__builtin_nans}, except the return type is
+@code{_Float@var{n}}.
+@end deftypefn
+
+@deftypefn {Built-in Function} _Float@var{n}x __builtin_nansf@var{n}x (const char *str)
+Similar to @code{__builtin_nans}, except the return type is
+@code{_Float@var{n}x}.
+@end deftypefn
+
 @deftypefn {Built-in Function} int __builtin_ffs (int x)
 Returns one plus the index of the least significant 1-bit of @var{x}, or
 if @var{x} is zero, returns zero.
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index 923a5d4..2bbc887 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -1131,12 +1131,14 @@  fold_const_call (combined_fn fn, tree type, tree arg)
       return NULL_TREE;
 
     CASE_CFN_NAN:
+    CASE_FLT_FN_FLOATN_NX (CFN_BUILT_IN_NAN):
     case CFN_BUILT_IN_NAND32:
     case CFN_BUILT_IN_NAND64:
     case CFN_BUILT_IN_NAND128:
       return fold_const_builtin_nan (type, arg, true);
 
     CASE_CFN_NANS:
+    CASE_FLT_FN_FLOATN_NX (CFN_BUILT_IN_NANS):
       return fold_const_builtin_nan (type, arg, false);
 
     default:
diff --git a/gcc/testsuite/gcc.dg/torture/float128-builtin.c b/gcc/testsuite/gcc.dg/torture/float128-builtin.c
new file mode 100644
index 0000000..2f4936f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float128-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float128 built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float128 } */
+/* { dg-options "" } */
+
+#define WIDTH 128
+#define EXT 0
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/float128x-builtin.c b/gcc/testsuite/gcc.dg/torture/float128x-builtin.c
new file mode 100644
index 0000000..33ceeec
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float128x-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float128x built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float128x } */
+/* { dg-options "" } */
+
+#define WIDTH 128
+#define EXT 1
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/float16-builtin.c b/gcc/testsuite/gcc.dg/torture/float16-builtin.c
new file mode 100644
index 0000000..2a043fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float16-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float16 built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float16 } */
+/* { dg-options "" } */
+
+#define WIDTH 16
+#define EXT 0
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/float32-builtin.c b/gcc/testsuite/gcc.dg/torture/float32-builtin.c
new file mode 100644
index 0000000..25c7072
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float32-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float32 built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float32 } */
+/* { dg-options "" } */
+
+#define WIDTH 32
+#define EXT 0
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/float32x-builtin.c b/gcc/testsuite/gcc.dg/torture/float32x-builtin.c
new file mode 100644
index 0000000..63f23e5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float32x-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float32x built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float32x } */
+/* { dg-options "" } */
+
+#define WIDTH 32
+#define EXT 1
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/float64-builtin.c b/gcc/testsuite/gcc.dg/torture/float64-builtin.c
new file mode 100644
index 0000000..8e8c123
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float64-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float64 built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float64 } */
+/* { dg-options "" } */
+
+#define WIDTH 64
+#define EXT 0
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/float64x-builtin.c b/gcc/testsuite/gcc.dg/torture/float64x-builtin.c
new file mode 100644
index 0000000..4d91c4b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/float64x-builtin.c
@@ -0,0 +1,8 @@ 
+/* Test _Float64x built-in functions.  */
+/* { dg-do run } */
+/* { dg-require-effective-target float64x } */
+/* { dg-options "" } */
+
+#define WIDTH 64
+#define EXT 1
+#include "floatn-builtin.h"
diff --git a/gcc/testsuite/gcc.dg/torture/floatn-builtin.h b/gcc/testsuite/gcc.dg/torture/floatn-builtin.h
new file mode 100644
index 0000000..c562812
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/floatn-builtin.h
@@ -0,0 +1,64 @@ 
+/* Tests for _FloatN / _FloatNx types: compile and execution tests for
+   built-in functions.  Before including this file, define WIDTH as
+   the value N; define EXT to 1 for _FloatNx and 0 for _FloatN.  */
+
+#define CONCATX(X, Y) X ## Y
+#define CONCAT(X, Y) CONCATX (X, Y)
+#define CONCAT3(X, Y, Z) CONCAT (CONCAT (X, Y), Z)
+#define CONCAT4(W, X, Y, Z) CONCAT (CONCAT (CONCAT (W, X), Y), Z)
+
+#if EXT
+# define TYPE CONCAT3 (_Float, WIDTH, x)
+# define CST(C) CONCAT4 (C, f, WIDTH, x)
+# define FN(F) CONCAT4 (F, f, WIDTH, x)
+#else
+# define TYPE CONCAT (_Float, WIDTH)
+# define CST(C) CONCAT3 (C, f, WIDTH)
+# define FN(F) CONCAT3 (F, f, WIDTH)
+#endif
+
+extern void exit (int);
+extern void abort (void);
+
+extern TYPE test_type;
+extern __typeof (FN (__builtin_inf) ()) test_type;
+extern __typeof (FN (__builtin_huge_val) ()) test_type;
+extern __typeof (FN (__builtin_nan) ("")) test_type;
+extern __typeof (FN (__builtin_nans) ("")) test_type;
+extern __typeof (FN (__builtin_fabs) (0)) test_type;
+extern __typeof (FN (__builtin_copysign) (0, 0)) test_type;
+
+volatile TYPE inf_cst = FN (__builtin_inf) ();
+volatile TYPE huge_val_cst = FN (__builtin_huge_val) ();
+volatile TYPE nan_cst = FN (__builtin_nan) ("");
+volatile TYPE nans_cst = FN (__builtin_nans) ("");
+volatile TYPE neg0 = -CST (0.0), neg1 = -CST (1.0), one = 1.0;
+
+int
+main (void)
+{
+  volatile TYPE r;
+  if (!__builtin_isinf (inf_cst))
+    abort ();
+  if (!__builtin_isinf (huge_val_cst))
+    abort ();
+  if (inf_cst != huge_val_cst)
+    abort ();
+  if (!__builtin_isnan (nan_cst))
+    abort ();
+  if (!__builtin_isnan (nans_cst))
+    abort ();
+  r = FN (__builtin_fabs) (neg1);
+  if (r != CST (1.0))
+    abort ();
+  r = FN (__builtin_copysign) (one, neg0);
+  if (r != neg1)
+    abort ();
+  r = FN (__builtin_copysign) (inf_cst, neg1);
+  if (r != -huge_val_cst)
+    abort ();
+  r = FN (__builtin_copysign) (-inf_cst, one);
+  if (r != huge_val_cst)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/tree.h b/gcc/tree.h
index acb8bf1..db6fbcf 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -234,6 +234,9 @@  as_internal_fn (combined_fn code)
 /* Helper macros for math builtins.  */
 
 #define CASE_FLT_FN(FN) case FN: case FN##F: case FN##L
+#define CASE_FLT_FN_FLOATN_NX(FN)			   \
+  case FN##F16: case FN##F32: case FN##F64: case FN##F128: \
+  case FN##F32X: case FN##F64X: case FN##F128X
 #define CASE_FLT_FN_REENT(FN) case FN##_R: case FN##F_R: case FN##L_R
 #define CASE_INT_FN(FN) case FN: case FN##L: case FN##LL: case FN##IMAX
 
@@ -3617,11 +3620,16 @@  tree_operand_check_code (const_tree __t, enum tree_code __code, int __i,
 #define FLOATN_NX_TYPE_NODE(IDX)	global_trees[TI_FLOATN_NX_TYPE_FIRST + (IDX)]
 #define FLOATNX_TYPE_NODE(IDX)		global_trees[TI_FLOATNX_TYPE_FIRST + (IDX)]
 
-/* Names for individual types, where required by back ends
-   (architecture-independent code should always iterate over all such
-   types).  */
+/* Names for individual types (code should normally iterate over all
+   such types; these are only for back-end use, or in contexts such as
+   *.def where iteration if not possible).  */
+#define float16_type_node		global_trees[TI_FLOAT16_TYPE]
+#define float32_type_node		global_trees[TI_FLOAT32_TYPE]
+#define float64_type_node		global_trees[TI_FLOAT64_TYPE]
 #define float128_type_node		global_trees[TI_FLOAT128_TYPE]
+#define float32x_type_node		global_trees[TI_FLOAT32X_TYPE]
 #define float64x_type_node		global_trees[TI_FLOAT64X_TYPE]
+#define float128x_type_node		global_trees[TI_FLOAT128X_TYPE]
 
 #define float_ptr_type_node		global_trees[TI_FLOAT_PTR_TYPE]
 #define double_ptr_type_node		global_trees[TI_DOUBLE_PTR_TYPE]