diff mbox

Implement C _FloatN, _FloatNx types [version 6]

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

Commit Message

Joseph Myers Aug. 17, 2016, 8:17 p.m. UTC
[Version 6 changes the testsuite to use dg-add-options systematically
to add any options that may be needed for the types to be supported;
this should allow the _Float128 and _Float64x tests to run for
powerpc64le, but I have not tested that; it could do with powerpc
maintainer testing that the tests do indeed run.  It also has fixes
for the fp-int-convert issues pointed out in
<https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01279.html>.  There are
no changes to the patch outside the testsuite and associated
documentation of effective-target and dg-add-options keywords.]


ISO/IEC TS 18661-3:2015 defines C bindings to IEEE interchange and
extended types, in the form of _FloatN and _FloatNx type names with
corresponding fN/FN and fNx/FNx constant suffixes and FLTN_* / FLTNX_*
<float.h> macros.  This patch implements support for this feature in
GCC.

The _FloatN types, for N = 16, 32, 64 or >= 128 and a multiple of 32,
are types encoded according to the corresponding IEEE interchange
format (endianness unspecified; may use either the NaN conventions
recommended in IEEE 754-2008, or the MIPS NaN conventions, since the
choice of convention is only an IEEE recommendation, not a
requirement).  The _FloatNx types, for N = 32, 64 and 128, are IEEE
"extended" types: types extending a narrower format with range and
precision at least as big as those specified in IEEE 754 for each
extended type (and with unspecified representation, but still
following IEEE semantics for their values and operations - and with
the set of values being determined by the precision and the maximum
exponent, which means that while Intel "extended" is suitable for
_Float64x, m68k "extended" is not).  These types are always distinct
from and not compatible with each other and the standard floating
types float, double, long double; thus, double, _Float64 and _Float32x
may all have the same ABI, but they are three still distinct types.
The type names may be used with _Complex to construct corresponding
complex types (unlike __float128, which acts more like a typedef name
than a keyword - thus, this patch may be considered to fix PR
c/32187).  The new suffixes can be combined with GNU "i" and "j"
suffixes for constants of complex types (e.g. 1.0if128, 2.0f64i).

The set of types supported is implementation-defined.  In this GCC
patch, _Float32 is SFmode if that is suitable; _Float32x and _Float64
are DFmode if that is suitable; _Float128 is TFmode if that is
suitable; _Float64x is XFmode if that is suitable, and otherwise
TFmode if that is suitable.  There is a target hook to override the
choices if necessary.  "Suitable" means both conforming to the
requirements of that type, and supported as a scalar type including in
libgcc.  The ABI is whatever the back end does for scalars of that
mode (but note that _Float32 is passed without promotion in variable
arguments, unlike float).  All the existing issues with exceptions and
rounding modes for existing types apply equally to the new type names.

No GCC port supports a floating-point format suitable for _Float128x.
Although there is HFmode support for ARM and AArch64, use of that for
_Float16 is not enabled.  Supporting _Float16 would require additional
work on the excess precision aspects of TS 18661-3: there are new
values of FLT_EVAL_METHOD, which are not currently supported in GCC,
and FLT_EVAL_METHOD == 0 now means that operations and constants on
types narrower than float are evaluated to the range and precision of
float.  Implementing that, so that _Float16 gets evaluated with excess
range and precision, would involve changes to the excess precision
infrastructure so that the _Float16 case is enabled by default, unlike
the x87 case which is only enabled for -fexcess-precision=standard.
Other differences between _Float16 and __fp16 would also need to be
disentangled.

GCC has some prior support for nonstandard floating-point types in the
form of __float80 and __float128.  Where these were previously types
distinct from long double, they are made by this patch into aliases
for _Float64x / _Float128 if those types have the required properties.

In principle the set of possible _FloatN types is infinite.  This
patch hardcodes the four such types for N <= 128, but with as much
code as possible using loops over types to minimize the number of
places with such hardcoding.  I don't think it's likely any further
such types will be of use in future (or indeed that formats suitable
for _Float128x will actually be implemented).  There is a corner case
that all _FloatN, for N >= 128 and a multiple of 32, should be treated
as keywords even when the corresponding type is not supported; I
intend to deal with that in a followup patch.

Tests are added for various functionality of the new types, mostly
using type-generic headers.  The tests use dg-add-options to pass any
extra options needed to enable the types; this is wired up to use the
same options as for __float128 on powerpc to enable _Float128 and
_Float64x, and effective-target keywords for runtime support do the
same hardware test as for __float128 to make sure the VSX instructions
generated by those options are supported.  (Corresponding additions
would be needed for _Float16 on ARM as well if that were enabled with
-mfp16-format=ieee required to use it rather than unconditionally
available.  Of course, -mfp16-format=alternative enables use of a
format which is not compatible with the requirements of the _Float16
type.)

C++ note: no support for the new types or constant suffixes is added
for C++.  C++ decimal floating-point support was very different from
the C support, using class types, and the same may well apply to any
future C++ bindings for IEEE interchange and extended types.  There is
a case, however, for supporting at least *f128 constants in C++, so
that code using __float128 can use the newer style for constants
throughout rather than needing to use the older *q constants in C++.
Also, if built-in functions are added that may provide a way in which
the types could leak into C++ code.

Fortran note: the float128_type_node used in the Fortran front end is
renamed to gfc_float128_type_node, since the semantics are different:
in particular, if long double has binary128 format, then the new
language-independent float128_type_node is a distinct type that also
has binary128 format, but the Fortran node is expected to be NULL in
that case.  Likewise, Fortran's complex_float128_type_node is renamed
to gfc_complex_float128_type_node.

PowerPC note: the back end had an inconsistency that if TFmode was
binary128, *q constants were TFmode instead of KFmode but __float128
was KFmode.  This patch follows the same logic as for *q constants, so
that _Float128 prefers TFmode (and __float128 becomes an alias for
_Float128).

ARM note: __fp16 is promoted to double (by convert_arguments) when
passed without a prototype / in variable arguments.  But this is only
about the argument promotion; it is not handled as promoting in
c-common.c:self_promoting_args_p / c-typeck.c:c_type_promotes_to,
meaning that a K&R function definition for an argument of type __fp16
corresponds to a prototype with an argument of that type, not to one
with an argument of type double, whereas a float argument in a K&R
function definition corresponds to a double prototype argument - and
the same functions are also what's involved in making va_arg give a
warning and generate a call to abort when called with type float.
This is preserved by this patch, while arranging for _Float16 not to
be promoted when passed without a prototype / in variable arguments
(the promotion of float being considered a legacy feature, not applied
to any new types in C99 or later).

TS 18661-3 extends the set of decimal floating-point types similarly,
and adds new constant suffixes for the existing types, but this patch
does not do anything regarding that extension.

This patch does nothing regarding built-in functions, although
type-generic functions such as __builtin_isinf work for the new types
and associated tests are included.  There are at least two levels of
built-in function support possible for these types.  The minimal
level, implemented in
<https://gcc.gnu.org/ml/gcc-patches/2016-06/msg01702.html> (which
needs updating to use dg-add-options), adds built-in functions similar
to those x86 has for __float128: __builtin_inf* __builtin_huge_val*,
__builtin_nan*, __builtin_nans*, __builtin_fabs*, __builtin_copysign*.
That would be sufficient for glibc to use the *f128 names for built-in
functions by default with *q used only for backwards compatibility
when using older GCC versions.  That would also allow c_cpp_builtins's
flag_building_libgcc code, defining __LIBGCC_%s_FUNC_EXT__, to use
such suffixes rather than the present code hardcoding logic about
target-specific constant suffixes and how those relate to function
suffixes.

Full built-in function support would cover the full range of built-in
functions for existing floating-point types, adding variants for all
the new types, except for a few obsolescent functions and
non-type-generic variants of type-generic functions.  Some but not all
references to such functions in GCC use macros such as CASE_FLT_FN to
be type-generic; a fair amount of work would be needed to identify all
places to update.  Adding all those functions would enable
optimizations (for constant arguments and otherwise) for TS 18661-3
functions, but it would also substantially expand the enum listing
built-in functions (and we've had problems with the size of that enum
in the past), and increase the amount of built-in function
initialization to do - I don't know what the startup cost involved in
built-in function initialization is, but it would be something to
consider when adding such a large set of functions.

There are also a range of optimizations, in match.pd and elsewhere,
that only operate on the three standard floating-point types.  Ideally
those would be made generic to all floating-point types, but this
patch does nothing in that regard.  Special care would be needed
regarding making sure library functions to which calls are generated
actually exist.  For example, if sqrt is called on an argument of type
_Float32, and the result converted to _Float32, this is equivalent to
doing a square root operation directly on _Float32.  But if the user's
libm does not have the sqrtf32 function, or the name is not reserved
because __STDC_WANT_IEC_60559_TYPES_EXT__ was not defined before
including <math.h>, you can only do that optimization if you convert
to a call to sqrtf instead.

DECIMAL_DIG now relates to all supported floating-point formats, not
just float, double and long double; I've raised the question with WG14
of how this relates to the formula for DECIMAL_DIG in C11 not
considering this.  TS 18661-3 says it also covers non-arithmetic
formats only supported by library conversion functions; this patch
does not add any target hooks to allow for the case where there are
such formats wider than any supported for arithmetic types (where
e.g. libc supports conversions involving the binary128 representation,
but the _Float128 type is not supported).

GCC provides its own <tgmath.h> for some targets.  No attempt is made
to adapt this to handle the new types.

Nothing is done regarding debug info for the new types (see the
"Debugger support for __float128 type?" thread on gcc@, Sep/Oct 2015).

No __SIZEOF_*__ macros are added for the new types.

Nothing is done with do_warn_double_promotion.

Nothing is done to include the new types in those determining
max_align_t, although properly it should be sufficiently aligned for
any of those types.

The logic for usual arithmetic conversions in c_common_type relies on
TYPE_PRECISION for floating-point types, which is less than ideal
(doesn't necessarily correspond to whether one type's values are
subset of another); looking in more detail at the formats might be
better.  But since I included code in build_common_tree_nodes to work
around rs6000 KFmode having precision 113 not 128, I think it should
work.  Ideally one might have errors in generic code for the case
where the two types do not have one type's values a subset of the
other (which is undefined behavior).  But the only case where this can
actually occur is mixing IBM long double with binary128 on powerpc,
and rs6000_invalid_binary_op deals with that at present.  TS 18661-3
does not fully specify the type resulting from the usual arithmetic
conversions in the case where two _FloatNx types have the same set of
values; I arranged the code to prefer the greater value of N in that
case.

The __FP_FAST_FMA* macros are not extended to cover the new types,
since there are no corresponding built-in functions (if built-in
fmafN, fmafNx are added, the macros should be extended, and the new
macros documented).  Also, only a limited set of modes is handled in
mode_has_fma.

Diagnostics relating to the use of the new types with -pedantic do not
try to distinguish them from purely nonstandard types such as __int128
and constant suffixes such as *q.

If you use an unsupported _FloatN / _FloatNx type you get a warning
about the type defaulting to int after the warning about the type not
being supported.  That's less than ideal, but it's also a pre-existing
condition if you use __int128 on a 32-bit system where it's
unsupported.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.  Other
back-end changes minimally tested by building cc1 for ia64-linux-gnu,
powerpc64le-linux-gnu, pdp11-none (the last failed for unrelated
reasons).  OK to commit (non-C-front-end parts; rs6000 parts were
approved in
<https://gcc.gnu.org/ml/gcc-patches/2016-06/msg01837.html>, and
Fortran parts in
<https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00858.html>)?

gcc:
2016-08-17  Joseph Myers  <joseph@codesourcery.com>

	PR c/32187
	* tree-core.h (TI_COMPLEX_FLOAT16_TYPE)
	(TI_COMPLEX_FLOATN_NX_TYPE_FIRST, TI_COMPLEX_FLOAT32_TYPE)
	(TI_COMPLEX_FLOAT64_TYPE, TI_COMPLEX_FLOAT128_TYPE)
	(TI_COMPLEX_FLOAT32X_TYPE, TI_COMPLEX_FLOAT64X_TYPE)
	(TI_COMPLEX_FLOAT128X_TYPE, TI_FLOAT16_TYPE, TI_FLOATN_TYPE_FIRST)
	(TI_FLOATN_NX_TYPE_FIRST, TI_FLOAT32_TYPE, TI_FLOAT64_TYPE)
	(TI_FLOAT128_TYPE, TI_FLOATN_TYPE_LAST, TI_FLOAT32X_TYPE)
	(TI_FLOATNX_TYPE_FIRST, TI_FLOAT64X_TYPE, TI_FLOAT128X_TYPE)
	(TI_FLOATNX_TYPE_LAST, TI_FLOATN_NX_TYPE_LAST): New enum
	tree_index values.
	(NUM_FLOATN_TYPES, NUM_FLOATNX_TYPES, NUM_FLOATN_NX_TYPES): New
	macros.
	(struct floatn_type_info): New structure type.
	(floatn_nx_types): New variable declaration.
	* tree.h (FLOATN_TYPE_NODE, FLOATN_NX_TYPE_NODE)
	(FLOATNX_TYPE_NODE, float128_type_node, float64x_type_node)
	(COMPLEX_FLOATN_NX_TYPE_NODE): New macros.
	* tree.c (floatn_nx_types): New variable.
	(build_common_tree_nodes): Initialize _FloatN, _FloatNx and
	corresponding complex types.
	* target.def (floatn_mode): New hook.
	* targhooks.c: Include "real.h".
	(default_floatn_mode): New function.
	* targhooks.h (default_floatn_mode): New prototype.
	* doc/extend.texi (Floating Types): Document _FloatN and _FloatNx
	types.
	* doc/sourcebuild.texi (float@var{n}, float@var{n}x): Document new
	effective-target and dg-add-options keywords.
	(float@var{n}_runtime, float@var{n}x_runtime, floatn_nx_runtime):
	Document new effective-target keywords.
	* doc/tm.texi.in (TARGET_FLOATN_MODE): New @hook.
	* doc/tm.texi: Regenerate.
	* ginclude/float.h (LDBL_DECIMAL_DIG): Define to
	__LDBL_DECIMAL_DIG__, not __DECIMAL_DIG__.
	[__STDC_WANT_IEC_60559_TYPES_EXT__]: Define macros from TS
	18661-3.
	* real.h (struct real_format): Add field ieee_bits.
	* real.c (ieee_single_format, mips_single_format)
	(motorola_single_format, spu_single_format, ieee_double_format)
	(mips_double_format, motorola_double_format)
	(ieee_extended_motorola_format, ieee_extended_intel_96_format)
	(ieee_extended_intel_128_format)
	(ieee_extended_intel_96_round_53_format, ibm_extended_format)
	(mips_extended_format, ieee_quad_format, mips_quad_format)
	(vax_f_format, vax_d_format, vax_g_format, decimal_single_format)
	(decimal_double_format, decimal_quad_format, ieee_half_format)
	(arm_half_format, real_internal_format: Initialize ieee_bits
	field.
	* config/i386/i386.c (ix86_init_builtin_types): Do not initialize
	float128_type_node.  Set float80_type_node to float64x_type_node
	if appropriate and long_double_type_node not appropriate.
	* config/ia64/ia64.c (ia64_init_builtins): Likewise.
	* config/pdp11/pdp11.c (pdp11_f_format, pdp11_d_format):
	Initialize ieee_bits field.
	* config/rs6000/rs6000.c (TARGET_FLOATN_MODE): New macro.
	(rs6000_init_builtins): Set ieee128_float_type_node to
	float128_type_node.
	(rs6000_floatn_mode): New function.

gcc/c:
2016-08-17  Joseph Myers  <joseph@codesourcery.com>

	PR c/32187
	* c-tree.h (cts_floatn_nx): New enum c_typespec_keyword value.
	(struct c_declspecs): Add field floatn_nx_idx.
	* c-decl.c (declspecs_add_type, finish_declspecs): Handle _FloatN
	and _FloatNx type specifiers.
	* c-parser.c (c_keyword_starts_typename, c_token_starts_declspecs)
	(c_parser_declspecs, c_parser_attribute_any_word)
	(c_parser_objc_selector): Use CASE_RID_FLOATN_NX.
	* c-typeck.c (c_common_type): Handle _FloatN and _FloatNx types.
	(convert_arguments): Avoid promoting _FloatN and _FloatNx types
	narrower than double.

gcc/c-family:
2016-08-17  Joseph Myers  <joseph@codesourcery.com>

	PR c/32187
	* c-common.h (RID_FLOAT16, RID_FLOATN_NX_FIRST, RID_FLOAT32)
	(RID_FLOAT64, RID_FLOAT128, RID_FLOAT32X, RID_FLOAT64X)
	(RID_FLOAT128X): New enum rid values.
	(CASE_RID_FLOATN_NX): New macro.
	* c-common.c (c_common_reswords): Add _FloatN and _FloatNx
	keywords.
	(c_common_type_for_mode): Check for _FloatN and _FloatNx and
	corresponding complex types.
	(c_common_nodes_and_builtins): For non-C++, register _FloatN and
	_FloatNx and corresponding complex types.
	(keyword_begins_type_specifier): Use CASE_RID_FLOATN_NX.
	* c-cppbuiltin.c (builtin_define_float_constants): Check _FloatN
	and _FloatNx types for the widest type for determining
	DECIMAL_DIG.  Define __LDBL_DECIMAL_DIG__ as well as
	__DECIMAL_DIG__ for long double.  Handle FMA_SUFFIX being NULL.
	(c_cpp_builtins): Call builtin_define_float_constants for _FloatN
	and _FloatNx types.
	* c-lex.c (interpret_float): Handle _FloatN and _FloatNx
	constants.
	* c-pretty-print.c (pp_c_floating_constant): Handle _FloatN and
	_FloatNx types.

gcc/fortran:
2016-08-17  Joseph Myers  <joseph@codesourcery.com>

	PR c/32187
	* trans-types.h (float128_type_node): Rename to
	gfc_float128_type_node.
	(complex_float128_type_node): Rename to
	gfc_complex_float128_type_node.
	* iso-c-binding.def, trans-intrinsic.c, trans-types.c: All users
	changed.

gcc/testsuite:
2016-08-17  Joseph Myers  <joseph@codesourcery.com>

	PR c/32187
	* lib/target-supports.exp (check_effective_target_float16)
	(check_effective_target_float32, check_effective_target_float64)
	(check_effective_target_float128, check_effective_target_float32x)
	(check_effective_target_float64x)
	(check_effective_target_float128x)
	(check_effective_target_float16_runtime)
	(check_effective_target_float32_runtime)
	(check_effective_target_float64_runtime)
	(check_effective_target_float128_runtime)
	(check_effective_target_float32x_runtime)
	(check_effective_target_float64x_runtime)
	(check_effective_target_float128x_runtime)
	(check_effective_target_floatn_nx_runtime)
	(add_options_for_float16, add_options_for_float32)
	(add_options_for_float64, add_options_for_float128)
	(add_options_for_float32x, add_options_for_float64x)
	(add_options_for_float128x): New procedures.
	* gcc.dg/dfp/floatn.c, gcc.dg/float128-typeof.c,
	gcc.dg/float128x-typeof.c, gcc.dg/float16-typeof.c,
	gcc.dg/float32-typeof.c, gcc.dg/float32x-typeof.c,
	gcc.dg/float64-typeof.c, gcc.dg/float64x-typeof.c,
	gcc.dg/floatn-arithconv.c, gcc.dg/floatn-errs.c,
	gcc.dg/floatn-typeof.h, gcc.dg/torture/float128-basic.c,
	gcc.dg/torture/float128-complex.c,
	gcc.dg/torture/float128-floath.c, gcc.dg/torture/float128-tg.c,
	gcc.dg/torture/float128x-basic.c,
	gcc.dg/torture/float128x-complex.c,
	gcc.dg/torture/float128x-floath.c, gcc.dg/torture/float128x-tg.c,
	gcc.dg/torture/float16-basic.c, gcc.dg/torture/float16-complex.c,
	gcc.dg/torture/float16-floath.c, gcc.dg/torture/float16-tg.c,
	gcc.dg/torture/float32-basic.c, gcc.dg/torture/float32-complex.c,
	gcc.dg/torture/float32-floath.c, gcc.dg/torture/float32-tg.c,
	gcc.dg/torture/float32x-basic.c,
	gcc.dg/torture/float32x-complex.c,
	gcc.dg/torture/float32x-floath.c, gcc.dg/torture/float32x-tg.c,
	gcc.dg/torture/float64-basic.c, gcc.dg/torture/float64-complex.c,
	gcc.dg/torture/float64-floath.c, gcc.dg/torture/float64-tg.c,
	gcc.dg/torture/float64x-basic.c,
	gcc.dg/torture/float64x-complex.c,
	gcc.dg/torture/float64x-floath.c, gcc.dg/torture/float64x-tg.c,
	gcc.dg/torture/floatn-basic.h, gcc.dg/torture/floatn-complex.h,
	gcc.dg/torture/floatn-convert.c, gcc.dg/torture/floatn-floath.h,
	gcc.dg/torture/floatn-tg.h,
	gcc.dg/torture/fp-int-convert-float128-ieee-timode.c,
	gcc.dg/torture/fp-int-convert-float128-ieee.c,
	gcc.dg/torture/fp-int-convert-float128x-timode.c,
	gcc.dg/torture/fp-int-convert-float128x.c,
	gcc.dg/torture/fp-int-convert-float16-timode.c,
	gcc.dg/torture/fp-int-convert-float16.c,
	gcc.dg/torture/fp-int-convert-float32-timode.c,
	gcc.dg/torture/fp-int-convert-float32.c,
	gcc.dg/torture/fp-int-convert-float32x-timode.c,
	gcc.dg/torture/fp-int-convert-float32x.c,
	gcc.dg/torture/fp-int-convert-float64-timode.c,
	gcc.dg/torture/fp-int-convert-float64.c,
	gcc.dg/torture/fp-int-convert-float64x-timode.c,
	gcc.dg/torture/fp-int-convert-float64x.c: New tests.
	* gcc.dg/torture/fp-int-convert.h (TEST_I_F): Add argument for
	maximum exponent of floating-point type.  Use it in testing
	whether 0x8...0 fits in the floating-point type.  Always treat -1
	(signed 0xf...f) as fitting in the floating-point type.
	(M_OK1): New macro.
	* gcc.dg/torture/fp-int-convert-double.c,
	gcc.dg/torture/fp-int-convert-float.c,
	gcc.dg/torture/fp-int-convert-float128-timode.c,
	gcc.dg/torture/fp-int-convert-float128.c,
	gcc.dg/torture/fp-int-convert-float80-timode.c,
	gcc.dg/torture/fp-int-convert-float80.c,
	gcc.dg/torture/fp-int-convert-long-double.c,
	gcc.dg/torture/fp-int-convert-timode.c: Update calls to TEST_I_F.

libcpp:
2016-08-17  Joseph Myers  <joseph@codesourcery.com>

	PR c/32187
	* include/cpplib.h (CPP_N_FLOATN, CPP_N_FLOATNX)
	(CPP_N_WIDTH_FLOATN_NX, CPP_FLOATN_SHIFT, CPP_FLOATN_MAX): New
	macros.
	* expr.c (interpret_float_suffix): Handle fN, fNx, FN and FNx
	suffixes.

Comments

Joseph Myers Aug. 19, 2016, 11:05 a.m. UTC | #1
On Fri, 19 Aug 2016, Richard Biener wrote:

> Ok if libcpp maintainers do not object.

I consider the libcpp changes something I can self-approve - but, any 
comments?

> Can you quickly verify if LTO works with the new types?  I don't see anything
> that would prevent it but having new global trees and backends initializing them
> might come up with surprises (see tree-streamer.c:preload_common_nodes)

Well, the execution tests are in gcc.dg/torture, which is run with various 
options including -flto (and I've checked the testsuite logs to confirm 
these tests are indeed run with such options).  Is there something else 
you think should be tested?
Richard Biener Aug. 19, 2016, 11:11 a.m. UTC | #2
On Fri, Aug 19, 2016 at 1:05 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Fri, 19 Aug 2016, Richard Biener wrote:
>
>> Ok if libcpp maintainers do not object.
>
> I consider the libcpp changes something I can self-approve - but, any
> comments?

No comments on that part.

>> Can you quickly verify if LTO works with the new types?  I don't see anything
>> that would prevent it but having new global trees and backends initializing them
>> might come up with surprises (see tree-streamer.c:preload_common_nodes)
>
> Well, the execution tests are in gcc.dg/torture, which is run with various
> options including -flto (and I've checked the testsuite logs to confirm
> these tests are indeed run with such options).  Is there something else
> you think should be tested?

No, I think that's enough.

Thanks,
Richard.

>
> --
> Joseph S. Myers
> joseph@codesourcery.com
Joseph Myers Aug. 19, 2016, 2:40 p.m. UTC | #3
On Fri, 19 Aug 2016, Richard Biener wrote:

> >> Can you quickly verify if LTO works with the new types?  I don't see anything
> >> that would prevent it but having new global trees and backends initializing them
> >> might come up with surprises (see tree-streamer.c:preload_common_nodes)
> >
> > Well, the execution tests are in gcc.dg/torture, which is run with various
> > options including -flto (and I've checked the testsuite logs to confirm
> > these tests are indeed run with such options).  Is there something else
> > you think should be tested?
> 
> No, I think that's enough.

Then I'll commit the patch later today in the absence of comments from 
other libcpp maintainers (and then go on to update and retest the built-in 
functions patch).
Szabolcs Nagy Aug. 19, 2016, 3:28 p.m. UTC | #4
On 17/08/16 21:17, Joseph Myers wrote:
> Although there is HFmode support for ARM and AArch64, use of that for
> _Float16 is not enabled.  Supporting _Float16 would require additional
> work on the excess precision aspects of TS 18661-3: there are new
> values of FLT_EVAL_METHOD, which are not currently supported in GCC,
> and FLT_EVAL_METHOD == 0 now means that operations and constants on
> types narrower than float are evaluated to the range and precision of
> float.  Implementing that, so that _Float16 gets evaluated with excess
> range and precision, would involve changes to the excess precision
> infrastructure so that the _Float16 case is enabled by default, unlike
> the x87 case which is only enabled for -fexcess-precision=standard.
> Other differences between _Float16 and __fp16 would also need to be
> disentangled.

i wonder how gcc can support _Float16 without excess
precision.

using FLT_EVAL_METHOD==16 can break conforming c99/c11
code which only expects 0,1,2 values to appear (and does
not use _Float16 at all), but it seems to be the better
fit for hardware with half precision instructions.
David Malcolm Aug. 19, 2016, 3:52 p.m. UTC | #5
On Fri, 2016-08-19 at 14:40 +0000, Joseph Myers wrote:
> On Fri, 19 Aug 2016, Richard Biener wrote:
> 
> > > > Can you quickly verify if LTO works with the new types?  I
> > > > don't see anything
> > > > that would prevent it but having new global trees and backends
> > > > initializing them
> > > > might come up with surprises (see tree
> > > > -streamer.c:preload_common_nodes)
> > > 
> > > Well, the execution tests are in gcc.dg/torture, which is run
> > > with various
> > > options including -flto (and I've checked the testsuite logs to
> > > confirm
> > > these tests are indeed run with such options).  Is there
> > > something else
> > > you think should be tested?
> > 
> > No, I think that's enough.
> 
> Then I'll commit the patch later today in the absence of comments
> from 
> other libcpp maintainers (and then go on to update and retest the
> built-in 
> functions patch).

[For reference, the latest version of the patch seems to be here:
  https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01290.html ]

Although I'm listed as a libcpp maintainer, I believe today is the
first time I've looked at libcpp/expr.c:interpret_float_suffix.  Also,
my attempts to search for the standard you're referring to are failing,
which isn't helping, so my apologies in advance.

I attempted to review your changes to interpret_float_suffix, and I'm
having a hard time understanding what the supported suffixes now are.

Please could you take this opportunity to add some examples to the
header comment for that function, both for the common cases e.g. "f",
and for the new suffixes; nothing in the patch body appears to document
them.  (ideally, referencing the standard).

Also, it would be good to add some more comments to the function body. 
 For example, in this hunk:

-  if (f + d + l + w + q > 1 || i > 1)
+  if (f + d + l + w + q + fn + fnx > 1 || i > 1)

should it read something like :
   /* Reject duplicate suffixes, contradictory suffixes [...] */

where "[...]" is something relating to fn + fnx, which I can't figure
out in the absence of the standard you're referring to.

Sorry about my ignorance, hope this is constructive feedback
Dave
Joseph Myers Aug. 19, 2016, 4:23 p.m. UTC | #6
On Fri, 19 Aug 2016, Szabolcs Nagy wrote:

> On 17/08/16 21:17, Joseph Myers wrote:
> > Although there is HFmode support for ARM and AArch64, use of that for
> > _Float16 is not enabled.  Supporting _Float16 would require additional
> > work on the excess precision aspects of TS 18661-3: there are new
> > values of FLT_EVAL_METHOD, which are not currently supported in GCC,
> > and FLT_EVAL_METHOD == 0 now means that operations and constants on
> > types narrower than float are evaluated to the range and precision of
> > float.  Implementing that, so that _Float16 gets evaluated with excess
> > range and precision, would involve changes to the excess precision
> > infrastructure so that the _Float16 case is enabled by default, unlike
> > the x87 case which is only enabled for -fexcess-precision=standard.
> > Other differences between _Float16 and __fp16 would also need to be
> > disentangled.
> 
> i wonder how gcc can support _Float16 without excess
> precision.
> 
> using FLT_EVAL_METHOD==16 can break conforming c99/c11
> code which only expects 0,1,2 values to appear (and does
> not use _Float16 at all), but it seems to be the better
> fit for hardware with half precision instructions.

Maybe this indicates that -fexcess-precision=standard, whether explicit or 
implies by a -std option, must cause FLT_EVAL_METHOD=0 for such hardware, 
and some new -fexcess-precision= option is needed to select 
FLT_EVAL_METHOD=16 (say -fexcess-precision=16, with no expectation that 
most numeric -fexcess-precision= arguments are supported except where a 
target hook says they are or where they are the default FLT_EVAL_METHOD 
value).  Then -std=c2x, if C2X integrates TS 18661-3, might not imply the 
value 0 for such hardware, because the value 16 would also be OK as a 
standard value in that case.  This can be part of the design issues to 
address alongside those I mentioned in 
<https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01899.html>.
Andreas Schwab Aug. 21, 2016, 9:50 a.m. UTC | #7
On Aug 17 2016, Joseph Myers <joseph@codesourcery.com> wrote:

> Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x-timode.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x-timode.c	(nonexistent)
> +++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x-timode.c	(working copy)
> @@ -0,0 +1,16 @@
> +/* Test floating-point conversions.  _Float128x type with TImode.  */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +/* { dg-add-options float128x } */
> +/* { dg-require-effective-target float128x_runtime } */
> +
> +#define __STDC_WANT_IEC_60559_TYPES_EXT__
> +#include <float.h>
> +#include "fp-int-convert.h"
> +
> +int
> +main (void)
> +{
> +  TEST_I_F(TItype, UTItype, _Float128, FLT128X_MANT_DIG, FLT128X_MAX_EXP);

s/_Float128/_Float128x/

> Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c	(nonexistent)
> +++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c	(working copy)
> @@ -0,0 +1,16 @@
> +/* Test floating-point conversions.  _Float32x type with TImode.  */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +/* { dg-add-options float32x } */
> +/* { dg-require-effective-target float32x_runtime } */
> +
> +#define __STDC_WANT_IEC_60559_TYPES_EXT__
> +#include <float.h>
> +#include "fp-int-convert.h"
> +
> +int
> +main (void)
> +{
> +  TEST_I_F(TItype, UTItype, _Float32, FLT32X_MANT_DIG, FLT32X_MAX_EXP);

s/_Float32/_Float32x/

> Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x-timode.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x-timode.c	(nonexistent)
> +++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x-timode.c	(working copy)
> @@ -0,0 +1,16 @@
> +/* Test floating-point conversions.  _Float64x type with TImode.  */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +/* { dg-add-options float64x } */
> +/* { dg-require-effective-target float64x_runtime } */
> +
> +#define __STDC_WANT_IEC_60559_TYPES_EXT__
> +#include <float.h>
> +#include "fp-int-convert.h"
> +
> +int
> +main (void)
> +{
> +  TEST_I_F(TItype, UTItype, _Float64, FLT64X_MANT_DIG, FLT64X_MAX_EXP);

s/_Float64/_Float64x/

Andreas.
Jan-Benedict Glaw Aug. 22, 2016, 8:09 a.m. UTC | #8
Hi Joseph!

On Wed, 2016-08-17 20:17:07 +0000, Joseph Myers <joseph@codesourcery.com> wrote:
[...]
> ISO/IEC TS 18661-3:2015 defines C bindings to IEEE interchange and
> extended types, in the form of _FloatN and _FloatNx type names with
> corresponding fN/FN and fNx/FNx constant suffixes and FLTN_* / FLTNX_*
> <float.h> macros.  This patch implements support for this feature in
> GCC.

Between dee8cef0c1c1ebf85fceb5c37996ed12a2bec352 (Fri Aug 19 15:42:11
2016 +0000) and 82c85aba845985e55c27a7a9c448810d433adb17 (Fri Aug 19
17:43:26 2016 +0000), a new build regression for
x86_64-{linux,rtems,elf} showed up and I think this patch caused it.
It occurs during GCC's self-test while it's setting up it's FP types:


/scratch/4/jbglaw/regular/build/x86_64-elf/build-gcc/./gcc/xgcc -B/scratch/4/jbglaw/regular/build/x86_64-elf/build-gcc/./gcc/ -xc -S -c /dev/null -fself-test
<built-in>: internal compiler error: Segmentation fault
0xb7803f crash_signal
/scratch/4/jbglaw/regular/repos/gcc/gcc/toplev.c:335
0x687952 tree_class_check
/scratch/4/jbglaw/regular/repos/gcc/gcc/tree.h:3145
0x687952 c_register_builtin_type(tree_node*, char const*)
/scratch/4/jbglaw/regular/repos/gcc/gcc/c-family/c-common.c:3876
0xeb6b36 ix86_init_builtin_types
/scratch/4/jbglaw/regular/repos/gcc/gcc/config/i386/i386.c:33351
0xeb6b36 ix86_init_builtins
/scratch/4/jbglaw/regular/repos/gcc/gcc/config/i386/i386.c:33366
0x6a8006 c_define_builtins
/scratch/4/jbglaw/regular/repos/gcc/gcc/c-family/c-common.c:5282
0x6a8006 c_common_nodes_and_builtins()
/scratch/4/jbglaw/regular/repos/gcc/gcc/c-family/c-common.c:5750
0x5ef719 c_init_decl_processing()
/scratch/4/jbglaw/regular/repos/gcc/gcc/c/c-decl.c:4097
0x63caf8 c_objc_common_init()
/scratch/4/jbglaw/regular/repos/gcc/gcc/c/c-objc-common.c:58
0x5de4c2 lang_dependent_init
/scratch/4/jbglaw/regular/repos/gcc/gcc/toplev.c:1766
0x5de4c2 do_compile
/scratch/4/jbglaw/regular/repos/gcc/gcc/toplev.c:1989
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.
make[1]: *** [s-selftest] Error 1



See eg. build http://toolchain.lug-owl.de/buildbot/show_build_details.php?id=608741


MfG, JBG
Matthew Wahab Aug. 22, 2016, 10:47 a.m. UTC | #9
Hello,

On 17/08/16 21:17, Joseph Myers wrote:
> [Version 6 changes the testsuite to use dg-add-options systematically
> to add any options that may be needed for the types to be supported;
> this should allow the _Float128 and _Float64x tests to run for
> powerpc64le, but I have not tested that; it could do with powerpc
> maintainer testing that the tests do indeed run.  It also has fixes
> for the fp-int-convert issues pointed out in
> <https://gcc.gnu.org/ml/gcc-patches/2016-08/msg01279.html>.  There are
> no changes to the patch outside the testsuite and associated
> documentation of effective-target and dg-add-options keywords.]
>
>
> ISO/IEC TS 18661-3:2015 defines C bindings to IEEE interchange and
> extended types, in the form of _FloatN and _FloatNx type names with
> corresponding fN/FN and fNx/FNx constant suffixes and FLTN_* / FLTNX_*
> <float.h> macros.  This patch implements support for this feature in
> GCC.
>

There are some test failure on arm that appear to be due to this patch.

> Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c	(nonexistent)
> +++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c	(working copy)
> @@ -0,0 +1,16 @@
> +/* Test floating-point conversions.  _Float32x type with TImode.  */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +/* { dg-add-options float32x } */
> +/* { dg-require-effective-target float32x_runtime } */
> +
> +#define __STDC_WANT_IEC_60559_TYPES_EXT__
> +#include <float.h>
> +#include "fp-int-convert.h"
> +
> +int
> +main (void)
> +{
> +  TEST_I_F(TItype, UTItype, _Float32, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
> +  exit (0);
> +

This test fails with an abort at runtime. The other float32x tests pass.

> Index: gcc/testsuite/gcc.dg/torture/fp-int-convert.h
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/fp-int-convert.h	(revision 239543)
> +++ gcc/testsuite/gcc.dg/torture/fp-int-convert.h	(working copy)
> @@ -15,20 +15,21 @@ typedef long TItype;
>   typedef unsigned long UTItype;
>   #endif
>
> -/* TEST_I_F(I, U, F, P) tests conversions between the pair of signed
> -   and unsigned integer types I and U and the floating-point type F,
> -   where P is the binary precision of the floating point type.  We
> -   test conversions of the values 0, 1, 0x7...f, 0x8...0, 0xf...f.  We
> -   also test conversions of values half way between two
> -   representable values (rounding both ways), just above half way, and
> -   just below half way.  */
> -#define TEST_I_F(I, U, F, P)					\
> +/* TEST_I_F(I, U, F, P, M) tests conversions between the pair of
> +   signed and unsigned integer types I and U and the floating-point
> +   type F, where P is the binary precision of the floating point type
> +   and M is the MAX_EXP value for that type (so 2^M overflows, 2^(M-1)
> +   does not).  We test conversions of the values 0, 1, 0x7...f,
> +   0x8...0, 0xf...f.  We also test conversions of values half way
> +   between two representable values (rounding both ways), just above
> +   half way, and just below half way.  */
> +#define TEST_I_F(I, U, F, P, M)					\

This change makes gcc.dg/torture/arm-fp16-int-convert-{alt,ieee].c fail because
they still pass four arguments to the macro, not five.

Matthew
Joseph Myers Aug. 22, 2016, 11:22 a.m. UTC | #10
On Mon, 22 Aug 2016, Jan-Benedict Glaw wrote:

> Between dee8cef0c1c1ebf85fceb5c37996ed12a2bec352 (Fri Aug 19 15:42:11
> 2016 +0000) and 82c85aba845985e55c27a7a9c448810d433adb17 (Fri Aug 19
> 17:43:26 2016 +0000), a new build regression for
> x86_64-{linux,rtems,elf} showed up and I think this patch caused it.

I do not see this in my x86_64-pc-linux-gnu tests (and the logs show those 
builds do run the self-tests as expected).
James Greenhalgh Aug. 31, 2016, 4:58 p.m. UTC | #11
On Fri, Aug 19, 2016 at 04:23:55PM +0000, Joseph Myers wrote:
> On Fri, 19 Aug 2016, Szabolcs Nagy wrote:
> 
> > On 17/08/16 21:17, Joseph Myers wrote:
> > > Although there is HFmode support for ARM and AArch64, use of that for
> > > _Float16 is not enabled.  Supporting _Float16 would require additional
> > > work on the excess precision aspects of TS 18661-3: there are new
> > > values of FLT_EVAL_METHOD, which are not currently supported in GCC,
> > > and FLT_EVAL_METHOD == 0 now means that operations and constants on
> > > types narrower than float are evaluated to the range and precision of
> > > float.  Implementing that, so that _Float16 gets evaluated with excess
> > > range and precision, would involve changes to the excess precision
> > > infrastructure so that the _Float16 case is enabled by default, unlike
> > > the x87 case which is only enabled for -fexcess-precision=standard.
> > > Other differences between _Float16 and __fp16 would also need to be
> > > disentangled.
> > 
> > i wonder how gcc can support _Float16 without excess
> > precision.
> > 
> > using FLT_EVAL_METHOD==16 can break conforming c99/c11
> > code which only expects 0,1,2 values to appear (and does
> > not use _Float16 at all), but it seems to be the better
> > fit for hardware with half precision instructions.
> 
> Maybe this indicates that -fexcess-precision=standard, whether explicit or 
> implies by a -std option, must cause FLT_EVAL_METHOD=0 for such hardware, 
> and some new -fexcess-precision= option is needed to select 
> FLT_EVAL_METHOD=16 (say -fexcess-precision=16, with no expectation that 
> most numeric -fexcess-precision= arguments are supported except where a 
> target hook says they are or where they are the default FLT_EVAL_METHOD 
> value).

That seems reasonable for -fexcess-precision=standard and where it is
implied by a -std=c?? option.

My concern with this is that the use of comparisons of FLT_EVAL_METHOD
against 0 that Szabolcs is referring to is common and can have performance
implications. In glibc for example, 

  static FLOAT
  overflow_value (int negative)
  {
    __set_errno (ERANGE);
  #if FLT_EVAL_METHOD != 0
    volatile
  #endif
    FLOAT result = (negative ? -MAX_VALUE : MAX_VALUE) * MAX_VALUE;
    return result;
  }

The effect of setting FLT_EVAL_METHOD = 16 for -fexcess-precision=fast (which
is the default) would be to introduce additional "volatile" qualifiers,
which is probably not what the user intends. Elsewhere (quick search of the
debian code archive) the effect is to introduce more complicated assignment
routines or (in Boost's math/tr1.hpp) to define float_t and double_t:

  #if !defined(FLT_EVAL_METHOD)
  typedef float float_t;
  typedef double double_t;
  #elif FLT_EVAL_METHOD == -1
  typedef float float_t;
  typedef double double_t;
  #elif FLT_EVAL_METHOD == 0
  typedef float float_t;
  typedef double double_t;
  #elif FLT_EVAL_METHOD == 1
  typedef double float_t;
  typedef double double_t;
  #else
  typedef long double float_t;
  typedef long double double_t;
  #endif

It seems to me that if I set FLT_EVAL_METHOD = 16, I'm opening the AArch64
port to a number of performance issues in floating-point code if a user
has configured --with-arch=armv8.2-a+fp16 .

On the other hand, it would be unfortunate if _Float16 could not use the
ARMv8.2-A floating-point arithmetic instructions where they were available.

> Then -std=c2x, if C2X integrates TS 18661-3, might not imply the 
> value 0 for such hardware, because the value 16 would also be OK as a 
> standard value in that case.  This can be part of the design issues to 
> address alongside those I mentioned in 
> <https://gcc.gnu.org/ml/gcc-patches/2016-07/msg01899.html>.

I'm working on these. Right now, I have AArch64 set up as so:

If ARMv8.2-A extensions are available,

  -fexcess-precision=standard -> FLT_EVAL_METHOD = 0
  -fexcess-precision=fast -> FLT_EVAL_METHOD = 16

If ARMv8.2-A extensions are not available,

  -fexcess-precision=standard -> FLT_EVAL_METHOD = 0
  -fexcess-precision=fast -> FLT_EVAL_METHOD = 0

In c-family/c-cppbuiltin.c I've updated cpp_iec_559_value such that it
also allows setting __GEC_IEC_559 if FLT_EVAL_METHOD = 16, and I've updated
c_cpp_builtins to continue to set excess_precision = false if
FLT_EVAL_METHOD == 16. Then I've updated init_excess_precision in toplev.c
with logic to understand that for targets that provide _Float16, we can't
set flag_excess_precision to "fast" when FLT_EVAL_METHOD=0. This is because
FLT_EVAL_METHOD=0 requires predictably using the precision of float for
_Float16 types.
 
In tree.c, I've modified excess_precision_type with the logic discussed
above, promoting _Float16 to float (or wider) if we are required to.

The code needs some cleanup, and I need to decide what to do about the
issue Szabolcs brought up, but I'm hoping to be able to send patches in
the near future for GCC and soft-fp in glibc/libgcc.

Thanks,
James
Joseph Myers Aug. 31, 2016, 5:26 p.m. UTC | #12
On Wed, 31 Aug 2016, James Greenhalgh wrote:

> My concern with this is that the use of comparisons of FLT_EVAL_METHOD
> against 0 that Szabolcs is referring to is common and can have performance
> implications. In glibc for example, 
> 
>   static FLOAT
>   overflow_value (int negative)
>   {
>     __set_errno (ERANGE);
>   #if FLT_EVAL_METHOD != 0
>     volatile
>   #endif
>     FLOAT result = (negative ? -MAX_VALUE : MAX_VALUE) * MAX_VALUE;
>     return result;
>   }

Well, it's unavoidable that existing code may misbehave with a new value 
and need updating.  In the glibc case: use of volatile for excess 
precision is the old approach.  That function now (since my 2015-09-23 
patch) uses math_narrow_eval.  And math_narrow_eval is defined using an 
excess_precision macro in math_private.h.  So only the definition of that 
macro based on FLT_EVAL_METHOD needs updating for new values (and 
math_narrow_eval uses __asm__ ("" : "+m" (math_narrow_eval_tmp)); rather 
than volatile, which may be slightly better, though of course you want to 
avoid the load and store to memory in cases where there is no excess 
precision, or where truncating doesn't require a load and store).

(Of course if you want actual TS 18661-3 support for _Float16 in glibc 
that implies a strtof16 function and lots of other *f16 functions which 
also need to know about excess precision for _Float16 in the 
FLT_EVAL_METHOD = 0 case.  Even given the _Float128 support, supporting 
_Float16 in glibc would be a complicated project since no _Float16 
function implementations for glibc presently exist, although many could, 
correctly if suboptimally, wrap float versions.)

> On the other hand, it would be unfortunate if _Float16 could not use the
> ARMv8.2-A floating-point arithmetic instructions where they were available.

In the cases where the two FLT_EVAL_METHOD values are equivalent (e.g. 
where the result is assigned directly back to a _Float16 variable) of 
course you can anyway.
Szabolcs Nagy Sept. 1, 2016, 10:52 a.m. UTC | #13
On 31/08/16 18:26, Joseph Myers wrote:
> On Wed, 31 Aug 2016, James Greenhalgh wrote:
> 
>> My concern with this is that the use of comparisons of FLT_EVAL_METHOD
>> against 0 that Szabolcs is referring to is common and can have performance
>> implications. In glibc for example, 
>>
>>   static FLOAT
>>   overflow_value (int negative)
>>   {
>>     __set_errno (ERANGE);
>>   #if FLT_EVAL_METHOD != 0
>>     volatile
>>   #endif
>>     FLOAT result = (negative ? -MAX_VALUE : MAX_VALUE) * MAX_VALUE;
>>     return result;
>>   }
> 
> Well, it's unavoidable that existing code may misbehave with a new value 
> and need updating.  In the glibc case: use of volatile for excess 
> precision is the old approach.  That function now (since my 2015-09-23 
> patch) uses math_narrow_eval.  And math_narrow_eval is defined using an 
> excess_precision macro in math_private.h.  So only the definition of that 
> macro based on FLT_EVAL_METHOD needs updating for new values (and 
> math_narrow_eval uses __asm__ ("" : "+m" (math_narrow_eval_tmp)); rather 
> than volatile, which may be slightly better, though of course you want to 
> avoid the load and store to memory in cases where there is no excess 
> precision, or where truncating doesn't require a load and store).
> 
> (Of course if you want actual TS 18661-3 support for _Float16 in glibc 
> that implies a strtof16 function and lots of other *f16 functions which 
> also need to know about excess precision for _Float16 in the 
> FLT_EVAL_METHOD = 0 case.  Even given the _Float128 support, supporting 

the goal was not to provide full support for some TS, but to
provide reasonable access to half precision floats from c.

it seems that the FLT_EVAL_METHOD change in TS 18661 was a
bad decision: existing code have to be modified to conform
to the new semantics. this situation could have been avoided
by introducing new macros or only changing behaviour when
the user requested it via __STDC_WANT_IEC_60559_TYPES_EXT__
(consistently with all other library changes..).

i think it makes sense to provide half precision support
on older c standards, so gcc should allow _Float16 without
excess precision and whatever __FLT_EVAL_METHOD setting
based on some cmd line option, so users can work around
this mess. (FLT_EVAL_METHOD < 0 would be fully conforming,
but it can still break existing code). user code can use
sizeof(_Float16_t), libc can get the real eval method
through some additional gcc specific macro.

> _Float16 in glibc would be a complicated project since no _Float16 
> function implementations for glibc presently exist, although many could, 
> correctly if suboptimally, wrap float versions.)
> 
>> On the other hand, it would be unfortunate if _Float16 could not use the
>> ARMv8.2-A floating-point arithmetic instructions where they were available.
> 
> In the cases where the two FLT_EVAL_METHOD values are equivalent (e.g. 
> where the result is assigned directly back to a _Float16 variable) of 
> course you can anyway.
>
Joseph Myers Sept. 1, 2016, 3:40 p.m. UTC | #14
On Thu, 1 Sep 2016, Szabolcs Nagy wrote:

> it seems that the FLT_EVAL_METHOD change in TS 18661 was a
> bad decision: existing code have to be modified to conform
> to the new semantics. this situation could have been avoided
> by introducing new macros or only changing behaviour when
> the user requested it via __STDC_WANT_IEC_60559_TYPES_EXT__
> (consistently with all other library changes..).

You could always raise the issue directly with WG14, since TS 18661 is 
supposed to be compatible with C11 (cf the issue I raised about whether 
the formula for DECIMAL_DIG in C11 is normatively required or a minimum).

Now a minimal fix for such an issue (interpreted as a DR against C11 
rather than against TS 18661-3) to make the definition of FLT_EVAL_METHOD 
extensible would be to remove the word "negative" in "All other negative 
values for FLT_EVAL_METHOD characterize implementation-defined behavior.", 
so making it more like FLT_ROUNDS.  Which would allow the value 16 to be 
used in existing standards modes, but not avoid the need to update 
existing code to handle it.  But you might prefer an interpretation as a 
DR against TS 18661-3 where the FLT_EVAL_METHOD definition does not have 
to reflect the new types unless __STDC_WANT_IEC_60559_TYPES_EXT__ is 
defined accordingly (and maybe for consistency DEC_EVAL_METHOD only has to 
reflect TS 18661-2 decimal types, not those from 18661-3, unless 
__STDC_WANT_IEC_60559_TYPES_EXT__ is defined).

I expect glibc will be defining __STDC_WANT_IEC_60559_TYPES_EXT__ soon 
anyway (in its <float.h> wrapper to get FLT128_* definitions from there 
where possible) so would still need adapting to be optimal with _Float16 
compiler support.
Andreas Schwab Sept. 3, 2016, 4:33 p.m. UTC | #15
On Aug 17 2016, Joseph Myers <joseph@codesourcery.com> wrote:

> Index: gcc/testsuite/gcc.dg/torture/float32-basic.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/float32-basic.c	(nonexistent)
> +++ gcc/testsuite/gcc.dg/torture/float32-basic.c	(working copy)
> @@ -0,0 +1,9 @@
> +/* Test _Float32.  */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +/* { dg-add-options float32 } */
> +/* { dg-require-effective-target float32_runtime } */
> +
> +#define WIDTH 32
> +#define EXT 0
> +#include "floatn-basic.h"

This fails on powerpc32, in vafn.

Andreas.
Joseph Myers Sept. 5, 2016, 11:40 a.m. UTC | #16
On Sat, 3 Sep 2016, Andreas Schwab wrote:

> On Aug 17 2016, Joseph Myers <joseph@codesourcery.com> wrote:
> 
> > Index: gcc/testsuite/gcc.dg/torture/float32-basic.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/torture/float32-basic.c	(nonexistent)
> > +++ gcc/testsuite/gcc.dg/torture/float32-basic.c	(working copy)
> > @@ -0,0 +1,9 @@
> > +/* Test _Float32.  */
> > +/* { dg-do run } */
> > +/* { dg-options "" } */
> > +/* { dg-add-options float32 } */
> > +/* { dg-require-effective-target float32_runtime } */
> > +
> > +#define WIDTH 32
> > +#define EXT 0
> > +#include "floatn-basic.h"
> 
> This fails on powerpc32, in vafn.

That seems like the alpha issue - an ABI needs to be defined and 
implemented.  Unfortunately the powerabi mailing list, which would have 
been the right place for ABI coordination between implementors, died 
several years ago.  (The 32-bit ABI source code is available at 
<https://github.com/ryanarn/powerabi>.)

If we suppose that _Float32 values should be passed in FPRs in the same 
circumstances in which float values are passed in FPRs, then 
rs6000_gimplify_va_arg would, in the case of an SFmode value coming from 
saved FPRs, need to extract a double value from the saved FPRs and then 
convert to float.  (There would also be the question of later _Float32 
arguments passed on the stack in variable arguments; if those are handled 
like prototyped arguments, they would go in 4-byte stack slots, and 
probably the compiler already does that.)  Of course other ABI choices are 
possible.
Richard Biener Sept. 6, 2016, 8:58 a.m. UTC | #17
On Mon, Sep 5, 2016 at 1:40 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Sat, 3 Sep 2016, Andreas Schwab wrote:
>
>> On Aug 17 2016, Joseph Myers <joseph@codesourcery.com> wrote:
>>
>> > Index: gcc/testsuite/gcc.dg/torture/float32-basic.c
>> > ===================================================================
>> > --- gcc/testsuite/gcc.dg/torture/float32-basic.c    (nonexistent)
>> > +++ gcc/testsuite/gcc.dg/torture/float32-basic.c    (working copy)
>> > @@ -0,0 +1,9 @@
>> > +/* Test _Float32.  */
>> > +/* { dg-do run } */
>> > +/* { dg-options "" } */
>> > +/* { dg-add-options float32 } */
>> > +/* { dg-require-effective-target float32_runtime } */
>> > +
>> > +#define WIDTH 32
>> > +#define EXT 0
>> > +#include "floatn-basic.h"
>>
>> This fails on powerpc32, in vafn.
>
> That seems like the alpha issue - an ABI needs to be defined and
> implemented.

Note that this makes it maybe a good idea to only enable _FloatXX support
for targets that have explicitely done so once we near the GCC 7 release.
Otherwise we risk a later ABI change if the ABI differs from GCCs implementation
from the time there was no ABI defined for those types.

Richard.

>  Unfortunately the powerabi mailing list, which would have
> been the right place for ABI coordination between implementors, died
> several years ago.  (The 32-bit ABI source code is available at
> <https://github.com/ryanarn/powerabi>.)
>
> If we suppose that _Float32 values should be passed in FPRs in the same
> circumstances in which float values are passed in FPRs, then
> rs6000_gimplify_va_arg would, in the case of an SFmode value coming from
> saved FPRs, need to extract a double value from the saved FPRs and then
> convert to float.  (There would also be the question of later _Float32
> arguments passed on the stack in variable arguments; if those are handled
> like prototyped arguments, they would go in 4-byte stack slots, and
> probably the compiler already does that.)  Of course other ABI choices are
> possible.
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
Joseph Myers Sept. 6, 2016, 11:17 a.m. UTC | #18
On Tue, 6 Sep 2016, Richard Biener wrote:

> Note that this makes it maybe a good idea to only enable _FloatXX support
> for targets that have explicitely done so once we near the GCC 7 release.

I don't think that's a good idea; it's a recipe for most targets never 
supporting the new types when in fact they'd work fine.  (Every case other 
than possibly _Float32 variable arguments will just work as long as the 
back end uses machine modes to determine argument passing for scalar types 
and assuming the ABI chosen is the same as for the corresponding standard 
types.  32-bit powerpc is one of the most complicated variable-arguments 
ABIs.  And since there are no printf formats for the new types, passing 
them in variable arguments is an unusual case anyway.)

Architecture maintainers where there are externally maintained 
architecture definitions are of course welcome to work on getting an ABI 
for these types properly documented.
Thomas Schwinge Sept. 7, 2016, 11:52 a.m. UTC | #19
Hi!

I trimmed the CC list -- I'm looking for advice about debugging a lto1
ICE.

On Fri, 19 Aug 2016 11:05:59 +0000, Joseph Myers <joseph@codesourcery.com> wrote:
> On Fri, 19 Aug 2016, Richard Biener wrote:
> > Can you quickly verify if LTO works with the new types?  I don't see anything
> > that would prevent it but having new global trees and backends initializing them
> > might come up with surprises (see tree-streamer.c:preload_common_nodes)
> 
> Well, the execution tests are in gcc.dg/torture, which is run with various 
> options including -flto (and I've checked the testsuite logs to confirm 
> these tests are indeed run with such options).  Is there something else 
> you think should be tested?

As I noted in <https://gcc.gnu.org/PR77458>:

    As of the PR32187 commit r239625 "Implement C _FloatN, _FloatNx types", nvptx
    offloading is broken, ICEs in LTO stream-in.  Probably some kind of data-type
    mismatch that is not visible with Intel MIC offloading (using the same data
    types) but explodes with nvptx.  I'm having a look.

I know how to use "-save-temps -v" to re-run the ICEing lto1 in GDB; a
backtrace of the ICE looks as follows:

    #0  fancy_abort (file=file@entry=0x10d61d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10d6e3a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
    #1  0x000000000058c9ef in vec<tree_node*, va_heap, vl_embed>::operator[] (this=0x16919c0, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:727
    #2  0x000000000058ca33 in vec<tree_node*, va_heap, vl_ptr>::operator[] (this=this@entry=0x1691998, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:1211
    #3  0x0000000000c73e54 in streamer_tree_cache_get_tree (cache=0x1691990, ix=ix@entry=185) at [...]/source-gcc/gcc/tree-streamer.h:98
    #4  0x0000000000c73eb9 in streamer_get_pickled_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930) at [...]/source-gcc/gcc/tree-streamer-in.c:1112
    #5  0x00000000008f841b in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, tag=tag@entry=LTO_tree_pickle_reference, hash=hash@entry=0) at [...]/source-gcc/gcc/lto-streamer-in.c:1404
    #6  0x00000000008f8844 in lto_input_tree (ib=0x7fffffffceb0, data_in=0x1691930) at [...]/source-gcc/gcc/lto-streamer-in.c:1444
    #7  0x0000000000c720d2 in lto_input_ts_list_tree_pointers (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:861
    #8  0x0000000000c7444e in streamer_read_tree_body (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:1077
    #9  0x00000000008f6428 in lto_read_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/lto-streamer-in.c:1285
    #10 0x00000000008f651b in lto_read_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1315
    #11 0x00000000008f85db in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1427
    #12 0x00000000008f8673 in lto_input_scc (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, len=len@entry=0x7fffffffceac, entry_len=entry_len@entry=0x7fffffffcea8) at [...]/source-gcc/gcc/lto-streamer-in.c:1339
    #13 0x00000000005890f7 in lto_read_decls (decl_data=decl_data@entry=0x7ffff7fc0000, data=data@entry=0x169d570, resolutions=...) at [...]/source-gcc/gcc/lto/lto.c:1693
    #14 0x00000000005898c8 in lto_file_finalize (file_data=file_data@entry=0x7ffff7fc0000, file=file@entry=0x15eedb0) at [...]/source-gcc/gcc/lto/lto.c:2037
    #15 0x0000000000589928 in lto_create_files_from_ids (file=file@entry=0x15eedb0, file_data=file_data@entry=0x7ffff7fc0000, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2047
    #16 0x0000000000589a7a in lto_file_read (file=0x15eedb0, resolution_file=resolution_file@entry=0x0, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2088
    #17 0x0000000000589e84 in read_cgraph_and_symbols (nfiles=1, fnames=0x160e990) at [...]/source-gcc/gcc/lto/lto.c:2798
    #18 0x000000000058a572 in lto_main () at [...]/source-gcc/gcc/lto/lto.c:3299
    #19 0x0000000000a48eff in compile_file () at [...]/source-gcc/gcc/toplev.c:466
    #20 0x0000000000550943 in do_compile () at [...]/source-gcc/gcc/toplev.c:2010
    #21 toplev::main (this=this@entry=0x7fffffffd180, argc=argc@entry=20, argv=0x15daf20, argv@entry=0x7fffffffd288) at [...]/source-gcc/gcc/toplev.c:2144
    #22 0x0000000000552717 in main (argc=20, argv=0x7fffffffd288) at [...]/source-gcc/gcc/main.c:39

(Comparing to yesterday's r240004, the line number are slightly off, as
I've added some stuff to aid debugging.)

Looking at frame 14, lto_file_finalize, the ICE happens inside
lto_read_decls, after the mode table setup:

    2025    #ifdef ACCEL_COMPILER
    2026      lto_input_mode_table (file_data);
    2027    #else
    2028      file_data->mode_table = lto_mode_identity_table;
    2029    #endif
    2030      data = lto_get_section_data (file_data, LTO_section_decls, NULL, &len);
    2031      if (data == NULL)
    2032        {
    2033          internal_error ("cannot read LTO decls from %s", file_data->file_name);
    2034          return;
    2035        }
    2036      /* Frees resolutions */
    2037      lto_read_decls (file_data, data, resolutions);

I have some confidence that it's not the offloading-specific
lto_write_mode_table/lto_input_mode_table mode table streaming; by manual
inspection it seems as if there's no change in the streamed information.

Looking at Joseph's gcc/tree.c:build_common_tree_nodes, I observe that
the x86_64 GNU/Linux target compiler does but the nvptx-offloading lto1
does not set up _Float128 and _Float64x types (expectedly, I'd day), but
I'm not sure if that's really the reason for the breakage.

From the backtrace I have difficulties to tell what exactly lto1 is
choking on -- are there any good strategies aside from stepping
before/after lto1s in GDB, and seeing where they diverge?  For example,
can I pretty-print the LTO stream that the ICEing lto1 is reading in, and
can I try to tell from that what it's choking on?


Grüße
 Thomas
Richard Biener Sept. 7, 2016, 12:23 p.m. UTC | #20
On Wed, Sep 7, 2016 at 1:52 PM, Thomas Schwinge <thomas@codesourcery.com> wrote:
> Hi!
>
> I trimmed the CC list -- I'm looking for advice about debugging a lto1
> ICE.
>
> On Fri, 19 Aug 2016 11:05:59 +0000, Joseph Myers <joseph@codesourcery.com> wrote:
>> On Fri, 19 Aug 2016, Richard Biener wrote:
>> > Can you quickly verify if LTO works with the new types?  I don't see anything
>> > that would prevent it but having new global trees and backends initializing them
>> > might come up with surprises (see tree-streamer.c:preload_common_nodes)
>>
>> Well, the execution tests are in gcc.dg/torture, which is run with various
>> options including -flto (and I've checked the testsuite logs to confirm
>> these tests are indeed run with such options).  Is there something else
>> you think should be tested?
>
> As I noted in <https://gcc.gnu.org/PR77458>:
>
>     As of the PR32187 commit r239625 "Implement C _FloatN, _FloatNx types", nvptx
>     offloading is broken, ICEs in LTO stream-in.  Probably some kind of data-type
>     mismatch that is not visible with Intel MIC offloading (using the same data
>     types) but explodes with nvptx.  I'm having a look.
>
> I know how to use "-save-temps -v" to re-run the ICEing lto1 in GDB; a
> backtrace of the ICE looks as follows:
>
>     #0  fancy_abort (file=file@entry=0x10d61d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10d6e3a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
>     #1  0x000000000058c9ef in vec<tree_node*, va_heap, vl_embed>::operator[] (this=0x16919c0, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:727
>     #2  0x000000000058ca33 in vec<tree_node*, va_heap, vl_ptr>::operator[] (this=this@entry=0x1691998, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:1211

so it wants tree 185 which is (given the low number) likely one streamed by
preload_common_nodes.  This is carefully crafted to _not_ diverge by
frontend (!) it wasn't even designed to cope with global trees being present
or not dependent on target (well, because the target is always the
same! mind you!)

Now -- in theory it should deal with NULLs just fine (resulting in
error_mark_node), but it can diverge when there are additional
compount types (like vectors, complex
or array or record types) whose element types are not in the set of
global trees.
The complex _FloatN types would be such a case given they appear before their
components.  That mixes up the ordering at least.

So I suggest to add a print_tree to where it does the streamer_tree_cache_append
and compare cc1 and lto1 outcome.

The ICE above means the lto1 has fewer preloaded nodes I guess.

Richard.

>     #3  0x0000000000c73e54 in streamer_tree_cache_get_tree (cache=0x1691990, ix=ix@entry=185) at [...]/source-gcc/gcc/tree-streamer.h:98
>     #4  0x0000000000c73eb9 in streamer_get_pickled_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930) at [...]/source-gcc/gcc/tree-streamer-in.c:1112
>     #5  0x00000000008f841b in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, tag=tag@entry=LTO_tree_pickle_reference, hash=hash@entry=0) at [...]/source-gcc/gcc/lto-streamer-in.c:1404
>     #6  0x00000000008f8844 in lto_input_tree (ib=0x7fffffffceb0, data_in=0x1691930) at [...]/source-gcc/gcc/lto-streamer-in.c:1444
>     #7  0x0000000000c720d2 in lto_input_ts_list_tree_pointers (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:861
>     #8  0x0000000000c7444e in streamer_read_tree_body (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:1077
>     #9  0x00000000008f6428 in lto_read_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/lto-streamer-in.c:1285
>     #10 0x00000000008f651b in lto_read_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1315
>     #11 0x00000000008f85db in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1427
>     #12 0x00000000008f8673 in lto_input_scc (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x1691930, len=len@entry=0x7fffffffceac, entry_len=entry_len@entry=0x7fffffffcea8) at [...]/source-gcc/gcc/lto-streamer-in.c:1339
>     #13 0x00000000005890f7 in lto_read_decls (decl_data=decl_data@entry=0x7ffff7fc0000, data=data@entry=0x169d570, resolutions=...) at [...]/source-gcc/gcc/lto/lto.c:1693
>     #14 0x00000000005898c8 in lto_file_finalize (file_data=file_data@entry=0x7ffff7fc0000, file=file@entry=0x15eedb0) at [...]/source-gcc/gcc/lto/lto.c:2037
>     #15 0x0000000000589928 in lto_create_files_from_ids (file=file@entry=0x15eedb0, file_data=file_data@entry=0x7ffff7fc0000, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2047
>     #16 0x0000000000589a7a in lto_file_read (file=0x15eedb0, resolution_file=resolution_file@entry=0x0, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2088
>     #17 0x0000000000589e84 in read_cgraph_and_symbols (nfiles=1, fnames=0x160e990) at [...]/source-gcc/gcc/lto/lto.c:2798
>     #18 0x000000000058a572 in lto_main () at [...]/source-gcc/gcc/lto/lto.c:3299
>     #19 0x0000000000a48eff in compile_file () at [...]/source-gcc/gcc/toplev.c:466
>     #20 0x0000000000550943 in do_compile () at [...]/source-gcc/gcc/toplev.c:2010
>     #21 toplev::main (this=this@entry=0x7fffffffd180, argc=argc@entry=20, argv=0x15daf20, argv@entry=0x7fffffffd288) at [...]/source-gcc/gcc/toplev.c:2144
>     #22 0x0000000000552717 in main (argc=20, argv=0x7fffffffd288) at [...]/source-gcc/gcc/main.c:39
>
> (Comparing to yesterday's r240004, the line number are slightly off, as
> I've added some stuff to aid debugging.)
>
> Looking at frame 14, lto_file_finalize, the ICE happens inside
> lto_read_decls, after the mode table setup:
>
>     2025    #ifdef ACCEL_COMPILER
>     2026      lto_input_mode_table (file_data);
>     2027    #else
>     2028      file_data->mode_table = lto_mode_identity_table;
>     2029    #endif
>     2030      data = lto_get_section_data (file_data, LTO_section_decls, NULL, &len);
>     2031      if (data == NULL)
>     2032        {
>     2033          internal_error ("cannot read LTO decls from %s", file_data->file_name);
>     2034          return;
>     2035        }
>     2036      /* Frees resolutions */
>     2037      lto_read_decls (file_data, data, resolutions);
>
> I have some confidence that it's not the offloading-specific
> lto_write_mode_table/lto_input_mode_table mode table streaming; by manual
> inspection it seems as if there's no change in the streamed information.
>
> Looking at Joseph's gcc/tree.c:build_common_tree_nodes, I observe that
> the x86_64 GNU/Linux target compiler does but the nvptx-offloading lto1
> does not set up _Float128 and _Float64x types (expectedly, I'd day), but
> I'm not sure if that's really the reason for the breakage.
>
> From the backtrace I have difficulties to tell what exactly lto1 is
> choking on -- are there any good strategies aside from stepping
> before/after lto1s in GDB, and seeing where they diverge?  For example,
> can I pretty-print the LTO stream that the ICEing lto1 is reading in, and
> can I try to tell from that what it's choking on?
>
>
> Grüße
>  Thomas
Thomas Schwinge Sept. 8, 2016, 11:43 a.m. UTC | #21
Hi!

On Wed, 7 Sep 2016 14:23:18 +0200, Richard Biener <richard.guenther@gmail.com> wrote:
> On Wed, Sep 7, 2016 at 1:52 PM, Thomas Schwinge <thomas@codesourcery.com> wrote:
> > I trimmed the CC list -- I'm looking for advice about debugging a lto1
> > ICE.
> >
> > On Fri, 19 Aug 2016 11:05:59 +0000, Joseph Myers <joseph@codesourcery.com> wrote:
> >> On Fri, 19 Aug 2016, Richard Biener wrote:
> >> > Can you quickly verify if LTO works with the new types?  I don't see anything
> >> > that would prevent it but having new global trees and backends initializing them
> >> > might come up with surprises (see tree-streamer.c:preload_common_nodes)
> >>
> >> Well, the execution tests are in gcc.dg/torture, which is run with various
> >> options including -flto (and I've checked the testsuite logs to confirm
> >> these tests are indeed run with such options).  Is there something else
> >> you think should be tested?
> >
> > As I noted in <https://gcc.gnu.org/PR77458>:
> >
> >     As of the PR32187 commit r239625 "Implement C _FloatN, _FloatNx types", nvptx
> >     offloading is broken, ICEs in LTO stream-in.  Probably some kind of data-type
> >     mismatch that is not visible with Intel MIC offloading (using the same data
> >     types) but explodes with nvptx.  I'm having a look.
> >
> > I know how to use "-save-temps -v" to re-run the ICEing lto1 in GDB; a
> > backtrace of the ICE looks as follows:
> >
> >     #0  fancy_abort (file=file@entry=0x10d61d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10d6e3a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
> >     #1  0x000000000058c9ef in vec<tree_node*, va_heap, vl_embed>::operator[] (this=0x16919c0, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:727
> >     #2  0x000000000058ca33 in vec<tree_node*, va_heap, vl_ptr>::operator[] (this=this@entry=0x1691998, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:1211
> 
> so it wants tree 185 which is (given the low number) likely one streamed by
> preload_common_nodes.  This is carefully crafted to _not_ diverge by
> frontend (!) it wasn't even designed to cope with global trees being present
> or not dependent on target (well, because the target is always the
> same! mind you!)

Scary.  ;-/

> Now -- in theory it should deal with NULLs just fine (resulting in
> error_mark_node), but it can diverge when there are additional
> compount types (like vectors, complex
> or array or record types) whose element types are not in the set of
> global trees.
> The complex _FloatN types would be such a case given they appear before their
> components.  That mixes up the ordering at least.

ACK, but that's also an issue for "regular" float/complex float, which
also is in "reverse" order.  But that's "fixed" by the recursion in
gcc/tree-streamer.c:record_common_node for "TREE_CODE (node) ==
COMPLEX_TYPE".  This likewise seems to work for the _FloatN types.  (I've
put "fixed" in quotes -- doesn't that recursion mean that we're thus
putting "complex float", "float", [...], "float" (again) into the cache?
Anyway that's for later...)

> So I suggest to add a print_tree to where it does the streamer_tree_cache_append
> and compare cc1 and lto1 outcome.

Thanks for all your suggestions!

As far as I can tell, tree 185 is in fact among the first trees just
after the preloaded ones...  (See record_common_node followed by
streamer_tree_cache_append with "ix == hash" vs., from "ix=180" onwards,
streamer_tree_cache_append called from elsewhere with "ix != hash".)
(I'm also noticing that this cache first is built from "ix=0" through
"ix=179", then apparently discarded, and rebuilt again, which seems
surprising but which I've not yet looked into; hopefully unrelated
issue.)  I'll continue to poke at this, but wanted to given an update
here at least.

    [...]
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:272:record_common_node
     <fixed_point_type 0x7ffff68e23f0 unsigned UDA
        size <integer_cst 0x7ffff68cd378 type <integer_type 0x7ffff68d2150 bitsizetype> constant 64>
        unit size <integer_cst 0x7ffff68cd390 type <integer_type 0x7ffff68d20a8 sizetype> constant 8>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff68e23f0 precision 64>
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=178 hash=178 tree=0x7ffff68e23f0
     <fixed_point_type 0x7ffff68e23f0 unsigned UDA
        size <integer_cst 0x7ffff68cd378 type <integer_type 0x7ffff68d2150 bitsizetype> constant 64>
        unit size <integer_cst 0x7ffff68cd390 type <integer_type 0x7ffff68d20a8 sizetype> constant 8>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff68e23f0 precision 64>
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:272:record_common_node
     <fixed_point_type 0x7ffff68e2690 unsigned UTA
        size <integer_cst 0x7ffff68cd6a8 type <integer_type 0x7ffff68d2150 bitsizetype> constant 128>
        unit size <integer_cst 0x7ffff68cd6c0 type <integer_type 0x7ffff68d20a8 sizetype> constant 16>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff68e2690 precision 128>
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=179 hash=179 tree=0x7ffff68e2690
     <fixed_point_type 0x7ffff68e2690 unsigned UTA
        size <integer_cst 0x7ffff68cd6a8 type <integer_type 0x7ffff68d2150 bitsizetype> constant 128>
        unit size <integer_cst 0x7ffff68cd6c0 type <integer_type 0x7ffff68d20a8 sizetype> constant 16>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff68e2690 precision 128>
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=180 hash=1889092561 tree=0x7ffff68cc930
     <optimization_node 0x7ffff68cc930
        flag_fp_contract_mode (0)
        flag_ira_algorithm (0)
        flag_ira_region (0)
        flag_reorder_blocks_algorithm (0)
        flag_simd_cost_model (0)
        flag_stack_reuse (0)
        flag_vect_cost_model (0)
    >
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=181 hash=2721827057 tree=0x7ffff6993708
     <target_option_node 0x7ffff6993708
    >
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=182 hash=3212777296 tree=0x7ffff6993730
     <identifier_node 0x7ffff6993730 _ZL5placev>
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=183 hash=1511527171 tree=0x7ffff6993758
     <identifier_node 0x7ffff6993758 noinline>
    PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
      ix=184 hash=4086308758 tree=0x7ffff6993780
     <tree_list 0x7ffff6993780>
    
    Breakpoint 1, fancy_abort (file=file@entry=0x10df3d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10e003a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
    1414    {
    (gdb) bt
    #0  fancy_abort (file=file@entry=0x10df3d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10e003a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
    #1  0x000000000059103f in vec<tree_node*, va_heap, vl_embed>::operator[] (this=0x16aba30, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:727
    #2  0x0000000000591083 in vec<tree_node*, va_heap, vl_ptr>::operator[] (this=this@entry=0x169c868, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:1211
    #3  0x0000000000c7d464 in streamer_tree_cache_get_tree (cache=0x169c860, ix=ix@entry=185) at [...]/source-gcc/gcc/tree-streamer.h:98
    #4  0x0000000000c7d4c9 in streamer_get_pickled_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880) at [...]/source-gcc/gcc/tree-streamer-in.c:1112
    #5  0x00000000008fca6b in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, tag=tag@entry=LTO_tree_pickle_reference, hash=hash@entry=0) at [...]/source-gcc/gcc/lto-streamer-in.c:1404
    #6  0x00000000008fce94 in lto_input_tree (ib=0x7fffffffceb0, data_in=0x169f880) at [...]/source-gcc/gcc/lto-streamer-in.c:1444
    #7  0x0000000000c7b6e2 in lto_input_ts_list_tree_pointers (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:861
    #8  0x0000000000c7da5e in streamer_read_tree_body (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:1077
    #9  0x00000000008faa78 in lto_read_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/lto-streamer-in.c:1285
    #10 0x00000000008fab6b in lto_read_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1315
    #11 0x00000000008fcc2b in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1427
    #12 0x00000000008fccc3 in lto_input_scc (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, len=len@entry=0x7fffffffceac, entry_len=entry_len@entry=0x7fffffffcea8) at [...]/source-gcc/gcc/lto-streamer-in.c:1339
    #13 0x000000000058d747 in lto_read_decls (decl_data=decl_data@entry=0x7ffff7fc0000, data=data@entry=0x16b0750, resolutions=...) at [...]/source-gcc/gcc/lto/lto.c:1693
    #14 0x000000000058df18 in lto_file_finalize (file_data=file_data@entry=0x7ffff7fc0000, file=file@entry=0x15f9db0) at [...]/source-gcc/gcc/lto/lto.c:2037
    #15 0x000000000058df78 in lto_create_files_from_ids (file=file@entry=0x15f9db0, file_data=file_data@entry=0x7ffff7fc0000, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2047
    #16 0x000000000058e0ca in lto_file_read (file=0x15f9db0, resolution_file=resolution_file@entry=0x0, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2088
    #17 0x000000000058e4d4 in read_cgraph_and_symbols (nfiles=1, fnames=0x1619990) at [...]/source-gcc/gcc/lto/lto.c:2798
    #18 0x000000000058ebc2 in lto_main () at [...]/source-gcc/gcc/lto/lto.c:3299
    #19 0x0000000000a5208f in compile_file () at [...]/source-gcc/gcc/toplev.c:466
    #20 0x0000000000554f93 in do_compile () at [...]/source-gcc/gcc/toplev.c:2010
    #21 toplev::main (this=this@entry=0x7fffffffd180, argc=argc@entry=20, argv=0x15e5f20, argv@entry=0x7fffffffd288) at [...]/source-gcc/gcc/toplev.c:2144
    #22 0x0000000000556d67 in main (argc=20, argv=0x7fffffffd288) at [...]/source-gcc/gcc/main.c:39


Grüße
 Thomas
Richard Biener Sept. 14, 2016, 10:18 a.m. UTC | #22
On Thu, Sep 8, 2016 at 1:43 PM, Thomas Schwinge <thomas@codesourcery.com> wrote:
> Hi!
>
> On Wed, 7 Sep 2016 14:23:18 +0200, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Wed, Sep 7, 2016 at 1:52 PM, Thomas Schwinge <thomas@codesourcery.com> wrote:
>> > I trimmed the CC list -- I'm looking for advice about debugging a lto1
>> > ICE.
>> >
>> > On Fri, 19 Aug 2016 11:05:59 +0000, Joseph Myers <joseph@codesourcery.com> wrote:
>> >> On Fri, 19 Aug 2016, Richard Biener wrote:
>> >> > Can you quickly verify if LTO works with the new types?  I don't see anything
>> >> > that would prevent it but having new global trees and backends initializing them
>> >> > might come up with surprises (see tree-streamer.c:preload_common_nodes)
>> >>
>> >> Well, the execution tests are in gcc.dg/torture, which is run with various
>> >> options including -flto (and I've checked the testsuite logs to confirm
>> >> these tests are indeed run with such options).  Is there something else
>> >> you think should be tested?
>> >
>> > As I noted in <https://gcc.gnu.org/PR77458>:
>> >
>> >     As of the PR32187 commit r239625 "Implement C _FloatN, _FloatNx types", nvptx
>> >     offloading is broken, ICEs in LTO stream-in.  Probably some kind of data-type
>> >     mismatch that is not visible with Intel MIC offloading (using the same data
>> >     types) but explodes with nvptx.  I'm having a look.
>> >
>> > I know how to use "-save-temps -v" to re-run the ICEing lto1 in GDB; a
>> > backtrace of the ICE looks as follows:
>> >
>> >     #0  fancy_abort (file=file@entry=0x10d61d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10d6e3a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
>> >     #1  0x000000000058c9ef in vec<tree_node*, va_heap, vl_embed>::operator[] (this=0x16919c0, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:727
>> >     #2  0x000000000058ca33 in vec<tree_node*, va_heap, vl_ptr>::operator[] (this=this@entry=0x1691998, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:1211
>>
>> so it wants tree 185 which is (given the low number) likely one streamed by
>> preload_common_nodes.  This is carefully crafted to _not_ diverge by
>> frontend (!) it wasn't even designed to cope with global trees being present
>> or not dependent on target (well, because the target is always the
>> same! mind you!)
>
> Scary.  ;-/
>
>> Now -- in theory it should deal with NULLs just fine (resulting in
>> error_mark_node), but it can diverge when there are additional
>> compount types (like vectors, complex
>> or array or record types) whose element types are not in the set of
>> global trees.
>> The complex _FloatN types would be such a case given they appear before their
>> components.  That mixes up the ordering at least.
>
> ACK, but that's also an issue for "regular" float/complex float, which
> also is in "reverse" order.  But that's "fixed" by the recursion in
> gcc/tree-streamer.c:record_common_node for "TREE_CODE (node) ==
> COMPLEX_TYPE".  This likewise seems to work for the _FloatN types.  (I've
> put "fixed" in quotes -- doesn't that recursion mean that we're thus
> putting "complex float", "float", [...], "float" (again) into the cache?
> Anyway that's for later...)
>
>> So I suggest to add a print_tree to where it does the streamer_tree_cache_append
>> and compare cc1 and lto1 outcome.
>
> Thanks for all your suggestions!
>
> As far as I can tell, tree 185 is in fact among the first trees just
> after the preloaded ones...  (See record_common_node followed by
> streamer_tree_cache_append with "ix == hash" vs., from "ix=180" onwards,
> streamer_tree_cache_append called from elsewhere with "ix != hash".)
> (I'm also noticing that this cache first is built from "ix=0" through
> "ix=179", then apparently discarded, and rebuilt again, which seems
> surprising but which I've not yet looked into; hopefully unrelated
> issue.)  I'll continue to poke at this, but wanted to given an update
> here at least.

Ok - so the only other suggestion is to do lock-step debugging of the
cc1 / lto1 process
starting from the last known "equal" tree we put into the cache...

Richard.

>     [...]
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:272:record_common_node
>      <fixed_point_type 0x7ffff68e23f0 unsigned UDA
>         size <integer_cst 0x7ffff68cd378 type <integer_type 0x7ffff68d2150 bitsizetype> constant 64>
>         unit size <integer_cst 0x7ffff68cd390 type <integer_type 0x7ffff68d20a8 sizetype> constant 8>
>         align 64 symtab 0 alias set -1 canonical type 0x7ffff68e23f0 precision 64>
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=178 hash=178 tree=0x7ffff68e23f0
>      <fixed_point_type 0x7ffff68e23f0 unsigned UDA
>         size <integer_cst 0x7ffff68cd378 type <integer_type 0x7ffff68d2150 bitsizetype> constant 64>
>         unit size <integer_cst 0x7ffff68cd390 type <integer_type 0x7ffff68d20a8 sizetype> constant 8>
>         align 64 symtab 0 alias set -1 canonical type 0x7ffff68e23f0 precision 64>
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:272:record_common_node
>      <fixed_point_type 0x7ffff68e2690 unsigned UTA
>         size <integer_cst 0x7ffff68cd6a8 type <integer_type 0x7ffff68d2150 bitsizetype> constant 128>
>         unit size <integer_cst 0x7ffff68cd6c0 type <integer_type 0x7ffff68d20a8 sizetype> constant 16>
>         align 64 symtab 0 alias set -1 canonical type 0x7ffff68e2690 precision 128>
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=179 hash=179 tree=0x7ffff68e2690
>      <fixed_point_type 0x7ffff68e2690 unsigned UTA
>         size <integer_cst 0x7ffff68cd6a8 type <integer_type 0x7ffff68d2150 bitsizetype> constant 128>
>         unit size <integer_cst 0x7ffff68cd6c0 type <integer_type 0x7ffff68d20a8 sizetype> constant 16>
>         align 64 symtab 0 alias set -1 canonical type 0x7ffff68e2690 precision 128>
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=180 hash=1889092561 tree=0x7ffff68cc930
>      <optimization_node 0x7ffff68cc930
>         flag_fp_contract_mode (0)
>         flag_ira_algorithm (0)
>         flag_ira_region (0)
>         flag_reorder_blocks_algorithm (0)
>         flag_simd_cost_model (0)
>         flag_stack_reuse (0)
>         flag_vect_cost_model (0)
>     >
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=181 hash=2721827057 tree=0x7ffff6993708
>      <target_option_node 0x7ffff6993708
>     >
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=182 hash=3212777296 tree=0x7ffff6993730
>      <identifier_node 0x7ffff6993730 _ZL5placev>
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=183 hash=1511527171 tree=0x7ffff6993758
>      <identifier_node 0x7ffff6993758 noinline>
>     PID=12052 [...]/source-gcc/gcc/tree-streamer.c:214:streamer_tree_cache_append
>       ix=184 hash=4086308758 tree=0x7ffff6993780
>      <tree_list 0x7ffff6993780>
>
>     Breakpoint 1, fancy_abort (file=file@entry=0x10df3d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10e003a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
>     1414    {
>     (gdb) bt
>     #0  fancy_abort (file=file@entry=0x10df3d0 "[...]/source-gcc/gcc/vec.h", line=line@entry=727, function=function@entry=0x10e003a <_ZZN3vecIP9tree_node7va_heap8vl_embedEixEjE12__FUNCTION__> "operator[]") at [...]/source-gcc/gcc/diagnostic.c:1414
>     #1  0x000000000059103f in vec<tree_node*, va_heap, vl_embed>::operator[] (this=0x16aba30, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:727
>     #2  0x0000000000591083 in vec<tree_node*, va_heap, vl_ptr>::operator[] (this=this@entry=0x169c868, ix=ix@entry=185) at [...]/source-gcc/gcc/vec.h:1211
>     #3  0x0000000000c7d464 in streamer_tree_cache_get_tree (cache=0x169c860, ix=ix@entry=185) at [...]/source-gcc/gcc/tree-streamer.h:98
>     #4  0x0000000000c7d4c9 in streamer_get_pickled_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880) at [...]/source-gcc/gcc/tree-streamer-in.c:1112
>     #5  0x00000000008fca6b in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, tag=tag@entry=LTO_tree_pickle_reference, hash=hash@entry=0) at [...]/source-gcc/gcc/lto-streamer-in.c:1404
>     #6  0x00000000008fce94 in lto_input_tree (ib=0x7fffffffceb0, data_in=0x169f880) at [...]/source-gcc/gcc/lto-streamer-in.c:1444
>     #7  0x0000000000c7b6e2 in lto_input_ts_list_tree_pointers (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:861
>     #8  0x0000000000c7da5e in streamer_read_tree_body (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/tree-streamer-in.c:1077
>     #9  0x00000000008faa78 in lto_read_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, expr=expr@entry=0x7ffff6993780) at [...]/source-gcc/gcc/lto-streamer-in.c:1285
>     #10 0x00000000008fab6b in lto_read_tree (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1315
>     #11 0x00000000008fcc2b in lto_input_tree_1 (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, tag=tag@entry=4, hash=hash@entry=4086308758) at [...]/source-gcc/gcc/lto-streamer-in.c:1427
>     #12 0x00000000008fccc3 in lto_input_scc (ib=ib@entry=0x7fffffffceb0, data_in=data_in@entry=0x169f880, len=len@entry=0x7fffffffceac, entry_len=entry_len@entry=0x7fffffffcea8) at [...]/source-gcc/gcc/lto-streamer-in.c:1339
>     #13 0x000000000058d747 in lto_read_decls (decl_data=decl_data@entry=0x7ffff7fc0000, data=data@entry=0x16b0750, resolutions=...) at [...]/source-gcc/gcc/lto/lto.c:1693
>     #14 0x000000000058df18 in lto_file_finalize (file_data=file_data@entry=0x7ffff7fc0000, file=file@entry=0x15f9db0) at [...]/source-gcc/gcc/lto/lto.c:2037
>     #15 0x000000000058df78 in lto_create_files_from_ids (file=file@entry=0x15f9db0, file_data=file_data@entry=0x7ffff7fc0000, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2047
>     #16 0x000000000058e0ca in lto_file_read (file=0x15f9db0, resolution_file=resolution_file@entry=0x0, count=count@entry=0x7fffffffd054) at [...]/source-gcc/gcc/lto/lto.c:2088
>     #17 0x000000000058e4d4 in read_cgraph_and_symbols (nfiles=1, fnames=0x1619990) at [...]/source-gcc/gcc/lto/lto.c:2798
>     #18 0x000000000058ebc2 in lto_main () at [...]/source-gcc/gcc/lto/lto.c:3299
>     #19 0x0000000000a5208f in compile_file () at [...]/source-gcc/gcc/toplev.c:466
>     #20 0x0000000000554f93 in do_compile () at [...]/source-gcc/gcc/toplev.c:2010
>     #21 toplev::main (this=this@entry=0x7fffffffd180, argc=argc@entry=20, argv=0x15e5f20, argv@entry=0x7fffffffd288) at [...]/source-gcc/gcc/toplev.c:2144
>     #22 0x0000000000556d67 in main (argc=20, argv=0x7fffffffd288) at [...]/source-gcc/gcc/main.c:39
>
>
> Grüße
>  Thomas
diff mbox

Patch

Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 239543)
+++ gcc/c/c-decl.c	(working copy)
@@ -9804,6 +9804,14 @@  declspecs_add_type (location_t loc, struct c_decls
 		error_at (loc,
 			  ("both %<long%> and %<float%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_floatn_nx)
+		error_at (loc,
+			  ("both %<long%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
 	      else if (specs->typespec_word == cts_dfloat32)
 		error_at (loc,
 			  ("both %<long%> and %<_Decimal32%> in "
@@ -9857,6 +9865,14 @@  declspecs_add_type (location_t loc, struct c_decls
 		error_at (loc,
 			  ("both %<short%> and %<double%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_floatn_nx)
+		error_at (loc,
+			  ("both %<short%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
 	      else if (specs->typespec_word == cts_dfloat32)
                 error_at (loc,
 			  ("both %<short%> and %<_Decimal32%> in "
@@ -9901,6 +9917,14 @@  declspecs_add_type (location_t loc, struct c_decls
 		error_at (loc,
 			  ("both %<signed%> and %<double%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_floatn_nx)
+		error_at (loc,
+			  ("both %<signed%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
 	      else if (specs->typespec_word == cts_dfloat32)
 		error_at (loc,
 			  ("both %<signed%> and %<_Decimal32%> in "
@@ -9945,6 +9969,14 @@  declspecs_add_type (location_t loc, struct c_decls
 		error_at (loc,
 			  ("both %<unsigned%> and %<double%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_floatn_nx)
+		error_at (loc,
+			  ("both %<unsigned%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
               else if (specs->typespec_word == cts_dfloat32)
 		error_at (loc,
 			  ("both %<unsigned%> and %<_Decimal32%> in "
@@ -10049,6 +10081,14 @@  declspecs_add_type (location_t loc, struct c_decls
 		error_at (loc,
 			  ("both %<_Sat%> and %<double%> in "
 			   "declaration specifiers"));
+	      else if (specs->typespec_word == cts_floatn_nx)
+		error_at (loc,
+			  ("both %<_Sat%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
               else if (specs->typespec_word == cts_dfloat32)
 		error_at (loc,
 			  ("both %<_Sat%> and %<_Decimal32%> in "
@@ -10082,8 +10122,9 @@  declspecs_add_type (location_t loc, struct c_decls
 	}
       else
 	{
-	  /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32",
-	     "__intN", "_Decimal64", "_Decimal128", "_Fract", "_Accum" or
+	  /* "void", "_Bool", "char", "int", "float", "double",
+	     "_FloatN", "_FloatNx", "_Decimal32", "__intN",
+	     "_Decimal64", "_Decimal128", "_Fract", "_Accum" or
 	     "__auto_type".  */
 	  if (specs->typespec_word != cts_none)
 	    {
@@ -10308,6 +10349,69 @@  declspecs_add_type (location_t loc, struct c_decls
 		  specs->locations[cdw_typespec] = loc;
 		}
 	      return specs;
+	    CASE_RID_FLOATN_NX:
+	      specs->floatn_nx_idx = i - RID_FLOATN_NX_FIRST;
+	      if (!in_system_header_at (input_location))
+		pedwarn (loc, OPT_Wpedantic,
+			 "ISO C does not support the %<_Float%d%s%> type",
+			 floatn_nx_types[specs->floatn_nx_idx].n,
+			 (floatn_nx_types[specs->floatn_nx_idx].extended
+			  ? "x"
+			  : ""));
+
+	      if (specs->long_p)
+		error_at (loc,
+			  ("both %<long%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
+	      else if (specs->short_p)
+		error_at (loc,
+			  ("both %<short%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
+	      else if (specs->signed_p)
+		error_at (loc,
+			  ("both %<signed%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
+	      else if (specs->unsigned_p)
+		error_at (loc,
+			  ("both %<unsigned%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
+	      else if (specs->saturating_p)
+		error_at (loc,
+			  ("both %<_Sat%> and %<_Float%d%s%> in "
+			   "declaration specifiers"),
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
+	      else if (FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx) == NULL_TREE)
+		error_at (loc,
+			  "%<_Float%d%s%> is not supported on this target",
+			  floatn_nx_types[specs->floatn_nx_idx].n,
+			  (floatn_nx_types[specs->floatn_nx_idx].extended
+			   ? "x"
+			   : ""));
+	      else
+		{
+		  specs->typespec_word = cts_floatn_nx;
+		  specs->locations[cdw_typespec] = loc;
+		}
+	      return specs;
 	    case RID_DFLOAT32:
 	    case RID_DFLOAT64:
 	    case RID_DFLOAT128:
@@ -10785,6 +10889,13 @@  finish_declspecs (struct c_declspecs *specs)
 			 : double_type_node);
 	}
       break;
+    case cts_floatn_nx:
+      gcc_assert (!specs->long_p && !specs->short_p
+		  && !specs->signed_p && !specs->unsigned_p);
+      specs->type = (specs->complex_p
+		     ? COMPLEX_FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx)
+		     : FLOATN_NX_TYPE_NODE (specs->floatn_nx_idx));
+      break;
     case cts_dfloat32:
     case cts_dfloat64:
     case cts_dfloat128:
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 239543)
+++ gcc/c/c-parser.c	(working copy)
@@ -540,6 +540,7 @@  c_keyword_starts_typename (enum rid keyword)
     case RID_DFLOAT32:
     case RID_DFLOAT64:
     case RID_DFLOAT128:
+    CASE_RID_FLOATN_NX:
     case RID_BOOL:
     case RID_ENUM:
     case RID_STRUCT:
@@ -727,6 +728,7 @@  c_token_starts_declspecs (c_token *token)
 	case RID_DFLOAT32:
 	case RID_DFLOAT64:
 	case RID_DFLOAT128:
+	CASE_RID_FLOATN_NX:
 	case RID_BOOL:
 	case RID_ENUM:
 	case RID_STRUCT:
@@ -2536,6 +2538,7 @@  c_parser_declspecs (c_parser *parser, struct c_dec
 	case RID_DFLOAT32:
 	case RID_DFLOAT64:
 	case RID_DFLOAT128:
+	CASE_RID_FLOATN_NX:
 	case RID_BOOL:
 	case RID_FRACT:
 	case RID_ACCUM:
@@ -4009,6 +4012,7 @@  c_parser_attribute_any_word (c_parser *parser)
 	case RID_DFLOAT32:
 	case RID_DFLOAT64:
 	case RID_DFLOAT128:
+	CASE_RID_FLOATN_NX:
 	case RID_BOOL:
 	case RID_FRACT:
 	case RID_ACCUM:
@@ -9638,6 +9642,7 @@  c_parser_objc_selector (c_parser *parser)
     case RID_CHAR:
     case RID_FLOAT:
     case RID_DOUBLE:
+    CASE_RID_FLOATN_NX:
     case RID_VOID:
     case RID_BOOL:
     case RID_ATOMIC:
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	(revision 239543)
+++ gcc/c/c-tree.h	(working copy)
@@ -230,6 +230,7 @@  enum c_typespec_keyword {
   cts_dfloat32,
   cts_dfloat64,
   cts_dfloat128,
+  cts_floatn_nx,
   cts_fract,
   cts_accum,
   cts_auto_type
@@ -295,6 +296,9 @@  struct c_declspecs {
   int align_log;
   /* For the __intN declspec, this stores the index into the int_n_* arrays.  */
   int int_n_idx;
+  /* For the _FloatN and _FloatNx declspec, this stores the index into
+     the floatn_nx_types array.  */
+  int floatn_nx_idx;
   /* The storage class specifier, or csc_none if none.  */
   enum c_storage_class storage_class;
   /* Any type specifier keyword used such as "int", not reflecting
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 239543)
+++ gcc/c/c-typeck.c	(working copy)
@@ -927,18 +927,41 @@  c_common_type (tree t1, tree t2)
 	return long_integer_type_node;
     }
 
+  /* For floating types of the same TYPE_PRECISION (which we here
+     assume means either the same set of values, or sets of values
+     neither a subset of the other, with behavior being undefined in
+     the latter case), follow the rules from TS 18661-3: prefer
+     interchange types _FloatN, then standard types long double,
+     double, float, then extended types _FloatNx.  For extended types,
+     check them starting with _Float128x as that seems most consistent
+     in spirit with preferring long double to double; for interchange
+     types, also check in that order for consistency although it's not
+     possible for more than one of them to have the same
+     precision.  */
+  tree mv1 = TYPE_MAIN_VARIANT (t1);
+  tree mv2 = TYPE_MAIN_VARIANT (t2);
+
+  for (int i = NUM_FLOATN_TYPES - 1; i >= 0; i--)
+    if (mv1 == FLOATN_TYPE_NODE (i) || mv2 == FLOATN_TYPE_NODE (i))
+      return FLOATN_TYPE_NODE (i);
+
   /* Likewise, prefer long double to double even if same size.  */
-  if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
-      || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
+  if (mv1 == long_double_type_node || mv2 == long_double_type_node)
     return long_double_type_node;
 
   /* Likewise, prefer double to float even if same size.
      We got a couple of embedded targets with 32 bit doubles, and the
      pdp11 might have 64 bit floats.  */
-  if (TYPE_MAIN_VARIANT (t1) == double_type_node
-      || TYPE_MAIN_VARIANT (t2) == double_type_node)
+  if (mv1 == double_type_node || mv2 == double_type_node)
     return double_type_node;
 
+  if (mv1 == float_type_node || mv2 == float_type_node)
+    return float_type_node;
+
+  for (int i = NUM_FLOATNX_TYPES - 1; i >= 0; i--)
+    if (mv1 == FLOATNX_TYPE_NODE (i) || mv2 == FLOATNX_TYPE_NODE (i))
+      return FLOATNX_TYPE_NODE (i);
+
   /* Otherwise prefer the unsigned one.  */
 
   if (TYPE_UNSIGNED (t1))
@@ -3284,6 +3307,30 @@  convert_arguments (location_t loc, vec<location_t>
 
       val = require_complete_type (ploc, val);
 
+      /* Some floating-point arguments must be promoted to double when
+	 no type is specified by a prototype.  This applies to
+	 arguments of type float, and to architecture-specific types
+	 (ARM __fp16), but not to _FloatN or _FloatNx types.  */
+      bool promote_float_arg = false;
+      if (type == NULL_TREE
+	  && TREE_CODE (valtype) == REAL_TYPE
+	  && (TYPE_PRECISION (valtype)
+	      <= TYPE_PRECISION (double_type_node))
+	  && TYPE_MAIN_VARIANT (valtype) != double_type_node
+	  && TYPE_MAIN_VARIANT (valtype) != long_double_type_node
+	  && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
+	{
+	  /* Promote this argument, unless it has a _FloatN or
+	     _FloatNx type.  */
+	  promote_float_arg = true;
+	  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+	    if (TYPE_MAIN_VARIANT (valtype) == FLOATN_NX_TYPE_NODE (i))
+	      {
+		promote_float_arg = false;
+		break;
+	      }
+	}
+
       if (type != 0)
 	{
 	  /* Formal parm type is specified by a function prototype.  */
@@ -3450,12 +3497,7 @@  convert_arguments (location_t loc, vec<location_t>
 		parmval = default_conversion (parmval);
 	    }
 	}
-      else if (TREE_CODE (valtype) == REAL_TYPE
-	       && (TYPE_PRECISION (valtype)
-		   <= TYPE_PRECISION (double_type_node))
-	       && TYPE_MAIN_VARIANT (valtype) != double_type_node
-	       && TYPE_MAIN_VARIANT (valtype) != long_double_type_node
-	       && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
+      else if (promote_float_arg)
         {
 	  if (type_generic)
 	    parmval = val;
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 239543)
+++ gcc/c-family/c-common.c	(working copy)
@@ -433,6 +433,13 @@  const struct c_common_resword c_common_reswords[]
   { "_Cilk_sync",       RID_CILK_SYNC,  0 },
   { "_Cilk_for",        RID_CILK_FOR,   0 },
   { "_Imaginary",	RID_IMAGINARY, D_CONLY },
+  { "_Float16",         RID_FLOAT16,   D_CONLY },
+  { "_Float32",         RID_FLOAT32,   D_CONLY },
+  { "_Float64",         RID_FLOAT64,   D_CONLY },
+  { "_Float128",        RID_FLOAT128,  D_CONLY },
+  { "_Float32x",        RID_FLOAT32X,  D_CONLY },
+  { "_Float64x",        RID_FLOAT64X,  D_CONLY },
+  { "_Float128x",       RID_FLOAT128X, D_CONLY },
   { "_Decimal32",       RID_DFLOAT32,  D_CONLY | D_EXT },
   { "_Decimal64",       RID_DFLOAT64,  D_CONLY | D_EXT },
   { "_Decimal128",      RID_DFLOAT128, D_CONLY | D_EXT },
@@ -3477,6 +3484,11 @@  c_common_type_for_mode (machine_mode mode, int uns
   if (mode == TYPE_MODE (long_double_type_node))
     return long_double_type_node;
 
+  for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+	&& mode == TYPE_MODE (FLOATN_NX_TYPE_NODE (i)))
+      return FLOATN_NX_TYPE_NODE (i);
+
   if (mode == TYPE_MODE (void_type_node))
     return void_type_node;
 
@@ -3502,6 +3514,11 @@  c_common_type_for_mode (machine_mode mode, int uns
       if (mode == TYPE_MODE (complex_long_double_type_node))
 	return complex_long_double_type_node;
 
+      for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+	if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+	    && mode == TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i)))
+	  return COMPLEX_FLOATN_NX_TYPE_NODE (i);
+
       if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
 	return complex_integer_type_node;
 
@@ -5405,6 +5422,12 @@  c_common_nodes_and_builtins (void)
   record_builtin_type (RID_DOUBLE, NULL, double_type_node);
   record_builtin_type (RID_MAX, "long double", long_double_type_node);
 
+  if (!c_dialect_cxx ())
+    for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+      if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE)
+	record_builtin_type ((enum rid) (RID_FLOATN_NX_FIRST + i), NULL,
+			     FLOATN_NX_TYPE_NODE (i));
+
   /* Only supported decimal floating point extension if the target
      actually supports underlying modes. */
   if (targetm.scalar_mode_supported_p (SDmode)
@@ -5494,6 +5517,20 @@  c_common_nodes_and_builtins (void)
 		 TYPE_DECL, get_identifier ("complex long double"),
 		 complex_long_double_type_node));
 
+  if (!c_dialect_cxx ())
+    for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+      if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE)
+	{
+	  char buf[30];
+	  sprintf (buf, "complex _Float%d%s", floatn_nx_types[i].n,
+		   floatn_nx_types[i].extended ? "x" : "");
+	  lang_hooks.decls.pushdecl
+	    (build_decl (UNKNOWN_LOCATION,
+			 TYPE_DECL,
+			 get_identifier (buf),
+			 COMPLEX_FLOATN_NX_TYPE_NODE (i)));
+	}
+
   if (c_dialect_cxx ())
     /* For C++, make fileptr_type_node a distinct void * type until
        FILE type is defined.  */
@@ -12508,6 +12545,7 @@  keyword_begins_type_specifier (enum rid keyword)
     case RID_LONG:
     case RID_SHORT:
     case RID_SIGNED:
+    CASE_RID_FLOATN_NX:
     case RID_DFLOAT32:
     case RID_DFLOAT64:
     case RID_DFLOAT128:
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 239543)
+++ gcc/c-family/c-common.h	(working copy)
@@ -102,6 +102,20 @@  enum rid
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	     RID_BUILTIN_SHUFFLE,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
+
+  /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
+  RID_FLOAT16,
+  RID_FLOATN_NX_FIRST = RID_FLOAT16,
+  RID_FLOAT32,
+  RID_FLOAT64,
+  RID_FLOAT128,
+  RID_FLOAT32X,
+  RID_FLOAT64X,
+  RID_FLOAT128X,
+#define CASE_RID_FLOATN_NX						\
+  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128: \
+  case RID_FLOAT32X: case RID_FLOAT64X: case RID_FLOAT128X
+
   RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
 
   /* C11 */
Index: gcc/c-family/c-cppbuiltin.c
===================================================================
--- gcc/c-family/c-cppbuiltin.c	(revision 239543)
+++ gcc/c-family/c-cppbuiltin.c	(working copy)
@@ -125,7 +125,7 @@  builtin_define_float_constants (const char *name_p
   const double log10_2 = .30102999566398119521;
   double log10_b;
   const struct real_format *fmt;
-  const struct real_format *ldfmt;
+  const struct real_format *widefmt;
 
   char name[64], buf[128];
   int dig, min_10_exp, max_10_exp;
@@ -134,8 +134,20 @@  builtin_define_float_constants (const char *name_p
 
   fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
   gcc_assert (fmt->b != 10);
-  ldfmt = REAL_MODE_FORMAT (TYPE_MODE (long_double_type_node));
-  gcc_assert (ldfmt->b != 10);
+  widefmt = REAL_MODE_FORMAT (TYPE_MODE (long_double_type_node));
+  gcc_assert (widefmt->b != 10);
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    {
+      tree wtype = FLOATN_NX_TYPE_NODE (i);
+      if (wtype != NULL_TREE)
+	{
+	  const struct real_format *wfmt
+	    = REAL_MODE_FORMAT (TYPE_MODE (wtype));
+	  gcc_assert (wfmt->b != 10);
+	  if (wfmt->p > widefmt->p)
+	    widefmt = wfmt;
+	}
+    }
 
   /* The radix of the exponent representation.  */
   if (type == float_type_node)
@@ -219,7 +231,7 @@  builtin_define_float_constants (const char *name_p
      floating type, but we want this value for rendering constants below.  */
   {
     double d_decimal_dig
-      = 1 + (fmt->p < ldfmt->p ? ldfmt->p : fmt->p) * log10_b;
+      = 1 + (fmt->p < widefmt->p ? widefmt->p : fmt->p) * log10_b;
     decimal_dig = d_decimal_dig;
     if (decimal_dig < d_decimal_dig)
       decimal_dig++;
@@ -231,13 +243,13 @@  builtin_define_float_constants (const char *name_p
     if (type_decimal_dig < type_d_decimal_dig)
       type_decimal_dig++;
   }
+  /* Arbitrarily, define __DECIMAL_DIG__ when defining macros for long
+     double, although it may be greater than the value for long
+     double.  */
   if (type == long_double_type_node)
     builtin_define_with_int_value ("__DECIMAL_DIG__", decimal_dig);
-  else
-    {
-      sprintf (name, "__%s_DECIMAL_DIG__", name_prefix);
-      builtin_define_with_int_value (name, type_decimal_dig);
-    }
+  sprintf (name, "__%s_DECIMAL_DIG__", name_prefix);
+  builtin_define_with_int_value (name, type_decimal_dig);
 
   /* Since, for the supported formats, B is always a power of 2, we
      construct the following numbers directly as a hexadecimal
@@ -289,7 +301,7 @@  builtin_define_float_constants (const char *name_p
   builtin_define_with_int_value (name, MODE_HAS_NANS (TYPE_MODE (type)));
 
   /* Note whether we have fast FMA.  */
-  if (mode_has_fma (TYPE_MODE (type)))
+  if (mode_has_fma (TYPE_MODE (type)) && fma_suffix != NULL)
     {
       sprintf (name, "__FP_FAST_FMA%s", fma_suffix);
       builtin_define_with_int_value (name, 1);
@@ -984,6 +996,19 @@  c_cpp_builtins (cpp_reader *pfile)
   builtin_define_float_constants ("LDBL", "L", "%s", "L",
 				  long_double_type_node);
 
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    {
+      if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
+	continue;
+      char prefix[20], csuffix[20];
+      sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
+	       floatn_nx_types[i].extended ? "X" : "");
+      sprintf (csuffix, "F%d%s", floatn_nx_types[i].n,
+	       floatn_nx_types[i].extended ? "x" : "");
+      builtin_define_float_constants (prefix, csuffix, "%s", NULL,
+				      FLOATN_NX_TYPE_NODE (i));
+    }
+
   /* For decfloat.h.  */
   builtin_define_decimal_float_constants ("DEC32", "DF", dfloat32_type_node);
   builtin_define_decimal_float_constants ("DEC64", "DD", dfloat64_type_node);
Index: gcc/c-family/c-lex.c
===================================================================
--- gcc/c-family/c-lex.c	(revision 239543)
+++ gcc/c-family/c-lex.c	(working copy)
@@ -839,6 +839,26 @@  interpret_float (const cpp_token *token, unsigned
 	type = c_common_type_for_mode (mode, 0);
 	gcc_assert (type);
       }
+    else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
+      {
+	unsigned int n = (flags & CPP_N_WIDTH_FLOATN_NX) >> CPP_FLOATN_SHIFT;
+	bool extended = (flags & CPP_N_FLOATNX) != 0;
+	type = NULL_TREE;
+	for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+	  if (floatn_nx_types[i].n == (int) n
+	      && floatn_nx_types[i].extended == extended)
+	    {
+	      type = FLOATN_NX_TYPE_NODE (i);
+	      break;
+	    }
+	if (type == NULL_TREE)
+	  {
+	    error ("unsupported non-standard suffix on floating constant");
+	    return error_mark_node;
+	  }
+	else
+	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
+      }
     else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE)
       type = long_double_type_node;
     else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL
@@ -867,6 +887,17 @@  interpret_float (const cpp_token *token, unsigned
       if (flags & CPP_N_IMAGINARY)
 	/* I or J suffix.  */
 	copylen--;
+      if (flags & CPP_N_FLOATNX)
+	copylen--;
+      if (flags & (CPP_N_FLOATN | CPP_N_FLOATNX))
+	{
+	  unsigned int n = (flags & CPP_N_WIDTH_FLOATN_NX) >> CPP_FLOATN_SHIFT;
+	  while (n > 0)
+	    {
+	      copylen--;
+	      n /= 10;
+	    }
+	}
     }
 
   copy = (char *) alloca (copylen + 1);
Index: gcc/c-family/c-pretty-print.c
===================================================================
--- gcc/c-family/c-pretty-print.c	(revision 239543)
+++ gcc/c-family/c-pretty-print.c	(working copy)
@@ -1045,6 +1045,16 @@  pp_c_floating_constant (c_pretty_printer *pp, tree
     pp_string (pp, "dd");
   else if (TREE_TYPE (r) == dfloat32_type_node)
     pp_string (pp, "df");
+  else if (TREE_TYPE (r) != double_type_node)
+    for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+      if (TREE_TYPE (r) == FLOATN_NX_TYPE_NODE (i))
+	{
+	  pp_character (pp, 'f');
+	  pp_decimal_int (pp, floatn_nx_types[i].n);
+	  if (floatn_nx_types[i].extended)
+	    pp_character (pp, 'x');
+	  break;
+	}
 }
 
 /* Print out a FIXED value as a decimal-floating-constant.  */
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 239543)
+++ gcc/config/i386/i386.c	(working copy)
@@ -38347,24 +38347,29 @@  ix86_init_builtins_va_builtins_abi (void)
 static void
 ix86_init_builtin_types (void)
 {
-  tree float128_type_node, float80_type_node, const_string_type_node;
+  tree float80_type_node, const_string_type_node;
 
   /* The __float80 type.  */
   float80_type_node = long_double_type_node;
   if (TYPE_MODE (float80_type_node) != XFmode)
     {
-      /* The __float80 type.  */
-      float80_type_node = make_node (REAL_TYPE);
+      if (float64x_type_node != NULL_TREE
+	  && TYPE_MODE (float64x_type_node) == XFmode)
+	float80_type_node = float64x_type_node;
+      else
+	{
+	  /* The __float80 type.  */
+	  float80_type_node = make_node (REAL_TYPE);
 
-      TYPE_PRECISION (float80_type_node) = 80;
-      layout_type (float80_type_node);
+	  TYPE_PRECISION (float80_type_node) = 80;
+	  layout_type (float80_type_node);
+	}
     }
   lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
 
-  /* The __float128 type.  */
-  float128_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (float128_type_node) = 128;
-  layout_type (float128_type_node);
+  /* The __float128 type.  The node has already been created as
+     _Float128, so we only need to register the __float128 name for
+     it.  */
   lang_hooks.types.register_builtin_type (float128_type_node, "__float128");
 
   const_string_type_node
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c	(revision 239543)
+++ gcc/config/ia64/ia64.c	(working copy)
@@ -10350,9 +10350,15 @@  ia64_init_builtins (void)
   (*lang_hooks.types.register_builtin_type) (fpreg_type, "__fpreg");
 
   /* The __float80 type.  */
-  float80_type = make_node (REAL_TYPE);
-  TYPE_PRECISION (float80_type) = 80;
-  layout_type (float80_type);
+  if (float64x_type_node != NULL_TREE
+      && TYPE_MODE (float64x_type_node) == XFmode)
+    float80_type = float64x_type_node;
+  else
+    {
+      float80_type = make_node (REAL_TYPE);
+      TYPE_PRECISION (float80_type) = 80;
+      layout_type (float80_type);
+    }
   (*lang_hooks.types.register_builtin_type) (float80_type, "__float80");
 
   /* The __float128 type.  */
@@ -10362,14 +10368,12 @@  ia64_init_builtins (void)
       tree const_string_type
 	= build_pointer_type (build_qualified_type
 			      (char_type_node, TYPE_QUAL_CONST));
-      tree float128_type = make_node (REAL_TYPE);
 
-      TYPE_PRECISION (float128_type) = 128;
-      layout_type (float128_type);
-      (*lang_hooks.types.register_builtin_type) (float128_type, "__float128");
+      (*lang_hooks.types.register_builtin_type) (float128_type_node,
+						 "__float128");
 
       /* TFmode support builtins.  */
-      ftype = build_function_type_list (float128_type, NULL_TREE);
+      ftype = build_function_type_list (float128_type_node, NULL_TREE);
       decl = add_builtin_function ("__builtin_infq", ftype,
 				   IA64_BUILTIN_INFQ, BUILT_IN_MD,
 				   NULL, NULL_TREE);
@@ -10380,7 +10384,7 @@  ia64_init_builtins (void)
 				   NULL, NULL_TREE);
       ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
 
-      ftype = build_function_type_list (float128_type,
+      ftype = build_function_type_list (float128_type_node,
 					const_string_type,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_nanq", ftype,
@@ -10395,8 +10399,8 @@  ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
 
-      ftype = build_function_type_list (float128_type,
-					float128_type,
+      ftype = build_function_type_list (float128_type_node,
+					float128_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_fabsq", ftype,
 				   IA64_BUILTIN_FABSQ, BUILT_IN_MD,
@@ -10404,9 +10408,9 @@  ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
 
-      ftype = build_function_type_list (float128_type,
-					float128_type,
-					float128_type,
+      ftype = build_function_type_list (float128_type_node,
+					float128_type_node,
+					float128_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_copysignq", ftype,
 				   IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
Index: gcc/config/pdp11/pdp11.c
===================================================================
--- gcc/config/pdp11/pdp11.c	(revision 239543)
+++ gcc/config/pdp11/pdp11.c	(working copy)
@@ -69,6 +69,7 @@  const struct real_format pdp11_f_format =
     127,
     15,
     15,
+    0,
     false,
     false,
     false,
@@ -91,6 +92,7 @@  const struct real_format pdp11_d_format =
     127,
     15,
     15,
+    0,
     false,
     false,
     false,
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 239543)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1703,6 +1703,9 @@  static const struct attribute_spec rs6000_attribut
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p
 
+#undef TARGET_FLOATN_MODE
+#define TARGET_FLOATN_MODE rs6000_floatn_mode
+
 #undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
 #define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
 
@@ -16303,10 +16306,7 @@  rs6000_init_builtins (void)
       layout_type (ibm128_float_type_node);
       SET_TYPE_MODE (ibm128_float_type_node, IFmode);
 
-      ieee128_float_type_node = make_node (REAL_TYPE);
-      TYPE_PRECISION (ieee128_float_type_node) = 128;
-      layout_type (ieee128_float_type_node);
-      SET_TYPE_MODE (ieee128_float_type_node, KFmode);
+      ieee128_float_type_node = float128_type_node;
 
       lang_hooks.types.register_builtin_type (ieee128_float_type_node,
 					      "__float128");
@@ -36199,6 +36199,54 @@  rs6000_vector_mode_supported_p (machine_mode mode)
     return false;
 }
 
+/* Target hook for floatn_mode.  */
+static machine_mode
+rs6000_floatn_mode (int n, bool extended)
+{
+  if (extended)
+    {
+      switch (n)
+	{
+	case 32:
+	  return DFmode;
+
+	case 64:
+	  if (TARGET_FLOAT128)
+	    return (FLOAT128_IEEE_P (TFmode)) ? TFmode : KFmode;
+	  else
+	    return VOIDmode;
+
+	case 128:
+	  return VOIDmode;
+
+	default:
+	  /* Those are the only valid _FloatNx types.  */
+	  gcc_unreachable ();
+	}
+    }
+  else
+    {
+      switch (n)
+	{
+	case 32:
+	  return SFmode;
+
+	case 64:
+	  return DFmode;
+
+	case 128:
+	  if (TARGET_FLOAT128)
+	    return (FLOAT128_IEEE_P (TFmode)) ? TFmode : KFmode;
+	  else
+	    return VOIDmode;
+
+	default:
+	  return VOIDmode;
+	}
+    }
+
+}
+
 /* Target hook for c_mode_for_suffix.  */
 static machine_mode
 rs6000_c_mode_for_suffix (char suffix)
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 239543)
+++ gcc/doc/extend.texi	(working copy)
@@ -927,6 +927,8 @@  examine and set these two fictitious variables wit
 @node Floating Types
 @section Additional Floating Types
 @cindex additional floating types
+@cindex @code{_Float@var{n}} data types
+@cindex @code{_Float@var{n}x} data types
 @cindex @code{__float80} data type
 @cindex @code{__float128} data type
 @cindex @code{__ibm128} data type
@@ -935,9 +937,19 @@  examine and set these two fictitious variables wit
 @cindex @code{W} floating point suffix
 @cindex @code{Q} floating point suffix
 
-As an extension, GNU C supports additional floating
+ISO/IEC TS 18661-3:2015 defines C support for additional floating
+types @code{_Float@var{n}} and @code{_Float@var{n}x}, and GCC supports
+these type names; the set of types supported depends on the target
+architecture.  These types are not supported when compiling C++.
+Constants with these types use suffixes @code{f@var{n}} or
+@code{F@var{n}} and @code{f@var{n}x} or @code{F@var{n}x}.  These type
+names can be used together with @code{_Complex} to declare complex
+types.
+
+As an extension, GNU C and GNU C++ support additional floating
 types, @code{__float80} and @code{__float128} to support 80-bit
-(@code{XFmode}) and 128-bit (@code{TFmode}) floating types.
+(@code{XFmode}) and 128-bit (@code{TFmode}) floating types; these are
+aliases for the type names @code{_Float64x} and @code{_Float128}.
 Support for additional types includes the arithmetic operators:
 add, subtract, multiply, divide; unary arithmetic operators;
 relational operators; equality operators; and conversions to and from
@@ -954,9 +966,11 @@  typedef _Complex float __attribute__((mode(TC))) _
 typedef _Complex float __attribute__((mode(XC))) _Complex80;
 @end smallexample
 
-In order to use @code{__float128} and @code{__ibm128} on PowerPC Linux
+In order to use @code{_Float128}, @code{__float128} and
+@code{__ibm128} on PowerPC Linux
 systems, you must use the @option{-mfloat128}. It is expected in
-future versions of GCC that @code{__float128} will be enabled
+future versions of GCC that @code{_Float128} and @code{__float128}
+will be enabled
 automatically.  In addition, there are currently problems in using the
 complex @code{__float128} type.  When these problems are fixed, you
 would use the following syntax to declare @code{_Complex128} to be a
@@ -976,7 +990,14 @@  Not all targets support additional floating-point
 IA-64 targets.  The @code{__float128} type is supported on hppa HP-UX.
 The @code{__float128} type is supported on PowerPC 64-bit Linux
 systems by default if the vector scalar instruction set (VSX) is
-enabled.
+enabled.  The @code{_Float128} type is supported on all systems where
+@code{__float128} is supported or where @code{long double} has the
+IEEE binary128 format.  The @code{_Float64x} type is supported on all
+systems where @code{__float128} is supported.  The @code{_Float32}
+type is supported on all systems supporting IEEE binary32; the
+@code{_Float64} and @code{Float32x} types are supported on all systems
+supporting IEEE binary64.  GCC does not currently support
+@code{_Float16} or @code{_Float128x} on any systems.
 
 On the PowerPC, @code{__ibm128} provides access to the IBM extended
 double format, and it is intended to be used by the library functions
Index: gcc/doc/sourcebuild.texi
===================================================================
--- gcc/doc/sourcebuild.texi	(revision 239543)
+++ gcc/doc/sourcebuild.texi	(working copy)
@@ -1321,6 +1321,25 @@  Target supports array and structure sizes that are
 
 @item 4byte_wchar_t
 Target has @code{wchar_t} that is at least 4 bytes.
+
+@item float@var{n}
+Target has the @code{_Float@var{n}} type.
+
+@item float@var{n}x
+Target has the @code{_Float@var{n}x} type.
+
+@item float@var{n}_runtime
+Target has the @code{_Float@var{n}} type, including runtime support
+for any options added with @code{dg-add-options}.
+
+@item float@var{n}x_runtime
+Target has the @code{_Float@var{n}x} type, including runtime support
+for any options added with @code{dg-add-options}.
+
+@item floatn_nx_runtime
+Target has runtime support for any options added with
+@code{dg-add-options} for any @code{_Float@var{n}} or
+@code{_Float@var{n}x} type.
 @end table
 
 @subsubsection Fortran-specific attributes
@@ -2135,6 +2154,12 @@  locally when using pic/PIC passes in the testsuite
 @item c99_runtime
 Add the target-specific flags needed to access the C99 runtime.
 
+@item float@var{n}
+Add the target-specific flags needed to use the @code{_Float@var{n}} type.
+
+@item float@var{n}x
+Add the target-specific flags needed to use the @code{_Float@var{n}x} type.
+
 @item ieee
 Add the target-specific flags needed to enable full IEEE
 compliance mode.
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 239543)
+++ gcc/doc/tm.texi	(working copy)
@@ -4269,6 +4269,24 @@  hook returns true for all of @code{SFmode}, @code{
 @code{XFmode} and @code{TFmode}, if such modes exist.
 @end deftypefn
 
+@deftypefn {Target Hook} machine_mode TARGET_FLOATN_MODE (int @var{n}, bool @var{extended})
+Define this to return the machine mode to use for the type 
+@code{_Float@var{n}}, if @var{extended} is false, or the type 
+@code{_Float@var{n}x}, if @var{extended} is true.  If such a type 
+is not supported, return @code{VOIDmode}.  The default version of this 
+hook returns @code{SFmode} for @code{_Float32}, @code{DFmode} for 
+@code{_Float64} and @code{_Float32x} and @code{TFmode} for 
+@code{_Float128}, if those modes exist and satisfy the requirements for 
+those types and pass @code{TARGET_SCALAR_MODE_SUPPORTED_P} and 
+@code{TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P}; for @code{_Float64x}, it 
+returns the first of @code{XFmode} and @code{TFmode} that exists and 
+satisfies the same requirements; for other types, it returns 
+@code{VOIDmode}.  The hook is only called for values of @var{n} and 
+@var{extended} that are valid according to ISO/IEC TS 18661-3:2015; that 
+is, @var{n} is one of 32, 64, 128, or, if @var{extended} is false, 16 or 
+greater than 128 and a multiple of 32.
+@end deftypefn
+
 @deftypefn {Target Hook} bool TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P (machine_mode @var{mode})
 Define this to return nonzero for machine modes for which the port has
 small register classes.  If this target hook returns nonzero for a given
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 239543)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -3527,6 +3527,8 @@  stack.
 
 @hook TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P
 
+@hook TARGET_FLOATN_MODE
+
 @hook TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P
 
 @node Scalar Return
Index: gcc/fortran/iso-c-binding.def
===================================================================
--- gcc/fortran/iso-c-binding.def	(revision 239543)
+++ gcc/fortran/iso-c-binding.def	(working copy)
@@ -115,8 +115,8 @@  NAMED_REALCST (ISOCBINDING_DOUBLE, "c_double", \
 NAMED_REALCST (ISOCBINDING_LONG_DOUBLE, "c_long_double", \
                get_real_kind_from_node (long_double_type_node), GFC_STD_F2003)
 NAMED_REALCST (ISOCBINDING_FLOAT128, "c_float128", \
-	       float128_type_node == NULL_TREE \
-		  ? -4 : get_real_kind_from_node (float128_type_node), \
+	       gfc_float128_type_node == NULL_TREE \
+		  ? -4 : get_real_kind_from_node (gfc_float128_type_node), \
 	       GFC_STD_GNU)
 NAMED_CMPXCST (ISOCBINDING_FLOAT_COMPLEX, "c_float_complex", \
                get_real_kind_from_node (float_type_node), GFC_STD_F2003)
@@ -125,8 +125,8 @@  NAMED_CMPXCST (ISOCBINDING_DOUBLE_COMPLEX, "c_doub
 NAMED_CMPXCST (ISOCBINDING_LONG_DOUBLE_COMPLEX, "c_long_double_complex", \
                get_real_kind_from_node (long_double_type_node), GFC_STD_F2003)
 NAMED_CMPXCST (ISOCBINDING_FLOAT128_COMPLEX, "c_float128_complex", \
-	       float128_type_node == NULL_TREE \
-		  ? -4 : get_real_kind_from_node (float128_type_node), \
+	       gfc_float128_type_node == NULL_TREE \
+		  ? -4 : get_real_kind_from_node (gfc_float128_type_node), \
 	       GFC_STD_GNU)
 
 NAMED_LOGCST (ISOCBINDING_BOOL, "c_bool", \
Index: gcc/fortran/trans-intrinsic.c
===================================================================
--- gcc/fortran/trans-intrinsic.c	(revision 239543)
+++ gcc/fortran/trans-intrinsic.c	(working copy)
@@ -149,7 +149,7 @@  builtin_decl_for_precision (enum built_in_function
     i = m->double_built_in;
   else if (precision == TYPE_PRECISION (long_double_type_node))
     i = m->long_double_built_in;
-  else if (precision == TYPE_PRECISION (float128_type_node))
+  else if (precision == TYPE_PRECISION (gfc_float128_type_node))
     {
       /* Special treatment, because it is not exactly a built-in, but
 	 a library function.  */
@@ -621,8 +621,8 @@  gfc_build_intrinsic_lib_fndecls (void)
 
     memset (quad_decls, 0, sizeof(tree) * (END_BUILTINS + 1));
 
-    type = float128_type_node;
-    complex_type = complex_float128_type_node;
+    type = gfc_float128_type_node;
+    complex_type = gfc_complex_float128_type_node;
     /* type (*) (type) */
     func_1 = build_function_type_list (type, type, NULL_TREE);
     /* int (*) (type) */
Index: gcc/fortran/trans-types.c
===================================================================
--- gcc/fortran/trans-types.c	(revision 239543)
+++ gcc/fortran/trans-types.c	(working copy)
@@ -62,8 +62,8 @@  tree pfunc_type_node;
 
 tree gfc_charlen_type_node;
 
-tree float128_type_node = NULL_TREE;
-tree complex_float128_type_node = NULL_TREE;
+tree gfc_float128_type_node = NULL_TREE;
+tree gfc_complex_float128_type_node = NULL_TREE;
 
 bool gfc_real16_is_float128 = false;
 
@@ -901,7 +901,7 @@  gfc_init_types (void)
       PUSH_TYPE (name_buf, type);
 
       if (gfc_real_kinds[index].c_float128)
-	float128_type_node = type;
+	gfc_float128_type_node = type;
 
       type = gfc_build_complex_type (type);
       gfc_complex_types[index] = type;
@@ -910,7 +910,7 @@  gfc_init_types (void)
       PUSH_TYPE (name_buf, type);
 
       if (gfc_real_kinds[index].c_float128)
-	complex_float128_type_node = type;
+	gfc_complex_float128_type_node = type;
     }
 
   for (index = 0; gfc_character_kinds[index].kind != 0; ++index)
Index: gcc/fortran/trans-types.h
===================================================================
--- gcc/fortran/trans-types.h	(revision 239543)
+++ gcc/fortran/trans-types.h	(working copy)
@@ -30,8 +30,8 @@  extern GTY(()) tree ppvoid_type_node;
 extern GTY(()) tree pvoid_type_node;
 extern GTY(()) tree prvoid_type_node;
 extern GTY(()) tree pchar_type_node;
-extern GTY(()) tree float128_type_node;
-extern GTY(()) tree complex_float128_type_node;
+extern GTY(()) tree gfc_float128_type_node;
+extern GTY(()) tree gfc_complex_float128_type_node;
 
 /* This is the type used to hold the lengths of character variables.
    It must be the same as the corresponding definition in gfortran.h.  */
Index: gcc/ginclude/float.h
===================================================================
--- gcc/ginclude/float.h	(revision 239543)
+++ gcc/ginclude/float.h	(working copy)
@@ -165,7 +165,7 @@  see the files COPYING3 and COPYING.RUNTIME respect
 #undef LDBL_DECIMAL_DIG
 #define FLT_DECIMAL_DIG		__FLT_DECIMAL_DIG__
 #define DBL_DECIMAL_DIG		__DBL_DECIMAL_DIG__
-#define LDBL_DECIMAL_DIG	__DECIMAL_DIG__
+#define LDBL_DECIMAL_DIG	__LDBL_DECIMAL_DIG__
 
 /* Whether types support subnormal numbers.  */
 #undef FLT_HAS_SUBNORM
@@ -185,6 +185,187 @@  see the files COPYING3 and COPYING.RUNTIME respect
 
 #endif /* C11 */
 
+#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__
+/* Constants for _FloatN and _FloatNx types from TS 18661-3.  See
+   comments above for their semantics.  */
+
+#ifdef __FLT16_MANT_DIG__
+#undef FLT16_MANT_DIG
+#define FLT16_MANT_DIG		__FLT16_MANT_DIG__
+#undef FLT16_DIG
+#define FLT16_DIG		__FLT16_DIG__
+#undef FLT16_MIN_EXP
+#define FLT16_MIN_EXP		__FLT16_MIN_EXP__
+#undef FLT16_MIN_10_EXP
+#define FLT16_MIN_10_EXP	__FLT16_MIN_10_EXP__
+#undef FLT16_MAX_EXP
+#define FLT16_MAX_EXP		__FLT16_MAX_EXP__
+#undef FLT16_MAX_10_EXP
+#define FLT16_MAX_10_EXP	__FLT16_MAX_10_EXP__
+#undef FLT16_MAX
+#define FLT16_MAX		__FLT16_MAX__
+#undef FLT16_EPSILON
+#define FLT16_EPSILON		__FLT16_EPSILON__
+#undef FLT16_MIN
+#define FLT16_MIN		__FLT16_MIN__
+#undef FLT16_DECIMAL_DIG
+#define FLT16_DECIMAL_DIG	__FLT16_DECIMAL_DIG__
+#undef FLT16_TRUE_MIN
+#define FLT16_TRUE_MIN		__FLT16_DENORM_MIN__
+#endif /* __FLT16_MANT_DIG__.  */
+
+#ifdef __FLT32_MANT_DIG__
+#undef FLT32_MANT_DIG
+#define FLT32_MANT_DIG		__FLT32_MANT_DIG__
+#undef FLT32_DIG
+#define FLT32_DIG		__FLT32_DIG__
+#undef FLT32_MIN_EXP
+#define FLT32_MIN_EXP		__FLT32_MIN_EXP__
+#undef FLT32_MIN_10_EXP
+#define FLT32_MIN_10_EXP	__FLT32_MIN_10_EXP__
+#undef FLT32_MAX_EXP
+#define FLT32_MAX_EXP		__FLT32_MAX_EXP__
+#undef FLT32_MAX_10_EXP
+#define FLT32_MAX_10_EXP	__FLT32_MAX_10_EXP__
+#undef FLT32_MAX
+#define FLT32_MAX		__FLT32_MAX__
+#undef FLT32_EPSILON
+#define FLT32_EPSILON		__FLT32_EPSILON__
+#undef FLT32_MIN
+#define FLT32_MIN		__FLT32_MIN__
+#undef FLT32_DECIMAL_DIG
+#define FLT32_DECIMAL_DIG	__FLT32_DECIMAL_DIG__
+#undef FLT32_TRUE_MIN
+#define FLT32_TRUE_MIN		__FLT32_DENORM_MIN__
+#endif /* __FLT32_MANT_DIG__.  */
+
+#ifdef __FLT64_MANT_DIG__
+#undef FLT64_MANT_DIG
+#define FLT64_MANT_DIG		__FLT64_MANT_DIG__
+#undef FLT64_DIG
+#define FLT64_DIG		__FLT64_DIG__
+#undef FLT64_MIN_EXP
+#define FLT64_MIN_EXP		__FLT64_MIN_EXP__
+#undef FLT64_MIN_10_EXP
+#define FLT64_MIN_10_EXP	__FLT64_MIN_10_EXP__
+#undef FLT64_MAX_EXP
+#define FLT64_MAX_EXP		__FLT64_MAX_EXP__
+#undef FLT64_MAX_10_EXP
+#define FLT64_MAX_10_EXP	__FLT64_MAX_10_EXP__
+#undef FLT64_MAX
+#define FLT64_MAX		__FLT64_MAX__
+#undef FLT64_EPSILON
+#define FLT64_EPSILON		__FLT64_EPSILON__
+#undef FLT64_MIN
+#define FLT64_MIN		__FLT64_MIN__
+#undef FLT64_DECIMAL_DIG
+#define FLT64_DECIMAL_DIG	__FLT64_DECIMAL_DIG__
+#undef FLT64_TRUE_MIN
+#define FLT64_TRUE_MIN		__FLT64_DENORM_MIN__
+#endif /* __FLT64_MANT_DIG__.  */
+
+#ifdef __FLT128_MANT_DIG__
+#undef FLT128_MANT_DIG
+#define FLT128_MANT_DIG		__FLT128_MANT_DIG__
+#undef FLT128_DIG
+#define FLT128_DIG		__FLT128_DIG__
+#undef FLT128_MIN_EXP
+#define FLT128_MIN_EXP		__FLT128_MIN_EXP__
+#undef FLT128_MIN_10_EXP
+#define FLT128_MIN_10_EXP	__FLT128_MIN_10_EXP__
+#undef FLT128_MAX_EXP
+#define FLT128_MAX_EXP		__FLT128_MAX_EXP__
+#undef FLT128_MAX_10_EXP
+#define FLT128_MAX_10_EXP	__FLT128_MAX_10_EXP__
+#undef FLT128_MAX
+#define FLT128_MAX		__FLT128_MAX__
+#undef FLT128_EPSILON
+#define FLT128_EPSILON		__FLT128_EPSILON__
+#undef FLT128_MIN
+#define FLT128_MIN		__FLT128_MIN__
+#undef FLT128_DECIMAL_DIG
+#define FLT128_DECIMAL_DIG	__FLT128_DECIMAL_DIG__
+#undef FLT128_TRUE_MIN
+#define FLT128_TRUE_MIN		__FLT128_DENORM_MIN__
+#endif /* __FLT128_MANT_DIG__.  */
+
+#ifdef __FLT32X_MANT_DIG__
+#undef FLT32X_MANT_DIG
+#define FLT32X_MANT_DIG		__FLT32X_MANT_DIG__
+#undef FLT32X_DIG
+#define FLT32X_DIG		__FLT32X_DIG__
+#undef FLT32X_MIN_EXP
+#define FLT32X_MIN_EXP		__FLT32X_MIN_EXP__
+#undef FLT32X_MIN_10_EXP
+#define FLT32X_MIN_10_EXP	__FLT32X_MIN_10_EXP__
+#undef FLT32X_MAX_EXP
+#define FLT32X_MAX_EXP		__FLT32X_MAX_EXP__
+#undef FLT32X_MAX_10_EXP
+#define FLT32X_MAX_10_EXP	__FLT32X_MAX_10_EXP__
+#undef FLT32X_MAX
+#define FLT32X_MAX		__FLT32X_MAX__
+#undef FLT32X_EPSILON
+#define FLT32X_EPSILON		__FLT32X_EPSILON__
+#undef FLT32X_MIN
+#define FLT32X_MIN		__FLT32X_MIN__
+#undef FLT32X_DECIMAL_DIG
+#define FLT32X_DECIMAL_DIG	__FLT32X_DECIMAL_DIG__
+#undef FLT32X_TRUE_MIN
+#define FLT32X_TRUE_MIN		__FLT32X_DENORM_MIN__
+#endif /* __FLT32X_MANT_DIG__.  */
+
+#ifdef __FLT64X_MANT_DIG__
+#undef FLT64X_MANT_DIG
+#define FLT64X_MANT_DIG		__FLT64X_MANT_DIG__
+#undef FLT64X_DIG
+#define FLT64X_DIG		__FLT64X_DIG__
+#undef FLT64X_MIN_EXP
+#define FLT64X_MIN_EXP		__FLT64X_MIN_EXP__
+#undef FLT64X_MIN_10_EXP
+#define FLT64X_MIN_10_EXP	__FLT64X_MIN_10_EXP__
+#undef FLT64X_MAX_EXP
+#define FLT64X_MAX_EXP		__FLT64X_MAX_EXP__
+#undef FLT64X_MAX_10_EXP
+#define FLT64X_MAX_10_EXP	__FLT64X_MAX_10_EXP__
+#undef FLT64X_MAX
+#define FLT64X_MAX		__FLT64X_MAX__
+#undef FLT64X_EPSILON
+#define FLT64X_EPSILON		__FLT64X_EPSILON__
+#undef FLT64X_MIN
+#define FLT64X_MIN		__FLT64X_MIN__
+#undef FLT64X_DECIMAL_DIG
+#define FLT64X_DECIMAL_DIG	__FLT64X_DECIMAL_DIG__
+#undef FLT64X_TRUE_MIN
+#define FLT64X_TRUE_MIN		__FLT64X_DENORM_MIN__
+#endif /* __FLT64X_MANT_DIG__.  */
+
+#ifdef __FLT128X_MANT_DIG__
+#undef FLT128X_MANT_DIG
+#define FLT128X_MANT_DIG	__FLT128X_MANT_DIG__
+#undef FLT128X_DIG
+#define FLT128X_DIG		__FLT128X_DIG__
+#undef FLT128X_MIN_EXP
+#define FLT128X_MIN_EXP		__FLT128X_MIN_EXP__
+#undef FLT128X_MIN_10_EXP
+#define FLT128X_MIN_10_EXP	__FLT128X_MIN_10_EXP__
+#undef FLT128X_MAX_EXP
+#define FLT128X_MAX_EXP		__FLT128X_MAX_EXP__
+#undef FLT128X_MAX_10_EXP
+#define FLT128X_MAX_10_EXP	__FLT128X_MAX_10_EXP__
+#undef FLT128X_MAX
+#define FLT128X_MAX		__FLT128X_MAX__
+#undef FLT128X_EPSILON
+#define FLT128X_EPSILON		__FLT128X_EPSILON__
+#undef FLT128X_MIN
+#define FLT128X_MIN		__FLT128X_MIN__
+#undef FLT128X_DECIMAL_DIG
+#define FLT128X_DECIMAL_DIG	__FLT128X_DECIMAL_DIG__
+#undef FLT128X_TRUE_MIN
+#define FLT128X_TRUE_MIN	__FLT128X_DENORM_MIN__
+#endif /* __FLT128X_MANT_DIG__.  */
+
+#endif /* __STDC_WANT_IEC_60559_TYPES_EXT__.  */
+
 #ifdef __STDC_WANT_DEC_FP__
 /* Draft Technical Report 24732, extension for decimal floating-point
    arithmetic: Characteristic of decimal floating types <float.h>.  */
Index: gcc/real.c
===================================================================
--- gcc/real.c	(revision 239543)
+++ gcc/real.c	(working copy)
@@ -3043,6 +3043,7 @@  const struct real_format ieee_single_format =
     128,
     31,
     31,
+    32,
     false,
     true,
     true,
@@ -3065,6 +3066,7 @@  const struct real_format mips_single_format =
     128,
     31,
     31,
+    32,
     false,
     true,
     true,
@@ -3087,6 +3089,7 @@  const struct real_format motorola_single_format =
     128,
     31,
     31,
+    32,
     false,
     true,
     true,
@@ -3120,6 +3123,7 @@  const struct real_format spu_single_format =
     129,
     31,
     31,
+    0,
     true,
     false,
     false,
@@ -3330,6 +3334,7 @@  const struct real_format ieee_double_format =
     1024,
     63,
     63,
+    64,
     false,
     true,
     true,
@@ -3352,6 +3357,7 @@  const struct real_format mips_double_format =
     1024,
     63,
     63,
+    64,
     false,
     true,
     true,
@@ -3374,6 +3380,7 @@  const struct real_format motorola_double_format =
     1024,
     63,
     63,
+    64,
     false,
     true,
     true,
@@ -3719,6 +3726,7 @@  const struct real_format ieee_extended_motorola_fo
     16384,
     95,
     95,
+    0,
     false,
     true,
     true,
@@ -3741,6 +3749,7 @@  const struct real_format ieee_extended_intel_96_fo
     16384,
     79,
     79,
+    65,
     false,
     true,
     true,
@@ -3763,6 +3772,7 @@  const struct real_format ieee_extended_intel_128_f
     16384,
     79,
     79,
+    65,
     false,
     true,
     true,
@@ -3787,6 +3797,7 @@  const struct real_format ieee_extended_intel_96_ro
     16384,
     79,
     79,
+    33,
     false,
     true,
     true,
@@ -3876,6 +3887,7 @@  const struct real_format ibm_extended_format =
     1024,
     127,
     -1,
+    0,
     false,
     true,
     true,
@@ -3898,6 +3910,7 @@  const struct real_format mips_extended_format =
     1024,
     127,
     -1,
+    0,
     false,
     true,
     true,
@@ -4162,6 +4175,7 @@  const struct real_format ieee_quad_format =
     16384,
     127,
     127,
+    128,
     false,
     true,
     true,
@@ -4184,6 +4198,7 @@  const struct real_format mips_quad_format =
     16384,
     127,
     127,
+    128,
     false,
     true,
     true,
@@ -4485,6 +4500,7 @@  const struct real_format vax_f_format =
     127,
     15,
     15,
+    0,
     false,
     false,
     false,
@@ -4507,6 +4523,7 @@  const struct real_format vax_d_format =
     127,
     15,
     15,
+    0,
     false,
     false,
     false,
@@ -4529,6 +4546,7 @@  const struct real_format vax_g_format =
     1023,
     15,
     15,
+    0,
     false,
     false,
     false,
@@ -4606,6 +4624,7 @@  const struct real_format decimal_single_format =
     97,
     31,
     31,
+    32,
     false,
     true,
     true,
@@ -4629,6 +4648,7 @@  const struct real_format decimal_double_format =
     385,
     63,
     63,
+    64,
     false,
     true,
     true,
@@ -4652,6 +4672,7 @@  const struct real_format decimal_quad_format =
     6145,
     127,
     127,
+    128,
     false,
     true,
     true,
@@ -4790,6 +4811,7 @@  const struct real_format ieee_half_format =
     16,
     15,
     15,
+    16,
     false,
     true,
     true,
@@ -4815,6 +4837,7 @@  const struct real_format arm_half_format =
     17,
     15,
     15,
+    0,
     false,
     true,
     false,
@@ -4861,6 +4884,7 @@  const struct real_format real_internal_format =
     MAX_EXP,
     -1,
     -1,
+    0,
     false,
     false,
     true,
Index: gcc/real.h
===================================================================
--- gcc/real.h	(revision 239543)
+++ gcc/real.h	(working copy)
@@ -139,6 +139,17 @@  struct real_format
      or -1 for a complex encoding.  */
   int signbit_rw;
 
+  /* If this is an IEEE interchange format, the number of bits in the
+     format; otherwise, if it is an IEEE extended format, one more
+     than the greatest number of bits in an interchange format it
+     extends; otherwise 0.  Formats need not follow the IEEE 754-2008
+     recommended practice regarding how signaling NaNs are identified,
+     and may vary in the choice of default NaN, but must follow other
+     IEEE practice regarding having NaNs, infinities and subnormal
+     values, and the relation of minimum and maximum exponents, and,
+     for interchange formats, the details of the encoding.  */
+  int ieee_bits;
+
   /* Default rounding mode for operations on this format.  */
   bool round_towards_zero;
   bool has_sign_dependent_rounding;
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 239543)
+++ gcc/target.def	(working copy)
@@ -3333,6 +3333,26 @@  hook returns true for all of @code{SFmode}, @code{
  bool, (machine_mode mode),
  default_libgcc_floating_mode_supported_p)
 
+DEFHOOK
+(floatn_mode,
+ "Define this to return the machine mode to use for the type \n\
+@code{_Float@var{n}}, if @var{extended} is false, or the type \n\
+@code{_Float@var{n}x}, if @var{extended} is true.  If such a type \n\
+is not supported, return @code{VOIDmode}.  The default version of this \n\
+hook returns @code{SFmode} for @code{_Float32}, @code{DFmode} for \n\
+@code{_Float64} and @code{_Float32x} and @code{TFmode} for \n\
+@code{_Float128}, if those modes exist and satisfy the requirements for \n\
+those types and pass @code{TARGET_SCALAR_MODE_SUPPORTED_P} and \n\
+@code{TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P}; for @code{_Float64x}, it \n\
+returns the first of @code{XFmode} and @code{TFmode} that exists and \n\
+satisfies the same requirements; for other types, it returns \n\
+@code{VOIDmode}.  The hook is only called for values of @var{n} and \n\
+@var{extended} that are valid according to ISO/IEC TS 18661-3:2015; that \n\
+is, @var{n} is one of 32, 64, 128, or, if @var{extended} is false, 16 or \n\
+greater than 128 and a multiple of 32.",
+ machine_mode, (int n, bool extended),
+ default_floatn_mode)
+
 /* Compute cost of moving data from a register of class FROM to one of
    TO, using MODE.  */
 DEFHOOK
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 239543)
+++ gcc/targhooks.c	(working copy)
@@ -76,6 +76,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "predict.h"
 #include "params.h"
+#include "real.h"
 
 
 bool
@@ -461,6 +462,92 @@  default_libgcc_floating_mode_supported_p (machine_
     }
 }
 
+/* Return the machine mode to use for the type _FloatN, if EXTENDED is
+   false, or _FloatNx, if EXTENDED is true, or VOIDmode if not
+   supported.  */
+machine_mode
+default_floatn_mode (int n, bool extended)
+{
+  if (extended)
+    {
+      machine_mode cand1 = VOIDmode, cand2 = VOIDmode;
+      switch (n)
+	{
+	case 32:
+#ifdef HAVE_DFmode
+	  cand1 = DFmode;
+#endif
+	  break;
+
+	case 64:
+#ifdef HAVE_XFmode
+	  cand1 = XFmode;
+#endif
+#ifdef HAVE_TFmode
+	  cand2 = TFmode;
+#endif
+	  break;
+
+	case 128:
+	  break;
+
+	default:
+	  /* Those are the only valid _FloatNx types.  */
+	  gcc_unreachable ();
+	}
+      if (cand1 != VOIDmode
+	  && REAL_MODE_FORMAT (cand1)->ieee_bits > n
+	  && targetm.scalar_mode_supported_p (cand1)
+	  && targetm.libgcc_floating_mode_supported_p (cand1))
+	return cand1;
+      if (cand2 != VOIDmode
+	  && REAL_MODE_FORMAT (cand2)->ieee_bits > n
+	  && targetm.scalar_mode_supported_p (cand2)
+	  && targetm.libgcc_floating_mode_supported_p (cand2))
+	return cand2;
+    }
+  else
+    {
+      machine_mode cand = VOIDmode;
+      switch (n)
+	{
+	case 16:
+	  /* We do not use HFmode for _Float16 by default because the
+	     required excess precision support is not present and the
+	     interactions with promotion of the older __fp16 need to
+	     be worked out.  */
+	  break;
+
+	case 32:
+#ifdef HAVE_SFmode
+	  cand = SFmode;
+#endif
+	  break;
+
+	case 64:
+#ifdef HAVE_DFmode
+	  cand = DFmode;
+#endif
+	  break;
+
+	case 128:
+#ifdef HAVE_TFmode
+	  cand = TFmode;
+#endif
+	  break;
+
+	default:
+	  break;
+	}
+      if (cand != VOIDmode
+	  && REAL_MODE_FORMAT (cand)->ieee_bits == n
+	  && targetm.scalar_mode_supported_p (cand)
+	  && targetm.libgcc_floating_mode_supported_p (cand))
+	return cand;
+    }
+  return VOIDmode;
+}
+
 /* Make some target macros useable by target-independent code.  */
 bool
 targhook_words_big_endian (void)
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 239543)
+++ gcc/targhooks.h	(working copy)
@@ -73,6 +73,7 @@  extern tree default_mangle_assembler_name (const c
 
 extern bool default_scalar_mode_supported_p (machine_mode);
 extern bool default_libgcc_floating_mode_supported_p (machine_mode);
+extern machine_mode default_floatn_mode (int, bool);
 extern bool targhook_words_big_endian (void);
 extern bool targhook_float_words_big_endian (void);
 extern bool default_float_exceptions_rounding_supported_p (void);
Index: gcc/testsuite/gcc.dg/dfp/floatn.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/floatn.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/dfp/floatn.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Tests for _FloatN / _FloatNx types: test erroneous mixing with DFP.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32 } */
+/* { dg-require-effective-target float32x } */
+
+_Decimal32 d32;
+_Float32 f32;
+_Float32x f32x;
+int i;
+
+void
+f (void)
+{
+  (void) (d32 + f32); /* { dg-error "mix operands" } */
+  (void) (f32x * d32); /* { dg-error "mix operands" } */
+  (void) (i ? d32 : f32); /* { dg-error "mix operands" } */
+}
Index: gcc/testsuite/gcc.dg/float128-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float128-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float128-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128 constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128 } */
+
+#define WIDTH 128
+#define EXT 0
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/float128x-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float128x-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float128x-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128x constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x } */
+
+#define WIDTH 128
+#define EXT 1
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/float16-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float16-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float16-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float16 constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16 } */
+
+#define WIDTH 16
+#define EXT 0
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/float32-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float32-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float32-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32 constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32 } */
+
+#define WIDTH 32
+#define EXT 0
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/float32x-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float32x-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float32x-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32x constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x } */
+
+#define WIDTH 32
+#define EXT 1
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/float64-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float64-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float64-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64 constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64 } */
+
+#define WIDTH 64
+#define EXT 0
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/float64x-typeof.c
===================================================================
--- gcc/testsuite/gcc.dg/float64x-typeof.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/float64x-typeof.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64x constant types.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x } */
+
+#define WIDTH 64
+#define EXT 1
+#include "floatn-typeof.h"
Index: gcc/testsuite/gcc.dg/floatn-arithconv.c
===================================================================
--- gcc/testsuite/gcc.dg/floatn-arithconv.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/floatn-arithconv.c	(working copy)
@@ -0,0 +1,50 @@ 
+/* Tests for _FloatN / _FloatNx types: test usual arithmetic
+   conversions.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-add-options float64 } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32 } */
+/* { dg-require-effective-target float64 } */
+/* { dg-require-effective-target float32x } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+
+int i;
+
+#define TEST(VAR, TYPE1, TYPE2, RESTYPE)			\
+  do								\
+    {								\
+      typedef __typeof__ ((TYPE1) 0 + (TYPE2) 1) restype;	\
+      typedef __typeof__ (i ? (TYPE1) 0 : (TYPE2) 1) restype2;	\
+      typedef RESTYPE exptype;					\
+      extern restype VAR;					\
+      extern restype2 VAR;					\
+      extern exptype VAR;					\
+    }								\
+  while (0)
+
+void
+f (void)
+{
+  TEST (v1, float, double, double);
+#if DBL_MANT_DIG > FLT32_MANT_DIG
+  TEST (v2, double, _Float32, double);
+#endif
+#if DBL_MANT_DIG <= FLT64_MANT_DIG
+  TEST (v3, double, _Float64, _Float64);
+#endif
+#if DBL_MANT_DIG >= FLT32X_MANT_DIG
+  TEST (v4, double, _Float32x, double);
+#endif
+#if FLT_MANT_DIG <= FLT32_MANT_DIG
+  TEST (v5, float, _Float32, _Float32);
+#endif
+#if FLT32X_MANT_DIG <= FLT64_MANT_DIG
+  TEST (v6, _Float32x, _Float64, _Float64);
+#endif
+  TEST (v7, _Float32, _Float64, _Float64);
+  TEST (v8, _Float32, _Float32x, _Float32x);
+}
Index: gcc/testsuite/gcc.dg/floatn-errs.c
===================================================================
--- gcc/testsuite/gcc.dg/floatn-errs.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/floatn-errs.c	(working copy)
@@ -0,0 +1,44 @@ 
+/* Tests for _FloatN / _FloatNx types: test erroneous code.  */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-add-options float64 } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32 } */
+/* { dg-require-effective-target float32x } */
+/* { dg-require-effective-target float64 } */
+
+/* _FloatN, _FloatNx and standard types are incompatible even if they
+   have the same ABI.  */
+
+extern float a; /* { dg-message "previous declaration" } */
+extern _Float32 a; /* { dg-error "conflicting" } */
+
+extern double b; /* { dg-message "previous declaration" } */
+extern _Float32x b; /* { dg-error "conflicting" } */
+
+extern _Float64 c; /* { dg-message "previous declaration" } */
+extern _Float32x c; /* { dg-error "conflicting" } */
+
+/* These types are not promoted in old-style function definitions.  */
+
+void f (_Float32);
+void
+f (x)
+     _Float32 x;
+{
+}
+
+void g (double); /* { dg-error "prototype declaration" } */
+void
+g (x)
+     _Float32 x; /* { dg-error "match prototype" } */
+{
+}
+
+void h (_Float64); /* { dg-error "prototype declaration" } */
+void
+h (x)
+     _Float32 x; /* { dg-error "match prototype" } */
+{
+}
Index: gcc/testsuite/gcc.dg/floatn-typeof.h
===================================================================
--- gcc/testsuite/gcc.dg/floatn-typeof.h	(nonexistent)
+++ gcc/testsuite/gcc.dg/floatn-typeof.h	(working copy)
@@ -0,0 +1,22 @@ 
+/* Tests for _FloatN / _FloatNx types: test types of constants.
+   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 CSTU(C) CONCAT4 (C, F, WIDTH, x)
+#else
+# define TYPE CONCAT (_Float, WIDTH)
+# define CST(C) CONCAT3 (C, f, WIDTH)
+# define CSTU(C) CONCAT3 (C, F, WIDTH)
+#endif
+
+extern TYPE test_type;
+extern __typeof (CST (1.0)) test_type;
+extern __typeof (CSTU (1.0)) test_type;
Index: gcc/testsuite/gcc.dg/torture/float128-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128_runtime } */
+
+#define WIDTH 128
+#define EXT 0
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float128-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128 complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128_runtime } */
+
+#define WIDTH 128
+#define EXT 0
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float128-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float128 <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128_runtime } */
+
+#define WIDTH 128
+#define EXT 0
+#include "floatn-floath.h"
+
+#ifndef FLT128_MANT_DIG
+# error "FLT128_MANT_DIG undefined"
+#endif
+
+#ifndef FLT128_DECIMAL_DIG
+# error "FLT128_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT128_DIG
+# error "FLT128_DIG undefined"
+#endif
+
+#ifndef FLT128_MIN_EXP
+# error "FLT128_MIN_EXP undefined"
+#endif
+
+#ifndef FLT128_MIN_10_EXP
+# error "FLT128_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT128_MAX_EXP
+# error "FLT128_MAX_EXP undefined"
+#endif
+
+#ifndef FLT128_MAX_10_EXP
+# error "FLT128_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT128_MAX
+# error "FLT128_MAX undefined"
+#endif
+
+#ifndef FLT128_EPSILON
+# error "FLT128_EPSILON undefined"
+#endif
+
+#ifndef FLT128_MIN
+# error "FLT128_MIN undefined"
+#endif
+
+#ifndef FLT128_TRUE_MIN
+# error "FLT128_TRUE_MIN undefined"
+#endif
+
+#if FLT128_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT128_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT128_MANT_DIG != 113 || FLT128_MAX_EXP != 16384 || FLT128_MIN_EXP != -16381
+# error "_Float128 bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float128-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128 type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128_runtime } */
+
+#define WIDTH 128
+#define EXT 0
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/float128x-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128x-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128x-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128x.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x_runtime } */
+
+#define WIDTH 128
+#define EXT 1
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float128x-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128x-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128x-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128x complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x_runtime } */
+
+#define WIDTH 128
+#define EXT 1
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float128x-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128x-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128x-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float128x <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x_runtime } */
+
+#define WIDTH 128
+#define EXT 1
+#include "floatn-floath.h"
+
+#ifndef FLT128X_MANT_DIG
+# error "FLT128X_MANT_DIG undefined"
+#endif
+
+#ifndef FLT128X_DECIMAL_DIG
+# error "FLT128X_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT128X_DIG
+# error "FLT128X_DIG undefined"
+#endif
+
+#ifndef FLT128X_MIN_EXP
+# error "FLT128X_MIN_EXP undefined"
+#endif
+
+#ifndef FLT128X_MIN_10_EXP
+# error "FLT128X_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT128X_MAX_EXP
+# error "FLT128X_MAX_EXP undefined"
+#endif
+
+#ifndef FLT128X_MAX_10_EXP
+# error "FLT128X_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT128X_MAX
+# error "FLT128X_MAX undefined"
+#endif
+
+#ifndef FLT128X_EPSILON
+# error "FLT128X_EPSILON undefined"
+#endif
+
+#ifndef FLT128X_MIN
+# error "FLT128X_MIN undefined"
+#endif
+
+#ifndef FLT128X_TRUE_MIN
+# error "FLT128X_TRUE_MIN undefined"
+#endif
+
+#if FLT128X_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT128X_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT128X_MANT_DIG < 128 || FLT128X_MAX_EXP < 65536 || FLT128X_MIN_EXP + FLT128X_MAX_EXP != 3
+# error "_Float128x bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float128x-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float128x-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float128x-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float128x type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x_runtime } */
+
+#define WIDTH 128
+#define EXT 1
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/float16-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float16-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float16-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float16.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+#define WIDTH 16
+#define EXT 0
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float16-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float16-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float16-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float16 complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+#define WIDTH 16
+#define EXT 0
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float16-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float16-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float16-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float16 <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+#define WIDTH 16
+#define EXT 0
+#include "floatn-floath.h"
+
+#ifndef FLT16_MANT_DIG
+# error "FLT16_MANT_DIG undefined"
+#endif
+
+#ifndef FLT16_DECIMAL_DIG
+# error "FLT16_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT16_DIG
+# error "FLT16_DIG undefined"
+#endif
+
+#ifndef FLT16_MIN_EXP
+# error "FLT16_MIN_EXP undefined"
+#endif
+
+#ifndef FLT16_MIN_10_EXP
+# error "FLT16_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT16_MAX_EXP
+# error "FLT16_MAX_EXP undefined"
+#endif
+
+#ifndef FLT16_MAX_10_EXP
+# error "FLT16_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT16_MAX
+# error "FLT16_MAX undefined"
+#endif
+
+#ifndef FLT16_EPSILON
+# error "FLT16_EPSILON undefined"
+#endif
+
+#ifndef FLT16_MIN
+# error "FLT16_MIN undefined"
+#endif
+
+#ifndef FLT16_TRUE_MIN
+# error "FLT16_TRUE_MIN undefined"
+#endif
+
+#if FLT16_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT16_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT16_MANT_DIG != 11 || FLT16_MAX_EXP != 16 || FLT16_MIN_EXP != -13
+# error "_Float16 bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float16-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float16-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float16-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float16 type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+#define WIDTH 16
+#define EXT 0
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/float32-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+#define WIDTH 32
+#define EXT 0
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float32-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32 complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+#define WIDTH 32
+#define EXT 0
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float32-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float32 <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+#define WIDTH 32
+#define EXT 0
+#include "floatn-floath.h"
+
+#ifndef FLT32_MANT_DIG
+# error "FLT32_MANT_DIG undefined"
+#endif
+
+#ifndef FLT32_DECIMAL_DIG
+# error "FLT32_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT32_DIG
+# error "FLT32_DIG undefined"
+#endif
+
+#ifndef FLT32_MIN_EXP
+# error "FLT32_MIN_EXP undefined"
+#endif
+
+#ifndef FLT32_MIN_10_EXP
+# error "FLT32_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT32_MAX_EXP
+# error "FLT32_MAX_EXP undefined"
+#endif
+
+#ifndef FLT32_MAX_10_EXP
+# error "FLT32_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT32_MAX
+# error "FLT32_MAX undefined"
+#endif
+
+#ifndef FLT32_EPSILON
+# error "FLT32_EPSILON undefined"
+#endif
+
+#ifndef FLT32_MIN
+# error "FLT32_MIN undefined"
+#endif
+
+#ifndef FLT32_TRUE_MIN
+# error "FLT32_TRUE_MIN undefined"
+#endif
+
+#if FLT32_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT32_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT32_MANT_DIG != 24 || FLT32_MAX_EXP != 128 || FLT32_MIN_EXP != -125
+# error "_Float32 bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float32-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32 type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+#define WIDTH 32
+#define EXT 0
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/float32x-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32x-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32x-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32x.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x_runtime } */
+
+#define WIDTH 32
+#define EXT 1
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float32x-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32x-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32x-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32x complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x_runtime } */
+
+#define WIDTH 32
+#define EXT 1
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float32x-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32x-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32x-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float32x <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x_runtime } */
+
+#define WIDTH 32
+#define EXT 1
+#include "floatn-floath.h"
+
+#ifndef FLT32X_MANT_DIG
+# error "FLT32X_MANT_DIG undefined"
+#endif
+
+#ifndef FLT32X_DECIMAL_DIG
+# error "FLT32X_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT32X_DIG
+# error "FLT32X_DIG undefined"
+#endif
+
+#ifndef FLT32X_MIN_EXP
+# error "FLT32X_MIN_EXP undefined"
+#endif
+
+#ifndef FLT32X_MIN_10_EXP
+# error "FLT32X_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT32X_MAX_EXP
+# error "FLT32X_MAX_EXP undefined"
+#endif
+
+#ifndef FLT32X_MAX_10_EXP
+# error "FLT32X_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT32X_MAX
+# error "FLT32X_MAX undefined"
+#endif
+
+#ifndef FLT32X_EPSILON
+# error "FLT32X_EPSILON undefined"
+#endif
+
+#ifndef FLT32X_MIN
+# error "FLT32X_MIN undefined"
+#endif
+
+#ifndef FLT32X_TRUE_MIN
+# error "FLT32X_TRUE_MIN undefined"
+#endif
+
+#if FLT32X_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT32X_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT32X_MANT_DIG < 32 || FLT32X_MAX_EXP < 1024 || FLT32X_MIN_EXP + FLT32X_MAX_EXP != 3
+# error "_Float32x bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float32x-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float32x-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float32x-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float32x type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x_runtime } */
+
+#define WIDTH 32
+#define EXT 1
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/float64-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64_runtime } */
+
+#define WIDTH 64
+#define EXT 0
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float64-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64 complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64_runtime } */
+
+#define WIDTH 64
+#define EXT 0
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float64-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float64 <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64_runtime } */
+
+#define WIDTH 64
+#define EXT 0
+#include "floatn-floath.h"
+
+#ifndef FLT64_MANT_DIG
+# error "FLT64_MANT_DIG undefined"
+#endif
+
+#ifndef FLT64_DECIMAL_DIG
+# error "FLT64_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT64_DIG
+# error "FLT64_DIG undefined"
+#endif
+
+#ifndef FLT64_MIN_EXP
+# error "FLT64_MIN_EXP undefined"
+#endif
+
+#ifndef FLT64_MIN_10_EXP
+# error "FLT64_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT64_MAX_EXP
+# error "FLT64_MAX_EXP undefined"
+#endif
+
+#ifndef FLT64_MAX_10_EXP
+# error "FLT64_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT64_MAX
+# error "FLT64_MAX undefined"
+#endif
+
+#ifndef FLT64_EPSILON
+# error "FLT64_EPSILON undefined"
+#endif
+
+#ifndef FLT64_MIN
+# error "FLT64_MIN undefined"
+#endif
+
+#ifndef FLT64_TRUE_MIN
+# error "FLT64_TRUE_MIN undefined"
+#endif
+
+#if FLT64_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT64_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT64_MANT_DIG != 53 || FLT64_MAX_EXP != 1024 || FLT64_MIN_EXP != -1021
+# error "_Float64 bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float64-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64 type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64_runtime } */
+
+#define WIDTH 64
+#define EXT 0
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/float64x-basic.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64x-basic.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64x-basic.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64x.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x_runtime } */
+
+#define WIDTH 64
+#define EXT 1
+#include "floatn-basic.h"
Index: gcc/testsuite/gcc.dg/torture/float64x-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64x-complex.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64x-complex.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64x complex arithmetic.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x_runtime } */
+
+#define WIDTH 64
+#define EXT 1
+#include "floatn-complex.h"
Index: gcc/testsuite/gcc.dg/torture/float64x-floath.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64x-floath.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64x-floath.c	(working copy)
@@ -0,0 +1,61 @@ 
+/* Test _Float64x <float.h> macros.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x_runtime } */
+
+#define WIDTH 64
+#define EXT 1
+#include "floatn-floath.h"
+
+#ifndef FLT64X_MANT_DIG
+# error "FLT64X_MANT_DIG undefined"
+#endif
+
+#ifndef FLT64X_DECIMAL_DIG
+# error "FLT64X_DECIMAL_DIG undefined"
+#endif
+
+#ifndef FLT64X_DIG
+# error "FLT64X_DIG undefined"
+#endif
+
+#ifndef FLT64X_MIN_EXP
+# error "FLT64X_MIN_EXP undefined"
+#endif
+
+#ifndef FLT64X_MIN_10_EXP
+# error "FLT64X_MIN_10_EXP undefined"
+#endif
+
+#ifndef FLT64X_MAX_EXP
+# error "FLT64X_MAX_EXP undefined"
+#endif
+
+#ifndef FLT64X_MAX_10_EXP
+# error "FLT64X_MAX_10_EXP undefined"
+#endif
+
+#ifndef FLT64X_MAX
+# error "FLT64X_MAX undefined"
+#endif
+
+#ifndef FLT64X_EPSILON
+# error "FLT64X_EPSILON undefined"
+#endif
+
+#ifndef FLT64X_MIN
+# error "FLT64X_MIN undefined"
+#endif
+
+#ifndef FLT64X_TRUE_MIN
+# error "FLT64X_TRUE_MIN undefined"
+#endif
+
+#if FLT64X_DECIMAL_DIG > DECIMAL_DIG
+# error "FLT64X_DECIMAL_DIG > DECIMAL_DIG"
+#endif
+
+#if FLT64X_MANT_DIG < 64 || FLT64X_MAX_EXP < 16384 || FLT64X_MIN_EXP + FLT64X_MAX_EXP != 3
+# error "_Float64x bad format"
+#endif
Index: gcc/testsuite/gcc.dg/torture/float64x-tg.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/float64x-tg.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/float64x-tg.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* Test _Float64x type-generic built-in functions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x_runtime } */
+
+#define WIDTH 64
+#define EXT 1
+#include "floatn-tg.h"
Index: gcc/testsuite/gcc.dg/torture/floatn-basic.h
===================================================================
--- gcc/testsuite/gcc.dg/torture/floatn-basic.h	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/floatn-basic.h	(working copy)
@@ -0,0 +1,141 @@ 
+/* Basic tests for _FloatN / _FloatNx types: compile and execution
+   tests for valid code.  Before including this file, define WIDTH as
+   the value N; define EXT to 1 for _FloatNx and 0 for _FloatN.  */
+
+#include <stdarg.h>
+
+#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 CSTU(C) CONCAT4 (C, F, WIDTH, x)
+#else
+# define TYPE CONCAT (_Float, WIDTH)
+# define CST(C) CONCAT3 (C, f, WIDTH)
+# define CSTU(C) CONCAT3 (C, F, WIDTH)
+#endif
+
+extern void exit (int);
+extern void abort (void);
+
+volatile TYPE a = CST (1.0), b = CSTU (2.5), c = -CST (2.5);
+volatile TYPE a2 = CST (1.0), z = CST (0.0), nz = -CST (0.0);
+
+/* These types are not subject to default argument promotions.  */
+
+TYPE
+vafn (TYPE arg1, ...)
+{
+  va_list ap;
+  TYPE ret;
+  va_start (ap, arg1);
+  ret = arg1 + va_arg (ap, TYPE);
+  va_end (ap);
+  return ret;
+}
+
+TYPE
+krfn (arg)
+     TYPE arg;
+{
+  return arg + 1;
+}
+
+TYPE krprofn (TYPE);
+TYPE
+krprofn (arg)
+     TYPE arg;
+{
+  return arg * 3;
+}
+
+TYPE
+profn (TYPE arg)
+{
+  return arg / 4;
+}
+
+int
+main (void)
+{
+  volatile TYPE r;
+  r = -b;
+  if (r != c)
+    abort ();
+  r = a + b;
+  if (r != CST (3.5))
+    abort ();
+  r = a - b;
+  if (r != -CST (1.5))
+    abort ();
+  r = 2 * c;
+  if (r != -5)
+    abort ();
+  r = b * c;
+  if (r != -CST (6.25))
+    abort ();
+  r = b / (a + a);
+  if (r != CST (1.25))
+    abort ();
+  r = c * 3;
+  if (r != -CST (7.5))
+    abort ();
+  volatile int i = r;
+  if (i != -7)
+    abort ();
+  r = vafn (a, c);
+  if (r != -CST (1.5))
+    abort ();
+  r = krfn (b);
+  if (r != CST (3.5))
+    abort ();
+  r = krprofn (a);
+  if (r != CST (3.0))
+    abort ();
+  r = profn (a);
+  if (r != CST (0.25))
+    abort ();
+  if ((a < b) != 1)
+    abort ();
+  if ((b < a) != 0)
+    abort ();
+  if ((a < a2) != 0)
+    abort ();
+  if ((nz < z) != 0)
+    abort ();
+  if ((a <= b) != 1)
+    abort ();
+  if ((b <= a) != 0)
+    abort ();
+  if ((a <= a2) != 1)
+    abort ();
+  if ((nz <= z) != 1)
+    abort ();
+  if ((a > b) != 0)
+    abort ();
+  if ((b > a) != 1)
+    abort ();
+  if ((a > a2) != 0)
+    abort ();
+  if ((nz > z) != 0)
+    abort ();
+  if ((a >= b) != 0)
+    abort ();
+  if ((b >= a) != 1)
+    abort ();
+  if ((a >= a2) != 1)
+    abort ();
+  if ((nz >= z) != 1)
+    abort ();
+  i = (nz == z);
+  if (i != 1)
+    abort ();
+  i = (a == b);
+  if (i != 0)
+    abort ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/floatn-complex.h
===================================================================
--- gcc/testsuite/gcc.dg/torture/floatn-complex.h	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/floatn-complex.h	(working copy)
@@ -0,0 +1,76 @@ 
+/* Tests for _FloatN / _FloatNx types: compile and execution tests for
+   valid code with complex arithmetic.  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 CSTI(C) CONCAT4 (C, if, WIDTH, x)
+# define CSTI2(C) CONCAT4 (C, F, WIDTH, xi)
+#else
+# define TYPE CONCAT (_Float, WIDTH)
+# define CST(C) CONCAT3 (C, f, WIDTH)
+# define CSTI(C) CONCAT3 (C, if, WIDTH)
+# define CSTI2(C) CONCAT4 (C, F, WIDTH, i)
+#endif
+
+extern void exit (int);
+extern void abort (void);
+
+volatile TYPE a = CST (1.0);
+volatile _Complex TYPE b = CST (2.0) + CSTI (3.0);
+volatile _Complex TYPE c = CST (2.0) + CSTI2 (3.0);
+volatile _Complex TYPE d = __builtin_complex (CST (2.0), CST (3.0));
+
+_Complex TYPE
+fn (_Complex TYPE arg)
+{
+  return arg / 4;
+}
+
+int
+main (void)
+{
+  volatile _Complex TYPE r;
+  if (b != c)
+    abort ();
+  if (b != d)
+    abort ();
+  r = a + b;
+  if (__real__ r != CST (3.0) || __imag__ r != CST (3.0))
+    abort ();
+  r += d;
+  if (__real__ r != CST (5.0) || __imag__ r != CST (6.0))
+    abort ();
+  r -= a;
+  if (__real__ r != CST (4.0) || __imag__ r != CST (6.0))
+    abort ();
+  r /= (a + a);
+  if (__real__ r != CST (2.0) || __imag__ r != CST (3.0))
+    abort ();
+  r *= (a + a);
+  if (__real__ r != CST (4.0) || __imag__ r != CST (6.0))
+    abort ();
+  r -= b;
+  if (__real__ r != CST (2.0) || __imag__ r != CST (3.0))
+    abort ();
+  r *= r;
+  if (__real__ r != -CST (5.0) || __imag__ r != CST (12.0))
+    abort ();
+  /* Division may not be exact, so round result before comparing.  */
+  r /= b;
+  r += __builtin_complex (CST (100.0), CST (100.0));
+  r -= __builtin_complex (CST (100.0), CST (100.0));
+  if (r != b)
+    abort ();
+  r = fn (r);
+  if (__real__ r != CST (0.5) || __imag__ r != CST (0.75))
+    abort ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/floatn-convert.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/floatn-convert.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/floatn-convert.c	(working copy)
@@ -0,0 +1,104 @@ 
+/* Tests for _FloatN / _FloatNx types: test conversions.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-add-options float32 } */
+/* { dg-add-options float64 } */
+/* { dg-add-options float128 } */
+/* { dg-add-options float32x } */
+/* { dg-add-options float64x } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float32 } */
+/* { dg-require-effective-target floatn_nx_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+
+#ifndef FLT16_MAX
+# define _Float16 _Float32
+# define FLT16_MAX FLT32_MAX
+# define FLT16_MANT_DIG FLT32_MANT_DIG
+# define FLT16_EPSILON FLT32_EPSILON
+#endif
+
+#ifndef FLT64_MAX
+# define _Float64 _Float32
+# define FLT64_MAX FLT32_MAX
+# define FLT64_MANT_DIG FLT32_MANT_DIG
+# define FLT64_EPSILON FLT32_EPSILON
+#endif
+
+#ifndef FLT128_MAX
+# define _Float128 _Float32
+# define FLT128_MAX FLT32_MAX
+# define FLT128_MANT_DIG FLT32_MANT_DIG
+# define FLT128_EPSILON FLT32_EPSILON
+#endif
+
+#ifndef FLT32X_MAX
+# define _Float32x _Float32
+# define FLT32X_MAX FLT32_MAX
+# define FLT32X_MANT_DIG FLT32_MANT_DIG
+# define FLT32X_EPSILON FLT32_EPSILON
+#endif
+
+#ifndef FLT64X_MAX
+# define _Float64x _Float32
+# define FLT64X_MAX FLT32_MAX
+# define FLT64X_MANT_DIG FLT32_MANT_DIG
+# define FLT64X_EPSILON FLT32_EPSILON
+#endif
+
+#ifndef FLT128X_MAX
+# define _Float128x _Float32
+# define FLT128X_MAX FLT32_MAX
+# define FLT128X_MANT_DIG FLT32_MANT_DIG
+# define FLT128X_EPSILON FLT32_EPSILON
+#endif
+
+#define CONCATX(X, Y) X ## Y
+#define CONCAT(X, Y) CONCATX (X, Y)
+
+extern void exit (int);
+extern void abort (void);
+
+#define DO_TEST(TYPE1, PFX1, TYPE2, PFX2)			\
+  do								\
+    {								\
+      volatile TYPE1 a = (TYPE1) 1 + CONCAT (PFX1, _EPSILON);	\
+      volatile TYPE2 b = (TYPE2) a;				\
+      volatile TYPE2 expected;					\
+      if (CONCAT (PFX2, _MANT_DIG) < CONCAT (PFX1, _MANT_DIG))	\
+	expected = (TYPE2) 1;					\
+      else							\
+	expected = (TYPE2) 1 + (TYPE2) CONCAT (PFX1, _EPSILON); \
+      if (b != expected)					\
+	abort ();						\
+    }								\
+  while (0)
+
+#define DO_TEST1(TYPE1, PFX1)				\
+  do							\
+    {							\
+      DO_TEST (TYPE1, PFX1, _Float16, FLT16);		\
+      DO_TEST (TYPE1, PFX1, _Float32, FLT32);		\
+      DO_TEST (TYPE1, PFX1, _Float64, FLT64);		\
+      DO_TEST (TYPE1, PFX1, _Float128, FLT128);		\
+      DO_TEST (TYPE1, PFX1, _Float32x, FLT32X);		\
+      DO_TEST (TYPE1, PFX1, _Float64x, FLT64X);		\
+      DO_TEST (TYPE1, PFX1, _Float128x, FLT128X);	\
+    }							\
+  while (0)
+
+int
+main (void)
+{
+  DO_TEST1 (_Float16, FLT16);
+  DO_TEST1 (_Float32, FLT32);
+  DO_TEST1 (_Float64, FLT64);
+  DO_TEST1 (_Float128, FLT128);
+  DO_TEST1 (_Float32x, FLT32X);
+  DO_TEST1 (_Float64x, FLT64X);
+  DO_TEST1 (_Float128x, FLT128X);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/floatn-floath.h
===================================================================
--- gcc/testsuite/gcc.dg/torture/floatn-floath.h	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/floatn-floath.h	(working copy)
@@ -0,0 +1,52 @@ 
+/* Tests for _FloatN / _FloatNx types: compile and execution tests for
+   <float.h>.  Before including this file, define WIDTH as the value
+   N; define EXT to 1 for _FloatNx and 0 for _FloatN.  */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+
+#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 FMAC(M) CONCAT4 (FLT, WIDTH, X_, M)
+#else
+# define TYPE CONCAT (_Float, WIDTH)
+# define CST(C) CONCAT3 (C, f, WIDTH)
+# define FMAC(M) CONCAT4 (FLT, WIDTH, _, M)
+#endif
+
+extern void exit (int);
+extern void abort (void);
+
+int
+main (void)
+{
+  volatile TYPE a = CST (1.0);
+  for (int i = 0; i >= FMAC (MIN_EXP); i--)
+    a *= CST (0.5);
+  if (a != FMAC (MIN))
+    abort ();
+  for (int i = 0; i < FMAC (MANT_DIG) - 1; i++)
+    a *= CST (0.5);
+  if (a != FMAC (TRUE_MIN))
+    abort ();
+  a *= CST (0.5);
+  if (a != CST (0.0))
+    abort ();
+  a = FMAC (EPSILON);
+  for (int i = 0; i < FMAC (MANT_DIG) - 1; i++)
+    a *= CST (2.0);
+  if (a != CST (1.0))
+    abort ();
+  a = FMAC (MAX);
+  for (int i = 0; i < FMAC (MAX_EXP); i++)
+    a *= CST (0.5);
+  if (a != CST (1.0) - FMAC (EPSILON) * CST (0.5))
+    abort ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/floatn-tg.h
===================================================================
--- gcc/testsuite/gcc.dg/torture/floatn-tg.h	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/floatn-tg.h	(working copy)
@@ -0,0 +1,113 @@ 
+/* Tests for _FloatN / _FloatNx types: compile and execution tests for
+   type-generic built-in functions.  Before including this file,
+   define WIDTH as the value N; define EXT to 1 for _FloatNx and 0 for
+   _FloatN.  */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+
+#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 TRUE_MIN CONCAT3 (FLT, WIDTH, X_TRUE_MIN)
+#else
+# define TYPE CONCAT (_Float, WIDTH)
+# define CST(C) CONCAT3 (C, f, WIDTH)
+# define TRUE_MIN CONCAT3 (FLT, WIDTH, _TRUE_MIN)
+#endif
+
+extern void exit (int);
+extern void abort (void);
+
+volatile TYPE inf = __builtin_inf (), nanval = __builtin_nan ("");
+volatile TYPE zero = CST (0.0), negzero = -CST (0.0), one = CST (1.0);
+volatile TYPE true_min = TRUE_MIN;
+
+int
+main (void)
+{
+  if (__builtin_signbit (inf) != 0)
+    abort ();
+  if (__builtin_signbit (zero) != 0)
+    abort ();
+  if (__builtin_signbit (negzero) == 0)
+    abort ();
+  if (__builtin_isfinite (nanval) != 0)
+    abort ();
+  if (__builtin_isfinite (inf) != 0)
+    abort ();
+  if (__builtin_isfinite (one) == 0)
+    abort ();
+  if (__builtin_isinf (nanval) != 0)
+    abort ();
+  if (__builtin_isinf (inf) == 0)
+    abort ();
+  if (__builtin_isnan (nanval) == 0)
+    abort ();
+  if (__builtin_isnan (inf) != 0)
+    abort ();
+  if (__builtin_isnormal (inf) != 0)
+    abort ();
+  if (__builtin_isnormal (one) == 0)
+    abort ();
+  if (__builtin_isnormal (nanval) != 0)
+    abort ();
+  if (__builtin_isnormal (zero) != 0)
+    abort ();
+  if (__builtin_isnormal (true_min) != 0)
+    abort ();
+  if (__builtin_islessequal (zero, one) != 1)
+    abort ();
+  if (__builtin_islessequal (one, zero) != 0)
+    abort ();
+  if (__builtin_islessequal (zero, negzero) != 1)
+    abort ();
+  if (__builtin_islessequal (zero, nanval) != 0)
+    abort ();
+  if (__builtin_isless (zero, one) != 1)
+    abort ();
+  if (__builtin_isless (one, zero) != 0)
+    abort ();
+  if (__builtin_isless (zero, negzero) != 0)
+    abort ();
+  if (__builtin_isless (zero, nanval) != 0)
+    abort ();
+  if (__builtin_isgreaterequal (zero, one) != 0)
+    abort ();
+  if (__builtin_isgreaterequal (one, zero) != 1)
+    abort ();
+  if (__builtin_isgreaterequal (zero, negzero) != 1)
+    abort ();
+  if (__builtin_isgreaterequal (zero, nanval) != 0)
+    abort ();
+  if (__builtin_isgreater (zero, one) != 0)
+    abort ();
+  if (__builtin_isgreater (one, zero) != 1)
+    abort ();
+  if (__builtin_isgreater (zero, negzero) != 0)
+    abort ();
+  if (__builtin_isgreater (zero, nanval) != 0)
+    abort ();
+  if (__builtin_islessgreater (zero, one) != 1)
+    abort ();
+  if (__builtin_islessgreater (one, zero) != 1)
+    abort ();
+  if (__builtin_islessgreater (zero, negzero) != 0)
+    abort ();
+  if (__builtin_islessgreater (zero, nanval) != 0)
+    abort ();
+  if (__builtin_isunordered (zero, one) != 0)
+    abort ();
+  if (__builtin_isunordered (one, zero) != 0)
+    abort ();
+  if (__builtin_isunordered (zero, negzero) != 0)
+    abort ();
+  if (__builtin_isunordered (zero, nanval) != 1)
+    abort ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c	(working copy)
@@ -9,10 +9,10 @@ 
 int
 main (void)
 {
-  TEST_I_F(signed char, unsigned char, double, DBL_MANT_DIG);
-  TEST_I_F(signed short, unsigned short, double, DBL_MANT_DIG);
-  TEST_I_F(signed int, unsigned int, double, DBL_MANT_DIG);
-  TEST_I_F(signed long, unsigned long, double, DBL_MANT_DIG);
-  TEST_I_F(signed long long, unsigned long long, double, DBL_MANT_DIG);
+  TEST_I_F(signed char, unsigned char, double, DBL_MANT_DIG, DBL_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, double, DBL_MANT_DIG, DBL_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, double, DBL_MANT_DIG, DBL_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, double, DBL_MANT_DIG, DBL_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, double, DBL_MANT_DIG, DBL_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c	(working copy)
@@ -9,10 +9,10 @@ 
 int
 main (void)
 {
-  TEST_I_F(signed char, unsigned char, float, FLT_MANT_DIG);
-  TEST_I_F(signed short, unsigned short, float, FLT_MANT_DIG);
-  TEST_I_F(signed int, unsigned int, float, FLT_MANT_DIG);
-  TEST_I_F(signed long, unsigned long, float, FLT_MANT_DIG);
-  TEST_I_F(signed long long, unsigned long long, float, FLT_MANT_DIG);
+  TEST_I_F(signed char, unsigned char, float, FLT_MANT_DIG, FLT_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, float, FLT_MANT_DIG, FLT_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, float, FLT_MANT_DIG, FLT_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, float, FLT_MANT_DIG, FLT_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, float, FLT_MANT_DIG, FLT_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-ieee-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-ieee-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-ieee-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float128 type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float128, FLT128_MANT_DIG, FLT128_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-ieee.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-ieee.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-ieee.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float128.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128 } */
+/* { dg-require-effective-target float128_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float128, FLT128_MANT_DIG, FLT128_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float128, FLT128_MANT_DIG, FLT128_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float128, FLT128_MANT_DIG, FLT128_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float128, FLT128_MANT_DIG, FLT128_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float128, FLT128_MANT_DIG, FLT128_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128-timode.c	(working copy)
@@ -9,10 +9,11 @@ 
 #include "fp-int-convert.h"
 
 #define FLOAT128_MANT_DIG 113
+#define FLOAT128_MAX_EXP 16384
 
 int
 main (void)
 {
-  TEST_I_F(TItype, UTItype, __float128, FLOAT128_MANT_DIG);
+  TEST_I_F(TItype, UTItype, __float128, FLOAT128_MANT_DIG, FLOAT128_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128.c	(working copy)
@@ -6,14 +6,15 @@ 
 #include "fp-int-convert.h"
 
 #define FLOAT128_MANT_DIG 113
+#define FLOAT128_MAX_EXP 16384
 
 int
 main (void)
 {
-  TEST_I_F(signed char, unsigned char, __float128, FLOAT128_MANT_DIG);
-  TEST_I_F(signed short, unsigned short, __float128, FLOAT128_MANT_DIG);
-  TEST_I_F(signed int, unsigned int, __float128, FLOAT128_MANT_DIG);
-  TEST_I_F(signed long, unsigned long, __float128, FLOAT128_MANT_DIG);
-  TEST_I_F(signed long long, unsigned long long, __float128, FLOAT128_MANT_DIG);
+  TEST_I_F(signed char, unsigned char, __float128, FLOAT128_MANT_DIG, FLOAT128_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, __float128, FLOAT128_MANT_DIG, FLOAT128_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, __float128, FLOAT128_MANT_DIG, FLOAT128_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, __float128, FLOAT128_MANT_DIG, FLOAT128_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, __float128, FLOAT128_MANT_DIG, FLOAT128_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float128x type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float128, FLT128X_MANT_DIG, FLT128X_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float128x.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float128x.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float128x } */
+/* { dg-require-effective-target float128x_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float128x, FLT128X_MANT_DIG, FLT128X_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float128x, FLT128X_MANT_DIG, FLT128X_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float128x, FLT128X_MANT_DIG, FLT128X_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float128x, FLT128X_MANT_DIG, FLT128X_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float128x, FLT128X_MANT_DIG, FLT128X_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float16-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float16-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float16-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float16 type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float16, FLT16_MANT_DIG, FLT16_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float16.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float16.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float16.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float16.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float16, FLT16_MANT_DIG, FLT16_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float16, FLT16_MANT_DIG, FLT16_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float16, FLT16_MANT_DIG, FLT16_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float16, FLT16_MANT_DIG, FLT16_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float16, FLT16_MANT_DIG, FLT16_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float32-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float32-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float32-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float32 type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float32, FLT32_MANT_DIG, FLT32_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float32.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float32.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float32.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float32.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-require-effective-target float32_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float32, FLT32_MANT_DIG, FLT32_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float32, FLT32_MANT_DIG, FLT32_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float32, FLT32_MANT_DIG, FLT32_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float32, FLT32_MANT_DIG, FLT32_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float32, FLT32_MANT_DIG, FLT32_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float32x type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float32, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float32x.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float32x.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32x } */
+/* { dg-require-effective-target float32x_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float32x, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float32x, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float32x, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float32x, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float32x, FLT32X_MANT_DIG, FLT32X_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float64-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float64-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float64-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float64 type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float64, FLT64_MANT_DIG, FLT64_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float64.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float64.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float64.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float64.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float64_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float64, FLT64_MANT_DIG, FLT64_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float64, FLT64_MANT_DIG, FLT64_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float64, FLT64_MANT_DIG, FLT64_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float64, FLT64_MANT_DIG, FLT64_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float64, FLT64_MANT_DIG, FLT64_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x-timode.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x-timode.c	(working copy)
@@ -0,0 +1,16 @@ 
+/* Test floating-point conversions.  _Float64x type with TImode.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(TItype, UTItype, _Float64, FLT64X_MANT_DIG, FLT64X_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float64x.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* Test floating-point conversions.  Standard types and _Float64x.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float64x } */
+/* { dg-require-effective-target float64x_runtime } */
+
+#define __STDC_WANT_IEC_60559_TYPES_EXT__
+#include <float.h>
+#include "fp-int-convert.h"
+
+int
+main (void)
+{
+  TEST_I_F(signed char, unsigned char, _Float64x, FLT64X_MANT_DIG, FLT64X_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, _Float64x, FLT64X_MANT_DIG, FLT64X_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, _Float64x, FLT64X_MANT_DIG, FLT64X_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, _Float64x, FLT64X_MANT_DIG, FLT64X_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, _Float64x, FLT64X_MANT_DIG, FLT64X_MAX_EXP);
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float80-timode.c	(working copy)
@@ -7,10 +7,11 @@ 
 #include "fp-int-convert.h"
 
 #define FLOAT80_MANT_DIG 64
+#define FLOAT80_MAX_EXP 16384
 
 int
 main (void)
 {
-  TEST_I_F(TItype, UTItype, __float80, FLOAT80_MANT_DIG);
+  TEST_I_F(TItype, UTItype, __float80, FLOAT80_MANT_DIG, FLOAT80_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-float80.c	(working copy)
@@ -6,14 +6,15 @@ 
 #include "fp-int-convert.h"
 
 #define FLOAT80_MANT_DIG 64
+#define FLOAT80_MAX_EXP 16384
 
 int
 main (void)
 {
-  TEST_I_F(signed char, unsigned char, __float80, FLOAT80_MANT_DIG);
-  TEST_I_F(signed short, unsigned short, __float80, FLOAT80_MANT_DIG);
-  TEST_I_F(signed int, unsigned int, __float80, FLOAT80_MANT_DIG);
-  TEST_I_F(signed long, unsigned long, __float80, FLOAT80_MANT_DIG);
-  TEST_I_F(signed long long, unsigned long long, __float80, FLOAT80_MANT_DIG);
+  TEST_I_F(signed char, unsigned char, __float80, FLOAT80_MANT_DIG, FLOAT80_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, __float80, FLOAT80_MANT_DIG, FLOAT80_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, __float80, FLOAT80_MANT_DIG, FLOAT80_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, __float80, FLOAT80_MANT_DIG, FLOAT80_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, __float80, FLOAT80_MANT_DIG, FLOAT80_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c	(working copy)
@@ -9,10 +9,10 @@ 
 int
 main (void)
 {
-  TEST_I_F(signed char, unsigned char, long double, LDBL_MANT_DIG);
-  TEST_I_F(signed short, unsigned short, long double, LDBL_MANT_DIG);
-  TEST_I_F(signed int, unsigned int, long double, LDBL_MANT_DIG);
-  TEST_I_F(signed long, unsigned long, long double, LDBL_MANT_DIG);
-  TEST_I_F(signed long long, unsigned long long, long double, LDBL_MANT_DIG);
+  TEST_I_F(signed char, unsigned char, long double, LDBL_MANT_DIG, LDBL_MAX_EXP);
+  TEST_I_F(signed short, unsigned short, long double, LDBL_MANT_DIG, LDBL_MAX_EXP);
+  TEST_I_F(signed int, unsigned int, long double, LDBL_MANT_DIG, LDBL_MAX_EXP);
+  TEST_I_F(signed long, unsigned long, long double, LDBL_MANT_DIG, LDBL_MAX_EXP);
+  TEST_I_F(signed long long, unsigned long long, long double, LDBL_MANT_DIG, LDBL_MAX_EXP);
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c	(working copy)
@@ -9,13 +9,13 @@ 
 int
 main (void)
 {
-  TEST_I_F(TItype, UTItype, float, FLT_MANT_DIG);
-  TEST_I_F(TItype, UTItype, double, DBL_MANT_DIG);
+  TEST_I_F(TItype, UTItype, float, FLT_MANT_DIG, FLT_MAX_EXP);
+  TEST_I_F(TItype, UTItype, double, DBL_MANT_DIG, DBL_MAX_EXP);
   /* Disable the long double tests when using IBM Extended Doubles.
      They have variable precision, but constants calculated by gcc's
      real.c assume fixed precision.  */
 #if DBL_MANT_DIG != LDBL_MANT_DIG  && LDBL_MANT_DIG != 106
-  TEST_I_F(TItype, UTItype, long double, LDBL_MANT_DIG);
+  TEST_I_F(TItype, UTItype, long double, LDBL_MANT_DIG, LDBL_MAX_EXP);
 #endif
   exit (0);
 }
Index: gcc/testsuite/gcc.dg/torture/fp-int-convert.h
===================================================================
--- gcc/testsuite/gcc.dg/torture/fp-int-convert.h	(revision 239543)
+++ gcc/testsuite/gcc.dg/torture/fp-int-convert.h	(working copy)
@@ -15,20 +15,21 @@  typedef long TItype;
 typedef unsigned long UTItype;
 #endif
 
-/* TEST_I_F(I, U, F, P) tests conversions between the pair of signed
-   and unsigned integer types I and U and the floating-point type F,
-   where P is the binary precision of the floating point type.  We
-   test conversions of the values 0, 1, 0x7...f, 0x8...0, 0xf...f.  We
-   also test conversions of values half way between two
-   representable values (rounding both ways), just above half way, and
-   just below half way.  */
-#define TEST_I_F(I, U, F, P)					\
+/* TEST_I_F(I, U, F, P, M) tests conversions between the pair of
+   signed and unsigned integer types I and U and the floating-point
+   type F, where P is the binary precision of the floating point type
+   and M is the MAX_EXP value for that type (so 2^M overflows, 2^(M-1)
+   does not).  We test conversions of the values 0, 1, 0x7...f,
+   0x8...0, 0xf...f.  We also test conversions of values half way
+   between two representable values (rounding both ways), just above
+   half way, and just below half way.  */
+#define TEST_I_F(I, U, F, P, M)					\
 do {								\
   TEST_I_F_VAL (I, F, (I)0, 1);					\
   TEST_I_F_VAL (I, F, (I)1, 1);					\
   TEST_I_F_VAL (I, F, (I)(((U)~(U)0) >> 1), P_OK1 (P, I));	\
-  TEST_I_F_VAL (I, F, (I)(U)~(((U)~(U)0) >> 1), 1);		\
-  TEST_I_F_VAL (I, F, (I)(U)~(U)0, P_OK (P, I));		\
+  TEST_I_F_VAL (I, F, (I)(U)~(((U)~(U)0) >> 1), M_OK1 (M, I));	\
+  TEST_I_F_VAL (I, F, (I)(U)~(U)0, 1);				\
   TEST_I_F_VAL (I, F, HVAL0S (P, I), P_OK (P, I));		\
   TEST_I_F_VAL (I, F, HVAL0S (P, I) + 1, P_OK (P, I));		\
   TEST_I_F_VAL (I, F, HVAL0S (P, I) - 1, P_OK (P, I));		\
@@ -44,7 +45,7 @@  do {								\
   TEST_I_F_VAL (U, F, (U)0, 1);					\
   TEST_I_F_VAL (U, F, (U)1, 1);					\
   TEST_I_F_VAL (U, F, (U)(((U)~(U)0) >> 1), P_OK1 (P, U));	\
-  TEST_I_F_VAL (U, F, (U)~(((U)~(U)0) >> 1), 1);		\
+  TEST_I_F_VAL (U, F, (U)~(((U)~(U)0) >> 1), M_OK1 (M, U));	\
   TEST_I_F_VAL (U, F, (U)~(U)0, P_OK (P, U));			\
   TEST_I_F_VAL (U, F, HVAL0U (P, U), P_OK (P, U));		\
   TEST_I_F_VAL (U, F, HVAL0U (P, U) + 1, P_OK (P, U));		\
@@ -56,6 +57,7 @@  do {								\
 
 #define P_OK(P, T) ((P) >= sizeof(T) * CHAR_BIT)
 #define P_OK1(P, T) ((P) >= sizeof(T) * CHAR_BIT - 1)
+#define M_OK1(M, T) ((M) > sizeof(T) * CHAR_BIT - 1)
 #define HVAL0U(P, U) (U)(P_OK (P, U)					 \
 			 ? (U)1						 \
 			 : (((U)1 << (sizeof(U) * CHAR_BIT - 1))	 \
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 239543)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -2433,6 +2433,135 @@  proc check_effective_target_has_q_floating_suffix
     } "$opts"]
 }
 
+# Return 1 if the target supports the _FloatN / _FloatNx type
+# indicated in the function name, 0 otherwise.
+
+proc check_effective_target_float16 {} {
+    return [check_no_compiler_messages_nocache float16 object {
+        _Float16 x;
+    }]
+}
+
+proc check_effective_target_float32 {} {
+    return [check_no_compiler_messages_nocache float32 object {
+        _Float32 x;
+    }]
+}
+
+proc check_effective_target_float64 {} {
+    return [check_no_compiler_messages_nocache float64 object {
+        _Float64 x;
+    }]
+}
+
+proc check_effective_target_float128 {} {
+    return [check_no_compiler_messages_nocache float128 object {
+        _Float128 x;
+    }]
+}
+
+proc check_effective_target_float32x {} {
+    return [check_no_compiler_messages_nocache float32x object {
+        _Float32x x;
+    }]
+}
+
+proc check_effective_target_float64x {} {
+    return [check_no_compiler_messages_nocache float64x object {
+        _Float64x x;
+    }]
+}
+
+proc check_effective_target_float128x {} {
+    return [check_no_compiler_messages_nocache float128x object {
+        _Float128x x;
+    }]
+}
+
+# Likewise, but runtime support for any special options used as well
+# as compile-time support is required.
+
+proc check_effective_target_float16_runtime {} {
+    return [check_effective_target_float16]
+}
+
+proc check_effective_target_float32_runtime {} {
+    return [check_effective_target_float32]
+}
+
+proc check_effective_target_float64_runtime {} {
+    return [check_effective_target_float64]
+}
+
+proc check_effective_target_float128_runtime {} {
+    if { ![check_effective_target_float128] } {
+	return 0
+    }
+    if { [istarget powerpc*-*-*] } {
+	return [check_effective_target_base_quadfloat_support]
+    }
+    return 1
+}
+
+proc check_effective_target_float32x_runtime {} {
+    return [check_effective_target_float32x]
+}
+
+proc check_effective_target_float64x_runtime {} {
+    if { ![check_effective_target_float64x] } {
+	return 0
+    }
+    if { [istarget powerpc*-*-*] } {
+	return [check_effective_target_base_quadfloat_support]
+    }
+    return 1
+}
+
+proc check_effective_target_float128x_runtime {} {
+    return [check_effective_target_float128x]
+}
+
+# Return 1 if the target hardware supports any options added for
+# _FloatN and _FloatNx types, 0 otherwise.
+
+proc check_effective_target_floatn_nx_runtime {} {
+    if { [istarget powerpc*-*-*] } {
+	return [check_effective_target_base_quadfloat_support]
+    }
+    return 1
+}
+
+# Add options needed to use the _FloatN / _FloatNx type indicated in
+# the function name.
+
+proc add_options_for_float16 { flags } {
+    return "$flags"
+}
+
+proc add_options_for_float32 { flags } {
+    return "$flags"
+}
+
+proc add_options_for_float64 { flags } {
+    return "$flags"
+}
+
+proc add_options_for_float128 { flags } {
+    return [add_options_for___float128 "$flags"]
+}
+
+proc add_options_for_float32x { flags } {
+    return "$flags"
+}
+
+proc add_options_for_float64x { flags } {
+    return [add_options_for___float128 "$flags"]
+}
+
+proc add_options_for_float128x { flags } {
+    return "$flags"
+}
+
 # Return 1 if the target supports __float128,
 # 0 otherwise.
 
Index: gcc/tree-core.h
===================================================================
--- gcc/tree-core.h	(revision 239543)
+++ gcc/tree-core.h	(working copy)
@@ -558,10 +558,44 @@  enum tree_index {
   TI_COMPLEX_DOUBLE_TYPE,
   TI_COMPLEX_LONG_DOUBLE_TYPE,
 
+  TI_COMPLEX_FLOAT16_TYPE,
+  TI_COMPLEX_FLOATN_NX_TYPE_FIRST = TI_COMPLEX_FLOAT16_TYPE,
+  TI_COMPLEX_FLOAT32_TYPE,
+  TI_COMPLEX_FLOAT64_TYPE,
+  TI_COMPLEX_FLOAT128_TYPE,
+  TI_COMPLEX_FLOAT32X_TYPE,
+  TI_COMPLEX_FLOAT64X_TYPE,
+  TI_COMPLEX_FLOAT128X_TYPE,
+
   TI_FLOAT_TYPE,
   TI_DOUBLE_TYPE,
   TI_LONG_DOUBLE_TYPE,
 
+  /* The _FloatN and _FloatNx types must be consecutive, and in the
+     same sequence as the corresponding complex types, which must also
+     be consecutive; _FloatN must come before _FloatNx; the order must
+     also be the same as in the floatn_nx_types array and the RID_*
+     values in c-common.h.  This is so that iterations over these
+     types work as intended.  */
+  TI_FLOAT16_TYPE,
+  TI_FLOATN_TYPE_FIRST = TI_FLOAT16_TYPE,
+  TI_FLOATN_NX_TYPE_FIRST = TI_FLOAT16_TYPE,
+  TI_FLOAT32_TYPE,
+  TI_FLOAT64_TYPE,
+  TI_FLOAT128_TYPE,
+  TI_FLOATN_TYPE_LAST = TI_FLOAT128_TYPE,
+#define NUM_FLOATN_TYPES (TI_FLOATN_TYPE_LAST - TI_FLOATN_TYPE_FIRST + 1)
+  TI_FLOAT32X_TYPE,
+  TI_FLOATNX_TYPE_FIRST = TI_FLOAT32X_TYPE,
+  TI_FLOAT64X_TYPE,
+  TI_FLOAT128X_TYPE,
+  TI_FLOATNX_TYPE_LAST = TI_FLOAT128X_TYPE,
+  TI_FLOATN_NX_TYPE_LAST = TI_FLOAT128X_TYPE,
+#define NUM_FLOATNX_TYPES (TI_FLOATNX_TYPE_LAST - TI_FLOATNX_TYPE_FIRST + 1)
+#define NUM_FLOATN_NX_TYPES (TI_FLOATN_NX_TYPE_LAST		\
+			     - TI_FLOATN_NX_TYPE_FIRST		\
+			     + 1)
+
   TI_FLOAT_PTR_TYPE,
   TI_DOUBLE_PTR_TYPE,
   TI_LONG_DOUBLE_PTR_TYPE,
@@ -1959,7 +1993,17 @@  struct GTY(()) builtin_info_type {
   unsigned declared_p : 1;
 };
 
+/* Information about a _FloatN or _FloatNx type that may be
+   supported.  */
+struct floatn_type_info {
+  /* The number N in the type name.  */
+  int n;
+  /* Whether it is an extended type _FloatNx (true) or an interchange
+     type (false).  */
+  bool extended;
+};
 
+
 /*---------------------------------------------------------------------------
                                 Global variables
 ---------------------------------------------------------------------------*/
@@ -2023,4 +2067,7 @@  extern GTY(()) tree current_function_decl;
 /* Nonzero means a FUNC_BEGIN label was emitted.  */
 extern GTY(()) const char * current_function_func_begin_label;
 
+/* Information about the _FloatN and _FloatNx types.  */
+extern const floatn_type_info floatn_nx_types[NUM_FLOATN_NX_TYPES];
+
 #endif  // GCC_TREE_CORE_H
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 239543)
+++ gcc/tree.c	(working copy)
@@ -10140,6 +10140,20 @@  build_atomic_base (tree type, unsigned int align)
   return t;
 }
 
+/* Information about the _FloatN and _FloatNx types.  This must be in
+   the same order as the corresponding TI_* enum values.  */
+const floatn_type_info floatn_nx_types[NUM_FLOATN_NX_TYPES] =
+  {
+    { 16, false },
+    { 32, false },
+    { 64, false },
+    { 128, false },
+    { 32, true },
+    { 64, true },
+    { 128, true },
+  };
+
+
 /* Create nodes for all integer types (and error_mark_node) using the sizes
    of C datatypes.  SIGNED_CHAR specifies whether char is signed.  */
 
@@ -10312,6 +10326,29 @@  build_common_tree_nodes (bool signed_char)
   TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
   layout_type (long_double_type_node);
 
+  for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    {
+      int n = floatn_nx_types[i].n;
+      bool extended = floatn_nx_types[i].extended;
+      machine_mode mode = targetm.floatn_mode (n, extended);
+      if (mode == VOIDmode)
+	continue;
+      int precision = GET_MODE_PRECISION (mode);
+      /* Work around the rs6000 KFmode having precision 113 not
+	 128.  */
+      const struct real_format *fmt = REAL_MODE_FORMAT (mode);
+      gcc_assert (fmt->b == 2 && fmt->emin + fmt->emax == 3);
+      int min_precision = fmt->p + ceil_log2 (fmt->emax - fmt->emin);
+      if (!extended)
+	gcc_assert (min_precision == n);
+      if (precision < min_precision)
+	precision = min_precision;
+      FLOATN_NX_TYPE_NODE (i) = make_node (REAL_TYPE);
+      TYPE_PRECISION (FLOATN_NX_TYPE_NODE (i)) = precision;
+      layout_type (FLOATN_NX_TYPE_NODE (i));
+      SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
+    }
+
   float_ptr_type_node = build_pointer_type (float_type_node);
   double_ptr_type_node = build_pointer_type (double_type_node);
   long_double_ptr_type_node = build_pointer_type (long_double_type_node);
@@ -10346,6 +10383,13 @@  build_common_tree_nodes (bool signed_char)
   complex_double_type_node = build_complex_type (double_type_node);
   complex_long_double_type_node = build_complex_type (long_double_type_node);
 
+  for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+    {
+      if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE)
+	COMPLEX_FLOATN_NX_TYPE_NODE (i)
+	  = build_complex_type (FLOATN_NX_TYPE_NODE (i));
+    }
+
 /* Make fixed-point nodes based on sat/non-sat and signed/unsigned.  */
 #define MAKE_FIXED_TYPE_NODE(KIND,SIZE) \
   sat_ ## KIND ## _type_node = \
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 239543)
+++ gcc/tree.h	(working copy)
@@ -3605,6 +3605,17 @@  tree_operand_check_code (const_tree __t, enum tree
 #define double_type_node		global_trees[TI_DOUBLE_TYPE]
 #define long_double_type_node		global_trees[TI_LONG_DOUBLE_TYPE]
 
+/* Nodes for particular _FloatN and _FloatNx types in sequence.  */
+#define FLOATN_TYPE_NODE(IDX)		global_trees[TI_FLOATN_TYPE_FIRST + (IDX)]
+#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).  */
+#define float128_type_node		global_trees[TI_FLOAT128_TYPE]
+#define float64x_type_node		global_trees[TI_FLOAT64X_TYPE]
+
 #define float_ptr_type_node		global_trees[TI_FLOAT_PTR_TYPE]
 #define double_ptr_type_node		global_trees[TI_DOUBLE_PTR_TYPE]
 #define long_double_ptr_type_node	global_trees[TI_LONG_DOUBLE_PTR_TYPE]
@@ -3615,6 +3626,8 @@  tree_operand_check_code (const_tree __t, enum tree
 #define complex_double_type_node	global_trees[TI_COMPLEX_DOUBLE_TYPE]
 #define complex_long_double_type_node	global_trees[TI_COMPLEX_LONG_DOUBLE_TYPE]
 
+#define COMPLEX_FLOATN_NX_TYPE_NODE(IDX)	global_trees[TI_COMPLEX_FLOATN_NX_TYPE_FIRST + (IDX)]
+
 #define pointer_bounds_type_node        global_trees[TI_POINTER_BOUNDS_TYPE]
 
 #define void_type_node			global_trees[TI_VOID_TYPE]
Index: libcpp/expr.c
===================================================================
--- libcpp/expr.c	(revision 239543)
+++ libcpp/expr.c	(working copy)
@@ -91,10 +91,10 @@  static unsigned int
 interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len)
 {
   size_t flags;
-  size_t f, d, l, w, q, i;
+  size_t f, d, l, w, q, i, fn, fnx, fn_bits;
 
   flags = 0;
-  f = d = l = w = q = i = 0;
+  f = d = l = w = q = i = fn = fnx = fn_bits = 0;
 
   /* Process decimal float suffixes, which are two letters starting
      with d or D.  Order and case are significant.  */
@@ -172,21 +172,59 @@  interpret_float_suffix (cpp_reader *pfile, const u
 
   /* In any remaining valid suffix, the case and order don't matter.  */
   while (len--)
-    switch (s[len])
-      {
-      case 'f': case 'F': f++; break;
-      case 'd': case 'D': d++; break;
-      case 'l': case 'L': l++; break;
-      case 'w': case 'W': w++; break;
-      case 'q': case 'Q': q++; break;
-      case 'i': case 'I':
-      case 'j': case 'J': i++; break;
-      default:
-	return 0;
-      }
+    {
+      switch (s[0])
+	{
+	case 'f': case 'F':
+	  f++;
+	  if (len > 0
+	      && !CPP_OPTION (pfile, cplusplus)
+	      && s[1] >= '1'
+	      && s[1] <= '9'
+	      && fn_bits == 0)
+	    {
+	      f--;
+	      while (len > 0
+		     && s[1] >= '0'
+		     && s[1] <= '9'
+		     && fn_bits < CPP_FLOATN_MAX)
+		{
+		  fn_bits = fn_bits * 10 + (s[1] - '0');
+		  len--;
+		  s++;
+		}
+	      if (len > 0 && s[1] == 'x')
+		{
+		  fnx++;
+		  len--;
+		  s++;
+		}
+	      else
+		fn++;
+	    }
+	  break;
+	case 'd': case 'D': d++; break;
+	case 'l': case 'L': l++; break;
+	case 'w': case 'W': w++; break;
+	case 'q': case 'Q': q++; break;
+	case 'i': case 'I':
+	case 'j': case 'J': i++; break;
+	default:
+	  return 0;
+	}
+      s++;
+    }
 
-  if (f + d + l + w + q > 1 || i > 1)
+  if (f + d + l + w + q + fn + fnx > 1 || i > 1)
     return 0;
+  if (fn_bits > CPP_FLOATN_MAX)
+    return 0;
+  if (fnx && fn_bits != 32 && fn_bits != 64 && fn_bits != 128)
+    return 0;
+  if (fn && fn_bits != 16 && fn_bits % 32 != 0)
+    return 0;
+  if (fn && fn_bits == 96)
+    return 0;
 
   if (i && !CPP_OPTION (pfile, ext_numeric_literals))
     return 0;
@@ -199,7 +237,10 @@  interpret_float_suffix (cpp_reader *pfile, const u
 	     d ? CPP_N_MEDIUM :
 	     l ? CPP_N_LARGE :
 	     w ? CPP_N_MD_W :
-	     q ? CPP_N_MD_Q : CPP_N_DEFAULT));
+	     q ? CPP_N_MD_Q :
+	     fn ? CPP_N_FLOATN | (fn_bits << CPP_FLOATN_SHIFT) :
+	     fnx ? CPP_N_FLOATNX | (fn_bits << CPP_FLOATN_SHIFT) :
+	     CPP_N_DEFAULT));
 }
 
 /* Return the classification flags for a float suffix.  */
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 239543)
+++ libcpp/include/cpplib.h	(working copy)
@@ -953,9 +953,16 @@  struct cpp_num
 
 #define CPP_N_FRACT	0x100000 /* Fract types.  */
 #define CPP_N_ACCUM	0x200000 /* Accum types.  */
+#define CPP_N_FLOATN	0x400000 /* _FloatN types.  */
+#define CPP_N_FLOATNX	0x800000 /* _FloatNx types.  */
 
 #define CPP_N_USERDEF	0x1000000 /* C++0x user-defined literal.  */
 
+#define CPP_N_WIDTH_FLOATN_NX	0xF0000000 /* _FloatN / _FloatNx value
+					      of N, divided by 16.  */
+#define CPP_FLOATN_SHIFT	24
+#define CPP_FLOATN_MAX	0xF0
+
 /* Classify a CPP_NUMBER token.  The return value is a combination of
    the flags from the above sets.  */
 extern unsigned cpp_classify_number (cpp_reader *, const cpp_token *,