public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
@ 2022-09-12  8:05 Jakub Jelinek
  2022-09-12 19:36 ` Joseph Myers
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-12  8:05 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely, Joseph S. Myers, Bruce Korb; +Cc: gcc-patches

Hi!

The following patch implements the compiler part of C++23
P1467R9 - Extended floating-point types and standard names compiler part
by introducing _Float{16,32,64,128} as keywords and builtin types
like they are implemented for C already since GCC 7.
It doesn't introduce _Float{32,64,128}x for C++, those remain C only
for now, mainly because https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
has mangling for:
::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
but doesn't for _FloatNx.  And it doesn't add anything for bfloat16_t
support, see below.
Regarding mangling, I think mangling _FloatNx as DF <number> x _ would be
possible, but would need to be discussed and voted in.
As there is no _FloatNx support for C++, I think it is wrong to announce
it through __FLT{32,64,128}X_*__ predefined macros (so the patch disables
those for C++; unfortunately g++ 7 to 12 will predefine those and also
__FLT{32,64,128}_*__ even when _FloatN support isn't implemented).
The patch wants to keep backwards compatibility with how __float128 has
been handled in C++ before, both for mangling and behavior in binary
operations, overload resolution etc.  So, there are some backend changes
where for C __float128 and _Float128 are the same type (float128_type_node
and float128t_type_node are the same pointer), but for C++ they are distinct
types which mangle differently and _Float128 is treated as extended
floating-point type while __float128 is treated as non-standard floating
point type.  The various C++23 changes about how floating-point types
are changed are actually implemented as written in the spec only if at least
one of the types involved is _Float{16,32,64,128} and kept previous behavior
otherwise.  For float/double/long double the rules are actually written that
they behave the same as before.
There is some backwards incompatibility at least on x86 regarding _Float16,
because that type was already used by that name and with the DF16_ mangling
(but only since GCC 12 and I think it isn't that widely used in the wild
yet).  E.g. config/i386/avx512fp16intrin.h shows the issues, where
in C or in GCC 12 in C++ one could pass 0.0f to a builtin taking _Float16
argument, but with the changes that is not possible anymore, one needs
to either use 0.0f16 or (_Float16) 0.0f.
We have also a problem with glibc headers, where since glibc 2.27
math.h and complex.h aren't compilable with these changes.  One gets
errors like:
In file included from /usr/include/math.h:43,
                 from abc.c:1:
/usr/include/bits/floatn.h:86:9: error: multiple types in one declaration
   86 | typedef __float128 _Float128;
      |         ^~~~~~~~~~
/usr/include/bits/floatn.h:86:20: error: declaration does not declare anything [-fpermissive]
   86 | typedef __float128 _Float128;
      |                    ^~~~~~~~~
In file included from /usr/include/bits/floatn.h:119:
/usr/include/bits/floatn-common.h:214:9: error: multiple types in one declaration
  214 | typedef float _Float32;
      |         ^~~~~
/usr/include/bits/floatn-common.h:214:15: error: declaration does not declare anything [-fpermissive]
  214 | typedef float _Float32;
      |               ^~~~~~~~
/usr/include/bits/floatn-common.h:251:9: error: multiple types in one declaration
  251 | typedef double _Float64;
      |         ^~~~~~
/usr/include/bits/floatn-common.h:251:16: error: declaration does not declare anything [-fpermissive]
  251 | typedef double _Float64;
      |                ^~~~~~~~
This is from snippets like:
/* The remaining of this file provides support for older compilers.  */
# if __HAVE_FLOAT128

/* The type _Float128 exists only since GCC 7.0.  */
#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
typedef __float128 _Float128;
#  endif
where it hardcodes that C++ doesn't have _Float{16,32,64,128} support nor
{f,F}{16,32,64,128} literal suffixes nor _Complex _Float{16,32,64,128}.
The patch fixincludes this for now and hopefully if this is committed, then
glibc can change those.  Right now the patch changes those
#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
conditions to
#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
where it relies on __FLT32X_*__ macros no longer being predefined for C++.
Now, I guess for the fixincludes it could also use
#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
where earlier GCC 13 snapshots would not be doing the fixincludes,
but the question is what to use for upstream glibc, because
there will be 13.0 snapshots where C++ doesn't support _Float{16,32,64,128}
and where it is essential to use what glibc has been doing previously
and using the #else would fail miserably, and then 13.0 snapshots where it
does support it and where using the if would fail miserably.
One option is to use
#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1))
in glibc and rely on fixincludes for 13.0 snapshots (or of course later when
using 13.1+ with older glibc).
Another thing is mangling, as said above, Itanium C++ ABI specifies
DF <number> _ as _Float{16,32,64,128} mangling, but GCC was implementing
a mangling incompatible with that starting with DF for fixed point types.
Fixed point was never supported in C++ though, I believe the reason why
the mangling has been added was that due to a bug it would leak into the
C++ FE through decltype (0.0r) etc.  But that has been shortly after the
mangling was added fixed (I think in the same GCC release cycle), so we
now reject 0.0r etc. in C++.  If we ever need the fixed point mangling,
I think it can be readded but better with a different prefix so that it
doesn't conflict with the published standard manglings.  So, this patch
also kills the fixed point mangling and implements the DF <number> _
demangling.
The patch predefines __STDCPP_FLOAT{16,32,64,128}_T__ macros when
those types are available, but only for C++23, while the underlying types
are available in C++98 and later including the {f,F}{16,32,64,128} literal
suffixes (but those with a pedwarn for C++20 and earlier).  My understanding
is that it needs to be predefined by the compiler, on the other side
predefining even for older modes when <stdfloat> is a new C++23 header
would be weird.  One can find out if _Float{16,32,64,128} is supported in
C++ by
defined(__FLT{16,32,64,128}_MANT_DIG__) && !defined(__FLT32X_MANT_DIG__)
(unfortunately not just the former because GCC 7-12 predefined those too)
or perhaps __GNUC__ >= 13 && defined(__FLT{16,32,64,128}_MANT_DIG__)
(but that doesn't work well with older G++ 13 snapshots).

As for std::bfloat16_t, three targets (aarch64, arm and x86) apparently
"support" __bf16 type which has the bfloat16 format, but isn't really
usable, e.g. {aarch64,arm,ix86}_invalid_conversion disallow any conversions
from or to type with BFmode, {aarch64,arm,ix86}_invalid_unary_op disallows
any unary operations on those except for ADDR_EXPR and
{aarch64,arm,ix86}_invalid_binary_op disallows any binary operation on
those.  So, I think we satisfy:
"If the implementation supports an extended floating-point type with the
properties, as specified by ISO/IEC/IEEE 60559, of radix (b) of 2, storage
width in bits (k) of 16, precision in bits (p) of 8, maximum exponent (emax)
of 127, and exponent field width in bits (w) of 8, then the typedef-name
std::bfloat16_t is defined in the header <stdfloat> and names such a type,
the macro __STDCPP_BFLOAT16_T__ is defined, and the floating-point literal
suffixes bf16 and BF16 are supported."
because we don't really support those right now.
The question is (mainly for aarch64, arm and x86 backend maintainers) if we
shouldn't support it, in the PR there is a partial patch to do so, but
the big question is if it should be supported as the __bf16 type those
3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
and add conversions to/from at least SFmode but probably also DFmode, TFmode
and XFmode on x86 and implement arithmetics on those through conversion to
SFmode, performing arithmetics there and conversion back.
Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
implemented inline, SFmode -> BFmode conversion is harder,
I think it is roughly:
__bf16
__truncsfbf2 (_Float32 x)
{
  unsigned int y;
  memcpy (&y, &x, sizeof (y));
  unsigned int z = x & 0x7fffffff;
  unsigned short r;
  __bf16 ret;
  if (z < 0x800000)
    // Zero or denormal, flush to zero.
    r = (x & 0x80000000) >> 16;
  else if (z < 0x7f800000)
    // Normal, round to nearest.
    r = (x + 0x7fff + ((x >> 16) & 1)) >> 16;
  else if (z == 0x7f800000)
    // Inf.
    r = x >> 16;
  else
    // NaN.
    r = (x >> 16) | (1 << 6);
  memcpy (&ret, &r, sizeof (r));
  return ret;
}
(untested) and the question is if it should be implemented in libgcc
(and using soft-fp or not), or inline, or both depending on -Os.
Or there is the possibility to keep __bf16 a lame type one can't convert
to/from or perform most unary and all binary ops on it, and add for C++
a new type (say __bfloat16_t or whatever else), agree on mangling in
Itanium ABI and implement full support just for that type.

Bootstrapped/regtested on x86_64-linux and i686-linux and additionally
tested on some of the testcases on crosses to powerpc64le-linux (various
cases including -mabi=ieeelongdouble and -mabi=ibmlongdouble), aarch64-linux
and s390x-linux.

Ok for trunk?

2022-09-12  Jakub Jelinek  <jakub@redhat.com>

	PR c++/106652
gcc/
	* tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE
	enumerator.
	* tree.h (float128t_type_node): Define.
	* tree.cc (build_common_tree_nodes): Initialize float128t_type_node.
	* builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that
	_Float<N> is supported in C++ too.
	* config/i386/i386.cc (ix86_mangle_type): Only mangle as "g"
	float128t_type_node.
	* config/i386/i386-builtins.cc (ix86_init_builtin_types): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
	* config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph,
	_mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of
	0.0f.
	* config/ia64/ia64.cc (ia64_init_builtins): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
	* config/rs6000/rs6000-c.cc (is_float128_p): Also return true
	for float128t_type_node if non-NULL.
	* config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle
	float128_type_node as "u9__ieee128".
	* config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
gcc/c-family/
	* c-common.cc (c_common_reswords): Change _Float{16,32,64,128} flags
	from D_CONLY to 0.
	(shorten_binary_op): Punt if common_type returns error_mark_node.
	(shorten_compare): Likewise.
	(c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128}
	builtin types if available but not _Float{32,64,128}x.  For C++
	clear float128t_type_node.
	* c-cppbuiltin.cc (c_cpp_builtins): For C++ don't predefine
	__FLT{32,64,128}X_*__ macros, on the other side predefine
	__STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported.
	* c-common.h (CASE_RID_FLOATN): Define.
	(CASE_RID_FLOATN_NX): Use it.
	* c-lex.cc (interpret_float): For q/Q suffixes prefer
	float128t_type_node over float128_type_node.  Allow
	{f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn
	for C++20 and older.  Don't call excess_precision_type for C++.
gcc/cp/
	* cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement
	P1467R9 - Extended floating-point types and standard names except
	for std::bfloat16_t for now.  Declare.
	(extended_float_type_p): New inline function.
	* mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node
	as DF{16,32,64,128}_.  Remove FIXED_POINT_TYPE mangling that conflicts
	with that.
	* typeck2.cc (check_narrowing): If one of ftype or type is extended
	floating-point type, compare floating-point conversion ranks.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Handle
	CASE_RID_FLOATN.
	(cp_parser_simple_type_specifier): Likewise and diagnose missing
	_Float<N> support if not supported by target.
	* typeck.cc (cp_compare_floating_point_conversion_ranks): New function.
	(cp_common_type): If both types are REAL_TYPE and one or both are
	extended floating-point types, select common type based on comparison
	of floating-point conversion ranks and subranks.
	(cp_build_binary_op): Diagnose operation with floating point arguments
	with unordered conversion ranks.
	* call.cc (standard_conversion): For floating-point conversion, if
	either from or to are extended floating-point types reject implicit
	conversion from larger to smaller conversion rank or with unordered
	conversion ranks.
	(build_conditional_expr): Diagnose operation with floating point
	arguments with unordered conversion ranks.
	(convert_arg_to_ellipsis): Don't promote extended floating-point types
	narrower than double to double.
	(compare_ics): Implement P1467R9 [over.ics.rank]/4 changes.
gcc/testsuite/
	* g++.dg/cpp23/ext-floating1.C: New test.
	* g++.dg/cpp23/ext-floating2.C: New test.
	* g++.dg/cpp23/ext-floating3.C: New test.
	* g++.dg/cpp23/ext-floating4.C: New test.
	* g++.dg/cpp23/ext-floating5.C: New test.
	* g++.dg/cpp23/ext-floating6.C: New test.
	* g++.dg/cpp23/ext-floating7.C: New test.
	* g++.dg/cpp23/ext-floating8.C: New test.
	* g++.dg/cpp23/ext-floating9.C: New test.
	* g++.dg/cpp23/ext-floating10.C: New test.
	* g++.dg/cpp23/ext-floating.h: New file.
	* g++.target/i386/float16-1.C: Adjust expected diagnostics.
libcpp/
	* expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} suffixes
	for C++, but not {f,F}{32,64,128}x.
include/
	* demangle.h (enum demangle_component_type): Add
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
	(struct demangle_component): Add u.s_extended_builtin member.
libiberty/
	* cp-demangle.c (d_dump): Handle
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Don't handle
	DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_make_extended_builtin_type): New function.
	(cplus_demangle_builtin_types): Add _Float entry.
	(cplus_demangle_type): For DF demangle it as _Float<N> rather
	than fixed point which conflicts with it.
	(d_count_templates_scopes): Handle
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Just break; for
	DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
	Don't handle DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_print_comp_inner): Likewise.
	* cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump.
	* testsuite/demangle-expected: Replace _Z3xxxDFyuVb test
	with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb.
fixincludes/
	* inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2,
	glibc_cxx_floatn_3): New fixes.
	* tests/base/bits/floatn.h: New file.
	* fixincl.x: Regenerated.

--- gcc/tree-core.h.jj	2022-09-09 12:27:23.180736449 +0200
+++ gcc/tree-core.h	2022-09-09 18:46:07.257922609 +0200
@@ -690,6 +690,10 @@ enum tree_index {
 			     - TI_FLOATN_NX_TYPE_FIRST		\
 			     + 1)
 
+  /* Type used by certain backends for __float128, which in C++ should be
+     distinct type from _Float128 for backwards compatibility reasons.  */
+  TI_FLOAT128T_TYPE,
+
   /* Put the complex types after their component types, so that in (sequential)
      tree streaming we can assert that their component types have already been
      handled (see tree-streamer.cc:record_common_node).  */
--- gcc/tree.h.jj	2022-09-09 12:27:23.183736409 +0200
+++ gcc/tree.h	2022-09-09 18:46:07.258922596 +0200
@@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree ex
 #define float64x_type_node		global_trees[TI_FLOAT64X_TYPE]
 #define float128x_type_node		global_trees[TI_FLOAT128X_TYPE]
 
+/* Type used by certain backends for __float128, which in C++ should be
+   distinct type from _Float128 for backwards compatibility reasons.  */
+#define float128t_type_node		global_trees[TI_FLOAT128T_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]
--- gcc/tree.cc.jj	2022-09-09 18:44:27.153255900 +0200
+++ gcc/tree.cc	2022-09-09 18:46:07.260922569 +0200
@@ -9459,6 +9459,7 @@ build_common_tree_nodes (bool signed_cha
       layout_type (FLOATN_NX_TYPE_NODE (i));
       SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
     }
+  float128t_type_node = float128_type_node;
 
   float_ptr_type_node = build_pointer_type (float_type_node);
   double_ptr_type_node = build_pointer_type (double_type_node);
--- gcc/builtins.def.jj	2022-09-09 12:27:23.136737041 +0200
+++ gcc/builtins.def	2022-09-09 18:46:07.261922555 +0200
@@ -115,8 +115,8 @@ along with GCC; see the file COPYING3.
    we are compiling for the C language with GNU extensions, we enable the name
    without the __builtin_ prefix as well as the name with the __builtin_
    prefix.  C++ does not enable these names by default because they don't have
-   the _Float<N> and _Float<N>X keywords, and a class based library should use
-   the __builtin_ names.  */
+   the _Float<N>x keywords, and a class based library should use the __builtin_
+   names.  */
 #undef DEF_FLOATN_BUILTIN
 #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS)	\
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,	\
--- gcc/config/i386/i386.cc.jj	2022-09-09 12:27:23.141736974 +0200
+++ gcc/config/i386/i386.cc	2022-09-10 11:21:26.997205883 +0200
@@ -22711,7 +22711,10 @@ ix86_mangle_type (const_tree type)
       return "DF16_";
     case E_TFmode:
       /* __float128 is "g".  */
-      return "g";
+      if (type == float128t_type_node)
+	return "g";
+      /* _Float128 should mangle as "DF128_" done in generic code.  */
+      return NULL;
     case E_XFmode:
       /* "long double" or __float80 is "e".  */
       return "e";
--- gcc/config/i386/i386-builtins.cc.jj	2022-09-09 12:27:23.138737014 +0200
+++ gcc/config/i386/i386-builtins.cc	2022-09-09 18:46:07.264922515 +0200
@@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void)
   lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
 
   /* 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");
+     _Float128, so for C we only need to register the __float128 name for
+     it.  For C++, we create a distinct type which will mangle differently
+     (g) vs. _Float128 (DF128_) and behave backwards compatibly.  */
+  if (float128t_type_node == NULL_TREE)
+    {
+      float128t_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (float128t_type_node)
+	= TYPE_PRECISION (float128_type_node);
+      SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
+      layout_type (float128t_type_node);
+    }
+  lang_hooks.types.register_builtin_type (float128t_type_node, "__float128");
 
   ix86_register_float16_builtin_type ();
 
--- gcc/config/i386/avx512fp16intrin.h.jj	2022-01-11 22:31:40.696768297 +0100
+++ gcc/config/i386/avx512fp16intrin.h	2022-09-11 23:23:28.617437158 +0200
@@ -183,21 +183,21 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_setzero_ph (void)
 {
-  return _mm_set1_ph (0.0f);
+  return _mm_set1_ph (0.0f16);
 }
 
 extern __inline __m256h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm256_setzero_ph (void)
 {
-  return _mm256_set1_ph (0.0f);
+  return _mm256_set1_ph (0.0f16);
 }
 
 extern __inline __m512h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm512_setzero_ph (void)
 {
-  return _mm512_set1_ph (0.0f);
+  return _mm512_set1_ph (0.0f16);
 }
 
 extern __inline __m128h
@@ -358,7 +358,8 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_set_sh (_Float16 __F)
 {
-  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F);
+  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
+		     __F);
 }
 
 /* Create a vector with element 0 as *P and the rest zero.  */
@@ -366,7 +367,7 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_load_sh (void const *__P)
 {
-  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
 		     *(_Float16 const *) __P);
 }
 
--- gcc/config/ia64/ia64.cc.jj	2022-09-09 12:27:23.143736947 +0200
+++ gcc/config/ia64/ia64.cc	2022-09-09 18:46:07.265922502 +0200
@@ -10466,11 +10466,19 @@ ia64_init_builtins (void)
 	= build_pointer_type (build_qualified_type
 			      (char_type_node, TYPE_QUAL_CONST));
 
-      (*lang_hooks.types.register_builtin_type) (float128_type_node,
+      if (float128t_type_node == NULL_TREE)
+	{
+	  float128t_type_node = make_node (REAL_TYPE);
+	  TYPE_PRECISION (float128t_type_node)
+	    = TYPE_PRECISION (float128_type_node);
+	  layout_type (float128t_type_node);
+	  SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
+	}
+      (*lang_hooks.types.register_builtin_type) (float128t_type_node,
 						 "__float128");
 
       /* TFmode support builtins.  */
-      ftype = build_function_type_list (float128_type_node, NULL_TREE);
+      ftype = build_function_type_list (float128t_type_node, NULL_TREE);
       decl = add_builtin_function ("__builtin_infq", ftype,
 				   IA64_BUILTIN_INFQ, BUILT_IN_MD,
 				   NULL, NULL_TREE);
@@ -10481,7 +10489,7 @@ ia64_init_builtins (void)
 				   NULL, NULL_TREE);
       ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
 					const_string_type,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_nanq", ftype,
@@ -10496,8 +10504,8 @@ ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
-					float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
+					float128t_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_fabsq", ftype,
 				   IA64_BUILTIN_FABSQ, BUILT_IN_MD,
@@ -10505,9 +10513,9 @@ ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
-					float128_type_node,
-					float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
+					float128t_type_node,
+					float128t_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_copysignq", ftype,
 				   IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
--- gcc/config/rs6000/rs6000-c.cc.jj	2022-09-09 12:27:23.144736933 +0200
+++ gcc/config/rs6000/rs6000-c.cc	2022-09-10 11:21:53.958838545 +0200
@@ -808,6 +808,7 @@ static inline bool
 is_float128_p (tree t)
 {
   return (t == float128_type_node
+	  || (t && t == float128t_type_node)
 	  || (TARGET_IEEEQUAD
 	      && TARGET_LONG_DOUBLE_128
 	      && t == long_double_type_node));
--- gcc/config/rs6000/rs6000.cc.jj	2022-09-09 12:27:23.147736893 +0200
+++ gcc/config/rs6000/rs6000.cc	2022-09-09 18:46:07.269922448 +0200
@@ -20118,7 +20118,11 @@ rs6000_mangle_type (const_tree type)
 
   if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type)))
     return "g";
-  if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type)))
+  if (SCALAR_FLOAT_TYPE_P (type)
+      && FLOAT128_IEEE_P (TYPE_MODE (type))
+      /* _Float128 should mangle as DF128_ (done in generic code)
+	 rather than u9__ieee128 (used for __ieee128 and __float128).  */
+      && type != float128_type_node)
     return "u9__ieee128";
 
   if (type == vector_pair_type_node)
--- gcc/config/rs6000/rs6000-builtin.cc.jj	2022-09-09 12:27:23.143736947 +0200
+++ gcc/config/rs6000/rs6000-builtin.cc	2022-09-09 18:46:07.270922435 +0200
@@ -733,7 +733,22 @@ rs6000_init_builtins (void)
       if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
 	ieee128_float_type_node = long_double_type_node;
       else
-	ieee128_float_type_node = float128_type_node;
+	{
+	  /* For C we only need to register the __ieee128 name for
+	     it.  For C++, we create a distinct type which will mangle
+	     differently (u9__ieee128) vs. _Float128 (DF128_) and behave
+	     backwards compatibly.  */
+	  if (float128t_type_node == NULL_TREE)
+	    {
+	      float128t_type_node = make_node (REAL_TYPE);
+	      TYPE_PRECISION (float128t_type_node)
+		= TYPE_PRECISION (float128_type_node);
+	      layout_type (float128t_type_node);
+	      SET_TYPE_MODE (float128t_type_node,
+			     TYPE_MODE (float128_type_node));
+	    }
+	  ieee128_float_type_node = float128t_type_node;
+	}
       t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
       lang_hooks.types.register_builtin_type (ieee128_float_type_node,
 					      "__ieee128");
--- gcc/c-family/c-common.cc.jj	2022-09-09 12:27:23.137737028 +0200
+++ gcc/c-family/c-common.cc	2022-09-09 19:43:50.730802597 +0200
@@ -352,10 +352,10 @@ const struct c_common_resword c_common_r
   { "_Bool",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	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 },
+  { "_Float16",         RID_FLOAT16,    0 },
+  { "_Float32",         RID_FLOAT32,    0 },
+  { "_Float64",         RID_FLOAT64,    0 },
+  { "_Float128",        RID_FLOAT128,   0 },
   { "_Float32x",        RID_FLOAT32X,  D_CONLY },
   { "_Float64x",        RID_FLOAT64X,  D_CONLY },
   { "_Float128x",       RID_FLOAT128X, D_CONLY },
@@ -1429,8 +1429,11 @@ shorten_binary_op (tree result_type, tre
 	  == TYPE_PRECISION (TREE_TYPE (arg0)))
       && unsigned0 == unsigned1
       && (unsigned0 || !uns))
-    return c_common_signed_or_unsigned_type
-      (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+    {
+      tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
+      if (ctype != error_mark_node)
+	return c_common_signed_or_unsigned_type (unsigned0, ctype);
+    }
 
   else if (TREE_CODE (arg0) == INTEGER_CST
 	   && (unsigned1 || !uns)
@@ -3202,9 +3205,10 @@ shorten_compare (location_t loc, tree *o
 
   else if (unsignedp0 == unsignedp1 && real1 == real2
 	   && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
-	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
+	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)
+	   && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)))
+	      != error_mark_node)
     {
-      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
       type = c_common_signed_or_unsigned_type (unsignedp0
 					       || TYPE_UNSIGNED (*restype_ptr),
 					       type);
@@ -4378,11 +4382,21 @@ 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++)
+  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));
+      /* Don't register _FloatNX types for C++, just _FloatN.  */
+      if (i == NUM_FLOATN_TYPES && c_dialect_cxx ())
+	break;
+    }
+
+  /* For C, let float128t_type_node (__float128 in some backends) be the
+     same type as float128_type_node (_Float128), for C++ let those
+     be distinct types that mangle and behave differently.  */
+  if (c_dialect_cxx ())
+    float128t_type_node = NULL_TREE;
 
   /* Only supported decimal floating point extension if the target
      actually supports underlying modes. */
--- gcc/c-family/c-cppbuiltin.cc.jj	2022-09-09 12:27:23.138737014 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2022-09-09 18:46:07.271922421 +0200
@@ -1246,6 +1246,14 @@ c_cpp_builtins (cpp_reader *pfile)
     {
       if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
 	continue;
+      if (floatn_nx_types[i].extended && c_dialect_cxx ())
+	continue;
+      if (c_dialect_cxx () && cxx_dialect > cxx20)
+	{
+	  char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
+	  sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
+	  cpp_define (pfile, name);
+	}
       char prefix[20], csuffix[20];
       sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
 	       floatn_nx_types[i].extended ? "X" : "");
--- gcc/c-family/c-common.h.jj	2022-09-09 12:27:23.137737028 +0200
+++ gcc/c-family/c-common.h	2022-09-09 18:46:07.271922421 +0200
@@ -120,8 +120,10 @@ enum rid
   RID_FLOAT32X,
   RID_FLOAT64X,
   RID_FLOAT128X,
+#define CASE_RID_FLOATN							\
+  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128
 #define CASE_RID_FLOATN_NX						\
-  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128: \
+  CASE_RID_FLOATN:							\
   case RID_FLOAT32X: case RID_FLOAT64X: case RID_FLOAT128X
 
   RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
--- gcc/c-family/c-lex.cc.jj	2022-09-09 12:27:23.138737014 +0200
+++ gcc/c-family/c-lex.cc	2022-09-09 18:46:07.271922421 +0200
@@ -960,6 +960,10 @@ interpret_float (const cpp_token *token,
 	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
 
 	type = c_common_type_for_mode (mode, 0);
+	/* For Q suffix, prefer float128t_type_node (__float128) type
+	   over float128_type_node (_Float128) type if they are distinct.  */
+	if (type == float128_type_node && float128t_type_node)
+	  type = float128t_type_node;
 	gcc_assert (type);
       }
     else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
@@ -979,8 +983,17 @@ interpret_float (const cpp_token *token,
 	    error ("unsupported non-standard suffix on floating constant");
 	    return error_mark_node;
 	  }
+	else if (c_dialect_cxx ())
+	  {
+	    if (cxx_dialect < cxx23)
+	      pedwarn (input_location, OPT_Wpedantic,
+		       "%<f%d%> or %<F%d%> suffix on floating constant only "
+		       "available with %<-std=c++2b%> or %<-std=gnu++2b%>",
+		       n, n);
+	  }
 	else
-	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
+	  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;
@@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token,
     else
       type = double_type_node;
 
-  const_type = excess_precision_type (type);
+  if (c_dialect_cxx ())
+    const_type = NULL_TREE;
+  else
+    const_type = excess_precision_type (type);
   if (!const_type)
     const_type = type;
 
--- gcc/cp/cp-tree.h.jj	2022-09-09 12:27:23.170736583 +0200
+++ gcc/cp/cp-tree.h	2022-09-10 11:22:11.612598030 +0200
@@ -7942,6 +7942,7 @@ extern tree require_complete_type_sfinae
 extern tree complete_type			(tree);
 extern tree complete_type_or_else		(tree, tree);
 extern tree complete_type_or_maybe_complain	(tree, tree, tsubst_flags_t);
+extern int cp_compare_floating_point_conversion_ranks (tree, tree);
 inline bool type_unknown_p			(const_tree);
 enum { ce_derived, ce_type, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
@@ -8682,6 +8683,18 @@ struct push_access_scope_guard
   }
 };
 
+/* True if TYPE is an extended floating-point type.  */
+
+inline bool
+extended_float_type_p (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  for (int i = 0; i < NUM_FLOATN_TYPES; ++i)
+    if (type == FLOATN_TYPE_NODE (i))
+      return true;
+  return false;
+}
+
 #if CHECKING_P
 namespace selftest {
   extern void run_cp_tests (void);
--- gcc/cp/mangle.cc.jj	2022-09-09 12:27:23.171736570 +0200
+++ gcc/cp/mangle.cc	2022-09-09 18:46:07.273922394 +0200
@@ -2648,63 +2648,18 @@ write_builtin_type (tree type)
 	write_string ("Dd");
       else if (type == dfloat128_type_node || type == fallback_dfloat128_type)
 	write_string ("De");
+      else if (type == float16_type_node)
+	write_string ("DF16_");
+      else if (type == float32_type_node)
+	write_string ("DF32_");
+      else if (type == float64_type_node)
+	write_string ("DF64_");
+      else if (type == float128_type_node)
+	write_string ("DF128_");
       else
 	gcc_unreachable ();
       break;
 
-    case FIXED_POINT_TYPE:
-      write_string ("DF");
-      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
-	write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
-      if (type == fract_type_node
-	  || type == sat_fract_type_node
-	  || type == accum_type_node
-	  || type == sat_accum_type_node)
-	write_char ('i');
-      else if (type == unsigned_fract_type_node
-	       || type == sat_unsigned_fract_type_node
-	       || type == unsigned_accum_type_node
-	       || type == sat_unsigned_accum_type_node)
-	write_char ('j');
-      else if (type == short_fract_type_node
-	       || type == sat_short_fract_type_node
-	       || type == short_accum_type_node
-	       || type == sat_short_accum_type_node)
-	write_char ('s');
-      else if (type == unsigned_short_fract_type_node
-	       || type == sat_unsigned_short_fract_type_node
-	       || type == unsigned_short_accum_type_node
-	       || type == sat_unsigned_short_accum_type_node)
-	write_char ('t');
-      else if (type == long_fract_type_node
-	       || type == sat_long_fract_type_node
-	       || type == long_accum_type_node
-	       || type == sat_long_accum_type_node)
-	write_char ('l');
-      else if (type == unsigned_long_fract_type_node
-	       || type == sat_unsigned_long_fract_type_node
-	       || type == unsigned_long_accum_type_node
-	       || type == sat_unsigned_long_accum_type_node)
-	write_char ('m');
-      else if (type == long_long_fract_type_node
-	       || type == sat_long_long_fract_type_node
-	       || type == long_long_accum_type_node
-	       || type == sat_long_long_accum_type_node)
-	write_char ('x');
-      else if (type == unsigned_long_long_fract_type_node
-	       || type == sat_unsigned_long_long_fract_type_node
-	       || type == unsigned_long_long_accum_type_node
-	       || type == sat_unsigned_long_long_accum_type_node)
-	write_char ('y');
-      else
-	sorry ("mangling unknown fixed point type");
-      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
-      if (TYPE_SATURATING (type))
-	write_char ('s');
-      else
-	write_char ('n');
-      break;
-
     default:
       gcc_unreachable ();
     }
--- gcc/cp/typeck2.cc.jj	2022-09-09 12:27:23.179736463 +0200
+++ gcc/cp/typeck2.cc	2022-09-09 18:46:07.273922394 +0200
@@ -1010,12 +1010,25 @@ check_narrowing (tree type, tree init, t
   else if (TREE_CODE (ftype) == REAL_TYPE
 	   && TREE_CODE (type) == REAL_TYPE)
     {
-      if ((same_type_p (ftype, long_double_type_node)
-	   && (same_type_p (type, double_type_node)
-	       || same_type_p (type, float_type_node)))
-	  || (same_type_p (ftype, double_type_node)
-	      && same_type_p (type, float_type_node))
-	  || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
+      if ((extended_float_type_p (ftype) || extended_float_type_p (type))
+	  ? /* "from a floating-point type T to another floating-point type
+	       whose floating-point conversion rank is neither greater than
+	       nor equal to that of T".
+	       So, it is ok if
+	       cp_compare_floating_point_conversion_ranks (ftype, type)
+	       returns -2 (type has greater conversion rank than ftype)
+	       or [-1..1] (type has equal conversion rank as ftype, possibly
+	       different subrank.  Only do this if at least one of the
+	       types is extended floating-point type, otherwise keep doing
+	       what we did before (for the sake of non-standard
+	       backend types).  */
+	    cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
+	  : ((same_type_p (ftype, long_double_type_node)
+	      && (same_type_p (type, double_type_node)
+		  || same_type_p (type, float_type_node)))
+	     || (same_type_p (ftype, double_type_node)
+		 && same_type_p (type, float_type_node))
+	     || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
 	{
 	  if (TREE_CODE (init) == REAL_CST)
 	    {
--- gcc/cp/parser.cc.jj	2022-09-09 12:27:23.177736489 +0200
+++ gcc/cp/parser.cc	2022-09-09 18:46:07.278922327 +0200
@@ -1129,6 +1129,7 @@ cp_keyword_starts_decl_specifier_p (enum
     case RID_UNSIGNED:
     case RID_FLOAT:
     case RID_DOUBLE:
+    CASE_RID_FLOATN:
     case RID_VOID:
       /* CV qualifiers.  */
     case RID_CONST:
@@ -19706,6 +19707,12 @@ cp_parser_simple_type_specifier (cp_pars
     case RID_DOUBLE:
       type = double_type_node;
       break;
+    CASE_RID_FLOATN:
+      type = FLOATN_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST);
+      if (type == NULL_TREE)
+	error ("%<_Float%d%> is not supported on this target",
+	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n);
+      break;
     case RID_VOID:
       type = void_type_node;
       break;
--- gcc/cp/typeck.cc.jj	2022-09-09 12:27:23.179736463 +0200
+++ gcc/cp/typeck.cc	2022-09-09 19:54:17.360423639 +0200
@@ -272,6 +272,116 @@ merge_type_attributes_from (tree type, t
   return cp_build_type_attribute_variant (type, attrs);
 }
 
+/* Compare floating point conversion ranks and subranks of T1 and T2
+   types.  If T1 and T2 have unordered conversion ranks, return 3.
+   If T1 has greater conversion rank than T2, return 2.
+   If T2 has greater conversion rank than T1, return -2.
+   If T1 has equal conversion rank as T2, return -1, 0 or 1 depending
+   on if T1 has smaller, equal or greater conversion subrank than
+   T2.  */
+
+int
+cp_compare_floating_point_conversion_ranks (tree t1, tree t2)
+{
+  tree mv1 = TYPE_MAIN_VARIANT (t1);
+  tree mv2 = TYPE_MAIN_VARIANT (t2);
+  bool extended1 = false;
+  bool extended2 = false;
+
+  if (mv1 == mv2)
+    return 0;
+
+  for (int i = 0; i < NUM_FLOATN_TYPES; ++i)
+    {
+      if (mv1 == FLOATN_TYPE_NODE (i))
+	extended1 = true;
+      if (mv2 == FLOATN_TYPE_NODE (i))
+	extended2 = true;
+    }
+  if (extended2 && !extended1)
+    {
+      int ret = cp_compare_floating_point_conversion_ranks (t2, t1);
+      return ret == 3 ? 3 : -ret;
+    }
+
+  const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
+  const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
+  gcc_assert (fmt1->b == 2 && fmt2->b == 2);
+  /* For {ibm,mips}_extended_format formats, the type has variable
+     precision up to ~2150 bits when the first double is around maximum
+     representable double and second double is subnormal minimum.
+     So, e.g. for __ibm128 vs. std::float128_t, they have unordered
+     ranks.  */
+  int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1))
+	    ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p);
+  int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2))
+	    ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p);
+  /* The rank of a floating point type T is greater than the rank of
+     any floating-point type whose set of values is a proper subset
+     of the set of values of T.  */
+  if ((p1 > p2 && fmt1->emax >= fmt2->emax)
+       || (p1 == p2 && fmt1->emax > fmt2->emax))
+    return 2;
+  if ((p1 < p2 && fmt1->emax <= fmt2->emax)
+       || (p1 == p2 && fmt1->emax < fmt2->emax))
+    return -2;
+  if ((p1 > p2 && fmt1->emax < fmt2->emax)
+       || (p1 < p2 && fmt1->emax > fmt2->emax))
+    return 3;
+  if (!extended1 && !extended2)
+    {
+      /* The rank of long double is greater than the rank of double, which
+	 is greater than the rank of float.  */
+      if (t1 == long_double_type_node)
+	return 2;
+      else if (t2 == long_double_type_node)
+	return -2;
+      if (t1 == double_type_node)
+	return 2;
+      else if (t2 == double_type_node)
+	return -2;
+      if (t1 == float_type_node)
+	return 2;
+      else if (t2 == float_type_node)
+	return -2;
+      return 0;
+    }
+  /* Two extended floating-point types with the same set of values have equal
+     ranks.  */
+  if (extended1 && extended2)
+    /* We shouldn't have multiple different extended floating-point types
+       with the same set of values.  */
+    gcc_unreachable ();
+
+  tree *p;
+  int cnt = 0;
+  for (p = &float_type_node; p <= &long_double_type_node; ++p)
+    {
+      const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p));
+      gcc_assert (fmt3->b == 2);
+      int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p))
+		? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p);
+      if (p1 == p3 && fmt1->emax == fmt3->emax)
+	++cnt;
+    }
+  /* An extended floating-point type with the same set of values
+     as exactly one cv-unqualified standard floating-point type
+     has a rank equal to the rank of that standard floating-point
+     type.
+
+     An extended floating-point type with the same set of values
+     as more than one cv-unqualified standard floating-point type
+     has a rank equal to the rank of double.
+
+     Thus, if the latter is true and t2 is long double, t2
+     has higher rank.  */
+  if (cnt > 1 && mv2 == long_double_type_node)
+    return -2;
+  /* Otherwise, they have equal rank, but extended types
+     (other than std::bfloat16_t) have higher subrank.  */
+  return 1;
+}
+
 /* Return the common type for two arithmetic types T1 and T2 under the
    usual arithmetic conversions.  The default conversions have already
    been applied, and enumerated types converted to their compatible
@@ -342,6 +452,23 @@ cp_common_type (tree t1, tree t2)
   if (code2 == REAL_TYPE && code1 != REAL_TYPE)
     return build_type_attribute_variant (t2, attributes);
 
+  if (code1 == REAL_TYPE
+      && (extended_float_type_p (t1) || extended_float_type_p (t2)))
+    {
+      tree mv1 = TYPE_MAIN_VARIANT (t1);
+      tree mv2 = TYPE_MAIN_VARIANT (t2);
+      if (mv1 == mv2)
+	return build_type_attribute_variant (t1, attributes);
+
+      int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2);
+      if (cmpret == 3)
+	return error_mark_node;
+      else if (cmpret >= 0)
+	return build_type_attribute_variant (t1, attributes);
+      else
+	return build_type_attribute_variant (t2, attributes);
+    }
+
   /* Both real or both integers; use the one with greater precision.  */
   if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
     return build_type_attribute_variant (t1, attributes);
@@ -5041,7 +5168,20 @@ cp_build_binary_op (const op_location_t
        = targetm.invalid_binary_op (code, type0, type1)))
     {
       if (complain & tf_error)
-	error (invalid_op_diag);
+	{
+	  if (code0 == REAL_TYPE
+	      && code1 == REAL_TYPE
+	      && (extended_float_type_p (type0)
+		  || extended_float_type_p (type1))
+	      && cp_compare_floating_point_conversion_ranks (type0,
+							     type1) == 3)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  else
+	    error (invalid_op_diag);
+	}
       return error_mark_node;
     }
 
@@ -5911,6 +6051,19 @@ cp_build_binary_op (const op_location_t
       && (shorten || common || short_compare))
     {
       result_type = cp_common_type (type0, type1);
+      if (result_type == error_mark_node
+	  && code0 == REAL_TYPE
+	  && code1 == REAL_TYPE
+	  && (extended_float_type_p (type0) || extended_float_type_p (type1))
+	  && cp_compare_floating_point_conversion_ranks (type0, type1) == 3)
+	{
+	  if (complain & tf_error)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  return error_mark_node;
+	}
       if (complain & tf_warning)
 	{
 	  do_warn_double_promotion (result_type, type0, type1,
--- gcc/cp/call.cc.jj	2022-09-09 12:27:23.169736597 +0200
+++ gcc/cp/call.cc	2022-09-10 11:14:41.361732371 +0200
@@ -1519,6 +1519,22 @@ standard_conversion (tree to, tree from,
           || SCOPED_ENUM_P (from))
 	return NULL;
 
+      /* A prvalue of floating-point type can be converted to a prvalue of
+	 another floating-point type with a greater or equal conversion
+	 rank ([conv.rank]).  A prvalue of standard floating-point type can
+	 be converted to a prvalue of another standard floating-point type.
+	 For backwards compatibility with handling __float128 and other
+	 non-standard floating point types, allow all implicit floating
+	 point conversions if neither type is extended floating-point
+	 type and if at least one of them is, fail if they have unordered
+	 conversion rank or from has higher conversion rank.  */
+      if (fcode == REAL_TYPE
+	  && tcode == REAL_TYPE
+	  && (extended_float_type_p (from)
+	      || extended_float_type_p (to))
+	  && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
+	return NULL;
+
       /* If we're parsing an enum with no fixed underlying type, we're
 	 dealing with an incomplete type, which renders the conversion
 	 ill-formed.  */
@@ -5842,6 +5858,21 @@ build_conditional_expr (const op_locatio
       /* In this case, there is always a common type.  */
       result_type = type_after_usual_arithmetic_conversions (arg2_type,
 							     arg3_type);
+      if (result_type == error_mark_node
+	  && TREE_CODE (arg2_type) == REAL_TYPE
+	  && TREE_CODE (arg3_type) == REAL_TYPE
+	  && (extended_float_type_p (arg2_type)
+	      || extended_float_type_p (arg3_type))
+	  && cp_compare_floating_point_conversion_ranks (arg2_type,
+							 arg3_type) == 3)
+	{
+	  if (complain & tf_error)
+	    error_at (loc, "operands to %<?:%> have unordered conversion rank "
+			   "of types %qT and %qT",
+		      arg2_type, arg3_type);
+	  return error_mark_node;
+	}
+
       if (complain & tf_warning)
 	do_warn_double_promotion (result_type, arg2_type, arg3_type,
 				  "implicit conversion from %qH to %qI to "
@@ -8531,7 +8562,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
   if (TREE_CODE (arg_type) == REAL_TYPE
       && (TYPE_PRECISION (arg_type)
 	  < TYPE_PRECISION (double_type_node))
-      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
+      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))
+      && !extended_float_type_p (arg_type))
     {
       if ((complain & tf_warning)
 	  && warn_double_promotion && !c_inhibit_evaluation_warnings)
@@ -11719,6 +11751,75 @@ compare_ics (conversion *ics1, conversio
 	return 1;
     }
 
+  {
+    /* A conversion in either direction between floating-point type FP1 and
+       floating-point type FP2 is better than a conversion in the same
+       direction between FP1 and arithmetic type T3 if
+       - the floating-point conversion rank of FP1 is equal to the rank of
+	 FP2, and
+       - T3 is not a floating-point type, or T3 is a floating-point type
+	 whose rank is not equal to the rank of FP1, or the floating-point
+	 conversion subrank of FP2 is greater than the subrank of T3.  */
+    tree fp1 = from_type1;
+    tree fp2 = to_type1;
+    tree fp3 = from_type2;
+    tree t3 = to_type2;
+    int ret = 1;
+    if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3))
+      {
+	std::swap (fp1, fp2);
+	std::swap (fp3, t3);
+      }
+    if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3)
+	&& TREE_CODE (fp1) == REAL_TYPE
+	/* Only apply this rule if at least one of the 3 types is
+	   extended floating-point type, otherwise keep them as
+	   before for compatibility reasons with types like __float128.
+	   float, double and long double alone have different conversion
+	   ranks and so when just those 3 types are involved, this
+	   rule doesn't trigger.  */
+	&& (extended_float_type_p (fp1)
+	    || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2))
+	    || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3))))
+      {
+	if (TREE_CODE (fp2) != REAL_TYPE)
+	  {
+	    ret = -ret;
+	    std::swap (fp2, t3);
+	  }
+	if (TREE_CODE (fp2) == REAL_TYPE)
+	  {
+	    if (cp_compare_floating_point_conversion_ranks (fp1, fp2) + 1U
+		<= 2U)
+	      {
+		/* Conversion ranks of FP1 and FP2 are equal.  */
+		if (TREE_CODE (t3) != REAL_TYPE
+		    || (cp_compare_floating_point_conversion_ranks (fp1, t3)
+			+ 1U > 2U))
+		  /* FP1 <-> FP2 conversion is better.  */
+		  return ret;
+		int c = cp_compare_floating_point_conversion_ranks (fp2, t3);
+		gcc_assert (c + 1U <= 2U);
+		if (c == 1)
+		  /* Conversion subrank of FP2 is greater than subrank of T3.
+		     FP1 <-> FP2 conversion is better.  */
+		  return ret;
+		else if (c == -1)
+		  /* Conversion subrank of FP2 is less than subrank of T3.
+		     FP1 <-> T3 conversion is better.  */
+		  return -ret;
+	      }
+	    else if (TREE_CODE (t3) == REAL_TYPE
+		     && (cp_compare_floating_point_conversion_ranks (fp1, t3)
+			 + 1U <= 2U))
+	      /* Conversion ranks of FP1 and FP2 are not equal, conversion
+		 ranks of FP1 and T3 are equal.
+		 FP1 <-> T3 conversion is better.  */
+	      return -ret;
+	  }
+      }
+  }
+
   if (TYPE_PTR_P (from_type1)
       && TYPE_PTR_P (from_type2)
       && TYPE_PTR_P (to_type1)
--- gcc/testsuite/g++.dg/cpp23/ext-floating1.C.jj	2022-09-09 18:46:07.281922287 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C	2022-09-09 18:46:07.281922287 +0200
@@ -0,0 +1,248 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+static_assert (!is_same<float, double>::value);
+static_assert (!is_same<float, long double>::value);
+static_assert (!is_same<double, long double>::value);
+static_assert (is_same<decltype (0.0f), float>::value);
+static_assert (is_same<decltype (0.0F), float>::value);
+static_assert (is_same<decltype (0.0), double>::value);
+static_assert (is_same<decltype (0.0l), long double>::value);
+static_assert (is_same<decltype (0.0L), long double>::value);
+static_assert (is_same<decltype (0.0f + 0.0F), float>::value);
+static_assert (is_same<decltype (0.0F + 0.0f), float>::value);
+static_assert (is_same<decltype (0.0 + 0.0), double>::value);
+static_assert (is_same<decltype (0.0l + 0.0L), long double>::value);
+static_assert (is_same<decltype (0.0L + 0.0l), long double>::value);
+#ifdef __SIZEOF_FLOAT128__
+static_assert (is_same<decltype (0.0q), __float128>::value);
+static_assert (is_same<decltype (0.0Q), __float128>::value);
+static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value);
+static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float, float16_t>::value);
+static_assert (!is_same<double, float16_t>::value);
+static_assert (!is_same<long double, float16_t>::value);
+static_assert (is_same<decltype (0.0f16), float16_t>::value);
+static_assert (is_same<decltype (0.0F16), float16_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float, float32_t>::value);
+static_assert (!is_same<double, float32_t>::value);
+static_assert (!is_same<long double, float32_t>::value);
+static_assert (!is_same<decltype (0.0f), float32_t>::value);
+static_assert (!is_same<decltype (0.0F), float32_t>::value);
+static_assert (is_same<decltype (0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32), float32_t>::value);
+static_assert (!is_same<decltype (0.0f32), float>::value);
+static_assert (!is_same<decltype (0.0F32), float>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float, float64_t>::value);
+static_assert (!is_same<double, float64_t>::value);
+static_assert (!is_same<long double, float64_t>::value);
+static_assert (!is_same<decltype (0.0), float64_t>::value);
+static_assert (is_same<decltype (0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64), float64_t>::value);
+static_assert (!is_same<decltype (0.0f64), double>::value);
+static_assert (!is_same<decltype (0.0F64), double>::value);
+static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float, float128_t>::value);
+static_assert (!is_same<double, float128_t>::value);
+static_assert (!is_same<long double, float128_t>::value);
+static_assert (!is_same<decltype (0.0l), float128_t>::value);
+static_assert (!is_same<decltype (0.0L), float128_t>::value);
+static_assert (is_same<decltype (0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128), float128_t>::value);
+static_assert (!is_same<decltype (0.0f128), long double>::value);
+static_assert (!is_same<decltype (0.0F128), long double>::value);
+static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value);
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<float128_t, __float128>::value);
+static_assert (!is_same<decltype (0.0q), float128_t>::value);
+static_assert (!is_same<decltype (0.0Q), float128_t>::value);
+static_assert (!is_same<decltype (0.0f128), __float128>::value);
+static_assert (!is_same<decltype (0.0F128), __float128>::value);
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+static_assert (!is_same<float, bfloat16_t>::value);
+static_assert (!is_same<double, bfloat16_t>::value);
+static_assert (!is_same<long double, bfloat16_t>::value);
+static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value);
+#endif
+static_assert (is_same<decltype (0.0f + 0.0), double>::value);
+static_assert (is_same<decltype (0.0 + 0.0F), double>::value);
+static_assert (is_same<decltype (0.0L + 0.0), long double>::value);
+static_assert (is_same<decltype (0.0 + 0.0L), long double>::value);
+static_assert (is_same<decltype (0.0L + 0.0f), long double>::value);
+static_assert (is_same<decltype (0.0F + 0.0l), long double>::value);
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
+static_assert (!is_same<float16_t, float32_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<float16_t, float64_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float16_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<float32_t, float64_t>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float32_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float64_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
+static_assert (!is_same<bfloat16_t, float32_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<bfloat16_t, float64_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<bfloat16_t, float128_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f16), float>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value);
+#endif
+#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f16), double>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value);
+#endif
+#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f32), double>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value);
+#endif
+#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
+#endif
+#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \
+    && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
+// An extended floating-point type with the same set of values as more than one
+// cv-unqualified standard floating-point type has a rank equal to the rank of
+// double.
+// Then long double will have higher rank than float64_t.
+static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value);
+#endif
+#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value);
+#endif
+#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \
+    && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered.
+static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value);
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value);
+#endif
+#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value);
+#endif
+#endif
+
+void foo (float) {}
+void foo (double) {}
+void foo (long double) {}
+#ifdef __STDCPP_FLOAT16_T__
+void foo (float16_t) {}
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+void foo (float32_t) {}
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+void foo (float64_t) {}
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+void foo (float128_t) {}
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+void foo (bfloat16_t) {}
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating2.C.jj	2022-09-09 18:46:07.281922287 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating2.C	2022-09-09 18:46:07.281922287 +0200
@@ -0,0 +1,157 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+float fa = 1.0f;
+float fb = (float) 1.0f;
+float fc = 1.0;
+float fd = (float) 1.0;
+float fe = 1.0L;
+float ff = (float) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float fg = 1.0Q;
+float fh = (float) 1.0Q;
+#endif
+double da = 1.0f;
+double db = (double) 1.0f;
+double dc = 1.0;
+double dd = (double) 1.0;
+double de = 1.0L;
+double df = (double) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+double dg = 1.0Q;
+double dh = (double) 1.0Q;
+#endif
+long double lda = 1.0f;
+long double ldb = (long double) 1.0f;
+long double ldc = 1.0;
+long double ldd = (long double) 1.0;
+long double lde = 1.0L;
+long double ldf = (long double) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+long double ldg = 1.0Q;
+long double ldh = (long double) 1.0Q;
+__float128 qa = 1.0f;
+__float128 qb = (__float128) 1.0f;
+__float128 qc = 1.0;
+__float128 qd = (__float128) 1.0;
+__float128 qe = 1.0L;
+__float128 qf = (__float128) 1.0L;
+__float128 qg = 1.0Q;
+__float128 qh = (__float128) 1.0Q;
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16a = 1.0F16;
+float16_t f16b = (float16_t) 1.0F16;
+#ifdef __STDCPP_FLOAT32_T__
+float16_t f16c = 1.0F32;		// { dg-error "cannot convert '_Float32' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float32 } } }
+float16_t f16d = (float16_t) 1.0F32;
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float16_t f16e = 1.0F64;		// { dg-error "cannot convert '_Float64' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float64 } } }
+float16_t f16f = (float16_t) 1.0F64;
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float16_t f16g = 1.0F128;		// { dg-error "cannot convert '_Float128' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float128 } } }
+float16_t f16h = (float16_t) 1.0F128;
+#endif
+float16_t f16j = (float16_t) 1.0f;
+float16_t f16l = (float16_t) 1.0;
+float16_t f16n = (float16_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float16_t f16p = (float16_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+#ifdef __STDCPP_FLOAT16_T__
+float32_t f32a = 1.0F16;
+float32_t f32b = (float32_t) 1.0F16;
+#endif
+float32_t f32c = 1.0F32;
+float32_t f32d = (float32_t) 1.0F32;
+#ifdef __STDCPP_FLOAT64_T__
+float32_t f32e = 1.0F64;		// { dg-error "cannot convert '_Float64' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" "" { target { float32 && float64 } } }
+float32_t f32f = (float32_t) 1.0F64;
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float32_t f32g = 1.0F128;		// { dg-error "cannot convert '_Float128' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" "" { target { float32 && float128 } } }
+float32_t f32h = (float32_t) 1.0F128;
+#endif
+#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__
+float32_t f32i = 1.0f;
+#endif
+float32_t f32j = (float32_t) 1.0f;
+float32_t f32l = (float32_t) 1.0;
+float32_t f32n = (float32_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float32_t f32p = (float32_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+#ifdef __STDCPP_FLOAT16_T__
+float64_t f64a = 1.0F16;
+float64_t f64b = (float64_t) 1.0F16;
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float64_t f64c = 1.0F32;
+float64_t f64d = (float64_t) 1.0F32;
+#endif
+float64_t f64e = 1.0F64;
+float64_t f64f = (float64_t) 1.0F64;
+#ifdef __STDCPP_FLOAT128_T__
+float64_t f64g = 1.0F128;		// { dg-error "cannot convert '_Float128' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" "" { target { float64 && float128 } } }
+float64_t f64h = (float64_t) 1.0F128;
+#endif
+#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__
+float64_t f64i = 1.0f;
+#endif
+float64_t f64j = (float64_t) 1.0f;
+#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__
+float64_t f64k = 1.0;
+#endif
+float64_t f64l = (float64_t) 1.0;
+float64_t f64n = (float64_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float64_t f64p = (float64_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+#ifdef __STDCPP_FLOAT16_T__
+float128_t f128a = 1.0F16;
+float128_t f128b = (float128_t) 1.0F16;
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float128_t f128c = 1.0F32;
+float128_t f128d = (float128_t) 1.0F32;
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float128_t f128e = 1.0F64;
+float128_t f128f = (float128_t) 1.0F64;
+#endif
+float128_t f128g = 1.0F128;
+float128_t f128h = (float128_t) 1.0F128;
+#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__
+float128_t f128i = 1.0f;
+#endif
+float128_t f128j = (float128_t) 1.0f;
+#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__
+float128_t f128k = 1.0;
+#endif
+float128_t f128l = (float128_t) 1.0;
+#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106
+float128_t f128m = 1.0L;
+#endif
+float128_t f128n = (float128_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float128_t f128o = 1.0Q;
+float128_t f128p = (float128_t) 1.0Q;
+#endif
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating3.C.jj	2022-09-09 18:46:07.281922287 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C	2022-09-10 10:21:25.748210213 +0200
@@ -0,0 +1,128 @@
+// P1467R9 - Extended floating-point types and standard names.
+// Variant of ext-floating2.C test with x86 specific assumptions
+// about float, double, long double and existence of __float128.
+// And some further tests.
+// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
+    || !defined(__SIZEOF_FLOAT128__)
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16i = 1.0f;			// { dg-error "cannot convert 'float' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+float16_t f16k = 1.0;			// { dg-error "cannot convert 'double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+float16_t f16m = 1.0L;			// { dg-error "cannot convert 'long double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+float16_t f16o = 1.0Q;			// { dg-error "cannot convert '__float128' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+#endif
+float32_t f32i = 1.0f;
+float32_t f32k = 1.0;			// { dg-error "cannot convert 'double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
+float32_t f32m = 1.0L;			// { dg-error "cannot convert 'long double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
+float32_t f32o = 1.0Q;			// { dg-error "cannot convert '__float128' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
+float64_t f64i = 1.0f;
+float64_t f64k = 1.0;
+float64_t f64m = 1.0L;			// { dg-error "cannot convert 'long double' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
+float64_t f64o = 1.0Q;			// { dg-error "cannot convert '__float128' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
+float128_t f128i = 1.0f;
+float128_t f128k = 1.0;
+float128_t f128m = 1.0L;
+float128_t f128o = 1.0Q;
+
+#ifdef __STDCPP_FLOAT16_T__
+constexpr float16_t f16x = 1.0F16;
+#endif
+constexpr float32_t f32x = 2.0F32;
+constexpr float64_t f64x = 3.0F64;
+constexpr float128_t f128x = 4.0F128;
+constexpr float fx = 5.0f;
+constexpr double dx = 6.0;
+constexpr long double ldx = 7.0L;
+
+constexpr int foo (float32_t) { return 1; }
+constexpr int foo (float64_t) { return 2; }
+constexpr int bar (float) { return 3; }
+constexpr int bar (double) { return 4; }
+constexpr int bar (long double) { return 5; }
+constexpr int baz (float32_t) { return 6; }
+constexpr int baz (float64_t) { return 7; }
+constexpr int baz (float128_t) { return 8; }
+constexpr int qux (float64_t) { return 9; }
+constexpr int qux (float32_t) { return 10; }
+constexpr int fred (long double) { return 11; }
+constexpr int fred (double) { return 12; }
+constexpr int fred (float) { return 13; }
+constexpr int thud (float128_t) { return 14; }
+constexpr int thud (float64_t) { return 15; }
+constexpr int thud (float32_t) { return 16; }
+struct S {
+  constexpr operator float32_t () const { return 1.0f32; }
+  constexpr operator float64_t () const { return 2.0f64; }
+};
+struct T {
+  constexpr operator float64_t () const { return 3.0f64; }
+  constexpr operator float32_t () const { return 4.0f32; }
+};
+
+void
+test (S s, T t)
+{
+#ifdef __STDCPP_FLOAT16_T__
+  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (foo (float (2.0)) == 1);
+  static_assert (foo (double (3.0)) == 2);
+  constexpr double x (s);
+  static_assert (x == 2.0);
+#ifdef __STDCPP_FLOAT16_T__
+  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (bar (f32x) == 3);
+  static_assert (bar (f64x) == 4);
+  bar (f128x);					// { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" }
+  static_assert (bar (fx) == 3);
+  static_assert (bar (dx) == 4);
+  static_assert (bar (ldx) == 5);
+#ifdef __STDCPP_FLOAT16_T__
+  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (baz (f32x) == 6);
+  static_assert (baz (f64x) == 7);
+  static_assert (baz (f128x) == 8);
+  static_assert (baz (fx) == 6);
+  static_assert (baz (dx) == 7);
+  static_assert (baz (ldx) == 8);
+#ifdef __STDCPP_FLOAT16_T__
+  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (qux (float (2.0)) == 10);
+  static_assert (qux (double (3.0)) == 9);
+  constexpr double y (t);
+  static_assert (y == 3.0);
+#ifdef __STDCPP_FLOAT16_T__
+  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (fred (f32x) == 13);
+  static_assert (fred (f64x) == 12);
+  fred (f128x);					// { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" }
+  static_assert (fred (fx) == 13);
+  static_assert (fred (dx) == 12);
+  static_assert (fred (ldx) == 11);
+#ifdef __STDCPP_FLOAT16_T__
+  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (thud (f32x) == 16);
+  static_assert (thud (f64x) == 15);
+  static_assert (thud (f128x) == 14);
+  static_assert (thud (fx) == 16);
+  static_assert (thud (dx) == 15);
+  static_assert (thud (ldx) == 14);
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating4.C.jj	2022-09-09 18:48:11.979261440 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C	2022-09-10 10:55:24.105457186 +0200
@@ -0,0 +1,126 @@
+// P1467R9 - Extended floating-point types and standard names.
+// Variant of ext-floating3.C test with different specific assumptions
+// about float, double, long double.
+// float, double and long double are assumed to be IEEE 754 single, double
+// and quad.
+// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } }
+// { dg-options "" }
+// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } }
+// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } }
+
+#include "ext-floating.h"
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16i = 1.0f;			// { dg-error "cannot convert 'float' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+float16_t f16k = 1.0;			// { dg-error "cannot convert 'double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+float16_t f16m = 1.0L;			// { dg-error "cannot convert 'long double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
+#endif
+float32_t f32i = 1.0f;
+float32_t f32k = 1.0;			// { dg-error "cannot convert 'double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
+float32_t f32m = 1.0L;			// { dg-error "cannot convert 'long double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
+float64_t f64i = 1.0f;
+float64_t f64k = 1.0;
+float64_t f64m = 1.0L;			// { dg-error "cannot convert 'long double' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
+float128_t f128i = 1.0f;
+float128_t f128k = 1.0;
+float128_t f128m = 1.0L;
+
+#ifdef __STDCPP_FLOAT16_T__
+constexpr float16_t f16x = 1.0F16;
+#endif
+constexpr float32_t f32x = 2.0F32;
+constexpr float64_t f64x = 3.0F64;
+constexpr float128_t f128x = 4.0F128;
+constexpr float fx = 5.0f;
+constexpr double dx = 6.0;
+constexpr long double ldx = 7.0L;
+
+constexpr int foo (float32_t) { return 1; }
+constexpr int foo (float64_t) { return 2; }
+constexpr int bar (float) { return 3; }
+constexpr int bar (double) { return 4; }
+constexpr int bar (long double) { return 5; }
+constexpr int baz (float32_t) { return 6; }
+constexpr int baz (float64_t) { return 7; }
+constexpr int baz (float128_t) { return 8; }
+constexpr int qux (float64_t) { return 9; }
+constexpr int qux (float32_t) { return 10; }
+constexpr int fred (long double) { return 11; }
+constexpr int fred (double) { return 12; }
+constexpr int fred (float) { return 13; }
+constexpr int thud (float128_t) { return 14; }
+constexpr int thud (float64_t) { return 15; }
+constexpr int thud (float32_t) { return 16; }
+struct S {
+  constexpr operator float32_t () const { return 1.0f32; }
+  constexpr operator float64_t () const { return 2.0f64; }
+};
+struct T {
+  constexpr operator float64_t () const { return 3.0f64; }
+  constexpr operator float32_t () const { return 4.0f32; }
+};
+
+void
+test (S s, T t)
+{
+#ifdef __STDCPP_FLOAT16_T__
+  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (foo (float (2.0)) == 1);
+  static_assert (foo (double (3.0)) == 2);
+  constexpr double x (s);
+  static_assert (x == 2.0);
+#ifdef __STDCPP_FLOAT16_T__
+  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (bar (f32x) == 3);
+  static_assert (bar (f64x) == 4);
+  static_assert (bar (f128x) == 5);
+  static_assert (bar (fx) == 3);
+  static_assert (bar (dx) == 4);
+  static_assert (bar (ldx) == 5);
+#ifdef __STDCPP_FLOAT16_T__
+  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (baz (f32x) == 6);
+  static_assert (baz (f64x) == 7);
+  static_assert (baz (f128x) == 8);
+  static_assert (baz (fx) == 6);
+  static_assert (baz (dx) == 7);
+  static_assert (baz (ldx) == 8);
+#ifdef __STDCPP_FLOAT16_T__
+  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (qux (float (2.0)) == 10);
+  static_assert (qux (double (3.0)) == 9);
+  constexpr double y (t);
+  static_assert (y == 3.0);
+#ifdef __STDCPP_FLOAT16_T__
+  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (fred (f32x) == 13);
+  static_assert (fred (f64x) == 12);
+  static_assert (fred (f128x) == 11);
+  static_assert (fred (fx) == 13);
+  static_assert (fred (dx) == 12);
+  static_assert (fred (ldx) == 11);
+#ifdef __STDCPP_FLOAT16_T__
+  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (thud (f32x) == 16);
+  static_assert (thud (f64x) == 15);
+  static_assert (thud (f128x) == 14);
+  static_assert (thud (fx) == 16);
+  static_assert (thud (dx) == 15);
+  static_assert (thud (ldx) == 14);
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating5.C.jj	2022-09-09 20:00:22.489534397 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C	2022-09-10 10:44:59.653943267 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// IBM extended long double and _Float128 should have unordered conversion
+// ranks as IBM extended long double has variable precision from 53 bits
+// for denormals to more than 2150 bits for certain numbers.
+// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" }
+
+auto a = 1.0F128 + 1.0L;	// { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" }
+auto b = 1.0L + 1.0F128;	// { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" }
+bool c;
+auto d = c ? 1.0F128 : 1.0L;	// { dg-error "operands to '\\\?:' have unordered conversion rank of types '_Float128' and 'long double'" }
+auto e = c ? 1.0L : 1.0F128;	// { dg-error "operands to '\\\?:' have unordered conversion rank of types 'long double' and '_Float128'" }
--- gcc/testsuite/g++.dg/cpp23/ext-floating6.C.jj	2022-09-10 10:19:12.402030094 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating6.C	2022-09-09 18:46:07.281922287 +0200
@@ -0,0 +1,30 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+float foo (float x, float y, float z) { return x * y + z; }
+double foo (double x, double y, double z) { return x * y + z; }
+long double foo (long double x, long double y, long double z) { return x * y + z; }
+#ifdef __STDCPP_FLOAT16_T__
+float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; }
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating7.C.jj	2022-09-10 10:47:37.550796997 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C	2022-09-10 10:53:25.622065903 +0200
@@ -0,0 +1,119 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float16_runtime } } }
+// { dg-options "" }
+// { dg-add-options float16 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT16_T__
+#error Unexpected
+#endif
+#define WIDTH 16
+#endif
+
+#include <stdarg.h>
+#include "ext-floating.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 TYPE CONCAT (_Float, WIDTH)
+#define CST(C) CONCAT3 (C, f, WIDTH)
+#define CSTU(C) CONCAT3 (C, F, WIDTH)
+
+extern "C" void abort ();
+
+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
+fn (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 = fn (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 ();
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating8.C.jj	2022-09-10 10:52:54.654486646 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C	2022-09-10 10:53:41.424851341 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float32_runtime } } }
+// { dg-options "" }
+// { dg-add-options float32 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT32_T__
+#error Unexpected
+#endif
+#define WIDTH 32
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating9.C.jj	2022-09-10 10:53:49.328744035 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating9.C	2022-09-10 10:53:57.280636056 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float64_runtime } } }
+// { dg-options "" }
+// { dg-add-options float64 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT64_T__
+#error Unexpected
+#endif
+#define WIDTH 64
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating10.C.jj	2022-09-10 10:54:08.224487463 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C	2022-09-10 10:54:21.578306159 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float128_runtime } } }
+// { dg-options "" }
+// { dg-add-options float128 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT128_T__
+#error Unexpected
+#endif
+#define WIDTH 128
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating.h.jj	2022-09-09 18:46:07.281922287 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating.h	2022-09-09 18:46:07.281922287 +0200
@@ -0,0 +1,30 @@
+// P1467R9 - Extended floating-point types and standard names.
+
+namespace std
+{
+  #ifdef __STDCPP_FLOAT16_T__
+  using float16_t = _Float16;
+  #endif
+  #ifdef __STDCPP_FLOAT32_T__
+  using float32_t = _Float32;
+  #endif
+  #ifdef __STDCPP_FLOAT64_T__
+  using float64_t = _Float64;
+  #endif
+  #ifdef __STDCPP_FLOAT128_T__
+  using float128_t = _Float128;
+  #endif
+  #undef __STDCPP_BFLOAT16_T__
+  #ifdef __STDCPP_BFLOAT16_T__
+  using bfloat16_t = __bf16; // ???
+  #endif
+  template<typename T, T v> struct integral_constant {
+    static constexpr T value = v;
+  };
+  typedef integral_constant<bool, false> false_type;
+  typedef integral_constant<bool, true> true_type;
+  template<class T, class U>
+  struct is_same : std::false_type {};
+  template <class T>
+  struct is_same<T, T> : std::true_type {};
+}
--- gcc/testsuite/g++.target/i386/float16-1.C.jj	2021-12-30 15:12:43.315149146 +0100
+++ gcc/testsuite/g++.target/i386/float16-1.C	2022-09-12 08:49:38.178955414 +0200
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -mno-sse2" } */
 
-_Float16/* { dg-error "does not name a type" } */
+_Float16	/* { dg-error "expected unqualified-id before '_Float16'" } */
 foo (_Float16 x) 
 {
   return x;
-}
+}		/* { dg-error "'_Float16' is not supported on this target" } */
--- libcpp/expr.cc.jj	2022-09-08 13:01:19.837771596 +0200
+++ libcpp/expr.cc	2022-09-09 09:52:46.533798139 +0200
@@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfil
 	case 'f': case 'F':
 	  f++;
 	  if (len > 0
-	      && !CPP_OPTION (pfile, cplusplus)
 	      && s[1] >= '1'
 	      && s[1] <= '9'
 	      && fn_bits == 0)
@@ -230,7 +229,9 @@ interpret_float_suffix (cpp_reader *pfil
 		  len--;
 		  s++;
 		}
-	      if (len > 0 && s[1] == 'x')
+	      if (len > 0
+		  && s[1] == 'x'
+		  && !CPP_OPTION (pfile, cplusplus))
 		{
 		  fnx++;
 		  len--;
--- include/demangle.h.jj	2022-08-26 09:23:37.788064821 +0200
+++ include/demangle.h	2022-09-09 09:52:46.533798139 +0200
@@ -457,6 +457,11 @@ enum demangle_component_type
   DEMANGLE_COMPONENT_MODULE_PARTITION,
   DEMANGLE_COMPONENT_MODULE_ENTITY,
   DEMANGLE_COMPONENT_MODULE_INIT,
+
+  /* A builtin type with argument.  This holds the builtin type
+     information.  */
+  DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
+
 };
 
 /* Types which are only used internally.  */
@@ -543,6 +548,14 @@ struct demangle_component
       const struct demangle_builtin_type_info *type;
     } s_builtin;
 
+    /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  */
+    struct
+    {
+      /* Builtin type.  */
+      const struct demangle_builtin_type_info *type;
+      int arg;
+    } s_extended_builtin;
+
     /* For DEMANGLE_COMPONENT_SUB_STD.  */
     struct
     {
--- libiberty/cp-demangle.c.jj	2022-08-26 09:23:37.788064821 +0200
+++ libiberty/cp-demangle.c	2022-09-09 09:52:46.957792397 +0200
@@ -648,6 +648,10 @@ d_dump (struct demangle_component *dc, i
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
       printf ("builtin type %s\n", dc->u.s_builtin.type->name);
       return;
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
+      printf ("builtin type %s%d\n", dc->u.s_extended_builtin.type->name,
+	      dc->u.s_extended_builtin.type->arg);
+      return;
     case DEMANGLE_COMPONENT_OPERATOR:
       printf ("operator %s\n", dc->u.s_operator.op->name);
       return;
@@ -771,11 +775,6 @@ d_dump (struct demangle_component *dc, i
     case DEMANGLE_COMPONENT_PTRMEM_TYPE:
       printf ("pointer to member type\n");
       break;
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      printf ("fixed-point type, accum? %d, sat? %d\n",
-              dc->u.s_fixed.accum, dc->u.s_fixed.sat);
-      d_dump (dc->u.s_fixed.length, indent + 2);
-      break;
     case DEMANGLE_COMPONENT_ARGLIST:
       printf ("argument list\n");
       break;
@@ -1109,6 +1108,27 @@ d_make_builtin_type (struct d_info *di,
   return p;
 }
 
+/* Add a new extended builtin type component.  */
+
+static struct demangle_component *
+d_make_extended_builtin_type (struct d_info *di,
+			      const struct demangle_builtin_type_info *type,
+			      int arg)
+{
+  struct demangle_component *p;
+
+  if (type == NULL)
+    return NULL;
+  p = d_make_empty (di);
+  if (p != NULL)
+    {
+      p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE;
+      p->u.s_extended_builtin.type = type;
+      p->u.s_extended_builtin.arg = arg;
+    }
+  return p;
+}
+
 /* Add a new operator component.  */
 
 static struct demangle_component *
@@ -2464,6 +2484,7 @@ cplus_demangle_builtin_types[D_BUILTIN_T
   /* 32 */ { NL ("char32_t"),	NL ("char32_t"),	D_PRINT_DEFAULT },
   /* 33 */ { NL ("decltype(nullptr)"),	NL ("decltype(nullptr)"),
 	     D_PRINT_DEFAULT },
+  /* 34 */ { NL ("_Float"),	NL ("_Float"),		D_PRINT_FLOAT },
 };
 
 CP_STATIC_IF_GLIBCPP_V3
@@ -2727,19 +2748,22 @@ cplus_demangle_type (struct d_info *di)
 	  break;
 
 	case 'F':
-	  /* Fixed point types. DF<int bits><length><fract bits><sat>  */
-	  ret = d_make_empty (di);
-	  ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
-	  if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
-	    /* For demangling we don't care about the bits.  */
-	    d_number (di);
-	  ret->u.s_fixed.length = cplus_demangle_type (di);
-	  if (ret->u.s_fixed.length == NULL)
-	    return NULL;
-	  d_number (di);
-	  peek = d_next_char (di);
-	  ret->u.s_fixed.sat = (peek == 's');
-	  break;
+	  /* DF<number>_ - _Float<number>.  */
+	  {
+	    int arg = d_number (di);
+	    char buf[12];
+	    if (d_peek_char (di) != '_')
+	      return NULL;
+	    ret
+	      = d_make_extended_builtin_type (di,
+					      &cplus_demangle_builtin_types[34],
+					      arg);
+	    d_advance (di, 1);
+	    sprintf (buf, "%d", arg);
+	    di->expansion += ret->u.s_extended_builtin.type->len
+			     + strlen (buf);
+	    break;
+	  }
 
 	case 'v':
 	  ret = d_vector_type (di);
@@ -4202,6 +4226,7 @@ d_count_templates_scopes (struct d_print
     case DEMANGLE_COMPONENT_FUNCTION_PARAM:
     case DEMANGLE_COMPONENT_SUB_STD:
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
     case DEMANGLE_COMPONENT_OPERATOR:
     case DEMANGLE_COMPONENT_CHARACTER:
     case DEMANGLE_COMPONENT_NUMBER:
@@ -4210,6 +4235,7 @@ d_count_templates_scopes (struct d_print
     case DEMANGLE_COMPONENT_MODULE_NAME:
     case DEMANGLE_COMPONENT_MODULE_PARTITION:
     case DEMANGLE_COMPONENT_MODULE_INIT:
+    case DEMANGLE_COMPONENT_FIXED_TYPE:
       break;
 
     case DEMANGLE_COMPONENT_TEMPLATE:
@@ -4309,10 +4335,6 @@ d_count_templates_scopes (struct d_print
       d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
       break;
 
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
-      break;
-
     case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
     case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
     case DEMANGLE_COMPONENT_MODULE_ENTITY:
@@ -4580,11 +4602,11 @@ d_find_pack (struct d_print_info *dpi,
     case DEMANGLE_COMPONENT_TAGGED_NAME:
     case DEMANGLE_COMPONENT_OPERATOR:
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
     case DEMANGLE_COMPONENT_SUB_STD:
     case DEMANGLE_COMPONENT_CHARACTER:
     case DEMANGLE_COMPONENT_FUNCTION_PARAM:
     case DEMANGLE_COMPONENT_UNNAMED_TYPE:
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
     case DEMANGLE_COMPONENT_DEFAULT_ARG:
     case DEMANGLE_COMPONENT_NUMBER:
       return NULL;
@@ -5387,6 +5409,16 @@ d_print_comp_inner (struct d_print_info
 			 dc->u.s_builtin.type->java_len);
       return;
 
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
+      if ((options & DMGL_JAVA) == 0)
+	d_append_buffer (dpi, dc->u.s_extended_builtin.type->name,
+			 dc->u.s_extended_builtin.type->len);
+      else
+	d_append_buffer (dpi, dc->u.s_extended_builtin.type->java_name,
+			 dc->u.s_extended_builtin.type->java_len);
+      d_append_num (dpi, dc->u.s_extended_builtin.arg);
+      return;
+
     case DEMANGLE_COMPONENT_VENDOR_TYPE:
       d_print_comp (dpi, options, d_left (dc));
       return;
@@ -5525,22 +5557,6 @@ d_print_comp_inner (struct d_print_info
 	return;
       }
 
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      if (dc->u.s_fixed.sat)
-	d_append_string (dpi, "_Sat ");
-      /* Don't print "int _Accum".  */
-      if (dc->u.s_fixed.length->u.s_builtin.type
-	  != &cplus_demangle_builtin_types['i'-'a'])
-	{
-	  d_print_comp (dpi, options, dc->u.s_fixed.length);
-	  d_append_char (dpi, ' ');
-	}
-      if (dc->u.s_fixed.accum)
-	d_append_string (dpi, "_Accum");
-      else
-	d_append_string (dpi, "_Fract");
-      return;
-
     case DEMANGLE_COMPONENT_ARGLIST:
     case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
       if (d_left (dc) != NULL)
--- libiberty/cp-demangle.h.jj	2022-08-26 09:23:37.788064821 +0200
+++ libiberty/cp-demangle.h	2022-09-09 09:52:46.978792113 +0200
@@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i)
 extern const struct demangle_operator_info cplus_demangle_operators[];
 #endif
 
-#define D_BUILTIN_TYPE_COUNT (34)
+#define D_BUILTIN_TYPE_COUNT (35)
 
 CP_STATIC_IF_GLIBCPP_V3
 const struct demangle_builtin_type_info
--- libiberty/testsuite/demangle-expected.jj	2022-08-26 09:23:37.788064821 +0200
+++ libiberty/testsuite/demangle-expected	2022-09-09 09:52:46.993791909 +0200
@@ -1242,8 +1242,8 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8fun
 post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
 #
 --format=auto --no-params
-_Z3xxxDFyuVb
-xxx(unsigned long long _Fract, bool volatile)
+_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb
+xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile)
 xxx
 # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
 --format=auto --no-params
--- fixincludes/inclhack.def.jj	2022-03-01 19:42:39.183264899 +0100
+++ fixincludes/inclhack.def	2022-09-11 20:08:07.787691125 +0200
@@ -2015,6 +2015,102 @@ fix = {
 	EOT;
 };
 
+/*  glibc-2.27 to 2.36 assume GCC 7 or later supports some or all
+ *  of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C,
+ *  but doesn't for C++.
+ */
+fix = {
+    hackname  = glibc_cxx_floatn_1;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\\*/\n)?"
+		"([ \t]*#[ \t]*if[^\n]*\n)?"
+		"[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* The literal suffix f128 exists only since GCC 7.0.  */
+	#   define __f128(x) x##l
+	#  else
+	#   define __f128(x) x##f128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
+	#   if __LDBL_MANT_DIG__ == 113
+	#    define __f128(x) x##l
+	#   else
+	#    define __f128(x) x##q
+	#   endif
+	#  else
+	#   define __f128(x) x##f128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   ifdef __NO_LONG_DOUBLE_MATH
+	#    define __f64(x) x##l
+	#   else
+	#    define __f64(x) x
+	#   endif
+	#  else
+	#   define __f64(x) x##f64
+	#  endif
+	EOT;
+};
+
+fix = {
+    hackname  = glibc_cxx_floatn_2;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\\*/\n)?"
+		"[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	typedef __float128 _Float128;
+	#  endif
+	EOT;
+};
+
+fix = {
+    hackname  = glibc_cxx_floatn_3;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?"
+		"([ \t]*#[ \t]*if[^\n]*\n)?"
+		"([ \t]*typedef[ \t]+[^\n]*;\n)?"
+		"[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   define __CFLOAT128 _Complex long double
+	#  else
+	#   define __CFLOAT128 _Complex _Float128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* Add a typedef for older GCC compilers which don't natively support
+	   _Complex _Float128.  */
+	typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
+	#   define __CFLOAT128 __cfloat128
+	#  else
+	#   define __CFLOAT128 _Complex _Float128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   ifdef __NO_LONG_DOUBLE_MATH
+	#    define __CFLOAT64 _Complex long double
+	#   else
+	#    define __CFLOAT64 _Complex double
+	#   endif
+	#  else
+	#   define __CFLOAT64 _Complex _Float64
+	#  endif
+	EOT;
+};
+
 /*  glibc-2.3.5 defines pthread mutex initializers incorrectly,
  *  so we replace them with versions that correspond to the
  *  definition.
--- fixincludes/tests/base/bits/floatn.h.jj	2022-09-11 20:11:34.991962782 +0200
+++ fixincludes/tests/base/bits/floatn.h	2022-09-11 20:09:48.323368533 +0200
@@ -0,0 +1,74 @@
+/*  DO NOT EDIT THIS FILE.
+
+    It has been auto-edited by fixincludes from:
+
+	"fixinc/tests/inc/bits/floatn.h"
+
+    This had to be done to correct non-standard usages in the
+    original, manufacturer supplied header file.  */
+
+
+
+#if defined( GLIBC_CXX_FLOATN_1_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+/* The literal suffix f128 exists only since GCC 7.0.  */
+#   define __f128(x) x##l
+#  else
+#   define __f128(x) x##f128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
+#   if __LDBL_MANT_DIG__ == 113
+#    define __f128(x) x##l
+#   else
+#    define __f128(x) x##q
+#   endif
+#  else
+#   define __f128(x) x##f128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+#   ifdef __NO_LONG_DOUBLE_MATH
+#    define __f64(x) x##l
+#   else
+#    define __f64(x) x
+#   endif
+#  else
+#   define __f64(x) x##f64
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_1_CHECK */
+
+
+#if defined( GLIBC_CXX_FLOATN_2_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+typedef __float128 _Float128;
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_2_CHECK */
+
+
+#if defined( GLIBC_CXX_FLOATN_3_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+#   define __CFLOAT128 _Complex long double
+#  else
+#   define __CFLOAT128 _Complex _Float128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+/* Add a typedef for older GCC compilers which don't natively support
+   _Complex _Float128.  */
+typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
+#   define __CFLOAT128 __cfloat128
+#  else
+#   define __CFLOAT128 _Complex _Float128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
+#   ifdef __NO_LONG_DOUBLE_MATH
+#    define __CFLOAT64 _Complex long double
+#   else
+#    define __CFLOAT64 _Complex double
+#   endif
+#  else
+#   define __CFLOAT64 _Complex _Float64
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_3_CHECK */
--- fixincludes/fixincl.x.jj	2022-03-01 19:42:39.169265091 +0100
+++ fixincludes/fixincl.x	2022-09-11 20:09:37.668565341 +0200
@@ -2,11 +2,11 @@
  *
  * DO NOT EDIT THIS FILE   (fixincl.x)
  *
- * It has been AutoGen-ed  February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16
+ * It has been AutoGen-ed  September 11, 2022 at 08:09:37 PM by AutoGen 5.18.16
  * From the definitions    inclhack.def
  * and the template file   fixincl
  */
-/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022
+/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Sep 11 20:09:37 CEST 2022
  *
  * You must regenerate it.  Use the ./genfixes script.
  *
@@ -15,7 +15,7 @@
  * certain ANSI-incompatible system header files which are fixed to work
  * correctly with ANSI C and placed in a directory that GNU C will search.
  *
- * This file contains 267 fixup descriptions.
+ * This file contains 270 fixup descriptions.
  *
  * See README for more information.
  *
@@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * *
  *
+ *  Description of Glibc_Cxx_Floatn_1 fix
+ */
+tSCC zGlibc_Cxx_Floatn_1Name[] =
+     "glibc_cxx_floatn_1";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_1List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_1Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\\*/\n\
+)?([ \t]*#[ \t]*if[^\n\
+]*\n\
+)?[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
+
+#define    GLIBC_CXX_FLOATN_1_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_1
+ */
+static const char* apzGlibc_Cxx_Floatn_1Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Glibc_Cxx_Floatn_2 fix
+ */
+tSCC zGlibc_Cxx_Floatn_2Name[] =
+     "glibc_cxx_floatn_2";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_2List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_2Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\\*/\n\
+)?[ \t]*typedef[ \t]+[^\n\
+]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
+
+#define    GLIBC_CXX_FLOATN_2_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_2
+ */
+static const char* apzGlibc_Cxx_Floatn_2Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Glibc_Cxx_Floatn_3 fix
+ */
+tSCC zGlibc_Cxx_Floatn_3Name[] =
+     "glibc_cxx_floatn_3";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_3List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_3Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\n\
+?[^\n\
+]*\\*/\n\
+)?([ \t]*#[ \t]*if[^\n\
+]*\n\
+)?([ \t]*typedef[ \t]+[^\n\
+]*;\n\
+)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
+
+#define    GLIBC_CXX_FLOATN_3_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_3
+ */
+static const char* apzGlibc_Cxx_Floatn_3Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
  *  Description of Glibc_Mutex_Init fix
  */
 tSCC zGlibc_Mutex_InitName[] =
@@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[]
  *
  *  List of all fixes
  */
-#define REGEX_COUNT          305
+#define REGEX_COUNT          308
 #define MACH_LIST_SIZE_LIMIT 187
-#define FIX_COUNT            267
+#define FIX_COUNT            270
 
 /*
  *  Enumerate the fixes
@@ -10977,6 +11103,9 @@ typedef enum {
     GLIBC_C99_INLINE_2_FIXIDX,
     GLIBC_C99_INLINE_3_FIXIDX,
     GLIBC_C99_INLINE_4_FIXIDX,
+    GLIBC_CXX_FLOATN_1_FIXIDX,
+    GLIBC_CXX_FLOATN_2_FIXIDX,
+    GLIBC_CXX_FLOATN_3_FIXIDX,
     GLIBC_MUTEX_INIT_FIXIDX,
     GLIBC_STDINT_FIXIDX,
     GLIBC_STRNCPY_FIXIDX,
@@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
      GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
      aGlibc_C99_Inline_4Tests,   apzGlibc_C99_Inline_4Patch, 0 },
 
+  {  zGlibc_Cxx_Floatn_1Name,    zGlibc_Cxx_Floatn_1List,
+     apzGlibc_Cxx_Floatn_1Machs,
+     GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_1Tests,   apzGlibc_Cxx_Floatn_1Patch, 0 },
+
+  {  zGlibc_Cxx_Floatn_2Name,    zGlibc_Cxx_Floatn_2List,
+     apzGlibc_Cxx_Floatn_2Machs,
+     GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_2Tests,   apzGlibc_Cxx_Floatn_2Patch, 0 },
+
+  {  zGlibc_Cxx_Floatn_3Name,    zGlibc_Cxx_Floatn_3List,
+     apzGlibc_Cxx_Floatn_3Machs,
+     GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_3Tests,   apzGlibc_Cxx_Floatn_3Patch, 0 },
+
   {  zGlibc_Mutex_InitName,    zGlibc_Mutex_InitList,
      apzGlibc_Mutex_InitMachs,
      GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,

	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-12  8:05 [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652] Jakub Jelinek
@ 2022-09-12 19:36 ` Joseph Myers
  2022-09-12 20:52   ` Jakub Jelinek
  2022-09-16 11:48 ` Jason Merrill
  2022-09-20  3:35 ` Hongtao Liu
  2 siblings, 1 reply; 16+ messages in thread
From: Joseph Myers @ 2022-09-12 19:36 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jonathan Wakely, Bruce Korb, gcc-patches

On Mon, 12 Sep 2022, Jakub Jelinek via Gcc-patches wrote:

> Now, I guess for the fixincludes it could also use
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> where earlier GCC 13 snapshots would not be doing the fixincludes,
> but the question is what to use for upstream glibc, because
> there will be 13.0 snapshots where C++ doesn't support _Float{16,32,64,128}
> and where it is essential to use what glibc has been doing previously
> and using the #else would fail miserably, and then 13.0 snapshots where it
> does support it and where using the if would fail miserably.

We don't claim in glibc to support old snapshots from master, so checking 
for __GNUC_PREREQ (13, 0) and failing for such older GCC 13 versions is 
fine.

> Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> implemented inline, SFmode -> BFmode conversion is harder,

Properly the right way for converting from BFmode to SFmode in the 
presence of -fsignaling-nans should depend on how the result is used.  If 
it's used for arithmetic, it's OK to have converted a BFmode signaling NaN 
to an SFmode signaling NaN, but if e.g. the result is examined with 
issignaling or otherwise stored so it may be significant later whether the 
result is a quiet or signaling NaN, IEEE semantics would mean a signaling 
NaN should be a converted to a quiet NaN with "invalid" raised.  Though I 
don't know how far hardware instructions for BFmode attempt to follow IEEE 
semantics.

(Cf. powerpc single-precision load instructions whose effect is defined as 
a purely bitwise conversion from single to double precision, so that 
single-precision load and store of a signaling NaN never end up converting 
it to a quiet NaN even though the in-register format is double precision.)

> (untested) and the question is if it should be implemented in libgcc
> (and using soft-fp or not), or inline, or both depending on -Os.

Also if you try to do a direct conversion between BFmode and HFmode, 
soft-fp's current support for conversions may not handle that case (where 
one type has wider exponent range and other type has higher precision).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-12 19:36 ` Joseph Myers
@ 2022-09-12 20:52   ` Jakub Jelinek
  2022-09-12 21:00     ` Jakub Jelinek
  2022-09-13 17:50     ` Joseph Myers
  0 siblings, 2 replies; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-12 20:52 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jonathan Wakely, gcc-patches, Bruce Korb

On Mon, Sep 12, 2022 at 07:36:05PM +0000, Joseph Myers wrote:
> On Mon, 12 Sep 2022, Jakub Jelinek via Gcc-patches wrote:
> 
> > Now, I guess for the fixincludes it could also use
> > #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> > where earlier GCC 13 snapshots would not be doing the fixincludes,
> > but the question is what to use for upstream glibc, because
> > there will be 13.0 snapshots where C++ doesn't support _Float{16,32,64,128}
> > and where it is essential to use what glibc has been doing previously
> > and using the #else would fail miserably, and then 13.0 snapshots where it
> > does support it and where using the if would fail miserably.
> 
> We don't claim in glibc to support old snapshots from master, so checking 
> for __GNUC_PREREQ (13, 0) and failing for such older GCC 13 versions is 
> fine.

Ok, makes sense, especially if it is applied on the glibc side a few months
after it is changed on the GCC side.  If it is applied immediately, there
could be people who have 2 weeks old GCC trunk snapshot and try it with latest
glibc, but if it will be say in December, it will be far less likely.

> > Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> > implemented inline, SFmode -> BFmode conversion is harder,
> 
> Properly the right way for converting from BFmode to SFmode in the 
> presence of -fsignaling-nans should depend on how the result is used.  If 
> it's used for arithmetic, it's OK to have converted a BFmode signaling NaN 
> to an SFmode signaling NaN, but if e.g. the result is examined with 
> issignaling or otherwise stored so it may be significant later whether the 
> result is a quiet or signaling NaN, IEEE semantics would mean a signaling 
> NaN should be a converted to a quiet NaN with "invalid" raised.  Though I 
> don't know how far hardware instructions for BFmode attempt to follow IEEE 
> semantics.
> 
> (Cf. powerpc single-precision load instructions whose effect is defined as 
> a purely bitwise conversion from single to double precision, so that 
> single-precision load and store of a signaling NaN never end up converting 
> it to a quiet NaN even though the in-register format is double precision.)

Looking at HW instructions, I believe x86 F16C VCVTPH2PS and VCVTPS2PH
raise invalid on SNaN and turn it into QNaN and from what I can understand,
the AVX512F16 conversion insns like VCVTSH2SS and VCVTSS2SH do too,
but AVX512_BF16 VCVTNE2PS2BF16 doesn't raise any exceptions (and there is
no insn for the other direction).

> > (untested) and the question is if it should be implemented in libgcc
> > (and using soft-fp or not), or inline, or both depending on -Os.
> 
> Also if you try to do a direct conversion between BFmode and HFmode, 
> soft-fp's current support for conversions may not handle that case (where 
> one type has wider exponent range and other type has higher precision).

Can't that be implemented as 2 conversions, convert BFmode to SFmode and
then back to HFmode (or the other way around)?
SFmode is a superset of both formats, so except for the raise exception on
SNaN and conversion to QNaN extension to SFmode from both formats should be
lossless?

In any case, the bfloat16 support is intended maybe for follow-up patches,
not in this patch.

	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-12 20:52   ` Jakub Jelinek
@ 2022-09-12 21:00     ` Jakub Jelinek
  2022-09-13 17:50     ` Joseph Myers
  1 sibling, 0 replies; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-12 21:00 UTC (permalink / raw)
  To: Joseph Myers, Jonathan Wakely, gcc-patches, Bruce Korb

On Mon, Sep 12, 2022 at 10:52:35PM +0200, Jakub Jelinek via Gcc-patches wrote:
> Can't that be implemented as 2 conversions, convert BFmode to SFmode and
> then back to HFmode (or the other way around)?
> SFmode is a superset of both formats, so except for the raise exception on
> SNaN and conversion to QNaN extension to SFmode from both formats should be
> lossless?
> 
> In any case, the bfloat16 support is intended maybe for follow-up patches,
> not in this patch.

Well, the BF -> HF conversion could be done just by << 16 + SF -> HF
conversion too.
But for BF -> HF and HF -> BF conversions (C++ allows them only
for explicit casts, not implicit), the question is what library routine
name to use, because it is neither pure extension nor pure truncation.
But guess that is the case for PowerPC IFmode vs. KFmode.  And the backend
has both truncifkf2 and extendifkf2 named patterns which presumably do the
same thing.

	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-12 20:52   ` Jakub Jelinek
  2022-09-12 21:00     ` Jakub Jelinek
@ 2022-09-13 17:50     ` Joseph Myers
  1 sibling, 0 replies; 16+ messages in thread
From: Joseph Myers @ 2022-09-13 17:50 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches, Bruce Korb

On Mon, 12 Sep 2022, Jakub Jelinek via Gcc-patches wrote:

> > We don't claim in glibc to support old snapshots from master, so checking 
> > for __GNUC_PREREQ (13, 0) and failing for such older GCC 13 versions is 
> > fine.
> 
> Ok, makes sense, especially if it is applied on the glibc side a few months
> after it is changed on the GCC side.  If it is applied immediately, there

Leaving the build of glibc C++ tests broken for months with mainline GCC 
doesn't seem like a good idea; it's a recipe for missing other 
regressions.  I think a fix should be applied to glibc immediately after 
the GCC change.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-12  8:05 [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652] Jakub Jelinek
  2022-09-12 19:36 ` Joseph Myers
@ 2022-09-16 11:48 ` Jason Merrill
  2022-09-16 17:34   ` Jakub Jelinek
  2022-09-20  3:35 ` Hongtao Liu
  2 siblings, 1 reply; 16+ messages in thread
From: Jason Merrill @ 2022-09-16 11:48 UTC (permalink / raw)
  To: Jakub Jelinek, Jonathan Wakely, Joseph S. Myers, Bruce Korb; +Cc: gcc-patches

On 9/12/22 04:05, Jakub Jelinek wrote:
> Hi!
> 
> The following patch implements the compiler part of C++23
> P1467R9 - Extended floating-point types and standard names compiler part
> by introducing _Float{16,32,64,128} as keywords and builtin types
> like they are implemented for C already since GCC 7.
> It doesn't introduce _Float{32,64,128}x for C++, those remain C only
> for now, mainly because https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
> has mangling for:
> ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
> but doesn't for _FloatNx.  And it doesn't add anything for bfloat16_t
> support, see below.
> Regarding mangling, I think mangling _FloatNx as DF <number> x _ would be
> possible, but would need to be discussed and voted in.

As you've seen, I opened a pull request for these.  I think we can go 
ahead and implement that and make sure it's resolved before the GCC 13 
release.

Or we could temporarily mangle them as an extension, i.e. u9_Float32x.

I would expect _Float64x, at least, to be fairly popular.

> As there is no _FloatNx support for C++, I think it is wrong to announce
> it through __FLT{32,64,128}X_*__ predefined macros (so the patch disables
> those for C++; unfortunately g++ 7 to 12 will predefine those and also
> __FLT{32,64,128}_*__ even when _FloatN support isn't implemented).

> The patch wants to keep backwards compatibility with how __float128 has
> been handled in C++ before, both for mangling and behavior in binary
> operations, overload resolution etc.  So, there are some backend changes
> where for C __float128 and _Float128 are the same type (float128_type_node
> and float128t_type_node are the same pointer), but for C++ they are distinct
> types which mangle differently and _Float128 is treated as extended
> floating-point type while __float128 is treated as non-standard floating
> point type.

How important do you think this backwards compatibility is?

As I mentioned in the ABI proposal, I think it makes sense to make 
__float128 an alias for std::float128_t, and continue using the current 
mangling for __float128.

I don't think we want the two types to have different semantics.  If we 
want to support existing __float128 code that relies on implicit 
narrowing conversions, we could allow them generally with a pedwarn 
using the 'bad' conversion machinery.  That's probably useful anyway for 
better diagnostics.

> The various C++23 changes about how floating-point types
> are changed are actually implemented as written in the spec only if at least
> one of the types involved is _Float{16,32,64,128} and kept previous behavior
> otherwise.  For float/double/long double the rules are actually written that
> they behave the same as before.
> There is some backwards incompatibility at least on x86 regarding _Float16,
> because that type was already used by that name and with the DF16_ mangling
> (but only since GCC 12 and I think it isn't that widely used in the wild
> yet).  E.g. config/i386/avx512fp16intrin.h shows the issues, where
> in C or in GCC 12 in C++ one could pass 0.0f to a builtin taking _Float16
> argument, but with the changes that is not possible anymore, one needs
> to either use 0.0f16 or (_Float16) 0.0f.
> We have also a problem with glibc headers, where since glibc 2.27
> math.h and complex.h aren't compilable with these changes.  One gets
> errors like:
> In file included from /usr/include/math.h:43,
>                   from abc.c:1:
> /usr/include/bits/floatn.h:86:9: error: multiple types in one declaration
>     86 | typedef __float128 _Float128;
>        |         ^~~~~~~~~~
> /usr/include/bits/floatn.h:86:20: error: declaration does not declare anything [-fpermissive]
>     86 | typedef __float128 _Float128;
>        |                    ^~~~~~~~~
> In file included from /usr/include/bits/floatn.h:119:
> /usr/include/bits/floatn-common.h:214:9: error: multiple types in one declaration
>    214 | typedef float _Float32;
>        |         ^~~~~
> /usr/include/bits/floatn-common.h:214:15: error: declaration does not declare anything [-fpermissive]
>    214 | typedef float _Float32;
>        |               ^~~~~~~~
> /usr/include/bits/floatn-common.h:251:9: error: multiple types in one declaration
>    251 | typedef double _Float64;
>        |         ^~~~~~
> /usr/include/bits/floatn-common.h:251:16: error: declaration does not declare anything [-fpermissive]
>    251 | typedef double _Float64;
>        |                ^~~~~~~~
> This is from snippets like:
> /* The remaining of this file provides support for older compilers.  */
> # if __HAVE_FLOAT128
> 
> /* The type _Float128 exists only since GCC 7.0.  */
> #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> typedef __float128 _Float128;
> #  endif
> where it hardcodes that C++ doesn't have _Float{16,32,64,128} support nor
> {f,F}{16,32,64,128} literal suffixes nor _Complex _Float{16,32,64,128}.
> The patch fixincludes this for now and hopefully if this is committed, then
> glibc can change those.  Right now the patch changes those
> #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> conditions to
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> where it relies on __FLT32X_*__ macros no longer being predefined for C++.
> Now, I guess for the fixincludes it could also use
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> where earlier GCC 13 snapshots would not be doing the fixincludes,
> but the question is what to use for upstream glibc, because
> there will be 13.0 snapshots where C++ doesn't support _Float{16,32,64,128}
> and where it is essential to use what glibc has been doing previously
> and using the #else would fail miserably, and then 13.0 snapshots where it
> does support it and where using the if would fail miserably.
> One option is to use
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1))
> in glibc and rely on fixincludes for 13.0 snapshots (or of course later when
> using 13.1+ with older glibc).
> Another thing is mangling, as said above, Itanium C++ ABI specifies
> DF <number> _ as _Float{16,32,64,128} mangling, but GCC was implementing
> a mangling incompatible with that starting with DF for fixed point types.
> Fixed point was never supported in C++ though, I believe the reason why
> the mangling has been added was that due to a bug it would leak into the
> C++ FE through decltype (0.0r) etc.  But that has been shortly after the
> mangling was added fixed (I think in the same GCC release cycle), so we
> now reject 0.0r etc. in C++.  If we ever need the fixed point mangling,
> I think it can be readded but better with a different prefix so that it
> doesn't conflict with the published standard manglings.  So, this patch
> also kills the fixed point mangling and implements the DF <number> _
> demangling.

Sounds good.

> The patch predefines __STDCPP_FLOAT{16,32,64,128}_T__ macros when
> those types are available, but only for C++23, while the underlying types
> are available in C++98 and later including the {f,F}{16,32,64,128} literal
> suffixes (but those with a pedwarn for C++20 and earlier).  My understanding
> is that it needs to be predefined by the compiler, on the other side
> predefining even for older modes when <stdfloat> is a new C++23 header
> would be weird.  One can find out if _Float{16,32,64,128} is supported in
> C++ by
> defined(__FLT{16,32,64,128}_MANT_DIG__) && !defined(__FLT32X_MANT_DIG__)
> (unfortunately not just the former because GCC 7-12 predefined those too)
> or perhaps __GNUC__ >= 13 && defined(__FLT{16,32,64,128}_MANT_DIG__)
> (but that doesn't work well with older G++ 13 snapshots).

As Joseph says, I wouldn't worry about older GCC 13 snapshots.

> As for std::bfloat16_t, three targets (aarch64, arm and x86) apparently
> "support" __bf16 type which has the bfloat16 format, but isn't really
> usable, e.g. {aarch64,arm,ix86}_invalid_conversion disallow any conversions
> from or to type with BFmode, {aarch64,arm,ix86}_invalid_unary_op disallows
> any unary operations on those except for ADDR_EXPR and
> {aarch64,arm,ix86}_invalid_binary_op disallows any binary operation on
> those.  So, I think we satisfy:
> "If the implementation supports an extended floating-point type with the
> properties, as specified by ISO/IEC/IEEE 60559, of radix (b) of 2, storage
> width in bits (k) of 16, precision in bits (p) of 8, maximum exponent (emax)
> of 127, and exponent field width in bits (w) of 8, then the typedef-name
> std::bfloat16_t is defined in the header <stdfloat> and names such a type,
> the macro __STDCPP_BFLOAT16_T__ is defined, and the floating-point literal
> suffixes bf16 and BF16 are supported."
> because we don't really support those right now.
> The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> shouldn't support it, in the PR there is a partial patch to do so, but
> the big question is if it should be supported as the __bf16 type those
> 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> and add conversions to/from at least SFmode but probably also DFmode, TFmode
> and XFmode on x86 and implement arithmetics on those through conversion to
> SFmode, performing arithmetics there and conversion back.

Sounds good.  And I've proposed DFb16_ mangling.

> Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> implemented inline, SFmode -> BFmode conversion is harder,
> I think it is roughly:
> __bf16
> __truncsfbf2 (_Float32 x)
> {
>    unsigned int y;
>    memcpy (&y, &x, sizeof (y));
>    unsigned int z = x & 0x7fffffff;
>    unsigned short r;
>    __bf16 ret;
>    if (z < 0x800000)
>      // Zero or denormal, flush to zero.
>      r = (x & 0x80000000) >> 16;
>    else if (z < 0x7f800000)
>      // Normal, round to nearest.
>      r = (x + 0x7fff + ((x >> 16) & 1)) >> 16;
>    else if (z == 0x7f800000)
>      // Inf.
>      r = x >> 16;
>    else
>      // NaN.
>      r = (x >> 16) | (1 << 6);
>    memcpy (&ret, &r, sizeof (r));
>    return ret;
> }
> (untested) and the question is if it should be implemented in libgcc
> (and using soft-fp or not), or inline, or both depending on -Os.

I'll leave that question to people more involved with FP codegen.

> Or there is the possibility to keep __bf16 a lame type one can't convert
> to/from or perform most unary and all binary ops on it, and add for C++
> a new type (say __bfloat16_t or whatever else), agree on mangling in
> Itanium ABI and implement full support just for that type.

Preserving the existing useless semantics doesn't sound worthwhile.

Jason


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-16 11:48 ` Jason Merrill
@ 2022-09-16 17:34   ` Jakub Jelinek
  2022-09-17  8:58     ` Jason Merrill
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-16 17:34 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On Fri, Sep 16, 2022 at 01:48:54PM +0200, Jason Merrill wrote:
> On 9/12/22 04:05, Jakub Jelinek wrote:
> > The following patch implements the compiler part of C++23
> > P1467R9 - Extended floating-point types and standard names compiler part
> > by introducing _Float{16,32,64,128} as keywords and builtin types
> > like they are implemented for C already since GCC 7.
> > It doesn't introduce _Float{32,64,128}x for C++, those remain C only
> > for now, mainly because https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
> > has mangling for:
> > ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
> > but doesn't for _FloatNx.  And it doesn't add anything for bfloat16_t
> > support, see below.
> > Regarding mangling, I think mangling _FloatNx as DF <number> x _ would be
> > possible, but would need to be discussed and voted in.
> 
> As you've seen, I opened a pull request for these.  I think we can go ahead
> and implement that and make sure it's resolved before the GCC 13 release.
> 
> Or we could temporarily mangle them as an extension, i.e. u9_Float32x.
> 
> I would expect _Float64x, at least, to be fairly popular.

If we get the mangling for _Float<N>x agreed on, whether it is DFx<N>_ as
you proposed, or DF<N>x or DF<N>x_, sure, I agree we should just enable
those too and will tweak the patch.  It would then fix also PR85518.

Though, when we add support for _Float<N>x and declare they are extended
floating-point types, the question is about subrank comparisons, shall those
have lower conversion subrank than _Float<M> type with the same conversion
rank or the other way around?  Say on x86_64 where _Float32x and _Float64
has the same rank, shall (_Float32x) x + 0.0f64 have _Float32x type or
_Float64?
And, shall we support f32x etc. constant literal suffixes (with pedwarn
always even in C++23)?

> > The patch wants to keep backwards compatibility with how __float128 has
> > been handled in C++ before, both for mangling and behavior in binary
> > operations, overload resolution etc.  So, there are some backend changes
> > where for C __float128 and _Float128 are the same type (float128_type_node
> > and float128t_type_node are the same pointer), but for C++ they are distinct
> > types which mangle differently and _Float128 is treated as extended
> > floating-point type while __float128 is treated as non-standard floating
> > point type.
> 
> How important do you think this backwards compatibility is?
> 
> As I mentioned in the ABI proposal, I think it makes sense to make
> __float128 an alias for std::float128_t, and continue using the current
> mangling for __float128.

I thought it is fairly important because __float128 has been around in GCC
for 19 years already.  To be precise, I think e.g. for x86_64 GCC 3.4
introduced it, but mangling was implemented only in GCC 4.1 (2006), before we ICEd
on those.  Until glibc 2.26 (2017) one had to use libquadmath when
math library functions were needed, but since then one can just use libm.
__float128 is on some targets (e.g. PA) just another name for long double,
not a distinct type.

Another thing are the PowerPC __ieee128 and __ibm128 type, I think for the
former we can't make it the same type as _Float128, because e.g. libstdc++
code relies on __ieee128 and __ibm128 being long double type of the other
ABI, so they should mangle as long double of the other ABI.  But in that
case they can't act as distinct types when long double should mangle the
same as they do.  And it would be weird if those types in one
-mabi=*longdouble mode worked as standard floating-point type and in another
as extended floating-point type, rather than just types which are neither
standard nor extended as before.

> I don't think we want the two types to have different semantics.  If we want
> to support existing __float128 code that relies on implicit narrowing
> conversions, we could allow them generally with a pedwarn using the 'bad'
> conversion machinery.  That's probably useful anyway for better diagnostics.

So you mean instead of
+      if (fcode == REAL_TYPE
+         && tcode == REAL_TYPE
+         && (extended_float_type_p (from)
+             || extended_float_type_p (to))
+         && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
+       return NULL;
before conv = build_conv (ck_std, to, conv); do those checks in else if
after:
      if ((same_type_p (to, type_promotes_to (from))
           || (underlying_type && same_type_p (to, underlying_type)))
          && next_conversion (conv)->rank <= cr_promotion)
        conv->rank = cr_promotion;
and pedwarn there (or somewhere later?) and set conv->bad_p = true;?
I can certainly try that what will it do on the tests in the patch.

> > The patch predefines __STDCPP_FLOAT{16,32,64,128}_T__ macros when
> > those types are available, but only for C++23, while the underlying types
> > are available in C++98 and later including the {f,F}{16,32,64,128} literal
> > suffixes (but those with a pedwarn for C++20 and earlier).  My understanding
> > is that it needs to be predefined by the compiler, on the other side
> > predefining even for older modes when <stdfloat> is a new C++23 header
> > would be weird.  One can find out if _Float{16,32,64,128} is supported in
> > C++ by
> > defined(__FLT{16,32,64,128}_MANT_DIG__) && !defined(__FLT32X_MANT_DIG__)
> > (unfortunately not just the former because GCC 7-12 predefined those too)
> > or perhaps __GNUC__ >= 13 && defined(__FLT{16,32,64,128}_MANT_DIG__)
> > (but that doesn't work well with older G++ 13 snapshots).
> 
> As Joseph says, I wouldn't worry about older GCC 13 snapshots.

Ok.

> > As for std::bfloat16_t, three targets (aarch64, arm and x86) apparently
> > "support" __bf16 type which has the bfloat16 format, but isn't really
> > usable, e.g. {aarch64,arm,ix86}_invalid_conversion disallow any conversions
> > from or to type with BFmode, {aarch64,arm,ix86}_invalid_unary_op disallows
> > any unary operations on those except for ADDR_EXPR and
> > {aarch64,arm,ix86}_invalid_binary_op disallows any binary operation on
> > those.  So, I think we satisfy:
> > "If the implementation supports an extended floating-point type with the
> > properties, as specified by ISO/IEC/IEEE 60559, of radix (b) of 2, storage
> > width in bits (k) of 16, precision in bits (p) of 8, maximum exponent (emax)
> > of 127, and exponent field width in bits (w) of 8, then the typedef-name
> > std::bfloat16_t is defined in the header <stdfloat> and names such a type,
> > the macro __STDCPP_BFLOAT16_T__ is defined, and the floating-point literal
> > suffixes bf16 and BF16 are supported."
> > because we don't really support those right now.
> > The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> > shouldn't support it, in the PR there is a partial patch to do so, but
> > the big question is if it should be supported as the __bf16 type those
> > 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> > and add conversions to/from at least SFmode but probably also DFmode, TFmode
> > and XFmode on x86 and implement arithmetics on those through conversion to
> > SFmode, performing arithmetics there and conversion back.
> 
> Sounds good.  And I've proposed DFb16_ mangling.

I saw, thanks for doing that.

> I'll leave that question to people more involved with FP codegen.

Yeah, we'll need to discuss this with the ARM and Intel folks.
In any case, that part is for incremental changes.

> > Or there is the possibility to keep __bf16 a lame type one can't convert
> > to/from or perform most unary and all binary ops on it, and add for C++
> > a new type (say __bfloat16_t or whatever else), agree on mangling in
> > Itanium ABI and implement full support just for that type.
> 
> Preserving the existing useless semantics doesn't sound worthwhile.

Ok.

	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-16 17:34   ` Jakub Jelinek
@ 2022-09-17  8:58     ` Jason Merrill
  2022-09-19 16:39       ` Jakub Jelinek
  0 siblings, 1 reply; 16+ messages in thread
From: Jason Merrill @ 2022-09-17  8:58 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On 9/16/22 13:34, Jakub Jelinek wrote:
> On Fri, Sep 16, 2022 at 01:48:54PM +0200, Jason Merrill wrote:
>> On 9/12/22 04:05, Jakub Jelinek wrote:
>>> The following patch implements the compiler part of C++23
>>> P1467R9 - Extended floating-point types and standard names compiler part
>>> by introducing _Float{16,32,64,128} as keywords and builtin types
>>> like they are implemented for C already since GCC 7.
>>> It doesn't introduce _Float{32,64,128}x for C++, those remain C only
>>> for now, mainly because https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
>>> has mangling for:
>>> ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
>>> but doesn't for _FloatNx.  And it doesn't add anything for bfloat16_t
>>> support, see below.
>>> Regarding mangling, I think mangling _FloatNx as DF <number> x _ would be
>>> possible, but would need to be discussed and voted in.
>>
>> As you've seen, I opened a pull request for these.  I think we can go ahead
>> and implement that and make sure it's resolved before the GCC 13 release.
>>
>> Or we could temporarily mangle them as an extension, i.e. u9_Float32x.
>>
>> I would expect _Float64x, at least, to be fairly popular.
> 
> If we get the mangling for _Float<N>x agreed on, whether it is DFx<N>_ as
> you proposed, or DF<N>x or DF<N>x_, sure, I agree we should just enable
> those too and will tweak the patch.  It would then fix also PR85518.
> 
> Though, when we add support for _Float<N>x and declare they are extended
> floating-point types, the question is about subrank comparisons, shall those
> have lower conversion subrank than _Float<M> type with the same conversion
> rank or the other way around?  Say on x86_64 where _Float32x and _Float64
> has the same rank, shall (_Float32x) x + 0.0f64 have _Float32x type or
> _Float64?
> And, shall we support f32x etc. constant literal suffixes (with pedwarn
> always even in C++23)?
> 
>>> The patch wants to keep backwards compatibility with how __float128 has
>>> been handled in C++ before, both for mangling and behavior in binary
>>> operations, overload resolution etc.  So, there are some backend changes
>>> where for C __float128 and _Float128 are the same type (float128_type_node
>>> and float128t_type_node are the same pointer), but for C++ they are distinct
>>> types which mangle differently and _Float128 is treated as extended
>>> floating-point type while __float128 is treated as non-standard floating
>>> point type.
>>
>> How important do you think this backwards compatibility is?
>>
>> As I mentioned in the ABI proposal, I think it makes sense to make
>> __float128 an alias for std::float128_t, and continue using the current
>> mangling for __float128.
> 
> I thought it is fairly important because __float128 has been around in GCC
> for 19 years already.  To be precise, I think e.g. for x86_64 GCC 3.4
> introduced it, but mangling was implemented only in GCC 4.1 (2006), before we ICEd
> on those.  Until glibc 2.26 (2017) one had to use libquadmath when
> math library functions were needed, but since then one can just use libm.
> __float128 is on some targets (e.g. PA) just another name for long double,
> not a distinct type.

I think we certainly want to continue to support __float128, what I'm 
wondering is how much changing it to mean _Float128 will affect existing 
code.  I would guess that a lot of code that just works on __float128 
will continue to work without modification.  Does anyone know of 
significant existing uses of __float128?

> Another thing are the PowerPC __ieee128 and __ibm128 type, I think for the
> former we can't make it the same type as _Float128, because e.g. libstdc++
> code relies on __ieee128 and __ibm128 being long double type of the other
> ABI, so they should mangle as long double of the other ABI.  But in that
> case they can't act as distinct types when long double should mangle the
> same as they do.  And it would be weird if those types in one
> -mabi=*longdouble mode worked as standard floating-point type and in another
> as extended floating-point type, rather than just types which are neither
> standard nor extended as before.

Absolutely we don't want to mess with __ieee128 and __ibm128.  And I 
guess that means that we need to preserve the non-standard type handling 
for the alternate long double.

I think we can still change __float128 to be _Float128 on PPC and other 
targets where it's currently an alias for long double.

It seems to me that it's a question of what provides the better 
transition path for users.  I imagine we'll want to encourage people to 
replace __float128 with std::float128_t everywhere.

In the existing model, it's not portable whether

void f(long double) { }
void f(__float128) { }

is an overload or an erroneous redefinition.  In the new model, you can 
portably write

void f(long double) { }
void f(std::float128_t) { }

and existing __float128 code will call the second one.  Old code that 
had conditional __float128 overloads when it's different from long 
double will need to change to have unconditional _Float128 overloads.

If we don't change __float128 to mean _Float128, we require fewer 
immediate changes for a library that does try to support all 
floating-point types, but it will need changes to support _Float128 and 
will need to keep around conditional __float128 overloads indefinitely.

>> I don't think we want the two types to have different semantics.  If we want
>> to support existing __float128 code that relies on implicit narrowing
>> conversions, we could allow them generally with a pedwarn using the 'bad'
>> conversion machinery.  That's probably useful anyway for better diagnostics.
> 
> So you mean instead of
> +      if (fcode == REAL_TYPE
> +         && tcode == REAL_TYPE
> +         && (extended_float_type_p (from)
> +             || extended_float_type_p (to))
> +         && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
> +       return NULL;
> before conv = build_conv (ck_std, to, conv); do those checks in else if
> after:
>        if ((same_type_p (to, type_promotes_to (from))
>             || (underlying_type && same_type_p (to, underlying_type)))
>            && next_conversion (conv)->rank <= cr_promotion)
>          conv->rank = cr_promotion;
> and pedwarn there (or somewhere later?) and set conv->bad_p = true;?
> I can certainly try that what will it do on the tests in the patch.

Set bad_p there; the pedwarn should go in the bad_p handling in 
convert_like_internal.

Jason


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-17  8:58     ` Jason Merrill
@ 2022-09-19 16:39       ` Jakub Jelinek
  2022-09-26 21:15         ` Jason Merrill
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-19 16:39 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On Sat, Sep 17, 2022 at 10:58:54AM +0200, Jason Merrill wrote:
> > I thought it is fairly important because __float128 has been around in GCC
> > for 19 years already.  To be precise, I think e.g. for x86_64 GCC 3.4
> > introduced it, but mangling was implemented only in GCC 4.1 (2006), before we ICEd
> > on those.  Until glibc 2.26 (2017) one had to use libquadmath when
> > math library functions were needed, but since then one can just use libm.
> > __float128 is on some targets (e.g. PA) just another name for long double,
> > not a distinct type.
> 
> I think we certainly want to continue to support __float128, what I'm
> wondering is how much changing it to mean _Float128 will affect existing
> code.  I would guess that a lot of code that just works on __float128 will
> continue to work without modification.  Does anyone know of significant
> existing uses of __float128?

I know boost uses it in its cstdfloat.hpp and stuff that uses it.

> > Another thing are the PowerPC __ieee128 and __ibm128 type, I think for the
> > former we can't make it the same type as _Float128, because e.g. libstdc++
> > code relies on __ieee128 and __ibm128 being long double type of the other
> > ABI, so they should mangle as long double of the other ABI.  But in that
> > case they can't act as distinct types when long double should mangle the
> > same as they do.  And it would be weird if those types in one
> > -mabi=*longdouble mode worked as standard floating-point type and in another
> > as extended floating-point type, rather than just types which are neither
> > standard nor extended as before.
> 
> Absolutely we don't want to mess with __ieee128 and __ibm128.  And I guess
> that means that we need to preserve the non-standard type handling for the
> alternate long double.
> 
> I think we can still change __float128 to be _Float128 on PPC and other
> targets where it's currently an alias for long double.
> 
> It seems to me that it's a question of what provides the better transition
> path for users.  I imagine we'll want to encourage people to replace
> __float128 with std::float128_t everywhere.
> 
> In the existing model, it's not portable whether
> 
> void f(long double) { }
> void f(__float128) { }
> 
> is an overload or an erroneous redefinition.  In the new model, you can
> portably write
> 
> void f(long double) { }
> void f(std::float128_t) { }
> 
> and existing __float128 code will call the second one.  Old code that had
> conditional __float128 overloads when it's different from long double will
> need to change to have unconditional _Float128 overloads.
> 
> If we don't change __float128 to mean _Float128, we require fewer immediate
> changes for a library that does try to support all floating-point types, but
> it will need changes to support _Float128 and will need to keep around
> conditional __float128 overloads indefinitely.

I agree that we should judge on what makes the forward path for users
better.
I just think we serve users better if we keep __float128 as is, it will be
then better consistent with other weird types like __float80 (on x86/ia64,
same representation/mode as long double, but distinct with separate
mangling), __fpreg on ia64 etc.  It is true that whether __float128 is
distinct or same type as other standard or non-standard types right now
differs from target to target (on x86 obviously it is distinct from all
other currently supported types because we didn't have other IEEE quad
type but __float80 was distinct even if we had one, ia64 has distinct
__float128 unless it is HP-UX where it is same type as long double,
on PA it is same as long double if __float128 exists at all, on powerpc
it is a define to __ieee128 right now where __ieee128 is same type as long
double in the -mabi=ieeelongdouble, and distinct type otherwise (but only
with -mvsx, otherwise it isn't supported (on by default for ppc64le but not
the others)).  So, code that wants to overload with __float128 or use
__float128 in template arguments needs to do some ifdefs to find out
what it should do.  But, if we make __float128 the same as _Float128,
I think it will mean people actually need to make the conditions even more
complex, because what __float128 will be and how it will behave will depend
on the compiler version.
I believe libraries with floating point stuff will want to add
std::{float{16,32,64,128},bfloat16}_t overloads eventually, not just
std::float128_t overloads, and it will be better if it uses the standard
f{16,32,64,128} literal suffixes, builtins, library functions etc. rather
than Q suffixes, *q builtins, libquadmath functions etc.
Say on x86 it would be inconsistent if __float80 remains to be some
non-standard type, but __float128 is now extended type.  And when
__float128 and _Float128 is distinct, we can keep clean DF128_ mangling
for the latter.

Anyway, here is an updated patch that adds also _Float{32,64,128}x support
with DF{32,64,128}x mangling and demangling and the conv->bad_p + pedwarn
change.  __float128 is still distinct from _Float128.

2022-09-19  Jakub Jelinek  <jakub@redhat.com>

	PR c++/106652
	PR c++/85518
gcc/
	* tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE
	enumerator.
	* tree.h (float128t_type_node): Define.
	* tree.cc (build_common_tree_nodes): Initialize float128t_type_node.
	* builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that
	_Float<N> is supported in C++ too.
	* config/i386/i386.cc (ix86_mangle_type): Only mangle as "g"
	float128t_type_node.
	* config/i386/i386-builtins.cc (ix86_init_builtin_types): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
	* config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph,
	_mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of
	0.0f.
	* config/ia64/ia64.cc (ia64_init_builtins): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
	* config/rs6000/rs6000-c.cc (is_float128_p): Also return true
	for float128t_type_node if non-NULL.
	* config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle
	float128_type_node as "u9__ieee128".
	* config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
gcc/c-family/
	* c-common.cc (c_common_reswords): Change _Float{16,32,64,128} and
	_Float{32,64,128}x flags from D_CONLY to 0.
	(shorten_binary_op): Punt if common_type returns error_mark_node.
	(shorten_compare): Likewise.
	(c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128}
	and _Float{32,64,128}x builtin types if available.  For C++
	clear float128t_type_node.
	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
	__STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported.
	* c-lex.cc (interpret_float): For q/Q suffixes prefer
	float128t_type_node over float128_type_node.  Allow
	{f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn
	for C++20 and older.  Allow {f,F}{32,64,128}x suffixes for C++
	with pedwarn.  Don't call excess_precision_type for C++.
gcc/cp/
	* cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement
	P1467R9 - Extended floating-point types and standard names except
	for std::bfloat16_t for now.  Declare.
	(extended_float_type_p): New inline function.
	* mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node
	as DF{16,32,64,128}_.  Mangle float{32,64,128}x_type_node as
	DF{32,64,128}x.  Remove FIXED_POINT_TYPE mangling that conflicts
	with that.
	* typeck2.cc (check_narrowing): If one of ftype or type is extended
	floating-point type, compare floating-point conversion ranks.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Handle
	CASE_RID_FLOATN_NX.
	(cp_parser_simple_type_specifier): Likewise and diagnose missing
	_Float<N> or _Float<N>x support if not supported by target.
	* typeck.cc (cp_compare_floating_point_conversion_ranks): New function.
	(cp_common_type): If both types are REAL_TYPE and one or both are
	extended floating-point types, select common type based on comparison
	of floating-point conversion ranks and subranks.
	(cp_build_binary_op): Diagnose operation with floating point arguments
	with unordered conversion ranks.
	* call.cc (standard_conversion): For floating-point conversion, if
	either from or to are extended floating-point types, set conv->bad_p
	for implicit conversion from larger to smaller conversion rank or
	with unordered conversion ranks.
	(convert_like_internal): Emit a pedwarn on such conversions.
	(build_conditional_expr): Diagnose operation with floating point
	arguments with unordered conversion ranks.
	(convert_arg_to_ellipsis): Don't promote extended floating-point types
	narrower than double to double.
	(compare_ics): Implement P1467R9 [over.ics.rank]/4 changes.
gcc/testsuite/
	* g++.dg/cpp23/ext-floating1.C: New test.
	* g++.dg/cpp23/ext-floating2.C: New test.
	* g++.dg/cpp23/ext-floating3.C: New test.
	* g++.dg/cpp23/ext-floating4.C: New test.
	* g++.dg/cpp23/ext-floating5.C: New test.
	* g++.dg/cpp23/ext-floating6.C: New test.
	* g++.dg/cpp23/ext-floating7.C: New test.
	* g++.dg/cpp23/ext-floating8.C: New test.
	* g++.dg/cpp23/ext-floating9.C: New test.
	* g++.dg/cpp23/ext-floating10.C: New test.
	* g++.dg/cpp23/ext-floating.h: New file.
	* g++.target/i386/float16-1.C: Adjust expected diagnostics.
libcpp/
	* expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} and
	{f,F}{32,64,128}x suffixes for C++.
include/
	* demangle.h (enum demangle_component_type): Add
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
	(struct demangle_component): Add u.s_extended_builtin member.
libiberty/
	* cp-demangle.c (d_dump): Handle
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Don't handle
	DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_make_extended_builtin_type): New function.
	(cplus_demangle_builtin_types): Add _Float entry.
	(cplus_demangle_type): For DF demangle it as _Float<N> or
	_Float<N>x rather than fixed point which conflicts with it.
	(d_count_templates_scopes): Handle
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Just break; for
	DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
	Don't handle DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_print_comp_inner): Likewise.
	* cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump.
	* testsuite/demangle-expected: Replace _Z3xxxDFyuVb test
	with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb.  Add
	_Z3xxxDF32xDF64xDF128xCDF32xVb test.
fixincludes/
	* inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2,
	glibc_cxx_floatn_3): New fixes.
	* tests/base/bits/floatn.h: New file.
	* fixincl.x: Regenerated.

--- gcc/tree-core.h.jj	2022-09-12 10:31:28.082541926 +0200
+++ gcc/tree-core.h	2022-09-19 15:13:26.501132289 +0200
@@ -690,6 +690,10 @@ enum tree_index {
 			     - TI_FLOATN_NX_TYPE_FIRST		\
 			     + 1)
 
+  /* Type used by certain backends for __float128, which in C++ should be
+     distinct type from _Float128 for backwards compatibility reasons.  */
+  TI_FLOAT128T_TYPE,
+
   /* Put the complex types after their component types, so that in (sequential)
      tree streaming we can assert that their component types have already been
      handled (see tree-streamer.cc:record_common_node).  */
--- gcc/tree.h.jj	2022-09-12 10:31:28.206540208 +0200
+++ gcc/tree.h	2022-09-19 15:13:26.502132276 +0200
@@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree ex
 #define float64x_type_node		global_trees[TI_FLOAT64X_TYPE]
 #define float128x_type_node		global_trees[TI_FLOAT128X_TYPE]
 
+/* Type used by certain backends for __float128, which in C++ should be
+   distinct type from _Float128 for backwards compatibility reasons.  */
+#define float128t_type_node		global_trees[TI_FLOAT128T_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]
--- gcc/tree.cc.jj	2022-09-16 20:40:14.075827838 +0200
+++ gcc/tree.cc	2022-09-19 15:13:26.504132248 +0200
@@ -9461,6 +9461,7 @@ build_common_tree_nodes (bool signed_cha
       layout_type (FLOATN_NX_TYPE_NODE (i));
       SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
     }
+  float128t_type_node = float128_type_node;
 
   float_ptr_type_node = build_pointer_type (float_type_node);
   double_ptr_type_node = build_pointer_type (double_type_node);
--- gcc/builtins.def.jj	2022-09-12 10:31:27.055556152 +0200
+++ gcc/builtins.def	2022-09-19 15:13:26.505132234 +0200
@@ -115,8 +115,8 @@ along with GCC; see the file COPYING3.
    we are compiling for the C language with GNU extensions, we enable the name
    without the __builtin_ prefix as well as the name with the __builtin_
    prefix.  C++ does not enable these names by default because they don't have
-   the _Float<N> and _Float<N>X keywords, and a class based library should use
-   the __builtin_ names.  */
+   the _Float<N>x keywords, and a class based library should use the __builtin_
+   names.  */
 #undef DEF_FLOATN_BUILTIN
 #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS)	\
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,	\
--- gcc/config/i386/i386.cc.jj	2022-09-12 10:31:27.422551068 +0200
+++ gcc/config/i386/i386.cc	2022-09-19 15:13:26.508132193 +0200
@@ -22711,7 +22711,10 @@ ix86_mangle_type (const_tree type)
       return "DF16_";
     case E_TFmode:
       /* __float128 is "g".  */
-      return "g";
+      if (type == float128t_type_node)
+	return "g";
+      /* _Float128 should mangle as "DF128_" done in generic code.  */
+      return NULL;
     case E_XFmode:
       /* "long double" or __float80 is "e".  */
       return "e";
--- gcc/config/i386/i386-builtins.cc.jj	2022-09-16 20:40:13.546835024 +0200
+++ gcc/config/i386/i386-builtins.cc	2022-09-19 15:13:26.508132193 +0200
@@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void)
   lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
 
   /* 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");
+     _Float128, so for C we only need to register the __float128 name for
+     it.  For C++, we create a distinct type which will mangle differently
+     (g) vs. _Float128 (DF128_) and behave backwards compatibly.  */
+  if (float128t_type_node == NULL_TREE)
+    {
+      float128t_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (float128t_type_node)
+	= TYPE_PRECISION (float128_type_node);
+      SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
+      layout_type (float128t_type_node);
+    }
+  lang_hooks.types.register_builtin_type (float128t_type_node, "__float128");
 
   ix86_register_float16_builtin_type ();
 
--- gcc/config/i386/avx512fp16intrin.h.jj	2022-01-11 23:11:21.760299007 +0100
+++ gcc/config/i386/avx512fp16intrin.h	2022-09-19 15:13:26.509132179 +0200
@@ -183,21 +183,21 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_setzero_ph (void)
 {
-  return _mm_set1_ph (0.0f);
+  return _mm_set1_ph (0.0f16);
 }
 
 extern __inline __m256h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm256_setzero_ph (void)
 {
-  return _mm256_set1_ph (0.0f);
+  return _mm256_set1_ph (0.0f16);
 }
 
 extern __inline __m512h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm512_setzero_ph (void)
 {
-  return _mm512_set1_ph (0.0f);
+  return _mm512_set1_ph (0.0f16);
 }
 
 extern __inline __m128h
@@ -358,7 +358,8 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_set_sh (_Float16 __F)
 {
-  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F);
+  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
+		     __F);
 }
 
 /* Create a vector with element 0 as *P and the rest zero.  */
@@ -366,7 +367,7 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_load_sh (void const *__P)
 {
-  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
 		     *(_Float16 const *) __P);
 }
 
--- gcc/config/ia64/ia64.cc.jj	2022-09-12 10:31:27.436550875 +0200
+++ gcc/config/ia64/ia64.cc	2022-09-19 15:13:26.510132166 +0200
@@ -10466,11 +10466,19 @@ ia64_init_builtins (void)
 	= build_pointer_type (build_qualified_type
 			      (char_type_node, TYPE_QUAL_CONST));
 
-      (*lang_hooks.types.register_builtin_type) (float128_type_node,
+      if (float128t_type_node == NULL_TREE)
+	{
+	  float128t_type_node = make_node (REAL_TYPE);
+	  TYPE_PRECISION (float128t_type_node)
+	    = TYPE_PRECISION (float128_type_node);
+	  layout_type (float128t_type_node);
+	  SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
+	}
+      (*lang_hooks.types.register_builtin_type) (float128t_type_node,
 						 "__float128");
 
       /* TFmode support builtins.  */
-      ftype = build_function_type_list (float128_type_node, NULL_TREE);
+      ftype = build_function_type_list (float128t_type_node, NULL_TREE);
       decl = add_builtin_function ("__builtin_infq", ftype,
 				   IA64_BUILTIN_INFQ, BUILT_IN_MD,
 				   NULL, NULL_TREE);
@@ -10481,7 +10489,7 @@ ia64_init_builtins (void)
 				   NULL, NULL_TREE);
       ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
 					const_string_type,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_nanq", ftype,
@@ -10496,8 +10504,8 @@ ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
-					float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
+					float128t_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_fabsq", ftype,
 				   IA64_BUILTIN_FABSQ, BUILT_IN_MD,
@@ -10505,9 +10513,9 @@ ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
-					float128_type_node,
-					float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
+					float128t_type_node,
+					float128t_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_copysignq", ftype,
 				   IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
--- gcc/config/rs6000/rs6000-c.cc.jj	2022-09-13 18:57:29.326969961 +0200
+++ gcc/config/rs6000/rs6000-c.cc	2022-09-19 15:13:26.511132152 +0200
@@ -808,6 +808,7 @@ static inline bool
 is_float128_p (tree t)
 {
   return (t == float128_type_node
+	  || (t && t == float128t_type_node)
 	  || (TARGET_IEEEQUAD
 	      && TARGET_LONG_DOUBLE_128
 	      && t == long_double_type_node));
--- gcc/config/rs6000/rs6000.cc.jj	2022-09-16 20:40:13.572834671 +0200
+++ gcc/config/rs6000/rs6000.cc	2022-09-19 15:13:26.514132111 +0200
@@ -20272,7 +20272,11 @@ rs6000_mangle_type (const_tree type)
 
   if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type)))
     return "g";
-  if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type)))
+  if (SCALAR_FLOAT_TYPE_P (type)
+      && FLOAT128_IEEE_P (TYPE_MODE (type))
+      /* _Float128 should mangle as DF128_ (done in generic code)
+	 rather than u9__ieee128 (used for __ieee128 and __float128).  */
+      && type != float128_type_node)
     return "u9__ieee128";
 
   if (type == vector_pair_type_node)
--- gcc/config/rs6000/rs6000-builtin.cc.jj	2022-09-13 18:57:29.325969975 +0200
+++ gcc/config/rs6000/rs6000-builtin.cc	2022-09-19 15:13:26.514132111 +0200
@@ -733,7 +733,22 @@ rs6000_init_builtins (void)
       if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
 	ieee128_float_type_node = long_double_type_node;
       else
-	ieee128_float_type_node = float128_type_node;
+	{
+	  /* For C we only need to register the __ieee128 name for
+	     it.  For C++, we create a distinct type which will mangle
+	     differently (u9__ieee128) vs. _Float128 (DF128_) and behave
+	     backwards compatibly.  */
+	  if (float128t_type_node == NULL_TREE)
+	    {
+	      float128t_type_node = make_node (REAL_TYPE);
+	      TYPE_PRECISION (float128t_type_node)
+		= TYPE_PRECISION (float128_type_node);
+	      layout_type (float128t_type_node);
+	      SET_TYPE_MODE (float128t_type_node,
+			     TYPE_MODE (float128_type_node));
+	    }
+	  ieee128_float_type_node = float128t_type_node;
+	}
       t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
       lang_hooks.types.register_builtin_type (ieee128_float_type_node,
 					      "__ieee128");
--- gcc/c-family/c-common.cc.jj	2022-09-16 20:40:13.507835554 +0200
+++ gcc/c-family/c-common.cc	2022-09-19 15:17:07.408105952 +0200
@@ -352,13 +352,13 @@ const struct c_common_resword c_common_r
   { "_Bool",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	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 },
+  { "_Float16",         RID_FLOAT16,    0 },
+  { "_Float32",         RID_FLOAT32,    0 },
+  { "_Float64",         RID_FLOAT64,    0 },
+  { "_Float128",        RID_FLOAT128,   0 },
+  { "_Float32x",        RID_FLOAT32X,   0 },
+  { "_Float64x",        RID_FLOAT64X,   0 },
+  { "_Float128x",       RID_FLOAT128X,  0 },
   { "_Decimal32",       RID_DFLOAT32,  D_CONLY },
   { "_Decimal64",       RID_DFLOAT64,  D_CONLY },
   { "_Decimal128",      RID_DFLOAT128, D_CONLY },
@@ -1429,8 +1429,11 @@ shorten_binary_op (tree result_type, tre
 	  == TYPE_PRECISION (TREE_TYPE (arg0)))
       && unsigned0 == unsigned1
       && (unsigned0 || !uns))
-    return c_common_signed_or_unsigned_type
-      (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+    {
+      tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
+      if (ctype != error_mark_node)
+	return c_common_signed_or_unsigned_type (unsigned0, ctype);
+    }
 
   else if (TREE_CODE (arg0) == INTEGER_CST
 	   && (unsigned1 || !uns)
@@ -3202,9 +3205,10 @@ shorten_compare (location_t loc, tree *o
 
   else if (unsignedp0 == unsignedp1 && real1 == real2
 	   && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
-	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
+	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)
+	   && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)))
+	      != error_mark_node)
     {
-      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
       type = c_common_signed_or_unsigned_type (unsignedp0
 					       || TYPE_UNSIGNED (*restype_ptr),
 					       type);
@@ -4378,11 +4382,18 @@ 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++)
+  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));
+    }
+
+  /* For C, let float128t_type_node (__float128 in some backends) be the
+     same type as float128_type_node (_Float128), for C++ let those
+     be distinct types that mangle and behave differently.  */
+  if (c_dialect_cxx ())
+    float128t_type_node = NULL_TREE;
 
   /* Only supported decimal floating point extension if the target
      actually supports underlying modes. */
--- gcc/c-family/c-cppbuiltin.cc.jj	2022-09-19 11:53:19.873593647 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2022-09-19 15:19:38.939030140 +0200
@@ -1247,6 +1247,14 @@ c_cpp_builtins (cpp_reader *pfile)
     {
       if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
 	continue;
+      if (c_dialect_cxx ()
+	  && cxx_dialect > cxx20
+	  && !floatn_nx_types[i].extended)
+	{
+	  char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
+	  sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
+	  cpp_define (pfile, name);
+	}
       char prefix[20], csuffix[20];
       sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
 	       floatn_nx_types[i].extended ? "X" : "");
--- gcc/c-family/c-lex.cc.jj	2022-09-12 10:31:27.254553396 +0200
+++ gcc/c-family/c-lex.cc	2022-09-19 15:20:48.373078972 +0200
@@ -960,6 +960,10 @@ interpret_float (const cpp_token *token,
 	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
 
 	type = c_common_type_for_mode (mode, 0);
+	/* For Q suffix, prefer float128t_type_node (__float128) type
+	   over float128_type_node (_Float128) type if they are distinct.  */
+	if (type == float128_type_node && float128t_type_node)
+	  type = float128t_type_node;
 	gcc_assert (type);
       }
     else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
@@ -979,8 +983,17 @@ interpret_float (const cpp_token *token,
 	    error ("unsupported non-standard suffix on floating constant");
 	    return error_mark_node;
 	  }
+	else if (c_dialect_cxx () && !extended)
+	  {
+	    if (cxx_dialect < cxx23)
+	      pedwarn (input_location, OPT_Wpedantic,
+		       "%<f%d%> or %<F%d%> suffix on floating constant only "
+		       "available with %<-std=c++2b%> or %<-std=gnu++2b%>",
+		       n, n);
+	  }
 	else
-	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
+	  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;
@@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token,
     else
       type = double_type_node;
 
-  const_type = excess_precision_type (type);
+  if (c_dialect_cxx ())
+    const_type = NULL_TREE;
+  else
+    const_type = excess_precision_type (type);
   if (!const_type)
     const_type = type;
 
--- gcc/cp/cp-tree.h.jj	2022-09-19 11:53:19.780594924 +0200
+++ gcc/cp/cp-tree.h	2022-09-19 15:38:36.820475429 +0200
@@ -7947,6 +7947,7 @@ extern tree require_complete_type		(tree
 extern tree complete_type			(tree);
 extern tree complete_type_or_else		(tree, tree);
 extern tree complete_type_or_maybe_complain	(tree, tree, tsubst_flags_t);
+extern int cp_compare_floating_point_conversion_ranks (tree, tree);
 inline bool type_unknown_p			(const_tree);
 enum { ce_derived, ce_type, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
@@ -8689,6 +8690,18 @@ struct push_access_scope_guard
   }
 };
 
+/* True if TYPE is an extended floating-point type.  */
+
+inline bool
+extended_float_type_p (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i)
+    if (type == FLOATN_TYPE_NODE (i))
+      return true;
+  return false;
+}
+
 #if CHECKING_P
 namespace selftest {
   extern void run_cp_tests (void);
--- gcc/cp/mangle.cc.jj	2022-09-12 10:31:27.754546470 +0200
+++ gcc/cp/mangle.cc	2022-09-19 15:39:17.863916098 +0200
@@ -2648,63 +2648,24 @@ write_builtin_type (tree type)
 	write_string ("Dd");
       else if (type == dfloat128_type_node || type == fallback_dfloat128_type)
 	write_string ("De");
+      else if (type == float16_type_node)
+	write_string ("DF16_");
+      else if (type == float32_type_node)
+	write_string ("DF32_");
+      else if (type == float64_type_node)
+	write_string ("DF64_");
+      else if (type == float128_type_node)
+	write_string ("DF128_");
+      else if (type == float32x_type_node)
+	write_string ("DF32x");
+      else if (type == float64x_type_node)
+	write_string ("DF64x");
+      else if (type == float128x_type_node)
+	write_string ("DF128x");
       else
 	gcc_unreachable ();
       break;
 
-    case FIXED_POINT_TYPE:
-      write_string ("DF");
-      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
-	write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
-      if (type == fract_type_node
-	  || type == sat_fract_type_node
-	  || type == accum_type_node
-	  || type == sat_accum_type_node)
-	write_char ('i');
-      else if (type == unsigned_fract_type_node
-	       || type == sat_unsigned_fract_type_node
-	       || type == unsigned_accum_type_node
-	       || type == sat_unsigned_accum_type_node)
-	write_char ('j');
-      else if (type == short_fract_type_node
-	       || type == sat_short_fract_type_node
-	       || type == short_accum_type_node
-	       || type == sat_short_accum_type_node)
-	write_char ('s');
-      else if (type == unsigned_short_fract_type_node
-	       || type == sat_unsigned_short_fract_type_node
-	       || type == unsigned_short_accum_type_node
-	       || type == sat_unsigned_short_accum_type_node)
-	write_char ('t');
-      else if (type == long_fract_type_node
-	       || type == sat_long_fract_type_node
-	       || type == long_accum_type_node
-	       || type == sat_long_accum_type_node)
-	write_char ('l');
-      else if (type == unsigned_long_fract_type_node
-	       || type == sat_unsigned_long_fract_type_node
-	       || type == unsigned_long_accum_type_node
-	       || type == sat_unsigned_long_accum_type_node)
-	write_char ('m');
-      else if (type == long_long_fract_type_node
-	       || type == sat_long_long_fract_type_node
-	       || type == long_long_accum_type_node
-	       || type == sat_long_long_accum_type_node)
-	write_char ('x');
-      else if (type == unsigned_long_long_fract_type_node
-	       || type == sat_unsigned_long_long_fract_type_node
-	       || type == unsigned_long_long_accum_type_node
-	       || type == sat_unsigned_long_long_accum_type_node)
-	write_char ('y');
-      else
-	sorry ("mangling unknown fixed point type");
-      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
-      if (TYPE_SATURATING (type))
-	write_char ('s');
-      else
-	write_char ('n');
-      break;
-
     default:
       gcc_unreachable ();
     }
--- gcc/cp/typeck2.cc.jj	2022-09-13 09:21:28.197539576 +0200
+++ gcc/cp/typeck2.cc	2022-09-19 15:13:26.518132056 +0200
@@ -997,12 +997,25 @@ check_narrowing (tree type, tree init, t
   else if (TREE_CODE (ftype) == REAL_TYPE
 	   && TREE_CODE (type) == REAL_TYPE)
     {
-      if ((same_type_p (ftype, long_double_type_node)
-	   && (same_type_p (type, double_type_node)
-	       || same_type_p (type, float_type_node)))
-	  || (same_type_p (ftype, double_type_node)
-	      && same_type_p (type, float_type_node))
-	  || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
+      if ((extended_float_type_p (ftype) || extended_float_type_p (type))
+	  ? /* "from a floating-point type T to another floating-point type
+	       whose floating-point conversion rank is neither greater than
+	       nor equal to that of T".
+	       So, it is ok if
+	       cp_compare_floating_point_conversion_ranks (ftype, type)
+	       returns -2 (type has greater conversion rank than ftype)
+	       or [-1..1] (type has equal conversion rank as ftype, possibly
+	       different subrank.  Only do this if at least one of the
+	       types is extended floating-point type, otherwise keep doing
+	       what we did before (for the sake of non-standard
+	       backend types).  */
+	    cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
+	  : ((same_type_p (ftype, long_double_type_node)
+	      && (same_type_p (type, double_type_node)
+		  || same_type_p (type, float_type_node)))
+	     || (same_type_p (ftype, double_type_node)
+		 && same_type_p (type, float_type_node))
+	     || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
 	{
 	  if (TREE_CODE (init) == REAL_CST)
 	    {
--- gcc/cp/parser.cc.jj	2022-09-19 12:11:15.891823798 +0200
+++ gcc/cp/parser.cc	2022-09-19 15:43:13.816700641 +0200
@@ -1129,6 +1129,7 @@ cp_keyword_starts_decl_specifier_p (enum
     case RID_UNSIGNED:
     case RID_FLOAT:
     case RID_DOUBLE:
+    CASE_RID_FLOATN_NX:
     case RID_VOID:
       /* CV qualifiers.  */
     case RID_CONST:
@@ -19746,6 +19747,14 @@ cp_parser_simple_type_specifier (cp_pars
     case RID_DOUBLE:
       type = double_type_node;
       break;
+    CASE_RID_FLOATN_NX:
+      type = FLOATN_NX_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST);
+      if (type == NULL_TREE)
+	error ("%<_Float%d%s%> is not supported on this target",
+	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n,
+	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].extended
+	       ? "x" : "");
+      break;
     case RID_VOID:
       type = void_type_node;
       break;
--- gcc/cp/typeck.cc.jj	2022-09-16 20:40:13.650833611 +0200
+++ gcc/cp/typeck.cc	2022-09-19 15:55:31.143706567 +0200
@@ -267,6 +267,132 @@ merge_type_attributes_from (tree type, t
   return cp_build_type_attribute_variant (type, attrs);
 }
 
+/* Compare floating point conversion ranks and subranks of T1 and T2
+   types.  If T1 and T2 have unordered conversion ranks, return 3.
+   If T1 has greater conversion rank than T2, return 2.
+   If T2 has greater conversion rank than T1, return -2.
+   If T1 has equal conversion rank as T2, return -1, 0 or 1 depending
+   on if T1 has smaller, equal or greater conversion subrank than
+   T2.  */
+
+int
+cp_compare_floating_point_conversion_ranks (tree t1, tree t2)
+{
+  tree mv1 = TYPE_MAIN_VARIANT (t1);
+  tree mv2 = TYPE_MAIN_VARIANT (t2);
+  int extended1 = 0;
+  int extended2 = 0;
+
+  if (mv1 == mv2)
+    return 0;
+
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i)
+    {
+      if (mv1 == FLOATN_NX_TYPE_NODE (i))
+	extended1 = i + 1;
+      if (mv2 == FLOATN_NX_TYPE_NODE (i))
+	extended2 = i + 1;
+    }
+  if (extended2 && !extended1)
+    {
+      int ret = cp_compare_floating_point_conversion_ranks (t2, t1);
+      return ret == 3 ? 3 : -ret;
+    }
+
+  const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
+  const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
+  gcc_assert (fmt1->b == 2 && fmt2->b == 2);
+  /* For {ibm,mips}_extended_format formats, the type has variable
+     precision up to ~2150 bits when the first double is around maximum
+     representable double and second double is subnormal minimum.
+     So, e.g. for __ibm128 vs. std::float128_t, they have unordered
+     ranks.  */
+  int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1))
+	    ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p);
+  int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2))
+	    ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p);
+  /* The rank of a floating point type T is greater than the rank of
+     any floating-point type whose set of values is a proper subset
+     of the set of values of T.  */
+  if ((p1 > p2 && fmt1->emax >= fmt2->emax)
+       || (p1 == p2 && fmt1->emax > fmt2->emax))
+    return 2;
+  if ((p1 < p2 && fmt1->emax <= fmt2->emax)
+       || (p1 == p2 && fmt1->emax < fmt2->emax))
+    return -2;
+  if ((p1 > p2 && fmt1->emax < fmt2->emax)
+       || (p1 < p2 && fmt1->emax > fmt2->emax))
+    return 3;
+  if (!extended1 && !extended2)
+    {
+      /* The rank of long double is greater than the rank of double, which
+	 is greater than the rank of float.  */
+      if (t1 == long_double_type_node)
+	return 2;
+      else if (t2 == long_double_type_node)
+	return -2;
+      if (t1 == double_type_node)
+	return 2;
+      else if (t2 == double_type_node)
+	return -2;
+      if (t1 == float_type_node)
+	return 2;
+      else if (t2 == float_type_node)
+	return -2;
+      return 0;
+    }
+  /* Two extended floating-point types with the same set of values have equal
+     ranks.  */
+  if (extended1 && extended2)
+    {
+      if ((extended1 <= NUM_FLOATN_TYPES) == (extended2 <= NUM_FLOATN_TYPES))
+	{
+	  /* Prefer higher extendedN value.  */
+	  if (extended1 > extended2)
+	    return 1;
+	  else if (extended1 < extended2)
+	    return -1;
+	  else
+	    return 0;
+	}
+      else if (extended1 <= NUM_FLOATN_TYPES)
+	/* Prefer _FloatN type over _FloatMx type.  */
+	return 1;
+      else if (extended2 <= NUM_FLOATN_TYPES)
+	return -1;
+      else
+	return 0;
+    }
+
+  tree *p;
+  int cnt = 0;
+  for (p = &float_type_node; p <= &long_double_type_node; ++p)
+    {
+      const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p));
+      gcc_assert (fmt3->b == 2);
+      int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p))
+		? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p);
+      if (p1 == p3 && fmt1->emax == fmt3->emax)
+	++cnt;
+    }
+  /* An extended floating-point type with the same set of values
+     as exactly one cv-unqualified standard floating-point type
+     has a rank equal to the rank of that standard floating-point
+     type.
+
+     An extended floating-point type with the same set of values
+     as more than one cv-unqualified standard floating-point type
+     has a rank equal to the rank of double.
+
+     Thus, if the latter is true and t2 is long double, t2
+     has higher rank.  */
+  if (cnt > 1 && mv2 == long_double_type_node)
+    return -2;
+  /* Otherwise, they have equal rank, but extended types
+     (other than std::bfloat16_t) have higher subrank.  */
+  return 1;
+}
+
 /* Return the common type for two arithmetic types T1 and T2 under the
    usual arithmetic conversions.  The default conversions have already
    been applied, and enumerated types converted to their compatible
@@ -337,6 +463,23 @@ cp_common_type (tree t1, tree t2)
   if (code2 == REAL_TYPE && code1 != REAL_TYPE)
     return build_type_attribute_variant (t2, attributes);
 
+  if (code1 == REAL_TYPE
+      && (extended_float_type_p (t1) || extended_float_type_p (t2)))
+    {
+      tree mv1 = TYPE_MAIN_VARIANT (t1);
+      tree mv2 = TYPE_MAIN_VARIANT (t2);
+      if (mv1 == mv2)
+	return build_type_attribute_variant (t1, attributes);
+
+      int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2);
+      if (cmpret == 3)
+	return error_mark_node;
+      else if (cmpret >= 0)
+	return build_type_attribute_variant (t1, attributes);
+      else
+	return build_type_attribute_variant (t2, attributes);
+    }
+
   /* Both real or both integers; use the one with greater precision.  */
   if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
     return build_type_attribute_variant (t1, attributes);
@@ -5037,7 +5180,20 @@ cp_build_binary_op (const op_location_t
        = targetm.invalid_binary_op (code, type0, type1)))
     {
       if (complain & tf_error)
-	error (invalid_op_diag);
+	{
+	  if (code0 == REAL_TYPE
+	      && code1 == REAL_TYPE
+	      && (extended_float_type_p (type0)
+		  || extended_float_type_p (type1))
+	      && cp_compare_floating_point_conversion_ranks (type0,
+							     type1) == 3)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  else
+	    error (invalid_op_diag);
+	}
       return error_mark_node;
     }
 
@@ -5907,6 +6063,19 @@ cp_build_binary_op (const op_location_t
       && (shorten || common || short_compare))
     {
       result_type = cp_common_type (type0, type1);
+      if (result_type == error_mark_node
+	  && code0 == REAL_TYPE
+	  && code1 == REAL_TYPE
+	  && (extended_float_type_p (type0) || extended_float_type_p (type1))
+	  && cp_compare_floating_point_conversion_ranks (type0, type1) == 3)
+	{
+	  if (complain & tf_error)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  return error_mark_node;
+	}
       if (complain & tf_warning)
 	{
 	  do_warn_double_promotion (result_type, type0, type1,
--- gcc/cp/call.cc.jj	2022-09-19 13:28:53.511058032 +0200
+++ gcc/cp/call.cc	2022-09-19 17:03:19.280237553 +0200
@@ -1541,6 +1541,22 @@ standard_conversion (tree to, tree from,
 	   || (underlying_type && same_type_p (to, underlying_type)))
 	  && next_conversion (conv)->rank <= cr_promotion)
 	conv->rank = cr_promotion;
+
+      /* A prvalue of floating-point type can be converted to a prvalue of
+	 another floating-point type with a greater or equal conversion
+	 rank ([conv.rank]).  A prvalue of standard floating-point type can
+	 be converted to a prvalue of another standard floating-point type.
+	 For backwards compatibility with handling __float128 and other
+	 non-standard floating point types, allow all implicit floating
+	 point conversions if neither type is extended floating-point
+	 type and if at least one of them is, fail if they have unordered
+	 conversion rank or from has higher conversion rank.  */
+      if (fcode == REAL_TYPE
+	  && tcode == REAL_TYPE
+	  && (extended_float_type_p (from)
+	      || extended_float_type_p (to))
+	  && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
+	conv->bad_p = true;
     }
   else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
 	   && vector_types_convertible_p (from, to, false))
@@ -5842,6 +5858,21 @@ build_conditional_expr (const op_locatio
       /* In this case, there is always a common type.  */
       result_type = type_after_usual_arithmetic_conversions (arg2_type,
 							     arg3_type);
+      if (result_type == error_mark_node
+	  && TREE_CODE (arg2_type) == REAL_TYPE
+	  && TREE_CODE (arg3_type) == REAL_TYPE
+	  && (extended_float_type_p (arg2_type)
+	      || extended_float_type_p (arg3_type))
+	  && cp_compare_floating_point_conversion_ranks (arg2_type,
+							 arg3_type) == 3)
+	{
+	  if (complain & tf_error)
+	    error_at (loc, "operands to %<?:%> have unordered conversion rank "
+			   "of types %qT and %qT",
+		      arg2_type, arg3_type);
+	  return error_mark_node;
+	}
+
       if (complain & tf_warning)
 	do_warn_double_promotion (result_type, arg2_type, arg3_type,
 				  "implicit conversion from %qH to %qI to "
@@ -7906,6 +7937,27 @@ convert_like_internal (conversion *convs
 				"direct-initialization",
 				totype, TREE_TYPE (expr));
 
+      if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+	  && TREE_CODE (totype) == REAL_TYPE
+	  && (extended_float_type_p (TREE_TYPE (expr))
+	      || extended_float_type_p (totype)))
+	switch (cp_compare_floating_point_conversion_ranks (TREE_TYPE (expr),
+							    totype))
+	  {
+	  case 2:
+	    pedwarn (loc, 0, "converting to %qH from %qI with greater "
+			     "conversion rank", totype, TREE_TYPE (expr));
+	    complained = true;
+	    break;
+	  case 3:
+	    pedwarn (loc, 0, "converting to %qH from %qI with unordered "
+			     "conversion ranks", totype, TREE_TYPE (expr));
+	    complained = true;
+	    break;
+	  default:
+	    break;
+	  }
+
       for (; t ; t = next_conversion (t))
 	{
 	  if (t->kind == ck_user && t->cand->reason)
@@ -8531,7 +8583,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
   if (TREE_CODE (arg_type) == REAL_TYPE
       && (TYPE_PRECISION (arg_type)
 	  < TYPE_PRECISION (double_type_node))
-      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
+      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))
+      && !extended_float_type_p (arg_type))
     {
       if ((complain & tf_warning)
 	  && warn_double_promotion && !c_inhibit_evaluation_warnings)
@@ -11719,6 +11772,75 @@ compare_ics (conversion *ics1, conversio
 	return 1;
     }
 
+  {
+    /* A conversion in either direction between floating-point type FP1 and
+       floating-point type FP2 is better than a conversion in the same
+       direction between FP1 and arithmetic type T3 if
+       - the floating-point conversion rank of FP1 is equal to the rank of
+	 FP2, and
+       - T3 is not a floating-point type, or T3 is a floating-point type
+	 whose rank is not equal to the rank of FP1, or the floating-point
+	 conversion subrank of FP2 is greater than the subrank of T3.  */
+    tree fp1 = from_type1;
+    tree fp2 = to_type1;
+    tree fp3 = from_type2;
+    tree t3 = to_type2;
+    int ret = 1;
+    if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3))
+      {
+	std::swap (fp1, fp2);
+	std::swap (fp3, t3);
+      }
+    if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3)
+	&& TREE_CODE (fp1) == REAL_TYPE
+	/* Only apply this rule if at least one of the 3 types is
+	   extended floating-point type, otherwise keep them as
+	   before for compatibility reasons with types like __float128.
+	   float, double and long double alone have different conversion
+	   ranks and so when just those 3 types are involved, this
+	   rule doesn't trigger.  */
+	&& (extended_float_type_p (fp1)
+	    || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2))
+	    || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3))))
+      {
+	if (TREE_CODE (fp2) != REAL_TYPE)
+	  {
+	    ret = -ret;
+	    std::swap (fp2, t3);
+	  }
+	if (TREE_CODE (fp2) == REAL_TYPE)
+	  {
+	    if (cp_compare_floating_point_conversion_ranks (fp1, fp2) + 1U
+		<= 2U)
+	      {
+		/* Conversion ranks of FP1 and FP2 are equal.  */
+		if (TREE_CODE (t3) != REAL_TYPE
+		    || (cp_compare_floating_point_conversion_ranks (fp1, t3)
+			+ 1U > 2U))
+		  /* FP1 <-> FP2 conversion is better.  */
+		  return ret;
+		int c = cp_compare_floating_point_conversion_ranks (fp2, t3);
+		gcc_assert (c + 1U <= 2U);
+		if (c == 1)
+		  /* Conversion subrank of FP2 is greater than subrank of T3.
+		     FP1 <-> FP2 conversion is better.  */
+		  return ret;
+		else if (c == -1)
+		  /* Conversion subrank of FP2 is less than subrank of T3.
+		     FP1 <-> T3 conversion is better.  */
+		  return -ret;
+	      }
+	    else if (TREE_CODE (t3) == REAL_TYPE
+		     && (cp_compare_floating_point_conversion_ranks (fp1, t3)
+			 + 1U <= 2U))
+	      /* Conversion ranks of FP1 and FP2 are not equal, conversion
+		 ranks of FP1 and T3 are equal.
+		 FP1 <-> T3 conversion is better.  */
+	      return -ret;
+	  }
+      }
+  }
+
   if (TYPE_PTR_P (from_type1)
       && TYPE_PTR_P (from_type2)
       && TYPE_PTR_P (to_type1)
--- gcc/testsuite/g++.dg/cpp23/ext-floating1.C.jj	2022-09-19 15:13:26.526131946 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C	2022-09-19 18:10:04.270447220 +0200
@@ -0,0 +1,447 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+static_assert (!is_same<float, double>::value);
+static_assert (!is_same<float, long double>::value);
+static_assert (!is_same<double, long double>::value);
+static_assert (is_same<decltype (0.0f), float>::value);
+static_assert (is_same<decltype (0.0F), float>::value);
+static_assert (is_same<decltype (0.0), double>::value);
+static_assert (is_same<decltype (0.0l), long double>::value);
+static_assert (is_same<decltype (0.0L), long double>::value);
+static_assert (is_same<decltype (0.0f + 0.0F), float>::value);
+static_assert (is_same<decltype (0.0F + 0.0f), float>::value);
+static_assert (is_same<decltype (0.0 + 0.0), double>::value);
+static_assert (is_same<decltype (0.0l + 0.0L), long double>::value);
+static_assert (is_same<decltype (0.0L + 0.0l), long double>::value);
+#ifdef __SIZEOF_FLOAT128__
+static_assert (is_same<decltype (0.0q), __float128>::value);
+static_assert (is_same<decltype (0.0Q), __float128>::value);
+static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value);
+static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float, float16_t>::value);
+static_assert (!is_same<double, float16_t>::value);
+static_assert (!is_same<long double, float16_t>::value);
+static_assert (is_same<decltype (0.0f16), float16_t>::value);
+static_assert (is_same<decltype (0.0F16), float16_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float, float32_t>::value);
+static_assert (!is_same<double, float32_t>::value);
+static_assert (!is_same<long double, float32_t>::value);
+static_assert (!is_same<decltype (0.0f), float32_t>::value);
+static_assert (!is_same<decltype (0.0F), float32_t>::value);
+static_assert (is_same<decltype (0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32), float32_t>::value);
+static_assert (!is_same<decltype (0.0f32), float>::value);
+static_assert (!is_same<decltype (0.0F32), float>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float, float64_t>::value);
+static_assert (!is_same<double, float64_t>::value);
+static_assert (!is_same<long double, float64_t>::value);
+static_assert (!is_same<decltype (0.0), float64_t>::value);
+static_assert (is_same<decltype (0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64), float64_t>::value);
+static_assert (!is_same<decltype (0.0f64), double>::value);
+static_assert (!is_same<decltype (0.0F64), double>::value);
+static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float, float128_t>::value);
+static_assert (!is_same<double, float128_t>::value);
+static_assert (!is_same<long double, float128_t>::value);
+static_assert (!is_same<decltype (0.0l), float128_t>::value);
+static_assert (!is_same<decltype (0.0L), float128_t>::value);
+static_assert (is_same<decltype (0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128), float128_t>::value);
+static_assert (!is_same<decltype (0.0f128), long double>::value);
+static_assert (!is_same<decltype (0.0F128), long double>::value);
+static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value);
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<float128_t, __float128>::value);
+static_assert (!is_same<decltype (0.0q), float128_t>::value);
+static_assert (!is_same<decltype (0.0Q), float128_t>::value);
+static_assert (!is_same<decltype (0.0f128), __float128>::value);
+static_assert (!is_same<decltype (0.0F128), __float128>::value);
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+static_assert (!is_same<float, bfloat16_t>::value);
+static_assert (!is_same<double, bfloat16_t>::value);
+static_assert (!is_same<long double, bfloat16_t>::value);
+static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value);
+#endif
+#ifdef __FLT32X_MANT_DIG__
+static_assert (!is_same<float, _Float32x>::value);
+static_assert (!is_same<double, _Float32x>::value);
+static_assert (!is_same<long double, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F), _Float32x>::value);
+static_assert (is_same<decltype (0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float>::value);
+static_assert (!is_same<decltype (0.0F32x), float>::value);
+static_assert (is_same<decltype (0.0f32x + 0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F32x), _Float32x>::value);
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float16_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f16), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F16), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float16_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float32_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F32), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float32_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float64_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f64), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F64), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float64_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float128_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f128), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F128), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float128_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float128_t>::value);
+#endif
+#endif
+#ifdef __FLT64X_MANT_DIG__
+static_assert (!is_same<float, _Float64x>::value);
+static_assert (!is_same<double, _Float64x>::value);
+static_assert (!is_same<long double, _Float64x>::value);
+static_assert (!is_same<decltype (0.0), _Float64x>::value);
+static_assert (is_same<decltype (0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), double>::value);
+static_assert (!is_same<decltype (0.0F64x), double>::value);
+static_assert (is_same<decltype (0.0f64x + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F64x), _Float64x>::value);
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float16_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f16), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F16), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float16_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float32_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f32), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F32), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float32_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float64_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F64), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float64_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float128_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f128), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F128), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float128_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<_Float64x, __float128>::value);
+static_assert (!is_same<decltype (0.0q), _Float64x>::value);
+static_assert (!is_same<decltype (0.0Q), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), __float128>::value);
+static_assert (!is_same<decltype (0.0F64x), __float128>::value);
+#endif
+#endif
+#ifdef __FLT128X_MANT_DIG__
+static_assert (!is_same<float, _Float128x>::value);
+static_assert (!is_same<double, _Float128x>::value);
+static_assert (!is_same<long double, _Float128x>::value);
+static_assert (!is_same<decltype (0.0l), _Float128x>::value);
+static_assert (!is_same<decltype (0.0L), _Float128x>::value);
+static_assert (is_same<decltype (0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), long double>::value);
+static_assert (!is_same<decltype (0.0F128x), long double>::value);
+static_assert (is_same<decltype (0.0f128x + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F128x), _Float128x>::value);
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float16_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f16), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F16), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float16_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float32_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f32), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F32), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float32_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float64_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f64), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F64), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float64_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float128_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F128), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float128_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<_Float128x, __float128>::value);
+static_assert (!is_same<decltype (0.0q), _Float128x>::value);
+static_assert (!is_same<decltype (0.0Q), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), __float128>::value);
+static_assert (!is_same<decltype (0.0F128x), __float128>::value);
+#endif
+#endif
+static_assert (is_same<decltype (0.0f + 0.0), double>::value);
+static_assert (is_same<decltype (0.0 + 0.0F), double>::value);
+static_assert (is_same<decltype (0.0L + 0.0), long double>::value);
+static_assert (is_same<decltype (0.0 + 0.0L), long double>::value);
+static_assert (is_same<decltype (0.0L + 0.0f), long double>::value);
+static_assert (is_same<decltype (0.0F + 0.0l), long double>::value);
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
+static_assert (!is_same<float16_t, float32_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<float16_t, float64_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float16_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT32X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f16 + 0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F16), _Float32x>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT64X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f16 + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F16), _Float64x>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f16 + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F16), _Float128x>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<float32_t, float64_t>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float32_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT32X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f32 + 0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F32), _Float32x>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT64X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f32 + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F32), _Float64x>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f32 + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F32), _Float128x>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float64_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT32X_MANT_DIG__) \
+    && __FLT64_MAX_EXP__ == __FLT32X_MAX_EXP__ \
+    && __FLT64_MANT_DIG__ == __FLT32X_MANT_DIG__
+static_assert (is_same<decltype (0.0f64 + 0.0f32x), float64_t>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F64), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT64X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f64 + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F64), _Float64x>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f64 + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F64), _Float128x>::value);
+#endif
+#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT32X_MANT_DIG__) \
+    && __FLT128_MAX_EXP__ >= __FLT32X_MAX_EXP__ \
+    && __FLT128_MANT_DIG__ >= __FLT32X_MANT_DIG__
+static_assert (is_same<decltype (0.0f128 + 0.0f32x), float128_t>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F128), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT64X_MANT_DIG__) \
+    && __FLT128_MAX_EXP__ >= __FLT64X_MAX_EXP__ \
+    && __FLT128_MANT_DIG__ >= __FLT64X_MANT_DIG__
+static_assert (is_same<decltype (0.0f128 + 0.0f64x), float128_t>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F128), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f128 + 0.0f128x), _Float128>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F128), _Float128>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
+static_assert (!is_same<bfloat16_t, float32_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<bfloat16_t, float64_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<bfloat16_t, float128_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f16), float>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value);
+#endif
+#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f16), double>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value);
+#endif
+#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f32), double>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value);
+#endif
+#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
+#endif
+#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \
+    && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
+// An extended floating-point type with the same set of values as more than one
+// cv-unqualified standard floating-point type has a rank equal to the rank of
+// double.
+// Then long double will have higher rank than float64_t.
+static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value);
+#endif
+#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value);
+#endif
+#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \
+    && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered.
+static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value);
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value);
+#endif
+#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value);
+#endif
+#endif
+
+void foo (float) {}
+void foo (double) {}
+void foo (long double) {}
+#ifdef __STDCPP_FLOAT16_T__
+void foo (float16_t) {}
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+void foo (float32_t) {}
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+void foo (float64_t) {}
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+void foo (float128_t) {}
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+void foo (bfloat16_t) {}
+#endif
+#ifdef __FLT32X_MANT_DIG__
+void foo (_Float32x) {}
+#endif
+#ifdef __FLT64X_MANT_DIG__
+void foo (_Float64x) {}
+#endif
+#ifdef __FLT128X_MANT_DIG__
+void foo (_Float128x) {}
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating2.C.jj	2022-09-19 15:13:26.526131946 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating2.C	2022-09-19 17:30:32.400901278 +0200
@@ -0,0 +1,157 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+float fa = 1.0f;
+float fb = (float) 1.0f;
+float fc = 1.0;
+float fd = (float) 1.0;
+float fe = 1.0L;
+float ff = (float) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float fg = 1.0Q;
+float fh = (float) 1.0Q;
+#endif
+double da = 1.0f;
+double db = (double) 1.0f;
+double dc = 1.0;
+double dd = (double) 1.0;
+double de = 1.0L;
+double df = (double) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+double dg = 1.0Q;
+double dh = (double) 1.0Q;
+#endif
+long double lda = 1.0f;
+long double ldb = (long double) 1.0f;
+long double ldc = 1.0;
+long double ldd = (long double) 1.0;
+long double lde = 1.0L;
+long double ldf = (long double) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+long double ldg = 1.0Q;
+long double ldh = (long double) 1.0Q;
+__float128 qa = 1.0f;
+__float128 qb = (__float128) 1.0f;
+__float128 qc = 1.0;
+__float128 qd = (__float128) 1.0;
+__float128 qe = 1.0L;
+__float128 qf = (__float128) 1.0L;
+__float128 qg = 1.0Q;
+__float128 qh = (__float128) 1.0Q;
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16a = 1.0F16;
+float16_t f16b = (float16_t) 1.0F16;
+#ifdef __STDCPP_FLOAT32_T__
+float16_t f16c = 1.0F32;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float32' with greater conversion rank" "" { target { float16 && float32 } } }
+float16_t f16d = (float16_t) 1.0F32;
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float16_t f16e = 1.0F64;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float64' with greater conversion rank" "" { target { float16 && float64 } } }
+float16_t f16f = (float16_t) 1.0F64;
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float16_t f16g = 1.0F128;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float128' with greater conversion rank" "" { target { float16 && float128 } } }
+float16_t f16h = (float16_t) 1.0F128;
+#endif
+float16_t f16j = (float16_t) 1.0f;
+float16_t f16l = (float16_t) 1.0;
+float16_t f16n = (float16_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float16_t f16p = (float16_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+#ifdef __STDCPP_FLOAT16_T__
+float32_t f32a = 1.0F16;
+float32_t f32b = (float32_t) 1.0F16;
+#endif
+float32_t f32c = 1.0F32;
+float32_t f32d = (float32_t) 1.0F32;
+#ifdef __STDCPP_FLOAT64_T__
+float32_t f32e = 1.0F64;		// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float64' with greater conversion rank" "" { target { float32 && float64 } } }
+float32_t f32f = (float32_t) 1.0F64;
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float32_t f32g = 1.0F128;		// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float128' with greater conversion rank" "" { target { float32 && float128 } } }
+float32_t f32h = (float32_t) 1.0F128;
+#endif
+#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__
+float32_t f32i = 1.0f;
+#endif
+float32_t f32j = (float32_t) 1.0f;
+float32_t f32l = (float32_t) 1.0;
+float32_t f32n = (float32_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float32_t f32p = (float32_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+#ifdef __STDCPP_FLOAT16_T__
+float64_t f64a = 1.0F16;
+float64_t f64b = (float64_t) 1.0F16;
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float64_t f64c = 1.0F32;
+float64_t f64d = (float64_t) 1.0F32;
+#endif
+float64_t f64e = 1.0F64;
+float64_t f64f = (float64_t) 1.0F64;
+#ifdef __STDCPP_FLOAT128_T__
+float64_t f64g = 1.0F128;		// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '_Float128' with greater conversion rank" "" { target { float64 && float128 } } }
+float64_t f64h = (float64_t) 1.0F128;
+#endif
+#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__
+float64_t f64i = 1.0f;
+#endif
+float64_t f64j = (float64_t) 1.0f;
+#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__
+float64_t f64k = 1.0;
+#endif
+float64_t f64l = (float64_t) 1.0;
+float64_t f64n = (float64_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float64_t f64p = (float64_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+#ifdef __STDCPP_FLOAT16_T__
+float128_t f128a = 1.0F16;
+float128_t f128b = (float128_t) 1.0F16;
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float128_t f128c = 1.0F32;
+float128_t f128d = (float128_t) 1.0F32;
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float128_t f128e = 1.0F64;
+float128_t f128f = (float128_t) 1.0F64;
+#endif
+float128_t f128g = 1.0F128;
+float128_t f128h = (float128_t) 1.0F128;
+#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__
+float128_t f128i = 1.0f;
+#endif
+float128_t f128j = (float128_t) 1.0f;
+#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__
+float128_t f128k = 1.0;
+#endif
+float128_t f128l = (float128_t) 1.0;
+#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106
+float128_t f128m = 1.0L;
+#endif
+float128_t f128n = (float128_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float128_t f128o = 1.0Q;
+float128_t f128p = (float128_t) 1.0Q;
+#endif
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating3.C.jj	2022-09-19 15:13:26.526131946 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C	2022-09-19 17:33:51.274179774 +0200
@@ -0,0 +1,134 @@
+// P1467R9 - Extended floating-point types and standard names.
+// Variant of ext-floating2.C test with x86 specific assumptions
+// about float, double, long double and existence of __float128.
+// And some further tests.
+// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
+    || !defined(__SIZEOF_FLOAT128__)
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16i = 1.0f;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } }
+float16_t f16k = 1.0;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } }
+float16_t f16m = 1.0L;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } }
+float16_t f16o = 1.0Q;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '__float128' with greater conversion rank" "" { target float16 } }
+#endif
+float32_t f32i = 1.0f;
+float32_t f32k = 1.0;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" }
+float32_t f32m = 1.0L;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" }
+float32_t f32o = 1.0Q;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '__float128' with greater conversion rank" }
+float64_t f64i = 1.0f;
+float64_t f64k = 1.0;
+float64_t f64m = 1.0L;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" }
+float64_t f64o = 1.0Q;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '__float128' with greater conversion rank" }
+float128_t f128i = 1.0f;
+float128_t f128k = 1.0;
+float128_t f128m = 1.0L;
+float128_t f128o = 1.0Q;
+
+#ifdef __STDCPP_FLOAT16_T__
+constexpr float16_t f16x = 1.0F16;
+#endif
+constexpr float32_t f32x = 2.0F32;
+constexpr float64_t f64x = 3.0F64;
+constexpr float128_t f128x = 4.0F128;
+constexpr float fx = 5.0f;
+constexpr double dx = 6.0;
+constexpr long double ldx = 7.0L;
+
+constexpr int foo (float32_t) { return 1; }
+constexpr int foo (float64_t) { return 2; }
+constexpr int bar (float) { return 3; }
+constexpr int bar (double) { return 4; }
+constexpr int bar (long double) { return 5; }
+constexpr int baz (float32_t) { return 6; }
+constexpr int baz (float64_t) { return 7; }
+constexpr int baz (float128_t) { return 8; }
+constexpr int qux (float64_t) { return 9; }
+constexpr int qux (float32_t) { return 10; }
+constexpr int fred (long double) { return 11; }
+constexpr int fred (double) { return 12; }
+constexpr int fred (float) { return 13; }
+constexpr int thud (float128_t) { return 14; }
+constexpr int thud (float64_t) { return 15; }
+constexpr int thud (float32_t) { return 16; }
+struct S {
+  constexpr operator float32_t () const { return 1.0f32; }
+  constexpr operator float64_t () const { return 2.0f64; }
+};
+struct T {
+  constexpr operator float64_t () const { return 3.0f64; }
+  constexpr operator float32_t () const { return 4.0f32; }
+};
+
+void
+test (S s, T t)
+{
+#ifdef __STDCPP_FLOAT16_T__
+  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (foo (float (2.0)) == 1);
+  static_assert (foo (double (3.0)) == 2);
+  constexpr double x (s);
+  static_assert (x == 2.0);
+#ifdef __STDCPP_FLOAT16_T__
+  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (bar (f32x) == 3);
+  static_assert (bar (f64x) == 4);
+  bar (f128x);					// { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" }
+						// { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 }
+						// { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 }
+						// { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 }
+  static_assert (bar (fx) == 3);
+  static_assert (bar (dx) == 4);
+  static_assert (bar (ldx) == 5);
+#ifdef __STDCPP_FLOAT16_T__
+  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (baz (f32x) == 6);
+  static_assert (baz (f64x) == 7);
+  static_assert (baz (f128x) == 8);
+  static_assert (baz (fx) == 6);
+  static_assert (baz (dx) == 7);
+  static_assert (baz (ldx) == 8);
+#ifdef __STDCPP_FLOAT16_T__
+  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (qux (float (2.0)) == 10);
+  static_assert (qux (double (3.0)) == 9);
+  constexpr double y (t);
+  static_assert (y == 3.0);
+#ifdef __STDCPP_FLOAT16_T__
+  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (fred (f32x) == 13);
+  static_assert (fred (f64x) == 12);
+  fred (f128x);					// { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" }
+						// { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 }
+						// { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 }
+						// { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 }
+  static_assert (fred (fx) == 13);
+  static_assert (fred (dx) == 12);
+  static_assert (fred (ldx) == 11);
+#ifdef __STDCPP_FLOAT16_T__
+  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (thud (f32x) == 16);
+  static_assert (thud (f64x) == 15);
+  static_assert (thud (f128x) == 14);
+  static_assert (thud (fx) == 16);
+  static_assert (thud (dx) == 15);
+  static_assert (thud (ldx) == 14);
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating4.C.jj	2022-09-19 15:13:26.540131753 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C	2022-09-19 17:31:01.429503718 +0200
@@ -0,0 +1,126 @@
+// P1467R9 - Extended floating-point types and standard names.
+// Variant of ext-floating3.C test with different specific assumptions
+// about float, double, long double.
+// float, double and long double are assumed to be IEEE 754 single, double
+// and quad.
+// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } }
+// { dg-options "" }
+// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } }
+// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } }
+
+#include "ext-floating.h"
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16i = 1.0f;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } }
+float16_t f16k = 1.0;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } }
+float16_t f16m = 1.0L;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } }
+#endif
+float32_t f32i = 1.0f;
+float32_t f32k = 1.0;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" }
+float32_t f32m = 1.0L;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" }
+float64_t f64i = 1.0f;
+float64_t f64k = 1.0;
+float64_t f64m = 1.0L;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" }
+float128_t f128i = 1.0f;
+float128_t f128k = 1.0;
+float128_t f128m = 1.0L;
+
+#ifdef __STDCPP_FLOAT16_T__
+constexpr float16_t f16x = 1.0F16;
+#endif
+constexpr float32_t f32x = 2.0F32;
+constexpr float64_t f64x = 3.0F64;
+constexpr float128_t f128x = 4.0F128;
+constexpr float fx = 5.0f;
+constexpr double dx = 6.0;
+constexpr long double ldx = 7.0L;
+
+constexpr int foo (float32_t) { return 1; }
+constexpr int foo (float64_t) { return 2; }
+constexpr int bar (float) { return 3; }
+constexpr int bar (double) { return 4; }
+constexpr int bar (long double) { return 5; }
+constexpr int baz (float32_t) { return 6; }
+constexpr int baz (float64_t) { return 7; }
+constexpr int baz (float128_t) { return 8; }
+constexpr int qux (float64_t) { return 9; }
+constexpr int qux (float32_t) { return 10; }
+constexpr int fred (long double) { return 11; }
+constexpr int fred (double) { return 12; }
+constexpr int fred (float) { return 13; }
+constexpr int thud (float128_t) { return 14; }
+constexpr int thud (float64_t) { return 15; }
+constexpr int thud (float32_t) { return 16; }
+struct S {
+  constexpr operator float32_t () const { return 1.0f32; }
+  constexpr operator float64_t () const { return 2.0f64; }
+};
+struct T {
+  constexpr operator float64_t () const { return 3.0f64; }
+  constexpr operator float32_t () const { return 4.0f32; }
+};
+
+void
+test (S s, T t)
+{
+#ifdef __STDCPP_FLOAT16_T__
+  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (foo (float (2.0)) == 1);
+  static_assert (foo (double (3.0)) == 2);
+  constexpr double x (s);
+  static_assert (x == 2.0);
+#ifdef __STDCPP_FLOAT16_T__
+  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (bar (f32x) == 3);
+  static_assert (bar (f64x) == 4);
+  static_assert (bar (f128x) == 5);
+  static_assert (bar (fx) == 3);
+  static_assert (bar (dx) == 4);
+  static_assert (bar (ldx) == 5);
+#ifdef __STDCPP_FLOAT16_T__
+  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (baz (f32x) == 6);
+  static_assert (baz (f64x) == 7);
+  static_assert (baz (f128x) == 8);
+  static_assert (baz (fx) == 6);
+  static_assert (baz (dx) == 7);
+  static_assert (baz (ldx) == 8);
+#ifdef __STDCPP_FLOAT16_T__
+  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (qux (float (2.0)) == 10);
+  static_assert (qux (double (3.0)) == 9);
+  constexpr double y (t);
+  static_assert (y == 3.0);
+#ifdef __STDCPP_FLOAT16_T__
+  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (fred (f32x) == 13);
+  static_assert (fred (f64x) == 12);
+  static_assert (fred (f128x) == 11);
+  static_assert (fred (fx) == 13);
+  static_assert (fred (dx) == 12);
+  static_assert (fred (ldx) == 11);
+#ifdef __STDCPP_FLOAT16_T__
+  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (thud (f32x) == 16);
+  static_assert (thud (f64x) == 15);
+  static_assert (thud (f128x) == 14);
+  static_assert (thud (fx) == 16);
+  static_assert (thud (dx) == 15);
+  static_assert (thud (ldx) == 14);
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating5.C.jj	2022-09-19 15:13:26.540131753 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C	2022-09-19 15:13:26.540131753 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// IBM extended long double and _Float128 should have unordered conversion
+// ranks as IBM extended long double has variable precision from 53 bits
+// for denormals to more than 2150 bits for certain numbers.
+// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" }
+
+auto a = 1.0F128 + 1.0L;	// { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" }
+auto b = 1.0L + 1.0F128;	// { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" }
+bool c;
+auto d = c ? 1.0F128 : 1.0L;	// { dg-error "operands to '\\\?:' have unordered conversion rank of types '_Float128' and 'long double'" }
+auto e = c ? 1.0L : 1.0F128;	// { dg-error "operands to '\\\?:' have unordered conversion rank of types 'long double' and '_Float128'" }
--- gcc/testsuite/g++.dg/cpp23/ext-floating6.C.jj	2022-09-19 15:13:26.540131753 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating6.C	2022-09-19 15:13:26.540131753 +0200
@@ -0,0 +1,30 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+float foo (float x, float y, float z) { return x * y + z; }
+double foo (double x, double y, double z) { return x * y + z; }
+long double foo (long double x, long double y, long double z) { return x * y + z; }
+#ifdef __STDCPP_FLOAT16_T__
+float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; }
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating7.C.jj	2022-09-19 15:13:26.540131753 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C	2022-09-19 15:13:26.540131753 +0200
@@ -0,0 +1,119 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float16_runtime } } }
+// { dg-options "" }
+// { dg-add-options float16 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT16_T__
+#error Unexpected
+#endif
+#define WIDTH 16
+#endif
+
+#include <stdarg.h>
+#include "ext-floating.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 TYPE CONCAT (_Float, WIDTH)
+#define CST(C) CONCAT3 (C, f, WIDTH)
+#define CSTU(C) CONCAT3 (C, F, WIDTH)
+
+extern "C" void abort ();
+
+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
+fn (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 = fn (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 ();
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating8.C.jj	2022-09-19 15:13:26.540131753 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C	2022-09-19 15:13:26.540131753 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float32_runtime } } }
+// { dg-options "" }
+// { dg-add-options float32 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT32_T__
+#error Unexpected
+#endif
+#define WIDTH 32
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating9.C.jj	2022-09-19 15:13:26.541131739 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating9.C	2022-09-19 15:13:26.540131753 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float64_runtime } } }
+// { dg-options "" }
+// { dg-add-options float64 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT64_T__
+#error Unexpected
+#endif
+#define WIDTH 64
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating10.C.jj	2022-09-19 15:13:26.541131739 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C	2022-09-19 15:13:26.541131739 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float128_runtime } } }
+// { dg-options "" }
+// { dg-add-options float128 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT128_T__
+#error Unexpected
+#endif
+#define WIDTH 128
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating.h.jj	2022-09-19 15:13:26.541131739 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating.h	2022-09-19 15:13:26.541131739 +0200
@@ -0,0 +1,30 @@
+// P1467R9 - Extended floating-point types and standard names.
+
+namespace std
+{
+  #ifdef __STDCPP_FLOAT16_T__
+  using float16_t = _Float16;
+  #endif
+  #ifdef __STDCPP_FLOAT32_T__
+  using float32_t = _Float32;
+  #endif
+  #ifdef __STDCPP_FLOAT64_T__
+  using float64_t = _Float64;
+  #endif
+  #ifdef __STDCPP_FLOAT128_T__
+  using float128_t = _Float128;
+  #endif
+  #undef __STDCPP_BFLOAT16_T__
+  #ifdef __STDCPP_BFLOAT16_T__
+  using bfloat16_t = __bf16; // ???
+  #endif
+  template<typename T, T v> struct integral_constant {
+    static constexpr T value = v;
+  };
+  typedef integral_constant<bool, false> false_type;
+  typedef integral_constant<bool, true> true_type;
+  template<class T, class U>
+  struct is_same : std::false_type {};
+  template <class T>
+  struct is_same<T, T> : std::true_type {};
+}
--- gcc/testsuite/g++.target/i386/float16-1.C.jj	2022-09-12 10:31:28.051542356 +0200
+++ gcc/testsuite/g++.target/i386/float16-1.C	2022-09-19 15:13:26.546131671 +0200
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -mno-sse2" } */
 
-_Float16/* { dg-error "does not name a type" } */
+_Float16	/* { dg-error "expected unqualified-id before '_Float16'" } */
 foo (_Float16 x) 
 {
   return x;
-}
+}		/* { dg-error "'_Float16' is not supported on this target" } */
--- libcpp/expr.cc.jj	2022-09-12 10:31:28.298538934 +0200
+++ libcpp/expr.cc	2022-09-19 15:13:59.664677834 +0200
@@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfil
 	case 'f': case 'F':
 	  f++;
 	  if (len > 0
-	      && !CPP_OPTION (pfile, cplusplus)
 	      && s[1] >= '1'
 	      && s[1] <= '9'
 	      && fn_bits == 0)
--- include/demangle.h.jj	2022-09-12 10:31:28.254539543 +0200
+++ include/demangle.h	2022-09-19 16:53:01.285662293 +0200
@@ -457,6 +457,11 @@ enum demangle_component_type
   DEMANGLE_COMPONENT_MODULE_PARTITION,
   DEMANGLE_COMPONENT_MODULE_ENTITY,
   DEMANGLE_COMPONENT_MODULE_INIT,
+
+  /* A builtin type with argument.  This holds the builtin type
+     information.  */
+  DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
+
 };
 
 /* Types which are only used internally.  */
@@ -543,6 +548,15 @@ struct demangle_component
       const struct demangle_builtin_type_info *type;
     } s_builtin;
 
+    /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  */
+    struct
+    {
+      /* Builtin type.  */
+      const struct demangle_builtin_type_info *type;
+      short arg;
+      char suffix;
+    } s_extended_builtin;
+
     /* For DEMANGLE_COMPONENT_SUB_STD.  */
     struct
     {
--- libiberty/cp-demangle.c.jj	2022-09-12 10:31:28.350538214 +0200
+++ libiberty/cp-demangle.c	2022-09-19 16:59:22.568468901 +0200
@@ -648,6 +648,13 @@ d_dump (struct demangle_component *dc, i
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
       printf ("builtin type %s\n", dc->u.s_builtin.type->name);
       return;
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
+      {
+	char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 };
+	printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name,
+		dc->u.s_extended_builtin.type->arg, suffix);
+      }
+      return;
     case DEMANGLE_COMPONENT_OPERATOR:
       printf ("operator %s\n", dc->u.s_operator.op->name);
       return;
@@ -771,11 +778,6 @@ d_dump (struct demangle_component *dc, i
     case DEMANGLE_COMPONENT_PTRMEM_TYPE:
       printf ("pointer to member type\n");
       break;
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      printf ("fixed-point type, accum? %d, sat? %d\n",
-              dc->u.s_fixed.accum, dc->u.s_fixed.sat);
-      d_dump (dc->u.s_fixed.length, indent + 2);
-      break;
     case DEMANGLE_COMPONENT_ARGLIST:
       printf ("argument list\n");
       break;
@@ -1109,6 +1111,28 @@ d_make_builtin_type (struct d_info *di,
   return p;
 }
 
+/* Add a new extended builtin type component.  */
+
+static struct demangle_component *
+d_make_extended_builtin_type (struct d_info *di,
+			      const struct demangle_builtin_type_info *type,
+			      short arg, char suffix)
+{
+  struct demangle_component *p;
+
+  if (type == NULL)
+    return NULL;
+  p = d_make_empty (di);
+  if (p != NULL)
+    {
+      p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE;
+      p->u.s_extended_builtin.type = type;
+      p->u.s_extended_builtin.arg = arg;
+      p->u.s_extended_builtin.suffix = suffix;
+    }
+  return p;
+}
+
 /* Add a new operator component.  */
 
 static struct demangle_component *
@@ -2464,6 +2488,7 @@ cplus_demangle_builtin_types[D_BUILTIN_T
   /* 32 */ { NL ("char32_t"),	NL ("char32_t"),	D_PRINT_DEFAULT },
   /* 33 */ { NL ("decltype(nullptr)"),	NL ("decltype(nullptr)"),
 	     D_PRINT_DEFAULT },
+  /* 34 */ { NL ("_Float"),	NL ("_Float"),		D_PRINT_FLOAT },
 };
 
 CP_STATIC_IF_GLIBCPP_V3
@@ -2727,19 +2752,26 @@ cplus_demangle_type (struct d_info *di)
 	  break;
 
 	case 'F':
-	  /* Fixed point types. DF<int bits><length><fract bits><sat>  */
-	  ret = d_make_empty (di);
-	  ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
-	  if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
-	    /* For demangling we don't care about the bits.  */
-	    d_number (di);
-	  ret->u.s_fixed.length = cplus_demangle_type (di);
-	  if (ret->u.s_fixed.length == NULL)
-	    return NULL;
-	  d_number (di);
-	  peek = d_next_char (di);
-	  ret->u.s_fixed.sat = (peek == 's');
-	  break;
+	  /* DF<number>_ - _Float<number>.
+	     DF<number>x - _Float<number>x.  */
+	  {
+	    int arg = d_number (di);
+	    char buf[12];
+	    char suffix = 0;
+	    if (d_peek_char (di) == 'x')
+	      suffix = 'x';
+	    if (!suffix && d_peek_char (di) != '_')
+	      return NULL;
+	    ret
+	      = d_make_extended_builtin_type (di,
+					      &cplus_demangle_builtin_types[34],
+					      arg, suffix);
+	    d_advance (di, 1);
+	    sprintf (buf, "%d", arg);
+	    di->expansion += ret->u.s_extended_builtin.type->len
+			     + strlen (buf) + (suffix != 0);
+	    break;
+	  }
 
 	case 'v':
 	  ret = d_vector_type (di);
@@ -4202,6 +4234,7 @@ d_count_templates_scopes (struct d_print
     case DEMANGLE_COMPONENT_FUNCTION_PARAM:
     case DEMANGLE_COMPONENT_SUB_STD:
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
     case DEMANGLE_COMPONENT_OPERATOR:
     case DEMANGLE_COMPONENT_CHARACTER:
     case DEMANGLE_COMPONENT_NUMBER:
@@ -4210,6 +4243,7 @@ d_count_templates_scopes (struct d_print
     case DEMANGLE_COMPONENT_MODULE_NAME:
     case DEMANGLE_COMPONENT_MODULE_PARTITION:
     case DEMANGLE_COMPONENT_MODULE_INIT:
+    case DEMANGLE_COMPONENT_FIXED_TYPE:
       break;
 
     case DEMANGLE_COMPONENT_TEMPLATE:
@@ -4309,10 +4343,6 @@ d_count_templates_scopes (struct d_print
       d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
       break;
 
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
-      break;
-
     case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
     case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
     case DEMANGLE_COMPONENT_MODULE_ENTITY:
@@ -4580,11 +4610,11 @@ d_find_pack (struct d_print_info *dpi,
     case DEMANGLE_COMPONENT_TAGGED_NAME:
     case DEMANGLE_COMPONENT_OPERATOR:
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
     case DEMANGLE_COMPONENT_SUB_STD:
     case DEMANGLE_COMPONENT_CHARACTER:
     case DEMANGLE_COMPONENT_FUNCTION_PARAM:
     case DEMANGLE_COMPONENT_UNNAMED_TYPE:
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
     case DEMANGLE_COMPONENT_DEFAULT_ARG:
     case DEMANGLE_COMPONENT_NUMBER:
       return NULL;
@@ -5387,6 +5417,18 @@ d_print_comp_inner (struct d_print_info
 			 dc->u.s_builtin.type->java_len);
       return;
 
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
+      if ((options & DMGL_JAVA) == 0)
+	d_append_buffer (dpi, dc->u.s_extended_builtin.type->name,
+			 dc->u.s_extended_builtin.type->len);
+      else
+	d_append_buffer (dpi, dc->u.s_extended_builtin.type->java_name,
+			 dc->u.s_extended_builtin.type->java_len);
+      d_append_num (dpi, dc->u.s_extended_builtin.arg);
+      if (dc->u.s_extended_builtin.suffix)
+	d_append_buffer (dpi, &dc->u.s_extended_builtin.suffix, 1);
+      return;
+
     case DEMANGLE_COMPONENT_VENDOR_TYPE:
       d_print_comp (dpi, options, d_left (dc));
       return;
@@ -5525,22 +5567,6 @@ d_print_comp_inner (struct d_print_info
 	return;
       }
 
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      if (dc->u.s_fixed.sat)
-	d_append_string (dpi, "_Sat ");
-      /* Don't print "int _Accum".  */
-      if (dc->u.s_fixed.length->u.s_builtin.type
-	  != &cplus_demangle_builtin_types['i'-'a'])
-	{
-	  d_print_comp (dpi, options, dc->u.s_fixed.length);
-	  d_append_char (dpi, ' ');
-	}
-      if (dc->u.s_fixed.accum)
-	d_append_string (dpi, "_Accum");
-      else
-	d_append_string (dpi, "_Fract");
-      return;
-
     case DEMANGLE_COMPONENT_ARGLIST:
     case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
       if (d_left (dc) != NULL)
--- libiberty/cp-demangle.h.jj	2022-09-12 10:31:28.399537535 +0200
+++ libiberty/cp-demangle.h	2022-09-19 15:13:26.635130450 +0200
@@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i)
 extern const struct demangle_operator_info cplus_demangle_operators[];
 #endif
 
-#define D_BUILTIN_TYPE_COUNT (34)
+#define D_BUILTIN_TYPE_COUNT (35)
 
 CP_STATIC_IF_GLIBCPP_V3
 const struct demangle_builtin_type_info
--- libiberty/testsuite/demangle-expected.jj	2022-09-12 10:31:28.436537023 +0200
+++ libiberty/testsuite/demangle-expected	2022-09-19 17:00:51.603253497 +0200
@@ -1242,8 +1242,12 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8fun
 post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
 #
 --format=auto --no-params
-_Z3xxxDFyuVb
-xxx(unsigned long long _Fract, bool volatile)
+_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb
+xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile)
+xxx
+--format=auto --no-params
+_Z3xxxDF32xDF64xDF128xCDF32xVb
+xxx(_Float32x, _Float64x, _Float128x, _Float32x _Complex, bool volatile)
 xxx
 # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
 --format=auto --no-params
--- fixincludes/inclhack.def.jj	2022-09-12 10:37:19.145679055 +0200
+++ fixincludes/inclhack.def	2022-09-19 18:14:45.768595397 +0200
@@ -2015,6 +2015,102 @@ fix = {
 	EOT;
 };
 
+/*  glibc-2.27 to 2.36 assume GCC 7 or later supports some or all
+ *  of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C,
+ *  but doesn't for C++.
+ */
+fix = {
+    hackname  = glibc_cxx_floatn_1;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\\*/\n)?"
+		"([ \t]*#[ \t]*if[^\n]*\n)?"
+		"[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* The literal suffix f128 exists only since GCC 7.0.  */
+	#   define __f128(x) x##l
+	#  else
+	#   define __f128(x) x##f128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
+	#   if __LDBL_MANT_DIG__ == 113
+	#    define __f128(x) x##l
+	#   else
+	#    define __f128(x) x##q
+	#   endif
+	#  else
+	#   define __f128(x) x##f128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   ifdef __NO_LONG_DOUBLE_MATH
+	#    define __f64(x) x##l
+	#   else
+	#    define __f64(x) x
+	#   endif
+	#  else
+	#   define __f64(x) x##f64
+	#  endif
+	EOT;
+};
+
+fix = {
+    hackname  = glibc_cxx_floatn_2;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\\*/\n)?"
+		"[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	typedef __float128 _Float128;
+	#  endif
+	EOT;
+};
+
+fix = {
+    hackname  = glibc_cxx_floatn_3;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?"
+		"([ \t]*#[ \t]*if[^\n]*\n)?"
+		"([ \t]*typedef[ \t]+[^\n]*;\n)?"
+		"[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   define __CFLOAT128 _Complex long double
+	#  else
+	#   define __CFLOAT128 _Complex _Float128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* Add a typedef for older GCC compilers which don't natively support
+	   _Complex _Float128.  */
+	typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
+	#   define __CFLOAT128 __cfloat128
+	#  else
+	#   define __CFLOAT128 _Complex _Float128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   ifdef __NO_LONG_DOUBLE_MATH
+	#    define __CFLOAT64 _Complex long double
+	#   else
+	#    define __CFLOAT64 _Complex double
+	#   endif
+	#  else
+	#   define __CFLOAT64 _Complex _Float64
+	#  endif
+	EOT;
+};
+
 /*  glibc-2.3.5 defines pthread mutex initializers incorrectly,
  *  so we replace them with versions that correspond to the
  *  definition.
--- fixincludes/tests/base/bits/floatn.h.jj	2022-09-19 15:13:26.673129929 +0200
+++ fixincludes/tests/base/bits/floatn.h	2022-09-19 18:16:10.934430067 +0200
@@ -0,0 +1,74 @@
+/*  DO NOT EDIT THIS FILE.
+
+    It has been auto-edited by fixincludes from:
+
+	"fixinc/tests/inc/bits/floatn.h"
+
+    This had to be done to correct non-standard usages in the
+    original, manufacturer supplied header file.  */
+
+
+
+#if defined( GLIBC_CXX_FLOATN_1_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+/* The literal suffix f128 exists only since GCC 7.0.  */
+#   define __f128(x) x##l
+#  else
+#   define __f128(x) x##f128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
+#   if __LDBL_MANT_DIG__ == 113
+#    define __f128(x) x##l
+#   else
+#    define __f128(x) x##q
+#   endif
+#  else
+#   define __f128(x) x##f128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+#   ifdef __NO_LONG_DOUBLE_MATH
+#    define __f64(x) x##l
+#   else
+#    define __f64(x) x
+#   endif
+#  else
+#   define __f64(x) x##f64
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_1_CHECK */
+
+
+#if defined( GLIBC_CXX_FLOATN_2_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+typedef __float128 _Float128;
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_2_CHECK */
+
+
+#if defined( GLIBC_CXX_FLOATN_3_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+#   define __CFLOAT128 _Complex long double
+#  else
+#   define __CFLOAT128 _Complex _Float128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+/* Add a typedef for older GCC compilers which don't natively support
+   _Complex _Float128.  */
+typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
+#   define __CFLOAT128 __cfloat128
+#  else
+#   define __CFLOAT128 _Complex _Float128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+#   ifdef __NO_LONG_DOUBLE_MATH
+#    define __CFLOAT64 _Complex long double
+#   else
+#    define __CFLOAT64 _Complex double
+#   endif
+#  else
+#   define __CFLOAT64 _Complex _Float64
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_3_CHECK */
--- fixincludes/fixincl.x.jj	2022-09-12 10:37:19.144679069 +0200
+++ fixincludes/fixincl.x	2022-09-19 18:15:18.850142748 +0200
@@ -2,11 +2,11 @@
  *
  * DO NOT EDIT THIS FILE   (fixincl.x)
  *
- * It has been AutoGen-ed  February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16
+ * It has been AutoGen-ed  September 11, 2022 at 08:09:37 PM by AutoGen 5.18.16
  * From the definitions    inclhack.def
  * and the template file   fixincl
  */
-/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022
+/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Sep 11 20:09:37 CEST 2022
  *
  * You must regenerate it.  Use the ./genfixes script.
  *
@@ -15,7 +15,7 @@
  * certain ANSI-incompatible system header files which are fixed to work
  * correctly with ANSI C and placed in a directory that GNU C will search.
  *
- * This file contains 267 fixup descriptions.
+ * This file contains 270 fixup descriptions.
  *
  * See README for more information.
  *
@@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * *
  *
+ *  Description of Glibc_Cxx_Floatn_1 fix
+ */
+tSCC zGlibc_Cxx_Floatn_1Name[] =
+     "glibc_cxx_floatn_1";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_1List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_1Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\\*/\n\
+)?([ \t]*#[ \t]*if[^\n\
+]*\n\
+)?[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
+
+#define    GLIBC_CXX_FLOATN_1_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_1
+ */
+static const char* apzGlibc_Cxx_Floatn_1Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Glibc_Cxx_Floatn_2 fix
+ */
+tSCC zGlibc_Cxx_Floatn_2Name[] =
+     "glibc_cxx_floatn_2";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_2List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_2Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\\*/\n\
+)?[ \t]*typedef[ \t]+[^\n\
+]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
+
+#define    GLIBC_CXX_FLOATN_2_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_2
+ */
+static const char* apzGlibc_Cxx_Floatn_2Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Glibc_Cxx_Floatn_3 fix
+ */
+tSCC zGlibc_Cxx_Floatn_3Name[] =
+     "glibc_cxx_floatn_3";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_3List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_3Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\n\
+?[^\n\
+]*\\*/\n\
+)?([ \t]*#[ \t]*if[^\n\
+]*\n\
+)?([ \t]*typedef[ \t]+[^\n\
+]*;\n\
+)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
+
+#define    GLIBC_CXX_FLOATN_3_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_3
+ */
+static const char* apzGlibc_Cxx_Floatn_3Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
  *  Description of Glibc_Mutex_Init fix
  */
 tSCC zGlibc_Mutex_InitName[] =
@@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[]
  *
  *  List of all fixes
  */
-#define REGEX_COUNT          305
+#define REGEX_COUNT          308
 #define MACH_LIST_SIZE_LIMIT 187
-#define FIX_COUNT            267
+#define FIX_COUNT            270
 
 /*
  *  Enumerate the fixes
@@ -10977,6 +11103,9 @@ typedef enum {
     GLIBC_C99_INLINE_2_FIXIDX,
     GLIBC_C99_INLINE_3_FIXIDX,
     GLIBC_C99_INLINE_4_FIXIDX,
+    GLIBC_CXX_FLOATN_1_FIXIDX,
+    GLIBC_CXX_FLOATN_2_FIXIDX,
+    GLIBC_CXX_FLOATN_3_FIXIDX,
     GLIBC_MUTEX_INIT_FIXIDX,
     GLIBC_STDINT_FIXIDX,
     GLIBC_STRNCPY_FIXIDX,
@@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
      GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
      aGlibc_C99_Inline_4Tests,   apzGlibc_C99_Inline_4Patch, 0 },
 
+  {  zGlibc_Cxx_Floatn_1Name,    zGlibc_Cxx_Floatn_1List,
+     apzGlibc_Cxx_Floatn_1Machs,
+     GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_1Tests,   apzGlibc_Cxx_Floatn_1Patch, 0 },
+
+  {  zGlibc_Cxx_Floatn_2Name,    zGlibc_Cxx_Floatn_2List,
+     apzGlibc_Cxx_Floatn_2Machs,
+     GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_2Tests,   apzGlibc_Cxx_Floatn_2Patch, 0 },
+
+  {  zGlibc_Cxx_Floatn_3Name,    zGlibc_Cxx_Floatn_3List,
+     apzGlibc_Cxx_Floatn_3Machs,
+     GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_3Tests,   apzGlibc_Cxx_Floatn_3Patch, 0 },
+
   {  zGlibc_Mutex_InitName,    zGlibc_Mutex_InitList,
      apzGlibc_Mutex_InitMachs,
      GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,


	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-12  8:05 [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652] Jakub Jelinek
  2022-09-12 19:36 ` Joseph Myers
  2022-09-16 11:48 ` Jason Merrill
@ 2022-09-20  3:35 ` Hongtao Liu
  2022-09-20  7:14   ` Hongtao Liu
  2022-09-20  8:51   ` Jakub Jelinek
  2 siblings, 2 replies; 16+ messages in thread
From: Hongtao Liu @ 2022-09-20  3:35 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jason Merrill, Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On Mon, Sep 12, 2022 at 4:06 PM Jakub Jelinek via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Hi!
>
> The following patch implements the compiler part of C++23
> P1467R9 - Extended floating-point types and standard names compiler part
> by introducing _Float{16,32,64,128} as keywords and builtin types
> like they are implemented for C already since GCC 7.
> It doesn't introduce _Float{32,64,128}x for C++, those remain C only
> for now, mainly because https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
> has mangling for:
> ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
> but doesn't for _FloatNx.  And it doesn't add anything for bfloat16_t
> support, see below.
> Regarding mangling, I think mangling _FloatNx as DF <number> x _ would be
> possible, but would need to be discussed and voted in.
> As there is no _FloatNx support for C++, I think it is wrong to announce
> it through __FLT{32,64,128}X_*__ predefined macros (so the patch disables
> those for C++; unfortunately g++ 7 to 12 will predefine those and also
> __FLT{32,64,128}_*__ even when _FloatN support isn't implemented).
> The patch wants to keep backwards compatibility with how __float128 has
> been handled in C++ before, both for mangling and behavior in binary
> operations, overload resolution etc.  So, there are some backend changes
> where for C __float128 and _Float128 are the same type (float128_type_node
> and float128t_type_node are the same pointer), but for C++ they are distinct
> types which mangle differently and _Float128 is treated as extended
> floating-point type while __float128 is treated as non-standard floating
> point type.  The various C++23 changes about how floating-point types
> are changed are actually implemented as written in the spec only if at least
> one of the types involved is _Float{16,32,64,128} and kept previous behavior
> otherwise.  For float/double/long double the rules are actually written that
> they behave the same as before.
> There is some backwards incompatibility at least on x86 regarding _Float16,
> because that type was already used by that name and with the DF16_ mangling
> (but only since GCC 12 and I think it isn't that widely used in the wild
> yet).  E.g. config/i386/avx512fp16intrin.h shows the issues, where
> in C or in GCC 12 in C++ one could pass 0.0f to a builtin taking _Float16
> argument, but with the changes that is not possible anymore, one needs
> to either use 0.0f16 or (_Float16) 0.0f.
> We have also a problem with glibc headers, where since glibc 2.27
> math.h and complex.h aren't compilable with these changes.  One gets
> errors like:
> In file included from /usr/include/math.h:43,
>                  from abc.c:1:
> /usr/include/bits/floatn.h:86:9: error: multiple types in one declaration
>    86 | typedef __float128 _Float128;
>       |         ^~~~~~~~~~
> /usr/include/bits/floatn.h:86:20: error: declaration does not declare anything [-fpermissive]
>    86 | typedef __float128 _Float128;
>       |                    ^~~~~~~~~
> In file included from /usr/include/bits/floatn.h:119:
> /usr/include/bits/floatn-common.h:214:9: error: multiple types in one declaration
>   214 | typedef float _Float32;
>       |         ^~~~~
> /usr/include/bits/floatn-common.h:214:15: error: declaration does not declare anything [-fpermissive]
>   214 | typedef float _Float32;
>       |               ^~~~~~~~
> /usr/include/bits/floatn-common.h:251:9: error: multiple types in one declaration
>   251 | typedef double _Float64;
>       |         ^~~~~~
> /usr/include/bits/floatn-common.h:251:16: error: declaration does not declare anything [-fpermissive]
>   251 | typedef double _Float64;
>       |                ^~~~~~~~
> This is from snippets like:
> /* The remaining of this file provides support for older compilers.  */
> # if __HAVE_FLOAT128
>
> /* The type _Float128 exists only since GCC 7.0.  */
> #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> typedef __float128 _Float128;
> #  endif
> where it hardcodes that C++ doesn't have _Float{16,32,64,128} support nor
> {f,F}{16,32,64,128} literal suffixes nor _Complex _Float{16,32,64,128}.
> The patch fixincludes this for now and hopefully if this is committed, then
> glibc can change those.  Right now the patch changes those
> #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> conditions to
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> where it relies on __FLT32X_*__ macros no longer being predefined for C++.
> Now, I guess for the fixincludes it could also use
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> where earlier GCC 13 snapshots would not be doing the fixincludes,
> but the question is what to use for upstream glibc, because
> there will be 13.0 snapshots where C++ doesn't support _Float{16,32,64,128}
> and where it is essential to use what glibc has been doing previously
> and using the #else would fail miserably, and then 13.0 snapshots where it
> does support it and where using the if would fail miserably.
> One option is to use
> #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1))
> in glibc and rely on fixincludes for 13.0 snapshots (or of course later when
> using 13.1+ with older glibc).
> Another thing is mangling, as said above, Itanium C++ ABI specifies
> DF <number> _ as _Float{16,32,64,128} mangling, but GCC was implementing
> a mangling incompatible with that starting with DF for fixed point types.
> Fixed point was never supported in C++ though, I believe the reason why
> the mangling has been added was that due to a bug it would leak into the
> C++ FE through decltype (0.0r) etc.  But that has been shortly after the
> mangling was added fixed (I think in the same GCC release cycle), so we
> now reject 0.0r etc. in C++.  If we ever need the fixed point mangling,
> I think it can be readded but better with a different prefix so that it
> doesn't conflict with the published standard manglings.  So, this patch
> also kills the fixed point mangling and implements the DF <number> _
> demangling.
> The patch predefines __STDCPP_FLOAT{16,32,64,128}_T__ macros when
> those types are available, but only for C++23, while the underlying types
> are available in C++98 and later including the {f,F}{16,32,64,128} literal
> suffixes (but those with a pedwarn for C++20 and earlier).  My understanding
> is that it needs to be predefined by the compiler, on the other side
> predefining even for older modes when <stdfloat> is a new C++23 header
> would be weird.  One can find out if _Float{16,32,64,128} is supported in
> C++ by
> defined(__FLT{16,32,64,128}_MANT_DIG__) && !defined(__FLT32X_MANT_DIG__)
> (unfortunately not just the former because GCC 7-12 predefined those too)
> or perhaps __GNUC__ >= 13 && defined(__FLT{16,32,64,128}_MANT_DIG__)
> (but that doesn't work well with older G++ 13 snapshots).
>
> As for std::bfloat16_t, three targets (aarch64, arm and x86) apparently
> "support" __bf16 type which has the bfloat16 format, but isn't really
> usable, e.g. {aarch64,arm,ix86}_invalid_conversion disallow any conversions
> from or to type with BFmode, {aarch64,arm,ix86}_invalid_unary_op disallows
> any unary operations on those except for ADDR_EXPR and
> {aarch64,arm,ix86}_invalid_binary_op disallows any binary operation on
> those.  So, I think we satisfy:
> "If the implementation supports an extended floating-point type with the
> properties, as specified by ISO/IEC/IEEE 60559, of radix (b) of 2, storage
> width in bits (k) of 16, precision in bits (p) of 8, maximum exponent (emax)
> of 127, and exponent field width in bits (w) of 8, then the typedef-name
> std::bfloat16_t is defined in the header <stdfloat> and names such a type,
> the macro __STDCPP_BFLOAT16_T__ is defined, and the floating-point literal
> suffixes bf16 and BF16 are supported."
> because we don't really support those right now.
> The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> shouldn't support it, in the PR there is a partial patch to do so, but
> the big question is if it should be supported as the __bf16 type those
> 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> and add conversions to/from at least SFmode but probably also DFmode, TFmode
> and XFmode on x86 and implement arithmetics on those through conversion to
> SFmode, performing arithmetics there and conversion back.
> Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> implemented inline, SFmode -> BFmode conversion is harder,
> I think it is roughly:
I'm not sure if there should be any floating point exceptions for
BFmode operation.
For x86, there's no floating point exceptions for AVX512_BF16 related
instructions
> __bf16
> __truncsfbf2 (_Float32 x)
> {
>   unsigned int y;
>   memcpy (&y, &x, sizeof (y));
>   unsigned int z = x & 0x7fffffff;
>   unsigned short r;
>   __bf16 ret;
>   if (z < 0x800000)
>     // Zero or denormal, flush to zero.
>     r = (x & 0x80000000) >> 16;
>   else if (z < 0x7f800000)
>     // Normal, round to nearest.
>     r = (x + 0x7fff + ((x >> 16) & 1)) >> 16;
>   else if (z == 0x7f800000)
>     // Inf.
>     r = x >> 16;
>   else
>     // NaN.
>     r = (x >> 16) | (1 << 6);
>   memcpy (&ret, &r, sizeof (r));
>   return ret;
> }
> (untested) and the question is if it should be implemented in libgcc
> (and using soft-fp or not), or inline, or both depending on -Os.
> Or there is the possibility to keep __bf16 a lame type one can't convert
> to/from or perform most unary and all binary ops on it, and add for C++
> a new type (say __bfloat16_t or whatever else), agree on mangling in
> Itanium ABI and implement full support just for that type.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux and additionally
> tested on some of the testcases on crosses to powerpc64le-linux (various
> cases including -mabi=ieeelongdouble and -mabi=ibmlongdouble), aarch64-linux
> and s390x-linux.
>
> Ok for trunk?
>
> 2022-09-12  Jakub Jelinek  <jakub@redhat.com>
>
>         PR c++/106652
> gcc/
>         * tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE
>         enumerator.
>         * tree.h (float128t_type_node): Define.
>         * tree.cc (build_common_tree_nodes): Initialize float128t_type_node.
>         * builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that
>         _Float<N> is supported in C++ too.
>         * config/i386/i386.cc (ix86_mangle_type): Only mangle as "g"
>         float128t_type_node.
>         * config/i386/i386-builtins.cc (ix86_init_builtin_types): Use
>         float128t_type_node for __float128 instead of float128_type_node
>         and create it if NULL.
>         * config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph,
>         _mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of
>         0.0f.
>         * config/ia64/ia64.cc (ia64_init_builtins): Use
>         float128t_type_node for __float128 instead of float128_type_node
>         and create it if NULL.
>         * config/rs6000/rs6000-c.cc (is_float128_p): Also return true
>         for float128t_type_node if non-NULL.
>         * config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle
>         float128_type_node as "u9__ieee128".
>         * config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use
>         float128t_type_node for __float128 instead of float128_type_node
>         and create it if NULL.
> gcc/c-family/
>         * c-common.cc (c_common_reswords): Change _Float{16,32,64,128} flags
>         from D_CONLY to 0.
>         (shorten_binary_op): Punt if common_type returns error_mark_node.
>         (shorten_compare): Likewise.
>         (c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128}
>         builtin types if available but not _Float{32,64,128}x.  For C++
>         clear float128t_type_node.
>         * c-cppbuiltin.cc (c_cpp_builtins): For C++ don't predefine
>         __FLT{32,64,128}X_*__ macros, on the other side predefine
>         __STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported.
>         * c-common.h (CASE_RID_FLOATN): Define.
>         (CASE_RID_FLOATN_NX): Use it.
>         * c-lex.cc (interpret_float): For q/Q suffixes prefer
>         float128t_type_node over float128_type_node.  Allow
>         {f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn
>         for C++20 and older.  Don't call excess_precision_type for C++.
> gcc/cp/
>         * cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement
>         P1467R9 - Extended floating-point types and standard names except
>         for std::bfloat16_t for now.  Declare.
>         (extended_float_type_p): New inline function.
>         * mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node
>         as DF{16,32,64,128}_.  Remove FIXED_POINT_TYPE mangling that conflicts
>         with that.
>         * typeck2.cc (check_narrowing): If one of ftype or type is extended
>         floating-point type, compare floating-point conversion ranks.
>         * parser.cc (cp_keyword_starts_decl_specifier_p): Handle
>         CASE_RID_FLOATN.
>         (cp_parser_simple_type_specifier): Likewise and diagnose missing
>         _Float<N> support if not supported by target.
>         * typeck.cc (cp_compare_floating_point_conversion_ranks): New function.
>         (cp_common_type): If both types are REAL_TYPE and one or both are
>         extended floating-point types, select common type based on comparison
>         of floating-point conversion ranks and subranks.
>         (cp_build_binary_op): Diagnose operation with floating point arguments
>         with unordered conversion ranks.
>         * call.cc (standard_conversion): For floating-point conversion, if
>         either from or to are extended floating-point types reject implicit
>         conversion from larger to smaller conversion rank or with unordered
>         conversion ranks.
>         (build_conditional_expr): Diagnose operation with floating point
>         arguments with unordered conversion ranks.
>         (convert_arg_to_ellipsis): Don't promote extended floating-point types
>         narrower than double to double.
>         (compare_ics): Implement P1467R9 [over.ics.rank]/4 changes.
> gcc/testsuite/
>         * g++.dg/cpp23/ext-floating1.C: New test.
>         * g++.dg/cpp23/ext-floating2.C: New test.
>         * g++.dg/cpp23/ext-floating3.C: New test.
>         * g++.dg/cpp23/ext-floating4.C: New test.
>         * g++.dg/cpp23/ext-floating5.C: New test.
>         * g++.dg/cpp23/ext-floating6.C: New test.
>         * g++.dg/cpp23/ext-floating7.C: New test.
>         * g++.dg/cpp23/ext-floating8.C: New test.
>         * g++.dg/cpp23/ext-floating9.C: New test.
>         * g++.dg/cpp23/ext-floating10.C: New test.
>         * g++.dg/cpp23/ext-floating.h: New file.
>         * g++.target/i386/float16-1.C: Adjust expected diagnostics.
> libcpp/
>         * expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} suffixes
>         for C++, but not {f,F}{32,64,128}x.
> include/
>         * demangle.h (enum demangle_component_type): Add
>         DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
>         (struct demangle_component): Add u.s_extended_builtin member.
> libiberty/
>         * cp-demangle.c (d_dump): Handle
>         DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Don't handle
>         DEMANGLE_COMPONENT_FIXED_TYPE.
>         (d_make_extended_builtin_type): New function.
>         (cplus_demangle_builtin_types): Add _Float entry.
>         (cplus_demangle_type): For DF demangle it as _Float<N> rather
>         than fixed point which conflicts with it.
>         (d_count_templates_scopes): Handle
>         DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Just break; for
>         DEMANGLE_COMPONENT_FIXED_TYPE.
>         (d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
>         Don't handle DEMANGLE_COMPONENT_FIXED_TYPE.
>         (d_print_comp_inner): Likewise.
>         * cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump.
>         * testsuite/demangle-expected: Replace _Z3xxxDFyuVb test
>         with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb.
> fixincludes/
>         * inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2,
>         glibc_cxx_floatn_3): New fixes.
>         * tests/base/bits/floatn.h: New file.
>         * fixincl.x: Regenerated.
>
> --- gcc/tree-core.h.jj  2022-09-09 12:27:23.180736449 +0200
> +++ gcc/tree-core.h     2022-09-09 18:46:07.257922609 +0200
> @@ -690,6 +690,10 @@ enum tree_index {
>                              - TI_FLOATN_NX_TYPE_FIRST          \
>                              + 1)
>
> +  /* Type used by certain backends for __float128, which in C++ should be
> +     distinct type from _Float128 for backwards compatibility reasons.  */
> +  TI_FLOAT128T_TYPE,
> +
>    /* Put the complex types after their component types, so that in (sequential)
>       tree streaming we can assert that their component types have already been
>       handled (see tree-streamer.cc:record_common_node).  */
> --- gcc/tree.h.jj       2022-09-09 12:27:23.183736409 +0200
> +++ gcc/tree.h  2022-09-09 18:46:07.258922596 +0200
> @@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree ex
>  #define float64x_type_node             global_trees[TI_FLOAT64X_TYPE]
>  #define float128x_type_node            global_trees[TI_FLOAT128X_TYPE]
>
> +/* Type used by certain backends for __float128, which in C++ should be
> +   distinct type from _Float128 for backwards compatibility reasons.  */
> +#define float128t_type_node            global_trees[TI_FLOAT128T_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]
> --- gcc/tree.cc.jj      2022-09-09 18:44:27.153255900 +0200
> +++ gcc/tree.cc 2022-09-09 18:46:07.260922569 +0200
> @@ -9459,6 +9459,7 @@ build_common_tree_nodes (bool signed_cha
>        layout_type (FLOATN_NX_TYPE_NODE (i));
>        SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
>      }
> +  float128t_type_node = float128_type_node;
>
>    float_ptr_type_node = build_pointer_type (float_type_node);
>    double_ptr_type_node = build_pointer_type (double_type_node);
> --- gcc/builtins.def.jj 2022-09-09 12:27:23.136737041 +0200
> +++ gcc/builtins.def    2022-09-09 18:46:07.261922555 +0200
> @@ -115,8 +115,8 @@ along with GCC; see the file COPYING3.
>     we are compiling for the C language with GNU extensions, we enable the name
>     without the __builtin_ prefix as well as the name with the __builtin_
>     prefix.  C++ does not enable these names by default because they don't have
> -   the _Float<N> and _Float<N>X keywords, and a class based library should use
> -   the __builtin_ names.  */
> +   the _Float<N>x keywords, and a class based library should use the __builtin_
> +   names.  */
>  #undef DEF_FLOATN_BUILTIN
>  #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS)    \
>    DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,   \
> --- gcc/config/i386/i386.cc.jj  2022-09-09 12:27:23.141736974 +0200
> +++ gcc/config/i386/i386.cc     2022-09-10 11:21:26.997205883 +0200
> @@ -22711,7 +22711,10 @@ ix86_mangle_type (const_tree type)
>        return "DF16_";
>      case E_TFmode:
>        /* __float128 is "g".  */
> -      return "g";
> +      if (type == float128t_type_node)
> +       return "g";
> +      /* _Float128 should mangle as "DF128_" done in generic code.  */
> +      return NULL;
>      case E_XFmode:
>        /* "long double" or __float80 is "e".  */
>        return "e";
> --- gcc/config/i386/i386-builtins.cc.jj 2022-09-09 12:27:23.138737014 +0200
> +++ gcc/config/i386/i386-builtins.cc    2022-09-09 18:46:07.264922515 +0200
> @@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void)
>    lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
>
>    /* 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");
> +     _Float128, so for C we only need to register the __float128 name for
> +     it.  For C++, we create a distinct type which will mangle differently
> +     (g) vs. _Float128 (DF128_) and behave backwards compatibly.  */
> +  if (float128t_type_node == NULL_TREE)
> +    {
> +      float128t_type_node = make_node (REAL_TYPE);
> +      TYPE_PRECISION (float128t_type_node)
> +       = TYPE_PRECISION (float128_type_node);
> +      SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
> +      layout_type (float128t_type_node);
> +    }
> +  lang_hooks.types.register_builtin_type (float128t_type_node, "__float128");
>
>    ix86_register_float16_builtin_type ();
>
> --- gcc/config/i386/avx512fp16intrin.h.jj       2022-01-11 22:31:40.696768297 +0100
> +++ gcc/config/i386/avx512fp16intrin.h  2022-09-11 23:23:28.617437158 +0200
> @@ -183,21 +183,21 @@ extern __inline __m128h
>  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>  _mm_setzero_ph (void)
>  {
> -  return _mm_set1_ph (0.0f);
> +  return _mm_set1_ph (0.0f16);
>  }
>
>  extern __inline __m256h
>  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>  _mm256_setzero_ph (void)
>  {
> -  return _mm256_set1_ph (0.0f);
> +  return _mm256_set1_ph (0.0f16);
>  }
>
>  extern __inline __m512h
>  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>  _mm512_setzero_ph (void)
>  {
> -  return _mm512_set1_ph (0.0f);
> +  return _mm512_set1_ph (0.0f16);
>  }
>
>  extern __inline __m128h
> @@ -358,7 +358,8 @@ extern __inline __m128h
>  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>  _mm_set_sh (_Float16 __F)
>  {
> -  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F);
> +  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
> +                    __F);
>  }
>
>  /* Create a vector with element 0 as *P and the rest zero.  */
> @@ -366,7 +367,7 @@ extern __inline __m128h
>  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>  _mm_load_sh (void const *__P)
>  {
> -  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
> +  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
>                      *(_Float16 const *) __P);
>  }
>
> --- gcc/config/ia64/ia64.cc.jj  2022-09-09 12:27:23.143736947 +0200
> +++ gcc/config/ia64/ia64.cc     2022-09-09 18:46:07.265922502 +0200
> @@ -10466,11 +10466,19 @@ ia64_init_builtins (void)
>         = build_pointer_type (build_qualified_type
>                               (char_type_node, TYPE_QUAL_CONST));
>
> -      (*lang_hooks.types.register_builtin_type) (float128_type_node,
> +      if (float128t_type_node == NULL_TREE)
> +       {
> +         float128t_type_node = make_node (REAL_TYPE);
> +         TYPE_PRECISION (float128t_type_node)
> +           = TYPE_PRECISION (float128_type_node);
> +         layout_type (float128t_type_node);
> +         SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
> +       }
> +      (*lang_hooks.types.register_builtin_type) (float128t_type_node,
>                                                  "__float128");
>
>        /* TFmode support builtins.  */
> -      ftype = build_function_type_list (float128_type_node, NULL_TREE);
> +      ftype = build_function_type_list (float128t_type_node, NULL_TREE);
>        decl = add_builtin_function ("__builtin_infq", ftype,
>                                    IA64_BUILTIN_INFQ, BUILT_IN_MD,
>                                    NULL, NULL_TREE);
> @@ -10481,7 +10489,7 @@ ia64_init_builtins (void)
>                                    NULL, NULL_TREE);
>        ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
>
> -      ftype = build_function_type_list (float128_type_node,
> +      ftype = build_function_type_list (float128t_type_node,
>                                         const_string_type,
>                                         NULL_TREE);
>        decl = add_builtin_function ("__builtin_nanq", ftype,
> @@ -10496,8 +10504,8 @@ ia64_init_builtins (void)
>        TREE_READONLY (decl) = 1;
>        ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
>
> -      ftype = build_function_type_list (float128_type_node,
> -                                       float128_type_node,
> +      ftype = build_function_type_list (float128t_type_node,
> +                                       float128t_type_node,
>                                         NULL_TREE);
>        decl = add_builtin_function ("__builtin_fabsq", ftype,
>                                    IA64_BUILTIN_FABSQ, BUILT_IN_MD,
> @@ -10505,9 +10513,9 @@ ia64_init_builtins (void)
>        TREE_READONLY (decl) = 1;
>        ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
>
> -      ftype = build_function_type_list (float128_type_node,
> -                                       float128_type_node,
> -                                       float128_type_node,
> +      ftype = build_function_type_list (float128t_type_node,
> +                                       float128t_type_node,
> +                                       float128t_type_node,
>                                         NULL_TREE);
>        decl = add_builtin_function ("__builtin_copysignq", ftype,
>                                    IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
> --- gcc/config/rs6000/rs6000-c.cc.jj    2022-09-09 12:27:23.144736933 +0200
> +++ gcc/config/rs6000/rs6000-c.cc       2022-09-10 11:21:53.958838545 +0200
> @@ -808,6 +808,7 @@ static inline bool
>  is_float128_p (tree t)
>  {
>    return (t == float128_type_node
> +         || (t && t == float128t_type_node)
>           || (TARGET_IEEEQUAD
>               && TARGET_LONG_DOUBLE_128
>               && t == long_double_type_node));
> --- gcc/config/rs6000/rs6000.cc.jj      2022-09-09 12:27:23.147736893 +0200
> +++ gcc/config/rs6000/rs6000.cc 2022-09-09 18:46:07.269922448 +0200
> @@ -20118,7 +20118,11 @@ rs6000_mangle_type (const_tree type)
>
>    if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type)))
>      return "g";
> -  if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type)))
> +  if (SCALAR_FLOAT_TYPE_P (type)
> +      && FLOAT128_IEEE_P (TYPE_MODE (type))
> +      /* _Float128 should mangle as DF128_ (done in generic code)
> +        rather than u9__ieee128 (used for __ieee128 and __float128).  */
> +      && type != float128_type_node)
>      return "u9__ieee128";
>
>    if (type == vector_pair_type_node)
> --- gcc/config/rs6000/rs6000-builtin.cc.jj      2022-09-09 12:27:23.143736947 +0200
> +++ gcc/config/rs6000/rs6000-builtin.cc 2022-09-09 18:46:07.270922435 +0200
> @@ -733,7 +733,22 @@ rs6000_init_builtins (void)
>        if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
>         ieee128_float_type_node = long_double_type_node;
>        else
> -       ieee128_float_type_node = float128_type_node;
> +       {
> +         /* For C we only need to register the __ieee128 name for
> +            it.  For C++, we create a distinct type which will mangle
> +            differently (u9__ieee128) vs. _Float128 (DF128_) and behave
> +            backwards compatibly.  */
> +         if (float128t_type_node == NULL_TREE)
> +           {
> +             float128t_type_node = make_node (REAL_TYPE);
> +             TYPE_PRECISION (float128t_type_node)
> +               = TYPE_PRECISION (float128_type_node);
> +             layout_type (float128t_type_node);
> +             SET_TYPE_MODE (float128t_type_node,
> +                            TYPE_MODE (float128_type_node));
> +           }
> +         ieee128_float_type_node = float128t_type_node;
> +       }
>        t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
>        lang_hooks.types.register_builtin_type (ieee128_float_type_node,
>                                               "__ieee128");
> --- gcc/c-family/c-common.cc.jj 2022-09-09 12:27:23.137737028 +0200
> +++ gcc/c-family/c-common.cc    2022-09-09 19:43:50.730802597 +0200
> @@ -352,10 +352,10 @@ const struct c_common_resword c_common_r
>    { "_Bool",           RID_BOOL,      D_CONLY },
>    { "_Complex",                RID_COMPLEX,    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 },
> +  { "_Float16",         RID_FLOAT16,    0 },
> +  { "_Float32",         RID_FLOAT32,    0 },
> +  { "_Float64",         RID_FLOAT64,    0 },
> +  { "_Float128",        RID_FLOAT128,   0 },
>    { "_Float32x",        RID_FLOAT32X,  D_CONLY },
>    { "_Float64x",        RID_FLOAT64X,  D_CONLY },
>    { "_Float128x",       RID_FLOAT128X, D_CONLY },
> @@ -1429,8 +1429,11 @@ shorten_binary_op (tree result_type, tre
>           == TYPE_PRECISION (TREE_TYPE (arg0)))
>        && unsigned0 == unsigned1
>        && (unsigned0 || !uns))
> -    return c_common_signed_or_unsigned_type
> -      (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
> +    {
> +      tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
> +      if (ctype != error_mark_node)
> +       return c_common_signed_or_unsigned_type (unsigned0, ctype);
> +    }
>
>    else if (TREE_CODE (arg0) == INTEGER_CST
>            && (unsigned1 || !uns)
> @@ -3202,9 +3205,10 @@ shorten_compare (location_t loc, tree *o
>
>    else if (unsignedp0 == unsignedp1 && real1 == real2
>            && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
> -          && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
> +          && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)
> +          && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)))
> +             != error_mark_node)
>      {
> -      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
>        type = c_common_signed_or_unsigned_type (unsignedp0
>                                                || TYPE_UNSIGNED (*restype_ptr),
>                                                type);
> @@ -4378,11 +4382,21 @@ 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++)
> +  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));
> +      /* Don't register _FloatNX types for C++, just _FloatN.  */
> +      if (i == NUM_FLOATN_TYPES && c_dialect_cxx ())
> +       break;
> +    }
> +
> +  /* For C, let float128t_type_node (__float128 in some backends) be the
> +     same type as float128_type_node (_Float128), for C++ let those
> +     be distinct types that mangle and behave differently.  */
> +  if (c_dialect_cxx ())
> +    float128t_type_node = NULL_TREE;
>
>    /* Only supported decimal floating point extension if the target
>       actually supports underlying modes. */
> --- gcc/c-family/c-cppbuiltin.cc.jj     2022-09-09 12:27:23.138737014 +0200
> +++ gcc/c-family/c-cppbuiltin.cc        2022-09-09 18:46:07.271922421 +0200
> @@ -1246,6 +1246,14 @@ c_cpp_builtins (cpp_reader *pfile)
>      {
>        if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
>         continue;
> +      if (floatn_nx_types[i].extended && c_dialect_cxx ())
> +       continue;
> +      if (c_dialect_cxx () && cxx_dialect > cxx20)
> +       {
> +         char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
> +         sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
> +         cpp_define (pfile, name);
> +       }
>        char prefix[20], csuffix[20];
>        sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
>                floatn_nx_types[i].extended ? "X" : "");
> --- gcc/c-family/c-common.h.jj  2022-09-09 12:27:23.137737028 +0200
> +++ gcc/c-family/c-common.h     2022-09-09 18:46:07.271922421 +0200
> @@ -120,8 +120,10 @@ enum rid
>    RID_FLOAT32X,
>    RID_FLOAT64X,
>    RID_FLOAT128X,
> +#define CASE_RID_FLOATN                                                        \
> +  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128
>  #define CASE_RID_FLOATN_NX                                             \
> -  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128: \
> +  CASE_RID_FLOATN:                                                     \
>    case RID_FLOAT32X: case RID_FLOAT64X: case RID_FLOAT128X
>
>    RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
> --- gcc/c-family/c-lex.cc.jj    2022-09-09 12:27:23.138737014 +0200
> +++ gcc/c-family/c-lex.cc       2022-09-09 18:46:07.271922421 +0200
> @@ -960,6 +960,10 @@ interpret_float (const cpp_token *token,
>           pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
>
>         type = c_common_type_for_mode (mode, 0);
> +       /* For Q suffix, prefer float128t_type_node (__float128) type
> +          over float128_type_node (_Float128) type if they are distinct.  */
> +       if (type == float128_type_node && float128t_type_node)
> +         type = float128t_type_node;
>         gcc_assert (type);
>        }
>      else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
> @@ -979,8 +983,17 @@ interpret_float (const cpp_token *token,
>             error ("unsupported non-standard suffix on floating constant");
>             return error_mark_node;
>           }
> +       else if (c_dialect_cxx ())
> +         {
> +           if (cxx_dialect < cxx23)
> +             pedwarn (input_location, OPT_Wpedantic,
> +                      "%<f%d%> or %<F%d%> suffix on floating constant only "
> +                      "available with %<-std=c++2b%> or %<-std=gnu++2b%>",
> +                      n, n);
> +         }
>         else
> -         pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
> +         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;
> @@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token,
>      else
>        type = double_type_node;
>
> -  const_type = excess_precision_type (type);
> +  if (c_dialect_cxx ())
> +    const_type = NULL_TREE;
> +  else
> +    const_type = excess_precision_type (type);
>    if (!const_type)
>      const_type = type;
>
> --- gcc/cp/cp-tree.h.jj 2022-09-09 12:27:23.170736583 +0200
> +++ gcc/cp/cp-tree.h    2022-09-10 11:22:11.612598030 +0200
> @@ -7942,6 +7942,7 @@ extern tree require_complete_type_sfinae
>  extern tree complete_type                      (tree);
>  extern tree complete_type_or_else              (tree, tree);
>  extern tree complete_type_or_maybe_complain    (tree, tree, tsubst_flags_t);
> +extern int cp_compare_floating_point_conversion_ranks (tree, tree);
>  inline bool type_unknown_p                     (const_tree);
>  enum { ce_derived, ce_type, ce_normal, ce_exact };
>  extern bool comp_except_specs                  (const_tree, const_tree, int);
> @@ -8682,6 +8683,18 @@ struct push_access_scope_guard
>    }
>  };
>
> +/* True if TYPE is an extended floating-point type.  */
> +
> +inline bool
> +extended_float_type_p (tree type)
> +{
> +  type = TYPE_MAIN_VARIANT (type);
> +  for (int i = 0; i < NUM_FLOATN_TYPES; ++i)
> +    if (type == FLOATN_TYPE_NODE (i))
> +      return true;
> +  return false;
> +}
> +
>  #if CHECKING_P
>  namespace selftest {
>    extern void run_cp_tests (void);
> --- gcc/cp/mangle.cc.jj 2022-09-09 12:27:23.171736570 +0200
> +++ gcc/cp/mangle.cc    2022-09-09 18:46:07.273922394 +0200
> @@ -2648,63 +2648,18 @@ write_builtin_type (tree type)
>         write_string ("Dd");
>        else if (type == dfloat128_type_node || type == fallback_dfloat128_type)
>         write_string ("De");
> +      else if (type == float16_type_node)
> +       write_string ("DF16_");
> +      else if (type == float32_type_node)
> +       write_string ("DF32_");
> +      else if (type == float64_type_node)
> +       write_string ("DF64_");
> +      else if (type == float128_type_node)
> +       write_string ("DF128_");
>        else
>         gcc_unreachable ();
>        break;
>
> -    case FIXED_POINT_TYPE:
> -      write_string ("DF");
> -      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
> -       write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
> -      if (type == fract_type_node
> -         || type == sat_fract_type_node
> -         || type == accum_type_node
> -         || type == sat_accum_type_node)
> -       write_char ('i');
> -      else if (type == unsigned_fract_type_node
> -              || type == sat_unsigned_fract_type_node
> -              || type == unsigned_accum_type_node
> -              || type == sat_unsigned_accum_type_node)
> -       write_char ('j');
> -      else if (type == short_fract_type_node
> -              || type == sat_short_fract_type_node
> -              || type == short_accum_type_node
> -              || type == sat_short_accum_type_node)
> -       write_char ('s');
> -      else if (type == unsigned_short_fract_type_node
> -              || type == sat_unsigned_short_fract_type_node
> -              || type == unsigned_short_accum_type_node
> -              || type == sat_unsigned_short_accum_type_node)
> -       write_char ('t');
> -      else if (type == long_fract_type_node
> -              || type == sat_long_fract_type_node
> -              || type == long_accum_type_node
> -              || type == sat_long_accum_type_node)
> -       write_char ('l');
> -      else if (type == unsigned_long_fract_type_node
> -              || type == sat_unsigned_long_fract_type_node
> -              || type == unsigned_long_accum_type_node
> -              || type == sat_unsigned_long_accum_type_node)
> -       write_char ('m');
> -      else if (type == long_long_fract_type_node
> -              || type == sat_long_long_fract_type_node
> -              || type == long_long_accum_type_node
> -              || type == sat_long_long_accum_type_node)
> -       write_char ('x');
> -      else if (type == unsigned_long_long_fract_type_node
> -              || type == sat_unsigned_long_long_fract_type_node
> -              || type == unsigned_long_long_accum_type_node
> -              || type == sat_unsigned_long_long_accum_type_node)
> -       write_char ('y');
> -      else
> -       sorry ("mangling unknown fixed point type");
> -      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
> -      if (TYPE_SATURATING (type))
> -       write_char ('s');
> -      else
> -       write_char ('n');
> -      break;
> -
>      default:
>        gcc_unreachable ();
>      }
> --- gcc/cp/typeck2.cc.jj        2022-09-09 12:27:23.179736463 +0200
> +++ gcc/cp/typeck2.cc   2022-09-09 18:46:07.273922394 +0200
> @@ -1010,12 +1010,25 @@ check_narrowing (tree type, tree init, t
>    else if (TREE_CODE (ftype) == REAL_TYPE
>            && TREE_CODE (type) == REAL_TYPE)
>      {
> -      if ((same_type_p (ftype, long_double_type_node)
> -          && (same_type_p (type, double_type_node)
> -              || same_type_p (type, float_type_node)))
> -         || (same_type_p (ftype, double_type_node)
> -             && same_type_p (type, float_type_node))
> -         || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
> +      if ((extended_float_type_p (ftype) || extended_float_type_p (type))
> +         ? /* "from a floating-point type T to another floating-point type
> +              whose floating-point conversion rank is neither greater than
> +              nor equal to that of T".
> +              So, it is ok if
> +              cp_compare_floating_point_conversion_ranks (ftype, type)
> +              returns -2 (type has greater conversion rank than ftype)
> +              or [-1..1] (type has equal conversion rank as ftype, possibly
> +              different subrank.  Only do this if at least one of the
> +              types is extended floating-point type, otherwise keep doing
> +              what we did before (for the sake of non-standard
> +              backend types).  */
> +           cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
> +         : ((same_type_p (ftype, long_double_type_node)
> +             && (same_type_p (type, double_type_node)
> +                 || same_type_p (type, float_type_node)))
> +            || (same_type_p (ftype, double_type_node)
> +                && same_type_p (type, float_type_node))
> +            || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
>         {
>           if (TREE_CODE (init) == REAL_CST)
>             {
> --- gcc/cp/parser.cc.jj 2022-09-09 12:27:23.177736489 +0200
> +++ gcc/cp/parser.cc    2022-09-09 18:46:07.278922327 +0200
> @@ -1129,6 +1129,7 @@ cp_keyword_starts_decl_specifier_p (enum
>      case RID_UNSIGNED:
>      case RID_FLOAT:
>      case RID_DOUBLE:
> +    CASE_RID_FLOATN:
>      case RID_VOID:
>        /* CV qualifiers.  */
>      case RID_CONST:
> @@ -19706,6 +19707,12 @@ cp_parser_simple_type_specifier (cp_pars
>      case RID_DOUBLE:
>        type = double_type_node;
>        break;
> +    CASE_RID_FLOATN:
> +      type = FLOATN_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST);
> +      if (type == NULL_TREE)
> +       error ("%<_Float%d%> is not supported on this target",
> +              floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n);
> +      break;
>      case RID_VOID:
>        type = void_type_node;
>        break;
> --- gcc/cp/typeck.cc.jj 2022-09-09 12:27:23.179736463 +0200
> +++ gcc/cp/typeck.cc    2022-09-09 19:54:17.360423639 +0200
> @@ -272,6 +272,116 @@ merge_type_attributes_from (tree type, t
>    return cp_build_type_attribute_variant (type, attrs);
>  }
>
> +/* Compare floating point conversion ranks and subranks of T1 and T2
> +   types.  If T1 and T2 have unordered conversion ranks, return 3.
> +   If T1 has greater conversion rank than T2, return 2.
> +   If T2 has greater conversion rank than T1, return -2.
> +   If T1 has equal conversion rank as T2, return -1, 0 or 1 depending
> +   on if T1 has smaller, equal or greater conversion subrank than
> +   T2.  */
> +
> +int
> +cp_compare_floating_point_conversion_ranks (tree t1, tree t2)
> +{
> +  tree mv1 = TYPE_MAIN_VARIANT (t1);
> +  tree mv2 = TYPE_MAIN_VARIANT (t2);
> +  bool extended1 = false;
> +  bool extended2 = false;
> +
> +  if (mv1 == mv2)
> +    return 0;
> +
> +  for (int i = 0; i < NUM_FLOATN_TYPES; ++i)
> +    {
> +      if (mv1 == FLOATN_TYPE_NODE (i))
> +       extended1 = true;
> +      if (mv2 == FLOATN_TYPE_NODE (i))
> +       extended2 = true;
> +    }
> +  if (extended2 && !extended1)
> +    {
> +      int ret = cp_compare_floating_point_conversion_ranks (t2, t1);
> +      return ret == 3 ? 3 : -ret;
> +    }
> +
> +  const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
> +  const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
> +  gcc_assert (fmt1->b == 2 && fmt2->b == 2);
> +  /* For {ibm,mips}_extended_format formats, the type has variable
> +     precision up to ~2150 bits when the first double is around maximum
> +     representable double and second double is subnormal minimum.
> +     So, e.g. for __ibm128 vs. std::float128_t, they have unordered
> +     ranks.  */
> +  int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1))
> +           ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p);
> +  int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2))
> +           ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p);
> +  /* The rank of a floating point type T is greater than the rank of
> +     any floating-point type whose set of values is a proper subset
> +     of the set of values of T.  */
> +  if ((p1 > p2 && fmt1->emax >= fmt2->emax)
> +       || (p1 == p2 && fmt1->emax > fmt2->emax))
> +    return 2;
> +  if ((p1 < p2 && fmt1->emax <= fmt2->emax)
> +       || (p1 == p2 && fmt1->emax < fmt2->emax))
> +    return -2;
> +  if ((p1 > p2 && fmt1->emax < fmt2->emax)
> +       || (p1 < p2 && fmt1->emax > fmt2->emax))
> +    return 3;
> +  if (!extended1 && !extended2)
> +    {
> +      /* The rank of long double is greater than the rank of double, which
> +        is greater than the rank of float.  */
> +      if (t1 == long_double_type_node)
> +       return 2;
> +      else if (t2 == long_double_type_node)
> +       return -2;
> +      if (t1 == double_type_node)
> +       return 2;
> +      else if (t2 == double_type_node)
> +       return -2;
> +      if (t1 == float_type_node)
> +       return 2;
> +      else if (t2 == float_type_node)
> +       return -2;
> +      return 0;
> +    }
> +  /* Two extended floating-point types with the same set of values have equal
> +     ranks.  */
> +  if (extended1 && extended2)
> +    /* We shouldn't have multiple different extended floating-point types
> +       with the same set of values.  */
> +    gcc_unreachable ();
> +
> +  tree *p;
> +  int cnt = 0;
> +  for (p = &float_type_node; p <= &long_double_type_node; ++p)
> +    {
> +      const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p));
> +      gcc_assert (fmt3->b == 2);
> +      int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p))
> +               ? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p);
> +      if (p1 == p3 && fmt1->emax == fmt3->emax)
> +       ++cnt;
> +    }
> +  /* An extended floating-point type with the same set of values
> +     as exactly one cv-unqualified standard floating-point type
> +     has a rank equal to the rank of that standard floating-point
> +     type.
> +
> +     An extended floating-point type with the same set of values
> +     as more than one cv-unqualified standard floating-point type
> +     has a rank equal to the rank of double.
> +
> +     Thus, if the latter is true and t2 is long double, t2
> +     has higher rank.  */
> +  if (cnt > 1 && mv2 == long_double_type_node)
> +    return -2;
> +  /* Otherwise, they have equal rank, but extended types
> +     (other than std::bfloat16_t) have higher subrank.  */
> +  return 1;
> +}
> +
>  /* Return the common type for two arithmetic types T1 and T2 under the
>     usual arithmetic conversions.  The default conversions have already
>     been applied, and enumerated types converted to their compatible
> @@ -342,6 +452,23 @@ cp_common_type (tree t1, tree t2)
>    if (code2 == REAL_TYPE && code1 != REAL_TYPE)
>      return build_type_attribute_variant (t2, attributes);
>
> +  if (code1 == REAL_TYPE
> +      && (extended_float_type_p (t1) || extended_float_type_p (t2)))
> +    {
> +      tree mv1 = TYPE_MAIN_VARIANT (t1);
> +      tree mv2 = TYPE_MAIN_VARIANT (t2);
> +      if (mv1 == mv2)
> +       return build_type_attribute_variant (t1, attributes);
> +
> +      int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2);
> +      if (cmpret == 3)
> +       return error_mark_node;
> +      else if (cmpret >= 0)
> +       return build_type_attribute_variant (t1, attributes);
> +      else
> +       return build_type_attribute_variant (t2, attributes);
> +    }
> +
>    /* Both real or both integers; use the one with greater precision.  */
>    if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
>      return build_type_attribute_variant (t1, attributes);
> @@ -5041,7 +5168,20 @@ cp_build_binary_op (const op_location_t
>         = targetm.invalid_binary_op (code, type0, type1)))
>      {
>        if (complain & tf_error)
> -       error (invalid_op_diag);
> +       {
> +         if (code0 == REAL_TYPE
> +             && code1 == REAL_TYPE
> +             && (extended_float_type_p (type0)
> +                 || extended_float_type_p (type1))
> +             && cp_compare_floating_point_conversion_ranks (type0,
> +                                                            type1) == 3)
> +           {
> +             rich_location richloc (line_table, location);
> +             binary_op_error (&richloc, code, type0, type1);
> +           }
> +         else
> +           error (invalid_op_diag);
> +       }
>        return error_mark_node;
>      }
>
> @@ -5911,6 +6051,19 @@ cp_build_binary_op (const op_location_t
>        && (shorten || common || short_compare))
>      {
>        result_type = cp_common_type (type0, type1);
> +      if (result_type == error_mark_node
> +         && code0 == REAL_TYPE
> +         && code1 == REAL_TYPE
> +         && (extended_float_type_p (type0) || extended_float_type_p (type1))
> +         && cp_compare_floating_point_conversion_ranks (type0, type1) == 3)
> +       {
> +         if (complain & tf_error)
> +           {
> +             rich_location richloc (line_table, location);
> +             binary_op_error (&richloc, code, type0, type1);
> +           }
> +         return error_mark_node;
> +       }
>        if (complain & tf_warning)
>         {
>           do_warn_double_promotion (result_type, type0, type1,
> --- gcc/cp/call.cc.jj   2022-09-09 12:27:23.169736597 +0200
> +++ gcc/cp/call.cc      2022-09-10 11:14:41.361732371 +0200
> @@ -1519,6 +1519,22 @@ standard_conversion (tree to, tree from,
>            || SCOPED_ENUM_P (from))
>         return NULL;
>
> +      /* A prvalue of floating-point type can be converted to a prvalue of
> +        another floating-point type with a greater or equal conversion
> +        rank ([conv.rank]).  A prvalue of standard floating-point type can
> +        be converted to a prvalue of another standard floating-point type.
> +        For backwards compatibility with handling __float128 and other
> +        non-standard floating point types, allow all implicit floating
> +        point conversions if neither type is extended floating-point
> +        type and if at least one of them is, fail if they have unordered
> +        conversion rank or from has higher conversion rank.  */
> +      if (fcode == REAL_TYPE
> +         && tcode == REAL_TYPE
> +         && (extended_float_type_p (from)
> +             || extended_float_type_p (to))
> +         && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
> +       return NULL;
> +
>        /* If we're parsing an enum with no fixed underlying type, we're
>          dealing with an incomplete type, which renders the conversion
>          ill-formed.  */
> @@ -5842,6 +5858,21 @@ build_conditional_expr (const op_locatio
>        /* In this case, there is always a common type.  */
>        result_type = type_after_usual_arithmetic_conversions (arg2_type,
>                                                              arg3_type);
> +      if (result_type == error_mark_node
> +         && TREE_CODE (arg2_type) == REAL_TYPE
> +         && TREE_CODE (arg3_type) == REAL_TYPE
> +         && (extended_float_type_p (arg2_type)
> +             || extended_float_type_p (arg3_type))
> +         && cp_compare_floating_point_conversion_ranks (arg2_type,
> +                                                        arg3_type) == 3)
> +       {
> +         if (complain & tf_error)
> +           error_at (loc, "operands to %<?:%> have unordered conversion rank "
> +                          "of types %qT and %qT",
> +                     arg2_type, arg3_type);
> +         return error_mark_node;
> +       }
> +
>        if (complain & tf_warning)
>         do_warn_double_promotion (result_type, arg2_type, arg3_type,
>                                   "implicit conversion from %qH to %qI to "
> @@ -8531,7 +8562,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
>    if (TREE_CODE (arg_type) == REAL_TYPE
>        && (TYPE_PRECISION (arg_type)
>           < TYPE_PRECISION (double_type_node))
> -      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
> +      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))
> +      && !extended_float_type_p (arg_type))
>      {
>        if ((complain & tf_warning)
>           && warn_double_promotion && !c_inhibit_evaluation_warnings)
> @@ -11719,6 +11751,75 @@ compare_ics (conversion *ics1, conversio
>         return 1;
>      }
>
> +  {
> +    /* A conversion in either direction between floating-point type FP1 and
> +       floating-point type FP2 is better than a conversion in the same
> +       direction between FP1 and arithmetic type T3 if
> +       - the floating-point conversion rank of FP1 is equal to the rank of
> +        FP2, and
> +       - T3 is not a floating-point type, or T3 is a floating-point type
> +        whose rank is not equal to the rank of FP1, or the floating-point
> +        conversion subrank of FP2 is greater than the subrank of T3.  */
> +    tree fp1 = from_type1;
> +    tree fp2 = to_type1;
> +    tree fp3 = from_type2;
> +    tree t3 = to_type2;
> +    int ret = 1;
> +    if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3))
> +      {
> +       std::swap (fp1, fp2);
> +       std::swap (fp3, t3);
> +      }
> +    if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3)
> +       && TREE_CODE (fp1) == REAL_TYPE
> +       /* Only apply this rule if at least one of the 3 types is
> +          extended floating-point type, otherwise keep them as
> +          before for compatibility reasons with types like __float128.
> +          float, double and long double alone have different conversion
> +          ranks and so when just those 3 types are involved, this
> +          rule doesn't trigger.  */
> +       && (extended_float_type_p (fp1)
> +           || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2))
> +           || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3))))
> +      {
> +       if (TREE_CODE (fp2) != REAL_TYPE)
> +         {
> +           ret = -ret;
> +           std::swap (fp2, t3);
> +         }
> +       if (TREE_CODE (fp2) == REAL_TYPE)
> +         {
> +           if (cp_compare_floating_point_conversion_ranks (fp1, fp2) + 1U
> +               <= 2U)
> +             {
> +               /* Conversion ranks of FP1 and FP2 are equal.  */
> +               if (TREE_CODE (t3) != REAL_TYPE
> +                   || (cp_compare_floating_point_conversion_ranks (fp1, t3)
> +                       + 1U > 2U))
> +                 /* FP1 <-> FP2 conversion is better.  */
> +                 return ret;
> +               int c = cp_compare_floating_point_conversion_ranks (fp2, t3);
> +               gcc_assert (c + 1U <= 2U);
> +               if (c == 1)
> +                 /* Conversion subrank of FP2 is greater than subrank of T3.
> +                    FP1 <-> FP2 conversion is better.  */
> +                 return ret;
> +               else if (c == -1)
> +                 /* Conversion subrank of FP2 is less than subrank of T3.
> +                    FP1 <-> T3 conversion is better.  */
> +                 return -ret;
> +             }
> +           else if (TREE_CODE (t3) == REAL_TYPE
> +                    && (cp_compare_floating_point_conversion_ranks (fp1, t3)
> +                        + 1U <= 2U))
> +             /* Conversion ranks of FP1 and FP2 are not equal, conversion
> +                ranks of FP1 and T3 are equal.
> +                FP1 <-> T3 conversion is better.  */
> +             return -ret;
> +         }
> +      }
> +  }
> +
>    if (TYPE_PTR_P (from_type1)
>        && TYPE_PTR_P (from_type2)
>        && TYPE_PTR_P (to_type1)
> --- gcc/testsuite/g++.dg/cpp23/ext-floating1.C.jj       2022-09-09 18:46:07.281922287 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C  2022-09-09 18:46:07.281922287 +0200
> @@ -0,0 +1,248 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do compile { target c++23 } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#ifdef __STRICT_ANSI__
> +#undef __SIZEOF_FLOAT128__
> +#endif
> +
> +using namespace std;
> +
> +static_assert (!is_same<float, double>::value);
> +static_assert (!is_same<float, long double>::value);
> +static_assert (!is_same<double, long double>::value);
> +static_assert (is_same<decltype (0.0f), float>::value);
> +static_assert (is_same<decltype (0.0F), float>::value);
> +static_assert (is_same<decltype (0.0), double>::value);
> +static_assert (is_same<decltype (0.0l), long double>::value);
> +static_assert (is_same<decltype (0.0L), long double>::value);
> +static_assert (is_same<decltype (0.0f + 0.0F), float>::value);
> +static_assert (is_same<decltype (0.0F + 0.0f), float>::value);
> +static_assert (is_same<decltype (0.0 + 0.0), double>::value);
> +static_assert (is_same<decltype (0.0l + 0.0L), long double>::value);
> +static_assert (is_same<decltype (0.0L + 0.0l), long double>::value);
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (is_same<decltype (0.0q), __float128>::value);
> +static_assert (is_same<decltype (0.0Q), __float128>::value);
> +static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value);
> +static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT16_T__
> +static_assert (!is_same<float, float16_t>::value);
> +static_assert (!is_same<double, float16_t>::value);
> +static_assert (!is_same<long double, float16_t>::value);
> +static_assert (is_same<decltype (0.0f16), float16_t>::value);
> +static_assert (is_same<decltype (0.0F16), float16_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +static_assert (!is_same<float, float32_t>::value);
> +static_assert (!is_same<double, float32_t>::value);
> +static_assert (!is_same<long double, float32_t>::value);
> +static_assert (!is_same<decltype (0.0f), float32_t>::value);
> +static_assert (!is_same<decltype (0.0F), float32_t>::value);
> +static_assert (is_same<decltype (0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32), float32_t>::value);
> +static_assert (!is_same<decltype (0.0f32), float>::value);
> +static_assert (!is_same<decltype (0.0F32), float>::value);
> +static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +static_assert (!is_same<float, float64_t>::value);
> +static_assert (!is_same<double, float64_t>::value);
> +static_assert (!is_same<long double, float64_t>::value);
> +static_assert (!is_same<decltype (0.0), float64_t>::value);
> +static_assert (is_same<decltype (0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64), float64_t>::value);
> +static_assert (!is_same<decltype (0.0f64), double>::value);
> +static_assert (!is_same<decltype (0.0F64), double>::value);
> +static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +static_assert (!is_same<float, float128_t>::value);
> +static_assert (!is_same<double, float128_t>::value);
> +static_assert (!is_same<long double, float128_t>::value);
> +static_assert (!is_same<decltype (0.0l), float128_t>::value);
> +static_assert (!is_same<decltype (0.0L), float128_t>::value);
> +static_assert (is_same<decltype (0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128), float128_t>::value);
> +static_assert (!is_same<decltype (0.0f128), long double>::value);
> +static_assert (!is_same<decltype (0.0F128), long double>::value);
> +static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value);
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (!is_same<float128_t, __float128>::value);
> +static_assert (!is_same<decltype (0.0q), float128_t>::value);
> +static_assert (!is_same<decltype (0.0Q), float128_t>::value);
> +static_assert (!is_same<decltype (0.0f128), __float128>::value);
> +static_assert (!is_same<decltype (0.0F128), __float128>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +static_assert (!is_same<float, bfloat16_t>::value);
> +static_assert (!is_same<double, bfloat16_t>::value);
> +static_assert (!is_same<long double, bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value);
> +#endif
> +static_assert (is_same<decltype (0.0f + 0.0), double>::value);
> +static_assert (is_same<decltype (0.0 + 0.0F), double>::value);
> +static_assert (is_same<decltype (0.0L + 0.0), long double>::value);
> +static_assert (is_same<decltype (0.0 + 0.0L), long double>::value);
> +static_assert (is_same<decltype (0.0L + 0.0f), long double>::value);
> +static_assert (is_same<decltype (0.0F + 0.0l), long double>::value);
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
> +static_assert (!is_same<float16_t, float32_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
> +static_assert (!is_same<float16_t, float64_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<float16_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__)
> +static_assert (!is_same<float32_t, float64_t>::value);
> +static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<float32_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<float64_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
> +static_assert (!is_same<bfloat16_t, float32_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value);
> +#endif
> +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
> +static_assert (!is_same<bfloat16_t, float64_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<bfloat16_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT16_T__
> +#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f16), float>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value);
> +#endif
> +#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f16), double>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0), double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value);
> +#endif
> +#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f32), double>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0), double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value);
> +#endif
> +#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \
> +    && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
> +// An extended floating-point type with the same set of values as more than one
> +// cv-unqualified standard floating-point type has a rank equal to the rank of
> +// double.
> +// Then long double will have higher rank than float64_t.
> +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value);
> +#endif
> +#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \
> +    && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered.
> +static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value);
> +#endif
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value);
> +#endif
> +#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value);
> +#endif
> +#endif
> +
> +void foo (float) {}
> +void foo (double) {}
> +void foo (long double) {}
> +#ifdef __STDCPP_FLOAT16_T__
> +void foo (float16_t) {}
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +void foo (float32_t) {}
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +void foo (float64_t) {}
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +void foo (float128_t) {}
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +void foo (bfloat16_t) {}
> +#endif
> --- gcc/testsuite/g++.dg/cpp23/ext-floating2.C.jj       2022-09-09 18:46:07.281922287 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating2.C  2022-09-09 18:46:07.281922287 +0200
> @@ -0,0 +1,157 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do compile { target c++23 } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#ifdef __STRICT_ANSI__
> +#undef __SIZEOF_FLOAT128__
> +#endif
> +
> +using namespace std;
> +
> +float fa = 1.0f;
> +float fb = (float) 1.0f;
> +float fc = 1.0;
> +float fd = (float) 1.0;
> +float fe = 1.0L;
> +float ff = (float) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float fg = 1.0Q;
> +float fh = (float) 1.0Q;
> +#endif
> +double da = 1.0f;
> +double db = (double) 1.0f;
> +double dc = 1.0;
> +double dd = (double) 1.0;
> +double de = 1.0L;
> +double df = (double) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +double dg = 1.0Q;
> +double dh = (double) 1.0Q;
> +#endif
> +long double lda = 1.0f;
> +long double ldb = (long double) 1.0f;
> +long double ldc = 1.0;
> +long double ldd = (long double) 1.0;
> +long double lde = 1.0L;
> +long double ldf = (long double) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +long double ldg = 1.0Q;
> +long double ldh = (long double) 1.0Q;
> +__float128 qa = 1.0f;
> +__float128 qb = (__float128) 1.0f;
> +__float128 qc = 1.0;
> +__float128 qd = (__float128) 1.0;
> +__float128 qe = 1.0L;
> +__float128 qf = (__float128) 1.0L;
> +__float128 qg = 1.0Q;
> +__float128 qh = (__float128) 1.0Q;
> +#endif
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t f16a = 1.0F16;
> +float16_t f16b = (float16_t) 1.0F16;
> +#ifdef __STDCPP_FLOAT32_T__
> +float16_t f16c = 1.0F32;               // { dg-error "cannot convert '_Float32' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float32 } } }
> +float16_t f16d = (float16_t) 1.0F32;
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +float16_t f16e = 1.0F64;               // { dg-error "cannot convert '_Float64' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float64 } } }
> +float16_t f16f = (float16_t) 1.0F64;
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +float16_t f16g = 1.0F128;              // { dg-error "cannot convert '_Float128' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float128 } } }
> +float16_t f16h = (float16_t) 1.0F128;
> +#endif
> +float16_t f16j = (float16_t) 1.0f;
> +float16_t f16l = (float16_t) 1.0;
> +float16_t f16n = (float16_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float16_t f16p = (float16_t) 1.0Q;
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +#ifdef __STDCPP_FLOAT16_T__
> +float32_t f32a = 1.0F16;
> +float32_t f32b = (float32_t) 1.0F16;
> +#endif
> +float32_t f32c = 1.0F32;
> +float32_t f32d = (float32_t) 1.0F32;
> +#ifdef __STDCPP_FLOAT64_T__
> +float32_t f32e = 1.0F64;               // { dg-error "cannot convert '_Float64' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" "" { target { float32 && float64 } } }
> +float32_t f32f = (float32_t) 1.0F64;
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +float32_t f32g = 1.0F128;              // { dg-error "cannot convert '_Float128' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" "" { target { float32 && float128 } } }
> +float32_t f32h = (float32_t) 1.0F128;
> +#endif
> +#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__
> +float32_t f32i = 1.0f;
> +#endif
> +float32_t f32j = (float32_t) 1.0f;
> +float32_t f32l = (float32_t) 1.0;
> +float32_t f32n = (float32_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float32_t f32p = (float32_t) 1.0Q;
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +#ifdef __STDCPP_FLOAT16_T__
> +float64_t f64a = 1.0F16;
> +float64_t f64b = (float64_t) 1.0F16;
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +float64_t f64c = 1.0F32;
> +float64_t f64d = (float64_t) 1.0F32;
> +#endif
> +float64_t f64e = 1.0F64;
> +float64_t f64f = (float64_t) 1.0F64;
> +#ifdef __STDCPP_FLOAT128_T__
> +float64_t f64g = 1.0F128;              // { dg-error "cannot convert '_Float128' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" "" { target { float64 && float128 } } }
> +float64_t f64h = (float64_t) 1.0F128;
> +#endif
> +#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__
> +float64_t f64i = 1.0f;
> +#endif
> +float64_t f64j = (float64_t) 1.0f;
> +#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__
> +float64_t f64k = 1.0;
> +#endif
> +float64_t f64l = (float64_t) 1.0;
> +float64_t f64n = (float64_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float64_t f64p = (float64_t) 1.0Q;
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +#ifdef __STDCPP_FLOAT16_T__
> +float128_t f128a = 1.0F16;
> +float128_t f128b = (float128_t) 1.0F16;
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +float128_t f128c = 1.0F32;
> +float128_t f128d = (float128_t) 1.0F32;
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +float128_t f128e = 1.0F64;
> +float128_t f128f = (float128_t) 1.0F64;
> +#endif
> +float128_t f128g = 1.0F128;
> +float128_t f128h = (float128_t) 1.0F128;
> +#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__
> +float128_t f128i = 1.0f;
> +#endif
> +float128_t f128j = (float128_t) 1.0f;
> +#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__
> +float128_t f128k = 1.0;
> +#endif
> +float128_t f128l = (float128_t) 1.0;
> +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106
> +float128_t f128m = 1.0L;
> +#endif
> +float128_t f128n = (float128_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float128_t f128o = 1.0Q;
> +float128_t f128p = (float128_t) 1.0Q;
> +#endif
> +#endif
> --- gcc/testsuite/g++.dg/cpp23/ext-floating3.C.jj       2022-09-09 18:46:07.281922287 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C  2022-09-10 10:21:25.748210213 +0200
> @@ -0,0 +1,128 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// Variant of ext-floating2.C test with x86 specific assumptions
> +// about float, double, long double and existence of __float128.
> +// And some further tests.
> +// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#if !defined(__STDCPP_FLOAT32_T__) \
> +    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
> +    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
> +    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
> +    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
> +    || !defined(__SIZEOF_FLOAT128__)
> +#error Unexpected set of floating point types
> +#endif
> +
> +using namespace std;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t f16i = 1.0f;                 // { dg-error "cannot convert 'float' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +float16_t f16k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +float16_t f16m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +float16_t f16o = 1.0Q;                 // { dg-error "cannot convert '__float128' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +#endif
> +float32_t f32i = 1.0f;
> +float32_t f32k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> +float32_t f32m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> +float32_t f32o = 1.0Q;                 // { dg-error "cannot convert '__float128' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> +float64_t f64i = 1.0f;
> +float64_t f64k = 1.0;
> +float64_t f64m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
> +float64_t f64o = 1.0Q;                 // { dg-error "cannot convert '__float128' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
> +float128_t f128i = 1.0f;
> +float128_t f128k = 1.0;
> +float128_t f128m = 1.0L;
> +float128_t f128o = 1.0Q;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +constexpr float16_t f16x = 1.0F16;
> +#endif
> +constexpr float32_t f32x = 2.0F32;
> +constexpr float64_t f64x = 3.0F64;
> +constexpr float128_t f128x = 4.0F128;
> +constexpr float fx = 5.0f;
> +constexpr double dx = 6.0;
> +constexpr long double ldx = 7.0L;
> +
> +constexpr int foo (float32_t) { return 1; }
> +constexpr int foo (float64_t) { return 2; }
> +constexpr int bar (float) { return 3; }
> +constexpr int bar (double) { return 4; }
> +constexpr int bar (long double) { return 5; }
> +constexpr int baz (float32_t) { return 6; }
> +constexpr int baz (float64_t) { return 7; }
> +constexpr int baz (float128_t) { return 8; }
> +constexpr int qux (float64_t) { return 9; }
> +constexpr int qux (float32_t) { return 10; }
> +constexpr int fred (long double) { return 11; }
> +constexpr int fred (double) { return 12; }
> +constexpr int fred (float) { return 13; }
> +constexpr int thud (float128_t) { return 14; }
> +constexpr int thud (float64_t) { return 15; }
> +constexpr int thud (float32_t) { return 16; }
> +struct S {
> +  constexpr operator float32_t () const { return 1.0f32; }
> +  constexpr operator float64_t () const { return 2.0f64; }
> +};
> +struct T {
> +  constexpr operator float64_t () const { return 3.0f64; }
> +  constexpr operator float32_t () const { return 4.0f32; }
> +};
> +
> +void
> +test (S s, T t)
> +{
> +#ifdef __STDCPP_FLOAT16_T__
> +  foo (float16_t (1.0));                       // { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (foo (float (2.0)) == 1);
> +  static_assert (foo (double (3.0)) == 2);
> +  constexpr double x (s);
> +  static_assert (x == 2.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  bar (f16x);                                  // { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (bar (f32x) == 3);
> +  static_assert (bar (f64x) == 4);
> +  bar (f128x);                                 // { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" }
> +  static_assert (bar (fx) == 3);
> +  static_assert (bar (dx) == 4);
> +  static_assert (bar (ldx) == 5);
> +#ifdef __STDCPP_FLOAT16_T__
> +  baz (f16x);                                  // { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (baz (f32x) == 6);
> +  static_assert (baz (f64x) == 7);
> +  static_assert (baz (f128x) == 8);
> +  static_assert (baz (fx) == 6);
> +  static_assert (baz (dx) == 7);
> +  static_assert (baz (ldx) == 8);
> +#ifdef __STDCPP_FLOAT16_T__
> +  qux (float16_t (1.0));                       // { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (qux (float (2.0)) == 10);
> +  static_assert (qux (double (3.0)) == 9);
> +  constexpr double y (t);
> +  static_assert (y == 3.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  fred (f16x);                                 // { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (fred (f32x) == 13);
> +  static_assert (fred (f64x) == 12);
> +  fred (f128x);                                        // { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" }
> +  static_assert (fred (fx) == 13);
> +  static_assert (fred (dx) == 12);
> +  static_assert (fred (ldx) == 11);
> +#ifdef __STDCPP_FLOAT16_T__
> +  thud (f16x);                                 // { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (thud (f32x) == 16);
> +  static_assert (thud (f64x) == 15);
> +  static_assert (thud (f128x) == 14);
> +  static_assert (thud (fx) == 16);
> +  static_assert (thud (dx) == 15);
> +  static_assert (thud (ldx) == 14);
> +}
> --- gcc/testsuite/g++.dg/cpp23/ext-floating4.C.jj       2022-09-09 18:48:11.979261440 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C  2022-09-10 10:55:24.105457186 +0200
> @@ -0,0 +1,126 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// Variant of ext-floating3.C test with different specific assumptions
> +// about float, double, long double.
> +// float, double and long double are assumed to be IEEE 754 single, double
> +// and quad.
> +// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } }
> +// { dg-options "" }
> +// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } }
> +// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } }
> +
> +#include "ext-floating.h"
> +
> +#if !defined(__STDCPP_FLOAT32_T__) \
> +    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
> +    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
> +    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
> +    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__
> +#error Unexpected set of floating point types
> +#endif
> +
> +using namespace std;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t f16i = 1.0f;                 // { dg-error "cannot convert 'float' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +float16_t f16k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +float16_t f16m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> +#endif
> +float32_t f32i = 1.0f;
> +float32_t f32k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> +float32_t f32m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> +float64_t f64i = 1.0f;
> +float64_t f64k = 1.0;
> +float64_t f64m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
> +float128_t f128i = 1.0f;
> +float128_t f128k = 1.0;
> +float128_t f128m = 1.0L;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +constexpr float16_t f16x = 1.0F16;
> +#endif
> +constexpr float32_t f32x = 2.0F32;
> +constexpr float64_t f64x = 3.0F64;
> +constexpr float128_t f128x = 4.0F128;
> +constexpr float fx = 5.0f;
> +constexpr double dx = 6.0;
> +constexpr long double ldx = 7.0L;
> +
> +constexpr int foo (float32_t) { return 1; }
> +constexpr int foo (float64_t) { return 2; }
> +constexpr int bar (float) { return 3; }
> +constexpr int bar (double) { return 4; }
> +constexpr int bar (long double) { return 5; }
> +constexpr int baz (float32_t) { return 6; }
> +constexpr int baz (float64_t) { return 7; }
> +constexpr int baz (float128_t) { return 8; }
> +constexpr int qux (float64_t) { return 9; }
> +constexpr int qux (float32_t) { return 10; }
> +constexpr int fred (long double) { return 11; }
> +constexpr int fred (double) { return 12; }
> +constexpr int fred (float) { return 13; }
> +constexpr int thud (float128_t) { return 14; }
> +constexpr int thud (float64_t) { return 15; }
> +constexpr int thud (float32_t) { return 16; }
> +struct S {
> +  constexpr operator float32_t () const { return 1.0f32; }
> +  constexpr operator float64_t () const { return 2.0f64; }
> +};
> +struct T {
> +  constexpr operator float64_t () const { return 3.0f64; }
> +  constexpr operator float32_t () const { return 4.0f32; }
> +};
> +
> +void
> +test (S s, T t)
> +{
> +#ifdef __STDCPP_FLOAT16_T__
> +  foo (float16_t (1.0));                       // { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (foo (float (2.0)) == 1);
> +  static_assert (foo (double (3.0)) == 2);
> +  constexpr double x (s);
> +  static_assert (x == 2.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  bar (f16x);                                  // { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (bar (f32x) == 3);
> +  static_assert (bar (f64x) == 4);
> +  static_assert (bar (f128x) == 5);
> +  static_assert (bar (fx) == 3);
> +  static_assert (bar (dx) == 4);
> +  static_assert (bar (ldx) == 5);
> +#ifdef __STDCPP_FLOAT16_T__
> +  baz (f16x);                                  // { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (baz (f32x) == 6);
> +  static_assert (baz (f64x) == 7);
> +  static_assert (baz (f128x) == 8);
> +  static_assert (baz (fx) == 6);
> +  static_assert (baz (dx) == 7);
> +  static_assert (baz (ldx) == 8);
> +#ifdef __STDCPP_FLOAT16_T__
> +  qux (float16_t (1.0));                       // { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (qux (float (2.0)) == 10);
> +  static_assert (qux (double (3.0)) == 9);
> +  constexpr double y (t);
> +  static_assert (y == 3.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  fred (f16x);                                 // { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (fred (f32x) == 13);
> +  static_assert (fred (f64x) == 12);
> +  static_assert (fred (f128x) == 11);
> +  static_assert (fred (fx) == 13);
> +  static_assert (fred (dx) == 12);
> +  static_assert (fred (ldx) == 11);
> +#ifdef __STDCPP_FLOAT16_T__
> +  thud (f16x);                                 // { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (thud (f32x) == 16);
> +  static_assert (thud (f64x) == 15);
> +  static_assert (thud (f128x) == 14);
> +  static_assert (thud (fx) == 16);
> +  static_assert (thud (dx) == 15);
> +  static_assert (thud (ldx) == 14);
> +}
> --- gcc/testsuite/g++.dg/cpp23/ext-floating5.C.jj       2022-09-09 20:00:22.489534397 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C  2022-09-10 10:44:59.653943267 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// IBM extended long double and _Float128 should have unordered conversion
> +// ranks as IBM extended long double has variable precision from 53 bits
> +// for denormals to more than 2150 bits for certain numbers.
> +// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } }
> +// { dg-require-effective-target ppc_float128_sw }
> +// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" }
> +
> +auto a = 1.0F128 + 1.0L;       // { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" }
> +auto b = 1.0L + 1.0F128;       // { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" }
> +bool c;
> +auto d = c ? 1.0F128 : 1.0L;   // { dg-error "operands to '\\\?:' have unordered conversion rank of types '_Float128' and 'long double'" }
> +auto e = c ? 1.0L : 1.0F128;   // { dg-error "operands to '\\\?:' have unordered conversion rank of types 'long double' and '_Float128'" }
> --- gcc/testsuite/g++.dg/cpp23/ext-floating6.C.jj       2022-09-10 10:19:12.402030094 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating6.C  2022-09-09 18:46:07.281922287 +0200
> @@ -0,0 +1,30 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do compile { target c++23 } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#ifdef __STRICT_ANSI__
> +#undef __SIZEOF_FLOAT128__
> +#endif
> +
> +using namespace std;
> +
> +float foo (float x, float y, float z) { return x * y + z; }
> +double foo (double x, double y, double z) { return x * y + z; }
> +long double foo (long double x, long double y, long double z) { return x * y + z; }
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; }
> +#endif
> --- gcc/testsuite/g++.dg/cpp23/ext-floating7.C.jj       2022-09-10 10:47:37.550796997 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C  2022-09-10 10:53:25.622065903 +0200
> @@ -0,0 +1,119 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float16_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float16 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT16_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 16
> +#endif
> +
> +#include <stdarg.h>
> +#include "ext-floating.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 TYPE CONCAT (_Float, WIDTH)
> +#define CST(C) CONCAT3 (C, f, WIDTH)
> +#define CSTU(C) CONCAT3 (C, F, WIDTH)
> +
> +extern "C" void abort ();
> +
> +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
> +fn (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 = fn (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 ();
> +}
> --- gcc/testsuite/g++.dg/cpp23/ext-floating8.C.jj       2022-09-10 10:52:54.654486646 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C  2022-09-10 10:53:41.424851341 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float32_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float32 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT32_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 32
> +#endif
> +
> +#include "ext-floating7.C"
> --- gcc/testsuite/g++.dg/cpp23/ext-floating9.C.jj       2022-09-10 10:53:49.328744035 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating9.C  2022-09-10 10:53:57.280636056 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float64_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float64 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT64_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 64
> +#endif
> +
> +#include "ext-floating7.C"
> --- gcc/testsuite/g++.dg/cpp23/ext-floating10.C.jj      2022-09-10 10:54:08.224487463 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C 2022-09-10 10:54:21.578306159 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float128_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float128 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT128_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 128
> +#endif
> +
> +#include "ext-floating7.C"
> --- gcc/testsuite/g++.dg/cpp23/ext-floating.h.jj        2022-09-09 18:46:07.281922287 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating.h   2022-09-09 18:46:07.281922287 +0200
> @@ -0,0 +1,30 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +
> +namespace std
> +{
> +  #ifdef __STDCPP_FLOAT16_T__
> +  using float16_t = _Float16;
> +  #endif
> +  #ifdef __STDCPP_FLOAT32_T__
> +  using float32_t = _Float32;
> +  #endif
> +  #ifdef __STDCPP_FLOAT64_T__
> +  using float64_t = _Float64;
> +  #endif
> +  #ifdef __STDCPP_FLOAT128_T__
> +  using float128_t = _Float128;
> +  #endif
> +  #undef __STDCPP_BFLOAT16_T__
> +  #ifdef __STDCPP_BFLOAT16_T__
> +  using bfloat16_t = __bf16; // ???
> +  #endif
> +  template<typename T, T v> struct integral_constant {
> +    static constexpr T value = v;
> +  };
> +  typedef integral_constant<bool, false> false_type;
> +  typedef integral_constant<bool, true> true_type;
> +  template<class T, class U>
> +  struct is_same : std::false_type {};
> +  template <class T>
> +  struct is_same<T, T> : std::true_type {};
> +}
> --- gcc/testsuite/g++.target/i386/float16-1.C.jj        2021-12-30 15:12:43.315149146 +0100
> +++ gcc/testsuite/g++.target/i386/float16-1.C   2022-09-12 08:49:38.178955414 +0200
> @@ -1,8 +1,8 @@
>  /* { dg-do compile } */
>  /* { dg-options "-O2 -mno-sse2" } */
>
> -_Float16/* { dg-error "does not name a type" } */
> +_Float16       /* { dg-error "expected unqualified-id before '_Float16'" } */
>  foo (_Float16 x)
>  {
>    return x;
> -}
> +}              /* { dg-error "'_Float16' is not supported on this target" } */
> --- libcpp/expr.cc.jj   2022-09-08 13:01:19.837771596 +0200
> +++ libcpp/expr.cc      2022-09-09 09:52:46.533798139 +0200
> @@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfil
>         case 'f': case 'F':
>           f++;
>           if (len > 0
> -             && !CPP_OPTION (pfile, cplusplus)
>               && s[1] >= '1'
>               && s[1] <= '9'
>               && fn_bits == 0)
> @@ -230,7 +229,9 @@ interpret_float_suffix (cpp_reader *pfil
>                   len--;
>                   s++;
>                 }
> -             if (len > 0 && s[1] == 'x')
> +             if (len > 0
> +                 && s[1] == 'x'
> +                 && !CPP_OPTION (pfile, cplusplus))
>                 {
>                   fnx++;
>                   len--;
> --- include/demangle.h.jj       2022-08-26 09:23:37.788064821 +0200
> +++ include/demangle.h  2022-09-09 09:52:46.533798139 +0200
> @@ -457,6 +457,11 @@ enum demangle_component_type
>    DEMANGLE_COMPONENT_MODULE_PARTITION,
>    DEMANGLE_COMPONENT_MODULE_ENTITY,
>    DEMANGLE_COMPONENT_MODULE_INIT,
> +
> +  /* A builtin type with argument.  This holds the builtin type
> +     information.  */
> +  DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
> +
>  };
>
>  /* Types which are only used internally.  */
> @@ -543,6 +548,14 @@ struct demangle_component
>        const struct demangle_builtin_type_info *type;
>      } s_builtin;
>
> +    /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  */
> +    struct
> +    {
> +      /* Builtin type.  */
> +      const struct demangle_builtin_type_info *type;
> +      int arg;
> +    } s_extended_builtin;
> +
>      /* For DEMANGLE_COMPONENT_SUB_STD.  */
>      struct
>      {
> --- libiberty/cp-demangle.c.jj  2022-08-26 09:23:37.788064821 +0200
> +++ libiberty/cp-demangle.c     2022-09-09 09:52:46.957792397 +0200
> @@ -648,6 +648,10 @@ d_dump (struct demangle_component *dc, i
>      case DEMANGLE_COMPONENT_BUILTIN_TYPE:
>        printf ("builtin type %s\n", dc->u.s_builtin.type->name);
>        return;
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> +      printf ("builtin type %s%d\n", dc->u.s_extended_builtin.type->name,
> +             dc->u.s_extended_builtin.type->arg);
> +      return;
>      case DEMANGLE_COMPONENT_OPERATOR:
>        printf ("operator %s\n", dc->u.s_operator.op->name);
>        return;
> @@ -771,11 +775,6 @@ d_dump (struct demangle_component *dc, i
>      case DEMANGLE_COMPONENT_PTRMEM_TYPE:
>        printf ("pointer to member type\n");
>        break;
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> -      printf ("fixed-point type, accum? %d, sat? %d\n",
> -              dc->u.s_fixed.accum, dc->u.s_fixed.sat);
> -      d_dump (dc->u.s_fixed.length, indent + 2);
> -      break;
>      case DEMANGLE_COMPONENT_ARGLIST:
>        printf ("argument list\n");
>        break;
> @@ -1109,6 +1108,27 @@ d_make_builtin_type (struct d_info *di,
>    return p;
>  }
>
> +/* Add a new extended builtin type component.  */
> +
> +static struct demangle_component *
> +d_make_extended_builtin_type (struct d_info *di,
> +                             const struct demangle_builtin_type_info *type,
> +                             int arg)
> +{
> +  struct demangle_component *p;
> +
> +  if (type == NULL)
> +    return NULL;
> +  p = d_make_empty (di);
> +  if (p != NULL)
> +    {
> +      p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE;
> +      p->u.s_extended_builtin.type = type;
> +      p->u.s_extended_builtin.arg = arg;
> +    }
> +  return p;
> +}
> +
>  /* Add a new operator component.  */
>
>  static struct demangle_component *
> @@ -2464,6 +2484,7 @@ cplus_demangle_builtin_types[D_BUILTIN_T
>    /* 32 */ { NL ("char32_t"),  NL ("char32_t"),        D_PRINT_DEFAULT },
>    /* 33 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
>              D_PRINT_DEFAULT },
> +  /* 34 */ { NL ("_Float"),    NL ("_Float"),          D_PRINT_FLOAT },
>  };
>
>  CP_STATIC_IF_GLIBCPP_V3
> @@ -2727,19 +2748,22 @@ cplus_demangle_type (struct d_info *di)
>           break;
>
>         case 'F':
> -         /* Fixed point types. DF<int bits><length><fract bits><sat>  */
> -         ret = d_make_empty (di);
> -         ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
> -         if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
> -           /* For demangling we don't care about the bits.  */
> -           d_number (di);
> -         ret->u.s_fixed.length = cplus_demangle_type (di);
> -         if (ret->u.s_fixed.length == NULL)
> -           return NULL;
> -         d_number (di);
> -         peek = d_next_char (di);
> -         ret->u.s_fixed.sat = (peek == 's');
> -         break;
> +         /* DF<number>_ - _Float<number>.  */
> +         {
> +           int arg = d_number (di);
> +           char buf[12];
> +           if (d_peek_char (di) != '_')
> +             return NULL;
> +           ret
> +             = d_make_extended_builtin_type (di,
> +                                             &cplus_demangle_builtin_types[34],
> +                                             arg);
> +           d_advance (di, 1);
> +           sprintf (buf, "%d", arg);
> +           di->expansion += ret->u.s_extended_builtin.type->len
> +                            + strlen (buf);
> +           break;
> +         }
>
>         case 'v':
>           ret = d_vector_type (di);
> @@ -4202,6 +4226,7 @@ d_count_templates_scopes (struct d_print
>      case DEMANGLE_COMPONENT_FUNCTION_PARAM:
>      case DEMANGLE_COMPONENT_SUB_STD:
>      case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
>      case DEMANGLE_COMPONENT_OPERATOR:
>      case DEMANGLE_COMPONENT_CHARACTER:
>      case DEMANGLE_COMPONENT_NUMBER:
> @@ -4210,6 +4235,7 @@ d_count_templates_scopes (struct d_print
>      case DEMANGLE_COMPONENT_MODULE_NAME:
>      case DEMANGLE_COMPONENT_MODULE_PARTITION:
>      case DEMANGLE_COMPONENT_MODULE_INIT:
> +    case DEMANGLE_COMPONENT_FIXED_TYPE:
>        break;
>
>      case DEMANGLE_COMPONENT_TEMPLATE:
> @@ -4309,10 +4335,6 @@ d_count_templates_scopes (struct d_print
>        d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
>        break;
>
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> -      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
> -      break;
> -
>      case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
>      case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
>      case DEMANGLE_COMPONENT_MODULE_ENTITY:
> @@ -4580,11 +4602,11 @@ d_find_pack (struct d_print_info *dpi,
>      case DEMANGLE_COMPONENT_TAGGED_NAME:
>      case DEMANGLE_COMPONENT_OPERATOR:
>      case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
>      case DEMANGLE_COMPONENT_SUB_STD:
>      case DEMANGLE_COMPONENT_CHARACTER:
>      case DEMANGLE_COMPONENT_FUNCTION_PARAM:
>      case DEMANGLE_COMPONENT_UNNAMED_TYPE:
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
>      case DEMANGLE_COMPONENT_DEFAULT_ARG:
>      case DEMANGLE_COMPONENT_NUMBER:
>        return NULL;
> @@ -5387,6 +5409,16 @@ d_print_comp_inner (struct d_print_info
>                          dc->u.s_builtin.type->java_len);
>        return;
>
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> +      if ((options & DMGL_JAVA) == 0)
> +       d_append_buffer (dpi, dc->u.s_extended_builtin.type->name,
> +                        dc->u.s_extended_builtin.type->len);
> +      else
> +       d_append_buffer (dpi, dc->u.s_extended_builtin.type->java_name,
> +                        dc->u.s_extended_builtin.type->java_len);
> +      d_append_num (dpi, dc->u.s_extended_builtin.arg);
> +      return;
> +
>      case DEMANGLE_COMPONENT_VENDOR_TYPE:
>        d_print_comp (dpi, options, d_left (dc));
>        return;
> @@ -5525,22 +5557,6 @@ d_print_comp_inner (struct d_print_info
>         return;
>        }
>
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> -      if (dc->u.s_fixed.sat)
> -       d_append_string (dpi, "_Sat ");
> -      /* Don't print "int _Accum".  */
> -      if (dc->u.s_fixed.length->u.s_builtin.type
> -         != &cplus_demangle_builtin_types['i'-'a'])
> -       {
> -         d_print_comp (dpi, options, dc->u.s_fixed.length);
> -         d_append_char (dpi, ' ');
> -       }
> -      if (dc->u.s_fixed.accum)
> -       d_append_string (dpi, "_Accum");
> -      else
> -       d_append_string (dpi, "_Fract");
> -      return;
> -
>      case DEMANGLE_COMPONENT_ARGLIST:
>      case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
>        if (d_left (dc) != NULL)
> --- libiberty/cp-demangle.h.jj  2022-08-26 09:23:37.788064821 +0200
> +++ libiberty/cp-demangle.h     2022-09-09 09:52:46.978792113 +0200
> @@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i)
>  extern const struct demangle_operator_info cplus_demangle_operators[];
>  #endif
>
> -#define D_BUILTIN_TYPE_COUNT (34)
> +#define D_BUILTIN_TYPE_COUNT (35)
>
>  CP_STATIC_IF_GLIBCPP_V3
>  const struct demangle_builtin_type_info
> --- libiberty/testsuite/demangle-expected.jj    2022-08-26 09:23:37.788064821 +0200
> +++ libiberty/testsuite/demangle-expected       2022-09-09 09:52:46.993791909 +0200
> @@ -1242,8 +1242,8 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8fun
>  post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
>  #
>  --format=auto --no-params
> -_Z3xxxDFyuVb
> -xxx(unsigned long long _Fract, bool volatile)
> +_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb
> +xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile)
>  xxx
>  # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
>  --format=auto --no-params
> --- fixincludes/inclhack.def.jj 2022-03-01 19:42:39.183264899 +0100
> +++ fixincludes/inclhack.def    2022-09-11 20:08:07.787691125 +0200
> @@ -2015,6 +2015,102 @@ fix = {
>         EOT;
>  };
>
> +/*  glibc-2.27 to 2.36 assume GCC 7 or later supports some or all
> + *  of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C,
> + *  but doesn't for C++.
> + */
> +fix = {
> +    hackname  = glibc_cxx_floatn_1;
> +    files     = bits/floatn.h, bits/floatn-common.h;
> +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> +               "(([ \t]*/\\*[^\n]*\\*/\n)?"
> +               "([ \t]*#[ \t]*if[^\n]*\n)?"
> +               "[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
> +    c_fix     = format;
> +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
> +    test_text = <<-EOT
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       /* The literal suffix f128 exists only since GCC 7.0.  */
> +       #   define __f128(x) x##l
> +       #  else
> +       #   define __f128(x) x##f128
> +       #  endif
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       /* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
> +       #   if __LDBL_MANT_DIG__ == 113
> +       #    define __f128(x) x##l
> +       #   else
> +       #    define __f128(x) x##q
> +       #   endif
> +       #  else
> +       #   define __f128(x) x##f128
> +       #  endif
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       #   ifdef __NO_LONG_DOUBLE_MATH
> +       #    define __f64(x) x##l
> +       #   else
> +       #    define __f64(x) x
> +       #   endif
> +       #  else
> +       #   define __f64(x) x##f64
> +       #  endif
> +       EOT;
> +};
> +
> +fix = {
> +    hackname  = glibc_cxx_floatn_2;
> +    files     = bits/floatn.h, bits/floatn-common.h;
> +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> +               "(([ \t]*/\\*[^\n]*\\*/\n)?"
> +               "[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
> +    c_fix     = format;
> +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
> +    test_text = <<-EOT
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
> +       #  endif
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       typedef __float128 _Float128;
> +       #  endif
> +       EOT;
> +};
> +
> +fix = {
> +    hackname  = glibc_cxx_floatn_3;
> +    files     = bits/floatn.h, bits/floatn-common.h;
> +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> +               "(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?"
> +               "([ \t]*#[ \t]*if[^\n]*\n)?"
> +               "([ \t]*typedef[ \t]+[^\n]*;\n)?"
> +               "[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
> +    c_fix     = format;
> +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
> +    test_text = <<-EOT
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       #   define __CFLOAT128 _Complex long double
> +       #  else
> +       #   define __CFLOAT128 _Complex _Float128
> +       #  endif
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       /* Add a typedef for older GCC compilers which don't natively support
> +          _Complex _Float128.  */
> +       typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
> +       #   define __CFLOAT128 __cfloat128
> +       #  else
> +       #   define __CFLOAT128 _Complex _Float128
> +       #  endif
> +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +       #   ifdef __NO_LONG_DOUBLE_MATH
> +       #    define __CFLOAT64 _Complex long double
> +       #   else
> +       #    define __CFLOAT64 _Complex double
> +       #   endif
> +       #  else
> +       #   define __CFLOAT64 _Complex _Float64
> +       #  endif
> +       EOT;
> +};
> +
>  /*  glibc-2.3.5 defines pthread mutex initializers incorrectly,
>   *  so we replace them with versions that correspond to the
>   *  definition.
> --- fixincludes/tests/base/bits/floatn.h.jj     2022-09-11 20:11:34.991962782 +0200
> +++ fixincludes/tests/base/bits/floatn.h        2022-09-11 20:09:48.323368533 +0200
> @@ -0,0 +1,74 @@
> +/*  DO NOT EDIT THIS FILE.
> +
> +    It has been auto-edited by fixincludes from:
> +
> +       "fixinc/tests/inc/bits/floatn.h"
> +
> +    This had to be done to correct non-standard usages in the
> +    original, manufacturer supplied header file.  */
> +
> +
> +
> +#if defined( GLIBC_CXX_FLOATN_1_CHECK )
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +/* The literal suffix f128 exists only since GCC 7.0.  */
> +#   define __f128(x) x##l
> +#  else
> +#   define __f128(x) x##f128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
> +#   if __LDBL_MANT_DIG__ == 113
> +#    define __f128(x) x##l
> +#   else
> +#    define __f128(x) x##q
> +#   endif
> +#  else
> +#   define __f128(x) x##f128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +#   ifdef __NO_LONG_DOUBLE_MATH
> +#    define __f64(x) x##l
> +#   else
> +#    define __f64(x) x
> +#   endif
> +#  else
> +#   define __f64(x) x##f64
> +#  endif
> +#endif  /* GLIBC_CXX_FLOATN_1_CHECK */
> +
> +
> +#if defined( GLIBC_CXX_FLOATN_2_CHECK )
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +typedef __float128 _Float128;
> +#  endif
> +#endif  /* GLIBC_CXX_FLOATN_2_CHECK */
> +
> +
> +#if defined( GLIBC_CXX_FLOATN_3_CHECK )
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +#   define __CFLOAT128 _Complex long double
> +#  else
> +#   define __CFLOAT128 _Complex _Float128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +/* Add a typedef for older GCC compilers which don't natively support
> +   _Complex _Float128.  */
> +typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
> +#   define __CFLOAT128 __cfloat128
> +#  else
> +#   define __CFLOAT128 _Complex _Float128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> +#   ifdef __NO_LONG_DOUBLE_MATH
> +#    define __CFLOAT64 _Complex long double
> +#   else
> +#    define __CFLOAT64 _Complex double
> +#   endif
> +#  else
> +#   define __CFLOAT64 _Complex _Float64
> +#  endif
> +#endif  /* GLIBC_CXX_FLOATN_3_CHECK */
> --- fixincludes/fixincl.x.jj    2022-03-01 19:42:39.169265091 +0100
> +++ fixincludes/fixincl.x       2022-09-11 20:09:37.668565341 +0200
> @@ -2,11 +2,11 @@
>   *
>   * DO NOT EDIT THIS FILE   (fixincl.x)
>   *
> - * It has been AutoGen-ed  February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16
> + * It has been AutoGen-ed  September 11, 2022 at 08:09:37 PM by AutoGen 5.18.16
>   * From the definitions    inclhack.def
>   * and the template file   fixincl
>   */
> -/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022
> +/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Sep 11 20:09:37 CEST 2022
>   *
>   * You must regenerate it.  Use the ./genfixes script.
>   *
> @@ -15,7 +15,7 @@
>   * certain ANSI-incompatible system header files which are fixed to work
>   * correctly with ANSI C and placed in a directory that GNU C will search.
>   *
> - * This file contains 267 fixup descriptions.
> + * This file contains 270 fixup descriptions.
>   *
>   * See README for more information.
>   *
> @@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4
>
>  /* * * * * * * * * * * * * * * * * * * * * * * * * *
>   *
> + *  Description of Glibc_Cxx_Floatn_1 fix
> + */
> +tSCC zGlibc_Cxx_Floatn_1Name[] =
> +     "glibc_cxx_floatn_1";
> +
> +/*
> + *  File name selection pattern
> + */
> +tSCC zGlibc_Cxx_Floatn_1List[] =
> +  "bits/floatn.h\0bits/floatn-common.h\0";
> +/*
> + *  Machine/OS name selection pattern
> + */
> +#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL
> +
> +/*
> + *  content selection pattern - do fix if pattern found
> + */
> +tSCC zGlibc_Cxx_Floatn_1Select0[] =
> +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> +(([ \t]*/\\*[^\n\
> +]*\\*/\n\
> +)?([ \t]*#[ \t]*if[^\n\
> +]*\n\
> +)?[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
> +
> +#define    GLIBC_CXX_FLOATN_1_TEST_CT  1
> +static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = {
> +  { TT_EGREP,    zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, };
> +
> +/*
> + *  Fix Command Arguments for Glibc_Cxx_Floatn_1
> + */
> +static const char* apzGlibc_Cxx_Floatn_1Patch[] = {
> +    "format",
> +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
> +%2",
> +    (char*)NULL };
> +
> +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> + *
> + *  Description of Glibc_Cxx_Floatn_2 fix
> + */
> +tSCC zGlibc_Cxx_Floatn_2Name[] =
> +     "glibc_cxx_floatn_2";
> +
> +/*
> + *  File name selection pattern
> + */
> +tSCC zGlibc_Cxx_Floatn_2List[] =
> +  "bits/floatn.h\0bits/floatn-common.h\0";
> +/*
> + *  Machine/OS name selection pattern
> + */
> +#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL
> +
> +/*
> + *  content selection pattern - do fix if pattern found
> + */
> +tSCC zGlibc_Cxx_Floatn_2Select0[] =
> +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> +(([ \t]*/\\*[^\n\
> +]*\\*/\n\
> +)?[ \t]*typedef[ \t]+[^\n\
> +]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
> +
> +#define    GLIBC_CXX_FLOATN_2_TEST_CT  1
> +static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = {
> +  { TT_EGREP,    zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, };
> +
> +/*
> + *  Fix Command Arguments for Glibc_Cxx_Floatn_2
> + */
> +static const char* apzGlibc_Cxx_Floatn_2Patch[] = {
> +    "format",
> +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
> +%2",
> +    (char*)NULL };
> +
> +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> + *
> + *  Description of Glibc_Cxx_Floatn_3 fix
> + */
> +tSCC zGlibc_Cxx_Floatn_3Name[] =
> +     "glibc_cxx_floatn_3";
> +
> +/*
> + *  File name selection pattern
> + */
> +tSCC zGlibc_Cxx_Floatn_3List[] =
> +  "bits/floatn.h\0bits/floatn-common.h\0";
> +/*
> + *  Machine/OS name selection pattern
> + */
> +#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL
> +
> +/*
> + *  content selection pattern - do fix if pattern found
> + */
> +tSCC zGlibc_Cxx_Floatn_3Select0[] =
> +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> +(([ \t]*/\\*[^\n\
> +]*\n\
> +?[^\n\
> +]*\\*/\n\
> +)?([ \t]*#[ \t]*if[^\n\
> +]*\n\
> +)?([ \t]*typedef[ \t]+[^\n\
> +]*;\n\
> +)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
> +
> +#define    GLIBC_CXX_FLOATN_3_TEST_CT  1
> +static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = {
> +  { TT_EGREP,    zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, };
> +
> +/*
> + *  Fix Command Arguments for Glibc_Cxx_Floatn_3
> + */
> +static const char* apzGlibc_Cxx_Floatn_3Patch[] = {
> +    "format",
> +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
> +%2",
> +    (char*)NULL };
> +
> +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> + *
>   *  Description of Glibc_Mutex_Init fix
>   */
>  tSCC zGlibc_Mutex_InitName[] =
> @@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[]
>   *
>   *  List of all fixes
>   */
> -#define REGEX_COUNT          305
> +#define REGEX_COUNT          308
>  #define MACH_LIST_SIZE_LIMIT 187
> -#define FIX_COUNT            267
> +#define FIX_COUNT            270
>
>  /*
>   *  Enumerate the fixes
> @@ -10977,6 +11103,9 @@ typedef enum {
>      GLIBC_C99_INLINE_2_FIXIDX,
>      GLIBC_C99_INLINE_3_FIXIDX,
>      GLIBC_C99_INLINE_4_FIXIDX,
> +    GLIBC_CXX_FLOATN_1_FIXIDX,
> +    GLIBC_CXX_FLOATN_2_FIXIDX,
> +    GLIBC_CXX_FLOATN_3_FIXIDX,
>      GLIBC_MUTEX_INIT_FIXIDX,
>      GLIBC_STDINT_FIXIDX,
>      GLIBC_STRNCPY_FIXIDX,
> @@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
>       GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
>       aGlibc_C99_Inline_4Tests,   apzGlibc_C99_Inline_4Patch, 0 },
>
> +  {  zGlibc_Cxx_Floatn_1Name,    zGlibc_Cxx_Floatn_1List,
> +     apzGlibc_Cxx_Floatn_1Machs,
> +     GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> +     aGlibc_Cxx_Floatn_1Tests,   apzGlibc_Cxx_Floatn_1Patch, 0 },
> +
> +  {  zGlibc_Cxx_Floatn_2Name,    zGlibc_Cxx_Floatn_2List,
> +     apzGlibc_Cxx_Floatn_2Machs,
> +     GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> +     aGlibc_Cxx_Floatn_2Tests,   apzGlibc_Cxx_Floatn_2Patch, 0 },
> +
> +  {  zGlibc_Cxx_Floatn_3Name,    zGlibc_Cxx_Floatn_3List,
> +     apzGlibc_Cxx_Floatn_3Machs,
> +     GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> +     aGlibc_Cxx_Floatn_3Tests,   apzGlibc_Cxx_Floatn_3Patch, 0 },
> +
>    {  zGlibc_Mutex_InitName,    zGlibc_Mutex_InitList,
>       apzGlibc_Mutex_InitMachs,
>       GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,
>
>         Jakub
>


-- 
BR,
Hongtao

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-20  3:35 ` Hongtao Liu
@ 2022-09-20  7:14   ` Hongtao Liu
  2022-09-20  8:51   ` Jakub Jelinek
  1 sibling, 0 replies; 16+ messages in thread
From: Hongtao Liu @ 2022-09-20  7:14 UTC (permalink / raw)
  To: phoebe.wang; +Cc: gcc-patches

+My intel folk phoebe working for llvm side.

On Tue, Sep 20, 2022 at 11:35 AM Hongtao Liu <crazylht@gmail.com> wrote:
>
> On Mon, Sep 12, 2022 at 4:06 PM Jakub Jelinek via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > Hi!
> >
> > The following patch implements the compiler part of C++23
> > P1467R9 - Extended floating-point types and standard names compiler part
> > by introducing _Float{16,32,64,128} as keywords and builtin types
> > like they are implemented for C already since GCC 7.
> > It doesn't introduce _Float{32,64,128}x for C++, those remain C only
> > for now, mainly because https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
> > has mangling for:
> > ::= DF <number> _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
> > but doesn't for _FloatNx.  And it doesn't add anything for bfloat16_t
> > support, see below.
> > Regarding mangling, I think mangling _FloatNx as DF <number> x _ would be
> > possible, but would need to be discussed and voted in.
> > As there is no _FloatNx support for C++, I think it is wrong to announce
> > it through __FLT{32,64,128}X_*__ predefined macros (so the patch disables
> > those for C++; unfortunately g++ 7 to 12 will predefine those and also
> > __FLT{32,64,128}_*__ even when _FloatN support isn't implemented).
> > The patch wants to keep backwards compatibility with how __float128 has
> > been handled in C++ before, both for mangling and behavior in binary
> > operations, overload resolution etc.  So, there are some backend changes
> > where for C __float128 and _Float128 are the same type (float128_type_node
> > and float128t_type_node are the same pointer), but for C++ they are distinct
> > types which mangle differently and _Float128 is treated as extended
> > floating-point type while __float128 is treated as non-standard floating
> > point type.  The various C++23 changes about how floating-point types
> > are changed are actually implemented as written in the spec only if at least
> > one of the types involved is _Float{16,32,64,128} and kept previous behavior
> > otherwise.  For float/double/long double the rules are actually written that
> > they behave the same as before.
> > There is some backwards incompatibility at least on x86 regarding _Float16,
> > because that type was already used by that name and with the DF16_ mangling
> > (but only since GCC 12 and I think it isn't that widely used in the wild
> > yet).  E.g. config/i386/avx512fp16intrin.h shows the issues, where
> > in C or in GCC 12 in C++ one could pass 0.0f to a builtin taking _Float16
> > argument, but with the changes that is not possible anymore, one needs
> > to either use 0.0f16 or (_Float16) 0.0f.
> > We have also a problem with glibc headers, where since glibc 2.27
> > math.h and complex.h aren't compilable with these changes.  One gets
> > errors like:
> > In file included from /usr/include/math.h:43,
> >                  from abc.c:1:
> > /usr/include/bits/floatn.h:86:9: error: multiple types in one declaration
> >    86 | typedef __float128 _Float128;
> >       |         ^~~~~~~~~~
> > /usr/include/bits/floatn.h:86:20: error: declaration does not declare anything [-fpermissive]
> >    86 | typedef __float128 _Float128;
> >       |                    ^~~~~~~~~
> > In file included from /usr/include/bits/floatn.h:119:
> > /usr/include/bits/floatn-common.h:214:9: error: multiple types in one declaration
> >   214 | typedef float _Float32;
> >       |         ^~~~~
> > /usr/include/bits/floatn-common.h:214:15: error: declaration does not declare anything [-fpermissive]
> >   214 | typedef float _Float32;
> >       |               ^~~~~~~~
> > /usr/include/bits/floatn-common.h:251:9: error: multiple types in one declaration
> >   251 | typedef double _Float64;
> >       |         ^~~~~~
> > /usr/include/bits/floatn-common.h:251:16: error: declaration does not declare anything [-fpermissive]
> >   251 | typedef double _Float64;
> >       |                ^~~~~~~~
> > This is from snippets like:
> > /* The remaining of this file provides support for older compilers.  */
> > # if __HAVE_FLOAT128
> >
> > /* The type _Float128 exists only since GCC 7.0.  */
> > #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > typedef __float128 _Float128;
> > #  endif
> > where it hardcodes that C++ doesn't have _Float{16,32,64,128} support nor
> > {f,F}{16,32,64,128} literal suffixes nor _Complex _Float{16,32,64,128}.
> > The patch fixincludes this for now and hopefully if this is committed, then
> > glibc can change those.  Right now the patch changes those
> > #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > conditions to
> > #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > where it relies on __FLT32X_*__ macros no longer being predefined for C++.
> > Now, I guess for the fixincludes it could also use
> > #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> > where earlier GCC 13 snapshots would not be doing the fixincludes,
> > but the question is what to use for upstream glibc, because
> > there will be 13.0 snapshots where C++ doesn't support _Float{16,32,64,128}
> > and where it is essential to use what glibc has been doing previously
> > and using the #else would fail miserably, and then 13.0 snapshots where it
> > does support it and where using the if would fail miserably.
> > One option is to use
> > #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1))
> > in glibc and rely on fixincludes for 13.0 snapshots (or of course later when
> > using 13.1+ with older glibc).
> > Another thing is mangling, as said above, Itanium C++ ABI specifies
> > DF <number> _ as _Float{16,32,64,128} mangling, but GCC was implementing
> > a mangling incompatible with that starting with DF for fixed point types.
> > Fixed point was never supported in C++ though, I believe the reason why
> > the mangling has been added was that due to a bug it would leak into the
> > C++ FE through decltype (0.0r) etc.  But that has been shortly after the
> > mangling was added fixed (I think in the same GCC release cycle), so we
> > now reject 0.0r etc. in C++.  If we ever need the fixed point mangling,
> > I think it can be readded but better with a different prefix so that it
> > doesn't conflict with the published standard manglings.  So, this patch
> > also kills the fixed point mangling and implements the DF <number> _
> > demangling.
> > The patch predefines __STDCPP_FLOAT{16,32,64,128}_T__ macros when
> > those types are available, but only for C++23, while the underlying types
> > are available in C++98 and later including the {f,F}{16,32,64,128} literal
> > suffixes (but those with a pedwarn for C++20 and earlier).  My understanding
> > is that it needs to be predefined by the compiler, on the other side
> > predefining even for older modes when <stdfloat> is a new C++23 header
> > would be weird.  One can find out if _Float{16,32,64,128} is supported in
> > C++ by
> > defined(__FLT{16,32,64,128}_MANT_DIG__) && !defined(__FLT32X_MANT_DIG__)
> > (unfortunately not just the former because GCC 7-12 predefined those too)
> > or perhaps __GNUC__ >= 13 && defined(__FLT{16,32,64,128}_MANT_DIG__)
> > (but that doesn't work well with older G++ 13 snapshots).
> >
> > As for std::bfloat16_t, three targets (aarch64, arm and x86) apparently
> > "support" __bf16 type which has the bfloat16 format, but isn't really
> > usable, e.g. {aarch64,arm,ix86}_invalid_conversion disallow any conversions
> > from or to type with BFmode, {aarch64,arm,ix86}_invalid_unary_op disallows
> > any unary operations on those except for ADDR_EXPR and
> > {aarch64,arm,ix86}_invalid_binary_op disallows any binary operation on
> > those.  So, I think we satisfy:
> > "If the implementation supports an extended floating-point type with the
> > properties, as specified by ISO/IEC/IEEE 60559, of radix (b) of 2, storage
> > width in bits (k) of 16, precision in bits (p) of 8, maximum exponent (emax)
> > of 127, and exponent field width in bits (w) of 8, then the typedef-name
> > std::bfloat16_t is defined in the header <stdfloat> and names such a type,
> > the macro __STDCPP_BFLOAT16_T__ is defined, and the floating-point literal
> > suffixes bf16 and BF16 are supported."
> > because we don't really support those right now.
> > The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> > shouldn't support it, in the PR there is a partial patch to do so, but
> > the big question is if it should be supported as the __bf16 type those
> > 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> > and add conversions to/from at least SFmode but probably also DFmode, TFmode
> > and XFmode on x86 and implement arithmetics on those through conversion to
> > SFmode, performing arithmetics there and conversion back.
> > Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> > implemented inline, SFmode -> BFmode conversion is harder,
> > I think it is roughly:
> I'm not sure if there should be any floating point exceptions for
> BFmode operation.
> For x86, there's no floating point exceptions for AVX512_BF16 related
> instructions
> > __bf16
> > __truncsfbf2 (_Float32 x)
> > {
> >   unsigned int y;
> >   memcpy (&y, &x, sizeof (y));
> >   unsigned int z = x & 0x7fffffff;
> >   unsigned short r;
> >   __bf16 ret;
> >   if (z < 0x800000)
> >     // Zero or denormal, flush to zero.
> >     r = (x & 0x80000000) >> 16;
> >   else if (z < 0x7f800000)
> >     // Normal, round to nearest.
> >     r = (x + 0x7fff + ((x >> 16) & 1)) >> 16;
> >   else if (z == 0x7f800000)
> >     // Inf.
> >     r = x >> 16;
> >   else
> >     // NaN.
> >     r = (x >> 16) | (1 << 6);
> >   memcpy (&ret, &r, sizeof (r));
> >   return ret;
> > }
> > (untested) and the question is if it should be implemented in libgcc
> > (and using soft-fp or not), or inline, or both depending on -Os.
> > Or there is the possibility to keep __bf16 a lame type one can't convert
> > to/from or perform most unary and all binary ops on it, and add for C++
> > a new type (say __bfloat16_t or whatever else), agree on mangling in
> > Itanium ABI and implement full support just for that type.
> >
> > Bootstrapped/regtested on x86_64-linux and i686-linux and additionally
> > tested on some of the testcases on crosses to powerpc64le-linux (various
> > cases including -mabi=ieeelongdouble and -mabi=ibmlongdouble), aarch64-linux
> > and s390x-linux.
> >
> > Ok for trunk?
> >
> > 2022-09-12  Jakub Jelinek  <jakub@redhat.com>
> >
> >         PR c++/106652
> > gcc/
> >         * tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE
> >         enumerator.
> >         * tree.h (float128t_type_node): Define.
> >         * tree.cc (build_common_tree_nodes): Initialize float128t_type_node.
> >         * builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that
> >         _Float<N> is supported in C++ too.
> >         * config/i386/i386.cc (ix86_mangle_type): Only mangle as "g"
> >         float128t_type_node.
> >         * config/i386/i386-builtins.cc (ix86_init_builtin_types): Use
> >         float128t_type_node for __float128 instead of float128_type_node
> >         and create it if NULL.
> >         * config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph,
> >         _mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of
> >         0.0f.
> >         * config/ia64/ia64.cc (ia64_init_builtins): Use
> >         float128t_type_node for __float128 instead of float128_type_node
> >         and create it if NULL.
> >         * config/rs6000/rs6000-c.cc (is_float128_p): Also return true
> >         for float128t_type_node if non-NULL.
> >         * config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle
> >         float128_type_node as "u9__ieee128".
> >         * config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use
> >         float128t_type_node for __float128 instead of float128_type_node
> >         and create it if NULL.
> > gcc/c-family/
> >         * c-common.cc (c_common_reswords): Change _Float{16,32,64,128} flags
> >         from D_CONLY to 0.
> >         (shorten_binary_op): Punt if common_type returns error_mark_node.
> >         (shorten_compare): Likewise.
> >         (c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128}
> >         builtin types if available but not _Float{32,64,128}x.  For C++
> >         clear float128t_type_node.
> >         * c-cppbuiltin.cc (c_cpp_builtins): For C++ don't predefine
> >         __FLT{32,64,128}X_*__ macros, on the other side predefine
> >         __STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported.
> >         * c-common.h (CASE_RID_FLOATN): Define.
> >         (CASE_RID_FLOATN_NX): Use it.
> >         * c-lex.cc (interpret_float): For q/Q suffixes prefer
> >         float128t_type_node over float128_type_node.  Allow
> >         {f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn
> >         for C++20 and older.  Don't call excess_precision_type for C++.
> > gcc/cp/
> >         * cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement
> >         P1467R9 - Extended floating-point types and standard names except
> >         for std::bfloat16_t for now.  Declare.
> >         (extended_float_type_p): New inline function.
> >         * mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node
> >         as DF{16,32,64,128}_.  Remove FIXED_POINT_TYPE mangling that conflicts
> >         with that.
> >         * typeck2.cc (check_narrowing): If one of ftype or type is extended
> >         floating-point type, compare floating-point conversion ranks.
> >         * parser.cc (cp_keyword_starts_decl_specifier_p): Handle
> >         CASE_RID_FLOATN.
> >         (cp_parser_simple_type_specifier): Likewise and diagnose missing
> >         _Float<N> support if not supported by target.
> >         * typeck.cc (cp_compare_floating_point_conversion_ranks): New function.
> >         (cp_common_type): If both types are REAL_TYPE and one or both are
> >         extended floating-point types, select common type based on comparison
> >         of floating-point conversion ranks and subranks.
> >         (cp_build_binary_op): Diagnose operation with floating point arguments
> >         with unordered conversion ranks.
> >         * call.cc (standard_conversion): For floating-point conversion, if
> >         either from or to are extended floating-point types reject implicit
> >         conversion from larger to smaller conversion rank or with unordered
> >         conversion ranks.
> >         (build_conditional_expr): Diagnose operation with floating point
> >         arguments with unordered conversion ranks.
> >         (convert_arg_to_ellipsis): Don't promote extended floating-point types
> >         narrower than double to double.
> >         (compare_ics): Implement P1467R9 [over.ics.rank]/4 changes.
> > gcc/testsuite/
> >         * g++.dg/cpp23/ext-floating1.C: New test.
> >         * g++.dg/cpp23/ext-floating2.C: New test.
> >         * g++.dg/cpp23/ext-floating3.C: New test.
> >         * g++.dg/cpp23/ext-floating4.C: New test.
> >         * g++.dg/cpp23/ext-floating5.C: New test.
> >         * g++.dg/cpp23/ext-floating6.C: New test.
> >         * g++.dg/cpp23/ext-floating7.C: New test.
> >         * g++.dg/cpp23/ext-floating8.C: New test.
> >         * g++.dg/cpp23/ext-floating9.C: New test.
> >         * g++.dg/cpp23/ext-floating10.C: New test.
> >         * g++.dg/cpp23/ext-floating.h: New file.
> >         * g++.target/i386/float16-1.C: Adjust expected diagnostics.
> > libcpp/
> >         * expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} suffixes
> >         for C++, but not {f,F}{32,64,128}x.
> > include/
> >         * demangle.h (enum demangle_component_type): Add
> >         DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
> >         (struct demangle_component): Add u.s_extended_builtin member.
> > libiberty/
> >         * cp-demangle.c (d_dump): Handle
> >         DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Don't handle
> >         DEMANGLE_COMPONENT_FIXED_TYPE.
> >         (d_make_extended_builtin_type): New function.
> >         (cplus_demangle_builtin_types): Add _Float entry.
> >         (cplus_demangle_type): For DF demangle it as _Float<N> rather
> >         than fixed point which conflicts with it.
> >         (d_count_templates_scopes): Handle
> >         DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Just break; for
> >         DEMANGLE_COMPONENT_FIXED_TYPE.
> >         (d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
> >         Don't handle DEMANGLE_COMPONENT_FIXED_TYPE.
> >         (d_print_comp_inner): Likewise.
> >         * cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump.
> >         * testsuite/demangle-expected: Replace _Z3xxxDFyuVb test
> >         with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb.
> > fixincludes/
> >         * inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2,
> >         glibc_cxx_floatn_3): New fixes.
> >         * tests/base/bits/floatn.h: New file.
> >         * fixincl.x: Regenerated.
> >
> > --- gcc/tree-core.h.jj  2022-09-09 12:27:23.180736449 +0200
> > +++ gcc/tree-core.h     2022-09-09 18:46:07.257922609 +0200
> > @@ -690,6 +690,10 @@ enum tree_index {
> >                              - TI_FLOATN_NX_TYPE_FIRST          \
> >                              + 1)
> >
> > +  /* Type used by certain backends for __float128, which in C++ should be
> > +     distinct type from _Float128 for backwards compatibility reasons.  */
> > +  TI_FLOAT128T_TYPE,
> > +
> >    /* Put the complex types after their component types, so that in (sequential)
> >       tree streaming we can assert that their component types have already been
> >       handled (see tree-streamer.cc:record_common_node).  */
> > --- gcc/tree.h.jj       2022-09-09 12:27:23.183736409 +0200
> > +++ gcc/tree.h  2022-09-09 18:46:07.258922596 +0200
> > @@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree ex
> >  #define float64x_type_node             global_trees[TI_FLOAT64X_TYPE]
> >  #define float128x_type_node            global_trees[TI_FLOAT128X_TYPE]
> >
> > +/* Type used by certain backends for __float128, which in C++ should be
> > +   distinct type from _Float128 for backwards compatibility reasons.  */
> > +#define float128t_type_node            global_trees[TI_FLOAT128T_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]
> > --- gcc/tree.cc.jj      2022-09-09 18:44:27.153255900 +0200
> > +++ gcc/tree.cc 2022-09-09 18:46:07.260922569 +0200
> > @@ -9459,6 +9459,7 @@ build_common_tree_nodes (bool signed_cha
> >        layout_type (FLOATN_NX_TYPE_NODE (i));
> >        SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
> >      }
> > +  float128t_type_node = float128_type_node;
> >
> >    float_ptr_type_node = build_pointer_type (float_type_node);
> >    double_ptr_type_node = build_pointer_type (double_type_node);
> > --- gcc/builtins.def.jj 2022-09-09 12:27:23.136737041 +0200
> > +++ gcc/builtins.def    2022-09-09 18:46:07.261922555 +0200
> > @@ -115,8 +115,8 @@ along with GCC; see the file COPYING3.
> >     we are compiling for the C language with GNU extensions, we enable the name
> >     without the __builtin_ prefix as well as the name with the __builtin_
> >     prefix.  C++ does not enable these names by default because they don't have
> > -   the _Float<N> and _Float<N>X keywords, and a class based library should use
> > -   the __builtin_ names.  */
> > +   the _Float<N>x keywords, and a class based library should use the __builtin_
> > +   names.  */
> >  #undef DEF_FLOATN_BUILTIN
> >  #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS)    \
> >    DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,   \
> > --- gcc/config/i386/i386.cc.jj  2022-09-09 12:27:23.141736974 +0200
> > +++ gcc/config/i386/i386.cc     2022-09-10 11:21:26.997205883 +0200
> > @@ -22711,7 +22711,10 @@ ix86_mangle_type (const_tree type)
> >        return "DF16_";
> >      case E_TFmode:
> >        /* __float128 is "g".  */
> > -      return "g";
> > +      if (type == float128t_type_node)
> > +       return "g";
> > +      /* _Float128 should mangle as "DF128_" done in generic code.  */
> > +      return NULL;
> >      case E_XFmode:
> >        /* "long double" or __float80 is "e".  */
> >        return "e";
> > --- gcc/config/i386/i386-builtins.cc.jj 2022-09-09 12:27:23.138737014 +0200
> > +++ gcc/config/i386/i386-builtins.cc    2022-09-09 18:46:07.264922515 +0200
> > @@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void)
> >    lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
> >
> >    /* 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");
> > +     _Float128, so for C we only need to register the __float128 name for
> > +     it.  For C++, we create a distinct type which will mangle differently
> > +     (g) vs. _Float128 (DF128_) and behave backwards compatibly.  */
> > +  if (float128t_type_node == NULL_TREE)
> > +    {
> > +      float128t_type_node = make_node (REAL_TYPE);
> > +      TYPE_PRECISION (float128t_type_node)
> > +       = TYPE_PRECISION (float128_type_node);
> > +      SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
> > +      layout_type (float128t_type_node);
> > +    }
> > +  lang_hooks.types.register_builtin_type (float128t_type_node, "__float128");
> >
> >    ix86_register_float16_builtin_type ();
> >
> > --- gcc/config/i386/avx512fp16intrin.h.jj       2022-01-11 22:31:40.696768297 +0100
> > +++ gcc/config/i386/avx512fp16intrin.h  2022-09-11 23:23:28.617437158 +0200
> > @@ -183,21 +183,21 @@ extern __inline __m128h
> >  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
> >  _mm_setzero_ph (void)
> >  {
> > -  return _mm_set1_ph (0.0f);
> > +  return _mm_set1_ph (0.0f16);
> >  }
> >
> >  extern __inline __m256h
> >  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
> >  _mm256_setzero_ph (void)
> >  {
> > -  return _mm256_set1_ph (0.0f);
> > +  return _mm256_set1_ph (0.0f16);
> >  }
> >
> >  extern __inline __m512h
> >  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
> >  _mm512_setzero_ph (void)
> >  {
> > -  return _mm512_set1_ph (0.0f);
> > +  return _mm512_set1_ph (0.0f16);
> >  }
> >
> >  extern __inline __m128h
> > @@ -358,7 +358,8 @@ extern __inline __m128h
> >  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
> >  _mm_set_sh (_Float16 __F)
> >  {
> > -  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F);
> > +  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
> > +                    __F);
> >  }
> >
> >  /* Create a vector with element 0 as *P and the rest zero.  */
> > @@ -366,7 +367,7 @@ extern __inline __m128h
> >  __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
> >  _mm_load_sh (void const *__P)
> >  {
> > -  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
> > +  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
> >                      *(_Float16 const *) __P);
> >  }
> >
> > --- gcc/config/ia64/ia64.cc.jj  2022-09-09 12:27:23.143736947 +0200
> > +++ gcc/config/ia64/ia64.cc     2022-09-09 18:46:07.265922502 +0200
> > @@ -10466,11 +10466,19 @@ ia64_init_builtins (void)
> >         = build_pointer_type (build_qualified_type
> >                               (char_type_node, TYPE_QUAL_CONST));
> >
> > -      (*lang_hooks.types.register_builtin_type) (float128_type_node,
> > +      if (float128t_type_node == NULL_TREE)
> > +       {
> > +         float128t_type_node = make_node (REAL_TYPE);
> > +         TYPE_PRECISION (float128t_type_node)
> > +           = TYPE_PRECISION (float128_type_node);
> > +         layout_type (float128t_type_node);
> > +         SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
> > +       }
> > +      (*lang_hooks.types.register_builtin_type) (float128t_type_node,
> >                                                  "__float128");
> >
> >        /* TFmode support builtins.  */
> > -      ftype = build_function_type_list (float128_type_node, NULL_TREE);
> > +      ftype = build_function_type_list (float128t_type_node, NULL_TREE);
> >        decl = add_builtin_function ("__builtin_infq", ftype,
> >                                    IA64_BUILTIN_INFQ, BUILT_IN_MD,
> >                                    NULL, NULL_TREE);
> > @@ -10481,7 +10489,7 @@ ia64_init_builtins (void)
> >                                    NULL, NULL_TREE);
> >        ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
> >
> > -      ftype = build_function_type_list (float128_type_node,
> > +      ftype = build_function_type_list (float128t_type_node,
> >                                         const_string_type,
> >                                         NULL_TREE);
> >        decl = add_builtin_function ("__builtin_nanq", ftype,
> > @@ -10496,8 +10504,8 @@ ia64_init_builtins (void)
> >        TREE_READONLY (decl) = 1;
> >        ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
> >
> > -      ftype = build_function_type_list (float128_type_node,
> > -                                       float128_type_node,
> > +      ftype = build_function_type_list (float128t_type_node,
> > +                                       float128t_type_node,
> >                                         NULL_TREE);
> >        decl = add_builtin_function ("__builtin_fabsq", ftype,
> >                                    IA64_BUILTIN_FABSQ, BUILT_IN_MD,
> > @@ -10505,9 +10513,9 @@ ia64_init_builtins (void)
> >        TREE_READONLY (decl) = 1;
> >        ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
> >
> > -      ftype = build_function_type_list (float128_type_node,
> > -                                       float128_type_node,
> > -                                       float128_type_node,
> > +      ftype = build_function_type_list (float128t_type_node,
> > +                                       float128t_type_node,
> > +                                       float128t_type_node,
> >                                         NULL_TREE);
> >        decl = add_builtin_function ("__builtin_copysignq", ftype,
> >                                    IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
> > --- gcc/config/rs6000/rs6000-c.cc.jj    2022-09-09 12:27:23.144736933 +0200
> > +++ gcc/config/rs6000/rs6000-c.cc       2022-09-10 11:21:53.958838545 +0200
> > @@ -808,6 +808,7 @@ static inline bool
> >  is_float128_p (tree t)
> >  {
> >    return (t == float128_type_node
> > +         || (t && t == float128t_type_node)
> >           || (TARGET_IEEEQUAD
> >               && TARGET_LONG_DOUBLE_128
> >               && t == long_double_type_node));
> > --- gcc/config/rs6000/rs6000.cc.jj      2022-09-09 12:27:23.147736893 +0200
> > +++ gcc/config/rs6000/rs6000.cc 2022-09-09 18:46:07.269922448 +0200
> > @@ -20118,7 +20118,11 @@ rs6000_mangle_type (const_tree type)
> >
> >    if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type)))
> >      return "g";
> > -  if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type)))
> > +  if (SCALAR_FLOAT_TYPE_P (type)
> > +      && FLOAT128_IEEE_P (TYPE_MODE (type))
> > +      /* _Float128 should mangle as DF128_ (done in generic code)
> > +        rather than u9__ieee128 (used for __ieee128 and __float128).  */
> > +      && type != float128_type_node)
> >      return "u9__ieee128";
> >
> >    if (type == vector_pair_type_node)
> > --- gcc/config/rs6000/rs6000-builtin.cc.jj      2022-09-09 12:27:23.143736947 +0200
> > +++ gcc/config/rs6000/rs6000-builtin.cc 2022-09-09 18:46:07.270922435 +0200
> > @@ -733,7 +733,22 @@ rs6000_init_builtins (void)
> >        if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
> >         ieee128_float_type_node = long_double_type_node;
> >        else
> > -       ieee128_float_type_node = float128_type_node;
> > +       {
> > +         /* For C we only need to register the __ieee128 name for
> > +            it.  For C++, we create a distinct type which will mangle
> > +            differently (u9__ieee128) vs. _Float128 (DF128_) and behave
> > +            backwards compatibly.  */
> > +         if (float128t_type_node == NULL_TREE)
> > +           {
> > +             float128t_type_node = make_node (REAL_TYPE);
> > +             TYPE_PRECISION (float128t_type_node)
> > +               = TYPE_PRECISION (float128_type_node);
> > +             layout_type (float128t_type_node);
> > +             SET_TYPE_MODE (float128t_type_node,
> > +                            TYPE_MODE (float128_type_node));
> > +           }
> > +         ieee128_float_type_node = float128t_type_node;
> > +       }
> >        t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
> >        lang_hooks.types.register_builtin_type (ieee128_float_type_node,
> >                                               "__ieee128");
> > --- gcc/c-family/c-common.cc.jj 2022-09-09 12:27:23.137737028 +0200
> > +++ gcc/c-family/c-common.cc    2022-09-09 19:43:50.730802597 +0200
> > @@ -352,10 +352,10 @@ const struct c_common_resword c_common_r
> >    { "_Bool",           RID_BOOL,      D_CONLY },
> >    { "_Complex",                RID_COMPLEX,    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 },
> > +  { "_Float16",         RID_FLOAT16,    0 },
> > +  { "_Float32",         RID_FLOAT32,    0 },
> > +  { "_Float64",         RID_FLOAT64,    0 },
> > +  { "_Float128",        RID_FLOAT128,   0 },
> >    { "_Float32x",        RID_FLOAT32X,  D_CONLY },
> >    { "_Float64x",        RID_FLOAT64X,  D_CONLY },
> >    { "_Float128x",       RID_FLOAT128X, D_CONLY },
> > @@ -1429,8 +1429,11 @@ shorten_binary_op (tree result_type, tre
> >           == TYPE_PRECISION (TREE_TYPE (arg0)))
> >        && unsigned0 == unsigned1
> >        && (unsigned0 || !uns))
> > -    return c_common_signed_or_unsigned_type
> > -      (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
> > +    {
> > +      tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
> > +      if (ctype != error_mark_node)
> > +       return c_common_signed_or_unsigned_type (unsigned0, ctype);
> > +    }
> >
> >    else if (TREE_CODE (arg0) == INTEGER_CST
> >            && (unsigned1 || !uns)
> > @@ -3202,9 +3205,10 @@ shorten_compare (location_t loc, tree *o
> >
> >    else if (unsignedp0 == unsignedp1 && real1 == real2
> >            && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
> > -          && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
> > +          && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)
> > +          && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)))
> > +             != error_mark_node)
> >      {
> > -      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
> >        type = c_common_signed_or_unsigned_type (unsignedp0
> >                                                || TYPE_UNSIGNED (*restype_ptr),
> >                                                type);
> > @@ -4378,11 +4382,21 @@ 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++)
> > +  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));
> > +      /* Don't register _FloatNX types for C++, just _FloatN.  */
> > +      if (i == NUM_FLOATN_TYPES && c_dialect_cxx ())
> > +       break;
> > +    }
> > +
> > +  /* For C, let float128t_type_node (__float128 in some backends) be the
> > +     same type as float128_type_node (_Float128), for C++ let those
> > +     be distinct types that mangle and behave differently.  */
> > +  if (c_dialect_cxx ())
> > +    float128t_type_node = NULL_TREE;
> >
> >    /* Only supported decimal floating point extension if the target
> >       actually supports underlying modes. */
> > --- gcc/c-family/c-cppbuiltin.cc.jj     2022-09-09 12:27:23.138737014 +0200
> > +++ gcc/c-family/c-cppbuiltin.cc        2022-09-09 18:46:07.271922421 +0200
> > @@ -1246,6 +1246,14 @@ c_cpp_builtins (cpp_reader *pfile)
> >      {
> >        if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
> >         continue;
> > +      if (floatn_nx_types[i].extended && c_dialect_cxx ())
> > +       continue;
> > +      if (c_dialect_cxx () && cxx_dialect > cxx20)
> > +       {
> > +         char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
> > +         sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
> > +         cpp_define (pfile, name);
> > +       }
> >        char prefix[20], csuffix[20];
> >        sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
> >                floatn_nx_types[i].extended ? "X" : "");
> > --- gcc/c-family/c-common.h.jj  2022-09-09 12:27:23.137737028 +0200
> > +++ gcc/c-family/c-common.h     2022-09-09 18:46:07.271922421 +0200
> > @@ -120,8 +120,10 @@ enum rid
> >    RID_FLOAT32X,
> >    RID_FLOAT64X,
> >    RID_FLOAT128X,
> > +#define CASE_RID_FLOATN                                                        \
> > +  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128
> >  #define CASE_RID_FLOATN_NX                                             \
> > -  case RID_FLOAT16: case RID_FLOAT32: case RID_FLOAT64: case RID_FLOAT128: \
> > +  CASE_RID_FLOATN:                                                     \
> >    case RID_FLOAT32X: case RID_FLOAT64X: case RID_FLOAT128X
> >
> >    RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
> > --- gcc/c-family/c-lex.cc.jj    2022-09-09 12:27:23.138737014 +0200
> > +++ gcc/c-family/c-lex.cc       2022-09-09 18:46:07.271922421 +0200
> > @@ -960,6 +960,10 @@ interpret_float (const cpp_token *token,
> >           pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
> >
> >         type = c_common_type_for_mode (mode, 0);
> > +       /* For Q suffix, prefer float128t_type_node (__float128) type
> > +          over float128_type_node (_Float128) type if they are distinct.  */
> > +       if (type == float128_type_node && float128t_type_node)
> > +         type = float128t_type_node;
> >         gcc_assert (type);
> >        }
> >      else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
> > @@ -979,8 +983,17 @@ interpret_float (const cpp_token *token,
> >             error ("unsupported non-standard suffix on floating constant");
> >             return error_mark_node;
> >           }
> > +       else if (c_dialect_cxx ())
> > +         {
> > +           if (cxx_dialect < cxx23)
> > +             pedwarn (input_location, OPT_Wpedantic,
> > +                      "%<f%d%> or %<F%d%> suffix on floating constant only "
> > +                      "available with %<-std=c++2b%> or %<-std=gnu++2b%>",
> > +                      n, n);
> > +         }
> >         else
> > -         pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
> > +         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;
> > @@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token,
> >      else
> >        type = double_type_node;
> >
> > -  const_type = excess_precision_type (type);
> > +  if (c_dialect_cxx ())
> > +    const_type = NULL_TREE;
> > +  else
> > +    const_type = excess_precision_type (type);
> >    if (!const_type)
> >      const_type = type;
> >
> > --- gcc/cp/cp-tree.h.jj 2022-09-09 12:27:23.170736583 +0200
> > +++ gcc/cp/cp-tree.h    2022-09-10 11:22:11.612598030 +0200
> > @@ -7942,6 +7942,7 @@ extern tree require_complete_type_sfinae
> >  extern tree complete_type                      (tree);
> >  extern tree complete_type_or_else              (tree, tree);
> >  extern tree complete_type_or_maybe_complain    (tree, tree, tsubst_flags_t);
> > +extern int cp_compare_floating_point_conversion_ranks (tree, tree);
> >  inline bool type_unknown_p                     (const_tree);
> >  enum { ce_derived, ce_type, ce_normal, ce_exact };
> >  extern bool comp_except_specs                  (const_tree, const_tree, int);
> > @@ -8682,6 +8683,18 @@ struct push_access_scope_guard
> >    }
> >  };
> >
> > +/* True if TYPE is an extended floating-point type.  */
> > +
> > +inline bool
> > +extended_float_type_p (tree type)
> > +{
> > +  type = TYPE_MAIN_VARIANT (type);
> > +  for (int i = 0; i < NUM_FLOATN_TYPES; ++i)
> > +    if (type == FLOATN_TYPE_NODE (i))
> > +      return true;
> > +  return false;
> > +}
> > +
> >  #if CHECKING_P
> >  namespace selftest {
> >    extern void run_cp_tests (void);
> > --- gcc/cp/mangle.cc.jj 2022-09-09 12:27:23.171736570 +0200
> > +++ gcc/cp/mangle.cc    2022-09-09 18:46:07.273922394 +0200
> > @@ -2648,63 +2648,18 @@ write_builtin_type (tree type)
> >         write_string ("Dd");
> >        else if (type == dfloat128_type_node || type == fallback_dfloat128_type)
> >         write_string ("De");
> > +      else if (type == float16_type_node)
> > +       write_string ("DF16_");
> > +      else if (type == float32_type_node)
> > +       write_string ("DF32_");
> > +      else if (type == float64_type_node)
> > +       write_string ("DF64_");
> > +      else if (type == float128_type_node)
> > +       write_string ("DF128_");
> >        else
> >         gcc_unreachable ();
> >        break;
> >
> > -    case FIXED_POINT_TYPE:
> > -      write_string ("DF");
> > -      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
> > -       write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
> > -      if (type == fract_type_node
> > -         || type == sat_fract_type_node
> > -         || type == accum_type_node
> > -         || type == sat_accum_type_node)
> > -       write_char ('i');
> > -      else if (type == unsigned_fract_type_node
> > -              || type == sat_unsigned_fract_type_node
> > -              || type == unsigned_accum_type_node
> > -              || type == sat_unsigned_accum_type_node)
> > -       write_char ('j');
> > -      else if (type == short_fract_type_node
> > -              || type == sat_short_fract_type_node
> > -              || type == short_accum_type_node
> > -              || type == sat_short_accum_type_node)
> > -       write_char ('s');
> > -      else if (type == unsigned_short_fract_type_node
> > -              || type == sat_unsigned_short_fract_type_node
> > -              || type == unsigned_short_accum_type_node
> > -              || type == sat_unsigned_short_accum_type_node)
> > -       write_char ('t');
> > -      else if (type == long_fract_type_node
> > -              || type == sat_long_fract_type_node
> > -              || type == long_accum_type_node
> > -              || type == sat_long_accum_type_node)
> > -       write_char ('l');
> > -      else if (type == unsigned_long_fract_type_node
> > -              || type == sat_unsigned_long_fract_type_node
> > -              || type == unsigned_long_accum_type_node
> > -              || type == sat_unsigned_long_accum_type_node)
> > -       write_char ('m');
> > -      else if (type == long_long_fract_type_node
> > -              || type == sat_long_long_fract_type_node
> > -              || type == long_long_accum_type_node
> > -              || type == sat_long_long_accum_type_node)
> > -       write_char ('x');
> > -      else if (type == unsigned_long_long_fract_type_node
> > -              || type == sat_unsigned_long_long_fract_type_node
> > -              || type == unsigned_long_long_accum_type_node
> > -              || type == sat_unsigned_long_long_accum_type_node)
> > -       write_char ('y');
> > -      else
> > -       sorry ("mangling unknown fixed point type");
> > -      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
> > -      if (TYPE_SATURATING (type))
> > -       write_char ('s');
> > -      else
> > -       write_char ('n');
> > -      break;
> > -
> >      default:
> >        gcc_unreachable ();
> >      }
> > --- gcc/cp/typeck2.cc.jj        2022-09-09 12:27:23.179736463 +0200
> > +++ gcc/cp/typeck2.cc   2022-09-09 18:46:07.273922394 +0200
> > @@ -1010,12 +1010,25 @@ check_narrowing (tree type, tree init, t
> >    else if (TREE_CODE (ftype) == REAL_TYPE
> >            && TREE_CODE (type) == REAL_TYPE)
> >      {
> > -      if ((same_type_p (ftype, long_double_type_node)
> > -          && (same_type_p (type, double_type_node)
> > -              || same_type_p (type, float_type_node)))
> > -         || (same_type_p (ftype, double_type_node)
> > -             && same_type_p (type, float_type_node))
> > -         || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
> > +      if ((extended_float_type_p (ftype) || extended_float_type_p (type))
> > +         ? /* "from a floating-point type T to another floating-point type
> > +              whose floating-point conversion rank is neither greater than
> > +              nor equal to that of T".
> > +              So, it is ok if
> > +              cp_compare_floating_point_conversion_ranks (ftype, type)
> > +              returns -2 (type has greater conversion rank than ftype)
> > +              or [-1..1] (type has equal conversion rank as ftype, possibly
> > +              different subrank.  Only do this if at least one of the
> > +              types is extended floating-point type, otherwise keep doing
> > +              what we did before (for the sake of non-standard
> > +              backend types).  */
> > +           cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
> > +         : ((same_type_p (ftype, long_double_type_node)
> > +             && (same_type_p (type, double_type_node)
> > +                 || same_type_p (type, float_type_node)))
> > +            || (same_type_p (ftype, double_type_node)
> > +                && same_type_p (type, float_type_node))
> > +            || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
> >         {
> >           if (TREE_CODE (init) == REAL_CST)
> >             {
> > --- gcc/cp/parser.cc.jj 2022-09-09 12:27:23.177736489 +0200
> > +++ gcc/cp/parser.cc    2022-09-09 18:46:07.278922327 +0200
> > @@ -1129,6 +1129,7 @@ cp_keyword_starts_decl_specifier_p (enum
> >      case RID_UNSIGNED:
> >      case RID_FLOAT:
> >      case RID_DOUBLE:
> > +    CASE_RID_FLOATN:
> >      case RID_VOID:
> >        /* CV qualifiers.  */
> >      case RID_CONST:
> > @@ -19706,6 +19707,12 @@ cp_parser_simple_type_specifier (cp_pars
> >      case RID_DOUBLE:
> >        type = double_type_node;
> >        break;
> > +    CASE_RID_FLOATN:
> > +      type = FLOATN_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST);
> > +      if (type == NULL_TREE)
> > +       error ("%<_Float%d%> is not supported on this target",
> > +              floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n);
> > +      break;
> >      case RID_VOID:
> >        type = void_type_node;
> >        break;
> > --- gcc/cp/typeck.cc.jj 2022-09-09 12:27:23.179736463 +0200
> > +++ gcc/cp/typeck.cc    2022-09-09 19:54:17.360423639 +0200
> > @@ -272,6 +272,116 @@ merge_type_attributes_from (tree type, t
> >    return cp_build_type_attribute_variant (type, attrs);
> >  }
> >
> > +/* Compare floating point conversion ranks and subranks of T1 and T2
> > +   types.  If T1 and T2 have unordered conversion ranks, return 3.
> > +   If T1 has greater conversion rank than T2, return 2.
> > +   If T2 has greater conversion rank than T1, return -2.
> > +   If T1 has equal conversion rank as T2, return -1, 0 or 1 depending
> > +   on if T1 has smaller, equal or greater conversion subrank than
> > +   T2.  */
> > +
> > +int
> > +cp_compare_floating_point_conversion_ranks (tree t1, tree t2)
> > +{
> > +  tree mv1 = TYPE_MAIN_VARIANT (t1);
> > +  tree mv2 = TYPE_MAIN_VARIANT (t2);
> > +  bool extended1 = false;
> > +  bool extended2 = false;
> > +
> > +  if (mv1 == mv2)
> > +    return 0;
> > +
> > +  for (int i = 0; i < NUM_FLOATN_TYPES; ++i)
> > +    {
> > +      if (mv1 == FLOATN_TYPE_NODE (i))
> > +       extended1 = true;
> > +      if (mv2 == FLOATN_TYPE_NODE (i))
> > +       extended2 = true;
> > +    }
> > +  if (extended2 && !extended1)
> > +    {
> > +      int ret = cp_compare_floating_point_conversion_ranks (t2, t1);
> > +      return ret == 3 ? 3 : -ret;
> > +    }
> > +
> > +  const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
> > +  const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
> > +  gcc_assert (fmt1->b == 2 && fmt2->b == 2);
> > +  /* For {ibm,mips}_extended_format formats, the type has variable
> > +     precision up to ~2150 bits when the first double is around maximum
> > +     representable double and second double is subnormal minimum.
> > +     So, e.g. for __ibm128 vs. std::float128_t, they have unordered
> > +     ranks.  */
> > +  int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1))
> > +           ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p);
> > +  int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2))
> > +           ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p);
> > +  /* The rank of a floating point type T is greater than the rank of
> > +     any floating-point type whose set of values is a proper subset
> > +     of the set of values of T.  */
> > +  if ((p1 > p2 && fmt1->emax >= fmt2->emax)
> > +       || (p1 == p2 && fmt1->emax > fmt2->emax))
> > +    return 2;
> > +  if ((p1 < p2 && fmt1->emax <= fmt2->emax)
> > +       || (p1 == p2 && fmt1->emax < fmt2->emax))
> > +    return -2;
> > +  if ((p1 > p2 && fmt1->emax < fmt2->emax)
> > +       || (p1 < p2 && fmt1->emax > fmt2->emax))
> > +    return 3;
> > +  if (!extended1 && !extended2)
> > +    {
> > +      /* The rank of long double is greater than the rank of double, which
> > +        is greater than the rank of float.  */
> > +      if (t1 == long_double_type_node)
> > +       return 2;
> > +      else if (t2 == long_double_type_node)
> > +       return -2;
> > +      if (t1 == double_type_node)
> > +       return 2;
> > +      else if (t2 == double_type_node)
> > +       return -2;
> > +      if (t1 == float_type_node)
> > +       return 2;
> > +      else if (t2 == float_type_node)
> > +       return -2;
> > +      return 0;
> > +    }
> > +  /* Two extended floating-point types with the same set of values have equal
> > +     ranks.  */
> > +  if (extended1 && extended2)
> > +    /* We shouldn't have multiple different extended floating-point types
> > +       with the same set of values.  */
> > +    gcc_unreachable ();
> > +
> > +  tree *p;
> > +  int cnt = 0;
> > +  for (p = &float_type_node; p <= &long_double_type_node; ++p)
> > +    {
> > +      const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p));
> > +      gcc_assert (fmt3->b == 2);
> > +      int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p))
> > +               ? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p);
> > +      if (p1 == p3 && fmt1->emax == fmt3->emax)
> > +       ++cnt;
> > +    }
> > +  /* An extended floating-point type with the same set of values
> > +     as exactly one cv-unqualified standard floating-point type
> > +     has a rank equal to the rank of that standard floating-point
> > +     type.
> > +
> > +     An extended floating-point type with the same set of values
> > +     as more than one cv-unqualified standard floating-point type
> > +     has a rank equal to the rank of double.
> > +
> > +     Thus, if the latter is true and t2 is long double, t2
> > +     has higher rank.  */
> > +  if (cnt > 1 && mv2 == long_double_type_node)
> > +    return -2;
> > +  /* Otherwise, they have equal rank, but extended types
> > +     (other than std::bfloat16_t) have higher subrank.  */
> > +  return 1;
> > +}
> > +
> >  /* Return the common type for two arithmetic types T1 and T2 under the
> >     usual arithmetic conversions.  The default conversions have already
> >     been applied, and enumerated types converted to their compatible
> > @@ -342,6 +452,23 @@ cp_common_type (tree t1, tree t2)
> >    if (code2 == REAL_TYPE && code1 != REAL_TYPE)
> >      return build_type_attribute_variant (t2, attributes);
> >
> > +  if (code1 == REAL_TYPE
> > +      && (extended_float_type_p (t1) || extended_float_type_p (t2)))
> > +    {
> > +      tree mv1 = TYPE_MAIN_VARIANT (t1);
> > +      tree mv2 = TYPE_MAIN_VARIANT (t2);
> > +      if (mv1 == mv2)
> > +       return build_type_attribute_variant (t1, attributes);
> > +
> > +      int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2);
> > +      if (cmpret == 3)
> > +       return error_mark_node;
> > +      else if (cmpret >= 0)
> > +       return build_type_attribute_variant (t1, attributes);
> > +      else
> > +       return build_type_attribute_variant (t2, attributes);
> > +    }
> > +
> >    /* Both real or both integers; use the one with greater precision.  */
> >    if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
> >      return build_type_attribute_variant (t1, attributes);
> > @@ -5041,7 +5168,20 @@ cp_build_binary_op (const op_location_t
> >         = targetm.invalid_binary_op (code, type0, type1)))
> >      {
> >        if (complain & tf_error)
> > -       error (invalid_op_diag);
> > +       {
> > +         if (code0 == REAL_TYPE
> > +             && code1 == REAL_TYPE
> > +             && (extended_float_type_p (type0)
> > +                 || extended_float_type_p (type1))
> > +             && cp_compare_floating_point_conversion_ranks (type0,
> > +                                                            type1) == 3)
> > +           {
> > +             rich_location richloc (line_table, location);
> > +             binary_op_error (&richloc, code, type0, type1);
> > +           }
> > +         else
> > +           error (invalid_op_diag);
> > +       }
> >        return error_mark_node;
> >      }
> >
> > @@ -5911,6 +6051,19 @@ cp_build_binary_op (const op_location_t
> >        && (shorten || common || short_compare))
> >      {
> >        result_type = cp_common_type (type0, type1);
> > +      if (result_type == error_mark_node
> > +         && code0 == REAL_TYPE
> > +         && code1 == REAL_TYPE
> > +         && (extended_float_type_p (type0) || extended_float_type_p (type1))
> > +         && cp_compare_floating_point_conversion_ranks (type0, type1) == 3)
> > +       {
> > +         if (complain & tf_error)
> > +           {
> > +             rich_location richloc (line_table, location);
> > +             binary_op_error (&richloc, code, type0, type1);
> > +           }
> > +         return error_mark_node;
> > +       }
> >        if (complain & tf_warning)
> >         {
> >           do_warn_double_promotion (result_type, type0, type1,
> > --- gcc/cp/call.cc.jj   2022-09-09 12:27:23.169736597 +0200
> > +++ gcc/cp/call.cc      2022-09-10 11:14:41.361732371 +0200
> > @@ -1519,6 +1519,22 @@ standard_conversion (tree to, tree from,
> >            || SCOPED_ENUM_P (from))
> >         return NULL;
> >
> > +      /* A prvalue of floating-point type can be converted to a prvalue of
> > +        another floating-point type with a greater or equal conversion
> > +        rank ([conv.rank]).  A prvalue of standard floating-point type can
> > +        be converted to a prvalue of another standard floating-point type.
> > +        For backwards compatibility with handling __float128 and other
> > +        non-standard floating point types, allow all implicit floating
> > +        point conversions if neither type is extended floating-point
> > +        type and if at least one of them is, fail if they have unordered
> > +        conversion rank or from has higher conversion rank.  */
> > +      if (fcode == REAL_TYPE
> > +         && tcode == REAL_TYPE
> > +         && (extended_float_type_p (from)
> > +             || extended_float_type_p (to))
> > +         && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
> > +       return NULL;
> > +
> >        /* If we're parsing an enum with no fixed underlying type, we're
> >          dealing with an incomplete type, which renders the conversion
> >          ill-formed.  */
> > @@ -5842,6 +5858,21 @@ build_conditional_expr (const op_locatio
> >        /* In this case, there is always a common type.  */
> >        result_type = type_after_usual_arithmetic_conversions (arg2_type,
> >                                                              arg3_type);
> > +      if (result_type == error_mark_node
> > +         && TREE_CODE (arg2_type) == REAL_TYPE
> > +         && TREE_CODE (arg3_type) == REAL_TYPE
> > +         && (extended_float_type_p (arg2_type)
> > +             || extended_float_type_p (arg3_type))
> > +         && cp_compare_floating_point_conversion_ranks (arg2_type,
> > +                                                        arg3_type) == 3)
> > +       {
> > +         if (complain & tf_error)
> > +           error_at (loc, "operands to %<?:%> have unordered conversion rank "
> > +                          "of types %qT and %qT",
> > +                     arg2_type, arg3_type);
> > +         return error_mark_node;
> > +       }
> > +
> >        if (complain & tf_warning)
> >         do_warn_double_promotion (result_type, arg2_type, arg3_type,
> >                                   "implicit conversion from %qH to %qI to "
> > @@ -8531,7 +8562,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
> >    if (TREE_CODE (arg_type) == REAL_TYPE
> >        && (TYPE_PRECISION (arg_type)
> >           < TYPE_PRECISION (double_type_node))
> > -      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
> > +      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))
> > +      && !extended_float_type_p (arg_type))
> >      {
> >        if ((complain & tf_warning)
> >           && warn_double_promotion && !c_inhibit_evaluation_warnings)
> > @@ -11719,6 +11751,75 @@ compare_ics (conversion *ics1, conversio
> >         return 1;
> >      }
> >
> > +  {
> > +    /* A conversion in either direction between floating-point type FP1 and
> > +       floating-point type FP2 is better than a conversion in the same
> > +       direction between FP1 and arithmetic type T3 if
> > +       - the floating-point conversion rank of FP1 is equal to the rank of
> > +        FP2, and
> > +       - T3 is not a floating-point type, or T3 is a floating-point type
> > +        whose rank is not equal to the rank of FP1, or the floating-point
> > +        conversion subrank of FP2 is greater than the subrank of T3.  */
> > +    tree fp1 = from_type1;
> > +    tree fp2 = to_type1;
> > +    tree fp3 = from_type2;
> > +    tree t3 = to_type2;
> > +    int ret = 1;
> > +    if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3))
> > +      {
> > +       std::swap (fp1, fp2);
> > +       std::swap (fp3, t3);
> > +      }
> > +    if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3)
> > +       && TREE_CODE (fp1) == REAL_TYPE
> > +       /* Only apply this rule if at least one of the 3 types is
> > +          extended floating-point type, otherwise keep them as
> > +          before for compatibility reasons with types like __float128.
> > +          float, double and long double alone have different conversion
> > +          ranks and so when just those 3 types are involved, this
> > +          rule doesn't trigger.  */
> > +       && (extended_float_type_p (fp1)
> > +           || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2))
> > +           || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3))))
> > +      {
> > +       if (TREE_CODE (fp2) != REAL_TYPE)
> > +         {
> > +           ret = -ret;
> > +           std::swap (fp2, t3);
> > +         }
> > +       if (TREE_CODE (fp2) == REAL_TYPE)
> > +         {
> > +           if (cp_compare_floating_point_conversion_ranks (fp1, fp2) + 1U
> > +               <= 2U)
> > +             {
> > +               /* Conversion ranks of FP1 and FP2 are equal.  */
> > +               if (TREE_CODE (t3) != REAL_TYPE
> > +                   || (cp_compare_floating_point_conversion_ranks (fp1, t3)
> > +                       + 1U > 2U))
> > +                 /* FP1 <-> FP2 conversion is better.  */
> > +                 return ret;
> > +               int c = cp_compare_floating_point_conversion_ranks (fp2, t3);
> > +               gcc_assert (c + 1U <= 2U);
> > +               if (c == 1)
> > +                 /* Conversion subrank of FP2 is greater than subrank of T3.
> > +                    FP1 <-> FP2 conversion is better.  */
> > +                 return ret;
> > +               else if (c == -1)
> > +                 /* Conversion subrank of FP2 is less than subrank of T3.
> > +                    FP1 <-> T3 conversion is better.  */
> > +                 return -ret;
> > +             }
> > +           else if (TREE_CODE (t3) == REAL_TYPE
> > +                    && (cp_compare_floating_point_conversion_ranks (fp1, t3)
> > +                        + 1U <= 2U))
> > +             /* Conversion ranks of FP1 and FP2 are not equal, conversion
> > +                ranks of FP1 and T3 are equal.
> > +                FP1 <-> T3 conversion is better.  */
> > +             return -ret;
> > +         }
> > +      }
> > +  }
> > +
> >    if (TYPE_PTR_P (from_type1)
> >        && TYPE_PTR_P (from_type2)
> >        && TYPE_PTR_P (to_type1)
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating1.C.jj       2022-09-09 18:46:07.281922287 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C  2022-09-09 18:46:07.281922287 +0200
> > @@ -0,0 +1,248 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do compile { target c++23 } }
> > +// { dg-options "" }
> > +
> > +#include "ext-floating.h"
> > +
> > +#ifdef __STRICT_ANSI__
> > +#undef __SIZEOF_FLOAT128__
> > +#endif
> > +
> > +using namespace std;
> > +
> > +static_assert (!is_same<float, double>::value);
> > +static_assert (!is_same<float, long double>::value);
> > +static_assert (!is_same<double, long double>::value);
> > +static_assert (is_same<decltype (0.0f), float>::value);
> > +static_assert (is_same<decltype (0.0F), float>::value);
> > +static_assert (is_same<decltype (0.0), double>::value);
> > +static_assert (is_same<decltype (0.0l), long double>::value);
> > +static_assert (is_same<decltype (0.0L), long double>::value);
> > +static_assert (is_same<decltype (0.0f + 0.0F), float>::value);
> > +static_assert (is_same<decltype (0.0F + 0.0f), float>::value);
> > +static_assert (is_same<decltype (0.0 + 0.0), double>::value);
> > +static_assert (is_same<decltype (0.0l + 0.0L), long double>::value);
> > +static_assert (is_same<decltype (0.0L + 0.0l), long double>::value);
> > +#ifdef __SIZEOF_FLOAT128__
> > +static_assert (is_same<decltype (0.0q), __float128>::value);
> > +static_assert (is_same<decltype (0.0Q), __float128>::value);
> > +static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value);
> > +static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value);
> > +#endif
> > +#ifdef __STDCPP_FLOAT16_T__
> > +static_assert (!is_same<float, float16_t>::value);
> > +static_assert (!is_same<double, float16_t>::value);
> > +static_assert (!is_same<long double, float16_t>::value);
> > +static_assert (is_same<decltype (0.0f16), float16_t>::value);
> > +static_assert (is_same<decltype (0.0F16), float16_t>::value);
> > +static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value);
> > +static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value);
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +static_assert (!is_same<float, float32_t>::value);
> > +static_assert (!is_same<double, float32_t>::value);
> > +static_assert (!is_same<long double, float32_t>::value);
> > +static_assert (!is_same<decltype (0.0f), float32_t>::value);
> > +static_assert (!is_same<decltype (0.0F), float32_t>::value);
> > +static_assert (is_same<decltype (0.0f32), float32_t>::value);
> > +static_assert (is_same<decltype (0.0F32), float32_t>::value);
> > +static_assert (!is_same<decltype (0.0f32), float>::value);
> > +static_assert (!is_same<decltype (0.0F32), float>::value);
> > +static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value);
> > +static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value);
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +static_assert (!is_same<float, float64_t>::value);
> > +static_assert (!is_same<double, float64_t>::value);
> > +static_assert (!is_same<long double, float64_t>::value);
> > +static_assert (!is_same<decltype (0.0), float64_t>::value);
> > +static_assert (is_same<decltype (0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64), float64_t>::value);
> > +static_assert (!is_same<decltype (0.0f64), double>::value);
> > +static_assert (!is_same<decltype (0.0F64), double>::value);
> > +static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value);
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +static_assert (!is_same<float, float128_t>::value);
> > +static_assert (!is_same<double, float128_t>::value);
> > +static_assert (!is_same<long double, float128_t>::value);
> > +static_assert (!is_same<decltype (0.0l), float128_t>::value);
> > +static_assert (!is_same<decltype (0.0L), float128_t>::value);
> > +static_assert (is_same<decltype (0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128), float128_t>::value);
> > +static_assert (!is_same<decltype (0.0f128), long double>::value);
> > +static_assert (!is_same<decltype (0.0F128), long double>::value);
> > +static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value);
> > +#ifdef __SIZEOF_FLOAT128__
> > +static_assert (!is_same<float128_t, __float128>::value);
> > +static_assert (!is_same<decltype (0.0q), float128_t>::value);
> > +static_assert (!is_same<decltype (0.0Q), float128_t>::value);
> > +static_assert (!is_same<decltype (0.0f128), __float128>::value);
> > +static_assert (!is_same<decltype (0.0F128), __float128>::value);
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_BFLOAT16_T__
> > +static_assert (!is_same<float, bfloat16_t>::value);
> > +static_assert (!is_same<double, bfloat16_t>::value);
> > +static_assert (!is_same<long double, bfloat16_t>::value);
> > +static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value);
> > +static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value);
> > +static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value);
> > +static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value);
> > +#endif
> > +static_assert (is_same<decltype (0.0f + 0.0), double>::value);
> > +static_assert (is_same<decltype (0.0 + 0.0F), double>::value);
> > +static_assert (is_same<decltype (0.0L + 0.0), long double>::value);
> > +static_assert (is_same<decltype (0.0 + 0.0L), long double>::value);
> > +static_assert (is_same<decltype (0.0L + 0.0f), long double>::value);
> > +static_assert (is_same<decltype (0.0F + 0.0l), long double>::value);
> > +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
> > +static_assert (!is_same<float16_t, float32_t>::value);
> > +static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value);
> > +static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value);
> > +#endif
> > +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
> > +static_assert (!is_same<float16_t, float64_t>::value);
> > +static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value);
> > +#endif
> > +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
> > +static_assert (!is_same<float16_t, float128_t>::value);
> > +static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value);
> > +#endif
> > +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__)
> > +static_assert (!is_same<float32_t, float64_t>::value);
> > +static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value);
> > +#endif
> > +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__)
> > +static_assert (!is_same<float32_t, float128_t>::value);
> > +static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value);
> > +#endif
> > +#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__)
> > +static_assert (!is_same<float64_t, float128_t>::value);
> > +static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
> > +#endif
> > +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
> > +static_assert (!is_same<bfloat16_t, float32_t>::value);
> > +static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value);
> > +static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value);
> > +#endif
> > +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
> > +static_assert (!is_same<bfloat16_t, float64_t>::value);
> > +static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value);
> > +#endif
> > +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
> > +static_assert (!is_same<bfloat16_t, float128_t>::value);
> > +static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value);
> > +#endif
> > +#ifdef __STDCPP_FLOAT16_T__
> > +#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__
> > +static_assert (is_same<decltype (0.0f + 0.0f16), float>::value);
> > +static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value);
> > +#endif
> > +#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__
> > +static_assert (is_same<decltype (0.0 + 0.0f16), double>::value);
> > +static_assert (is_same<decltype (0.0F16 + 0.0), double>::value);
> > +#endif
> > +#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__
> > +static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value);
> > +static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value);
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__
> > +static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value);
> > +static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value);
> > +#endif
> > +#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__
> > +static_assert (is_same<decltype (0.0 + 0.0f32), double>::value);
> > +static_assert (is_same<decltype (0.0F32 + 0.0), double>::value);
> > +#endif
> > +#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__
> > +static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value);
> > +static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value);
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__
> > +static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value);
> > +#endif
> > +#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
> > +static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value);
> > +#endif
> > +#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__
> > +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
> > +#endif
> > +#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \
> > +    && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
> > +// An extended floating-point type with the same set of values as more than one
> > +// cv-unqualified standard floating-point type has a rank equal to the rank of
> > +// double.
> > +// Then long double will have higher rank than float64_t.
> > +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
> > +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__
> > +static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value);
> > +#endif
> > +#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__
> > +static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value);
> > +#endif
> > +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \
> > +    && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered.
> > +static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value);
> > +#endif
> > +#ifdef __SIZEOF_FLOAT128__
> > +static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value);
> > +static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value);
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_BFLOAT16_T__
> > +#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__
> > +static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value);
> > +static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value);
> > +#endif
> > +#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__
> > +static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value);
> > +static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value);
> > +#endif
> > +#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__
> > +static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value);
> > +static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value);
> > +#endif
> > +#endif
> > +
> > +void foo (float) {}
> > +void foo (double) {}
> > +void foo (long double) {}
> > +#ifdef __STDCPP_FLOAT16_T__
> > +void foo (float16_t) {}
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +void foo (float32_t) {}
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +void foo (float64_t) {}
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +void foo (float128_t) {}
> > +#endif
> > +#ifdef __STDCPP_BFLOAT16_T__
> > +void foo (bfloat16_t) {}
> > +#endif
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating2.C.jj       2022-09-09 18:46:07.281922287 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating2.C  2022-09-09 18:46:07.281922287 +0200
> > @@ -0,0 +1,157 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do compile { target c++23 } }
> > +// { dg-options "" }
> > +
> > +#include "ext-floating.h"
> > +
> > +#ifdef __STRICT_ANSI__
> > +#undef __SIZEOF_FLOAT128__
> > +#endif
> > +
> > +using namespace std;
> > +
> > +float fa = 1.0f;
> > +float fb = (float) 1.0f;
> > +float fc = 1.0;
> > +float fd = (float) 1.0;
> > +float fe = 1.0L;
> > +float ff = (float) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +float fg = 1.0Q;
> > +float fh = (float) 1.0Q;
> > +#endif
> > +double da = 1.0f;
> > +double db = (double) 1.0f;
> > +double dc = 1.0;
> > +double dd = (double) 1.0;
> > +double de = 1.0L;
> > +double df = (double) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +double dg = 1.0Q;
> > +double dh = (double) 1.0Q;
> > +#endif
> > +long double lda = 1.0f;
> > +long double ldb = (long double) 1.0f;
> > +long double ldc = 1.0;
> > +long double ldd = (long double) 1.0;
> > +long double lde = 1.0L;
> > +long double ldf = (long double) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +long double ldg = 1.0Q;
> > +long double ldh = (long double) 1.0Q;
> > +__float128 qa = 1.0f;
> > +__float128 qb = (__float128) 1.0f;
> > +__float128 qc = 1.0;
> > +__float128 qd = (__float128) 1.0;
> > +__float128 qe = 1.0L;
> > +__float128 qf = (__float128) 1.0L;
> > +__float128 qg = 1.0Q;
> > +__float128 qh = (__float128) 1.0Q;
> > +#endif
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float16_t f16a = 1.0F16;
> > +float16_t f16b = (float16_t) 1.0F16;
> > +#ifdef __STDCPP_FLOAT32_T__
> > +float16_t f16c = 1.0F32;               // { dg-error "cannot convert '_Float32' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float32 } } }
> > +float16_t f16d = (float16_t) 1.0F32;
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +float16_t f16e = 1.0F64;               // { dg-error "cannot convert '_Float64' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float64 } } }
> > +float16_t f16f = (float16_t) 1.0F64;
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +float16_t f16g = 1.0F128;              // { dg-error "cannot convert '_Float128' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target { float16 && float128 } } }
> > +float16_t f16h = (float16_t) 1.0F128;
> > +#endif
> > +float16_t f16j = (float16_t) 1.0f;
> > +float16_t f16l = (float16_t) 1.0;
> > +float16_t f16n = (float16_t) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +float16_t f16p = (float16_t) 1.0Q;
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float32_t f32a = 1.0F16;
> > +float32_t f32b = (float32_t) 1.0F16;
> > +#endif
> > +float32_t f32c = 1.0F32;
> > +float32_t f32d = (float32_t) 1.0F32;
> > +#ifdef __STDCPP_FLOAT64_T__
> > +float32_t f32e = 1.0F64;               // { dg-error "cannot convert '_Float64' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" "" { target { float32 && float64 } } }
> > +float32_t f32f = (float32_t) 1.0F64;
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +float32_t f32g = 1.0F128;              // { dg-error "cannot convert '_Float128' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" "" { target { float32 && float128 } } }
> > +float32_t f32h = (float32_t) 1.0F128;
> > +#endif
> > +#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__
> > +float32_t f32i = 1.0f;
> > +#endif
> > +float32_t f32j = (float32_t) 1.0f;
> > +float32_t f32l = (float32_t) 1.0;
> > +float32_t f32n = (float32_t) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +float32_t f32p = (float32_t) 1.0Q;
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float64_t f64a = 1.0F16;
> > +float64_t f64b = (float64_t) 1.0F16;
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +float64_t f64c = 1.0F32;
> > +float64_t f64d = (float64_t) 1.0F32;
> > +#endif
> > +float64_t f64e = 1.0F64;
> > +float64_t f64f = (float64_t) 1.0F64;
> > +#ifdef __STDCPP_FLOAT128_T__
> > +float64_t f64g = 1.0F128;              // { dg-error "cannot convert '_Float128' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" "" { target { float64 && float128 } } }
> > +float64_t f64h = (float64_t) 1.0F128;
> > +#endif
> > +#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__
> > +float64_t f64i = 1.0f;
> > +#endif
> > +float64_t f64j = (float64_t) 1.0f;
> > +#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__
> > +float64_t f64k = 1.0;
> > +#endif
> > +float64_t f64l = (float64_t) 1.0;
> > +float64_t f64n = (float64_t) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +float64_t f64p = (float64_t) 1.0Q;
> > +#endif
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float128_t f128a = 1.0F16;
> > +float128_t f128b = (float128_t) 1.0F16;
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +float128_t f128c = 1.0F32;
> > +float128_t f128d = (float128_t) 1.0F32;
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +float128_t f128e = 1.0F64;
> > +float128_t f128f = (float128_t) 1.0F64;
> > +#endif
> > +float128_t f128g = 1.0F128;
> > +float128_t f128h = (float128_t) 1.0F128;
> > +#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__
> > +float128_t f128i = 1.0f;
> > +#endif
> > +float128_t f128j = (float128_t) 1.0f;
> > +#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__
> > +float128_t f128k = 1.0;
> > +#endif
> > +float128_t f128l = (float128_t) 1.0;
> > +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106
> > +float128_t f128m = 1.0L;
> > +#endif
> > +float128_t f128n = (float128_t) 1.0L;
> > +#ifdef __SIZEOF_FLOAT128__
> > +float128_t f128o = 1.0Q;
> > +float128_t f128p = (float128_t) 1.0Q;
> > +#endif
> > +#endif
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating3.C.jj       2022-09-09 18:46:07.281922287 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C  2022-09-10 10:21:25.748210213 +0200
> > @@ -0,0 +1,128 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// Variant of ext-floating2.C test with x86 specific assumptions
> > +// about float, double, long double and existence of __float128.
> > +// And some further tests.
> > +// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
> > +// { dg-options "" }
> > +
> > +#include "ext-floating.h"
> > +
> > +#if !defined(__STDCPP_FLOAT32_T__) \
> > +    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
> > +    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
> > +    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
> > +    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
> > +    || !defined(__SIZEOF_FLOAT128__)
> > +#error Unexpected set of floating point types
> > +#endif
> > +
> > +using namespace std;
> > +
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float16_t f16i = 1.0f;                 // { dg-error "cannot convert 'float' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +float16_t f16k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +float16_t f16m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +float16_t f16o = 1.0Q;                 // { dg-error "cannot convert '__float128' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +#endif
> > +float32_t f32i = 1.0f;
> > +float32_t f32k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> > +float32_t f32m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> > +float32_t f32o = 1.0Q;                 // { dg-error "cannot convert '__float128' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> > +float64_t f64i = 1.0f;
> > +float64_t f64k = 1.0;
> > +float64_t f64m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
> > +float64_t f64o = 1.0Q;                 // { dg-error "cannot convert '__float128' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
> > +float128_t f128i = 1.0f;
> > +float128_t f128k = 1.0;
> > +float128_t f128m = 1.0L;
> > +float128_t f128o = 1.0Q;
> > +
> > +#ifdef __STDCPP_FLOAT16_T__
> > +constexpr float16_t f16x = 1.0F16;
> > +#endif
> > +constexpr float32_t f32x = 2.0F32;
> > +constexpr float64_t f64x = 3.0F64;
> > +constexpr float128_t f128x = 4.0F128;
> > +constexpr float fx = 5.0f;
> > +constexpr double dx = 6.0;
> > +constexpr long double ldx = 7.0L;
> > +
> > +constexpr int foo (float32_t) { return 1; }
> > +constexpr int foo (float64_t) { return 2; }
> > +constexpr int bar (float) { return 3; }
> > +constexpr int bar (double) { return 4; }
> > +constexpr int bar (long double) { return 5; }
> > +constexpr int baz (float32_t) { return 6; }
> > +constexpr int baz (float64_t) { return 7; }
> > +constexpr int baz (float128_t) { return 8; }
> > +constexpr int qux (float64_t) { return 9; }
> > +constexpr int qux (float32_t) { return 10; }
> > +constexpr int fred (long double) { return 11; }
> > +constexpr int fred (double) { return 12; }
> > +constexpr int fred (float) { return 13; }
> > +constexpr int thud (float128_t) { return 14; }
> > +constexpr int thud (float64_t) { return 15; }
> > +constexpr int thud (float32_t) { return 16; }
> > +struct S {
> > +  constexpr operator float32_t () const { return 1.0f32; }
> > +  constexpr operator float64_t () const { return 2.0f64; }
> > +};
> > +struct T {
> > +  constexpr operator float64_t () const { return 3.0f64; }
> > +  constexpr operator float32_t () const { return 4.0f32; }
> > +};
> > +
> > +void
> > +test (S s, T t)
> > +{
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  foo (float16_t (1.0));                       // { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (foo (float (2.0)) == 1);
> > +  static_assert (foo (double (3.0)) == 2);
> > +  constexpr double x (s);
> > +  static_assert (x == 2.0);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  bar (f16x);                                  // { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (bar (f32x) == 3);
> > +  static_assert (bar (f64x) == 4);
> > +  bar (f128x);                                 // { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" }
> > +  static_assert (bar (fx) == 3);
> > +  static_assert (bar (dx) == 4);
> > +  static_assert (bar (ldx) == 5);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  baz (f16x);                                  // { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (baz (f32x) == 6);
> > +  static_assert (baz (f64x) == 7);
> > +  static_assert (baz (f128x) == 8);
> > +  static_assert (baz (fx) == 6);
> > +  static_assert (baz (dx) == 7);
> > +  static_assert (baz (ldx) == 8);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  qux (float16_t (1.0));                       // { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (qux (float (2.0)) == 10);
> > +  static_assert (qux (double (3.0)) == 9);
> > +  constexpr double y (t);
> > +  static_assert (y == 3.0);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  fred (f16x);                                 // { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (fred (f32x) == 13);
> > +  static_assert (fred (f64x) == 12);
> > +  fred (f128x);                                        // { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" }
> > +  static_assert (fred (fx) == 13);
> > +  static_assert (fred (dx) == 12);
> > +  static_assert (fred (ldx) == 11);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  thud (f16x);                                 // { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (thud (f32x) == 16);
> > +  static_assert (thud (f64x) == 15);
> > +  static_assert (thud (f128x) == 14);
> > +  static_assert (thud (fx) == 16);
> > +  static_assert (thud (dx) == 15);
> > +  static_assert (thud (ldx) == 14);
> > +}
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating4.C.jj       2022-09-09 18:48:11.979261440 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C  2022-09-10 10:55:24.105457186 +0200
> > @@ -0,0 +1,126 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// Variant of ext-floating3.C test with different specific assumptions
> > +// about float, double, long double.
> > +// float, double and long double are assumed to be IEEE 754 single, double
> > +// and quad.
> > +// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } }
> > +// { dg-options "" }
> > +// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } }
> > +// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } }
> > +
> > +#include "ext-floating.h"
> > +
> > +#if !defined(__STDCPP_FLOAT32_T__) \
> > +    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
> > +    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
> > +    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
> > +    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__
> > +#error Unexpected set of floating point types
> > +#endif
> > +
> > +using namespace std;
> > +
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float16_t f16i = 1.0f;                 // { dg-error "cannot convert 'float' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +float16_t f16k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +float16_t f16m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float16_t' \\\{aka '_Float16'\\\} in initialization" "" { target float16 } }
> > +#endif
> > +float32_t f32i = 1.0f;
> > +float32_t f32k = 1.0;                  // { dg-error "cannot convert 'double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> > +float32_t f32m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float32_t' \\\{aka '_Float32'\\\} in initialization" }
> > +float64_t f64i = 1.0f;
> > +float64_t f64k = 1.0;
> > +float64_t f64m = 1.0L;                 // { dg-error "cannot convert 'long double' to 'std::float64_t' \\\{aka '_Float64'\\\} in initialization" }
> > +float128_t f128i = 1.0f;
> > +float128_t f128k = 1.0;
> > +float128_t f128m = 1.0L;
> > +
> > +#ifdef __STDCPP_FLOAT16_T__
> > +constexpr float16_t f16x = 1.0F16;
> > +#endif
> > +constexpr float32_t f32x = 2.0F32;
> > +constexpr float64_t f64x = 3.0F64;
> > +constexpr float128_t f128x = 4.0F128;
> > +constexpr float fx = 5.0f;
> > +constexpr double dx = 6.0;
> > +constexpr long double ldx = 7.0L;
> > +
> > +constexpr int foo (float32_t) { return 1; }
> > +constexpr int foo (float64_t) { return 2; }
> > +constexpr int bar (float) { return 3; }
> > +constexpr int bar (double) { return 4; }
> > +constexpr int bar (long double) { return 5; }
> > +constexpr int baz (float32_t) { return 6; }
> > +constexpr int baz (float64_t) { return 7; }
> > +constexpr int baz (float128_t) { return 8; }
> > +constexpr int qux (float64_t) { return 9; }
> > +constexpr int qux (float32_t) { return 10; }
> > +constexpr int fred (long double) { return 11; }
> > +constexpr int fred (double) { return 12; }
> > +constexpr int fred (float) { return 13; }
> > +constexpr int thud (float128_t) { return 14; }
> > +constexpr int thud (float64_t) { return 15; }
> > +constexpr int thud (float32_t) { return 16; }
> > +struct S {
> > +  constexpr operator float32_t () const { return 1.0f32; }
> > +  constexpr operator float64_t () const { return 2.0f64; }
> > +};
> > +struct T {
> > +  constexpr operator float64_t () const { return 3.0f64; }
> > +  constexpr operator float32_t () const { return 4.0f32; }
> > +};
> > +
> > +void
> > +test (S s, T t)
> > +{
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  foo (float16_t (1.0));                       // { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (foo (float (2.0)) == 1);
> > +  static_assert (foo (double (3.0)) == 2);
> > +  constexpr double x (s);
> > +  static_assert (x == 2.0);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  bar (f16x);                                  // { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (bar (f32x) == 3);
> > +  static_assert (bar (f64x) == 4);
> > +  static_assert (bar (f128x) == 5);
> > +  static_assert (bar (fx) == 3);
> > +  static_assert (bar (dx) == 4);
> > +  static_assert (bar (ldx) == 5);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  baz (f16x);                                  // { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (baz (f32x) == 6);
> > +  static_assert (baz (f64x) == 7);
> > +  static_assert (baz (f128x) == 8);
> > +  static_assert (baz (fx) == 6);
> > +  static_assert (baz (dx) == 7);
> > +  static_assert (baz (ldx) == 8);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  qux (float16_t (1.0));                       // { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (qux (float (2.0)) == 10);
> > +  static_assert (qux (double (3.0)) == 9);
> > +  constexpr double y (t);
> > +  static_assert (y == 3.0);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  fred (f16x);                                 // { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (fred (f32x) == 13);
> > +  static_assert (fred (f64x) == 12);
> > +  static_assert (fred (f128x) == 11);
> > +  static_assert (fred (fx) == 13);
> > +  static_assert (fred (dx) == 12);
> > +  static_assert (fred (ldx) == 11);
> > +#ifdef __STDCPP_FLOAT16_T__
> > +  thud (f16x);                                 // { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> > +#endif
> > +  static_assert (thud (f32x) == 16);
> > +  static_assert (thud (f64x) == 15);
> > +  static_assert (thud (f128x) == 14);
> > +  static_assert (thud (fx) == 16);
> > +  static_assert (thud (dx) == 15);
> > +  static_assert (thud (ldx) == 14);
> > +}
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating5.C.jj       2022-09-09 20:00:22.489534397 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C  2022-09-10 10:44:59.653943267 +0200
> > @@ -0,0 +1,13 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// IBM extended long double and _Float128 should have unordered conversion
> > +// ranks as IBM extended long double has variable precision from 53 bits
> > +// for denormals to more than 2150 bits for certain numbers.
> > +// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } }
> > +// { dg-require-effective-target ppc_float128_sw }
> > +// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" }
> > +
> > +auto a = 1.0F128 + 1.0L;       // { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" }
> > +auto b = 1.0L + 1.0F128;       // { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" }
> > +bool c;
> > +auto d = c ? 1.0F128 : 1.0L;   // { dg-error "operands to '\\\?:' have unordered conversion rank of types '_Float128' and 'long double'" }
> > +auto e = c ? 1.0L : 1.0F128;   // { dg-error "operands to '\\\?:' have unordered conversion rank of types 'long double' and '_Float128'" }
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating6.C.jj       2022-09-10 10:19:12.402030094 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating6.C  2022-09-09 18:46:07.281922287 +0200
> > @@ -0,0 +1,30 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do compile { target c++23 } }
> > +// { dg-options "" }
> > +
> > +#include "ext-floating.h"
> > +
> > +#ifdef __STRICT_ANSI__
> > +#undef __SIZEOF_FLOAT128__
> > +#endif
> > +
> > +using namespace std;
> > +
> > +float foo (float x, float y, float z) { return x * y + z; }
> > +double foo (double x, double y, double z) { return x * y + z; }
> > +long double foo (long double x, long double y, long double z) { return x * y + z; }
> > +#ifdef __STDCPP_FLOAT16_T__
> > +float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; }
> > +#endif
> > +#ifdef __STDCPP_FLOAT32_T__
> > +float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; }
> > +#endif
> > +#ifdef __STDCPP_FLOAT64_T__
> > +float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; }
> > +#endif
> > +#ifdef __STDCPP_FLOAT128_T__
> > +float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; }
> > +#endif
> > +#ifdef __STDCPP_BFLOAT16_T__
> > +bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; }
> > +#endif
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating7.C.jj       2022-09-10 10:47:37.550796997 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C  2022-09-10 10:53:25.622065903 +0200
> > @@ -0,0 +1,119 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do run { target { c++23 && float16_runtime } } }
> > +// { dg-options "" }
> > +// { dg-add-options float16 }
> > +
> > +#ifndef WIDTH
> > +#ifndef __STDCPP_FLOAT16_T__
> > +#error Unexpected
> > +#endif
> > +#define WIDTH 16
> > +#endif
> > +
> > +#include <stdarg.h>
> > +#include "ext-floating.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 TYPE CONCAT (_Float, WIDTH)
> > +#define CST(C) CONCAT3 (C, f, WIDTH)
> > +#define CSTU(C) CONCAT3 (C, F, WIDTH)
> > +
> > +extern "C" void abort ();
> > +
> > +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
> > +fn (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 = fn (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 ();
> > +}
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating8.C.jj       2022-09-10 10:52:54.654486646 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C  2022-09-10 10:53:41.424851341 +0200
> > @@ -0,0 +1,13 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do run { target { c++23 && float32_runtime } } }
> > +// { dg-options "" }
> > +// { dg-add-options float32 }
> > +
> > +#ifndef WIDTH
> > +#ifndef __STDCPP_FLOAT32_T__
> > +#error Unexpected
> > +#endif
> > +#define WIDTH 32
> > +#endif
> > +
> > +#include "ext-floating7.C"
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating9.C.jj       2022-09-10 10:53:49.328744035 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating9.C  2022-09-10 10:53:57.280636056 +0200
> > @@ -0,0 +1,13 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do run { target { c++23 && float64_runtime } } }
> > +// { dg-options "" }
> > +// { dg-add-options float64 }
> > +
> > +#ifndef WIDTH
> > +#ifndef __STDCPP_FLOAT64_T__
> > +#error Unexpected
> > +#endif
> > +#define WIDTH 64
> > +#endif
> > +
> > +#include "ext-floating7.C"
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating10.C.jj      2022-09-10 10:54:08.224487463 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C 2022-09-10 10:54:21.578306159 +0200
> > @@ -0,0 +1,13 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +// { dg-do run { target { c++23 && float128_runtime } } }
> > +// { dg-options "" }
> > +// { dg-add-options float128 }
> > +
> > +#ifndef WIDTH
> > +#ifndef __STDCPP_FLOAT128_T__
> > +#error Unexpected
> > +#endif
> > +#define WIDTH 128
> > +#endif
> > +
> > +#include "ext-floating7.C"
> > --- gcc/testsuite/g++.dg/cpp23/ext-floating.h.jj        2022-09-09 18:46:07.281922287 +0200
> > +++ gcc/testsuite/g++.dg/cpp23/ext-floating.h   2022-09-09 18:46:07.281922287 +0200
> > @@ -0,0 +1,30 @@
> > +// P1467R9 - Extended floating-point types and standard names.
> > +
> > +namespace std
> > +{
> > +  #ifdef __STDCPP_FLOAT16_T__
> > +  using float16_t = _Float16;
> > +  #endif
> > +  #ifdef __STDCPP_FLOAT32_T__
> > +  using float32_t = _Float32;
> > +  #endif
> > +  #ifdef __STDCPP_FLOAT64_T__
> > +  using float64_t = _Float64;
> > +  #endif
> > +  #ifdef __STDCPP_FLOAT128_T__
> > +  using float128_t = _Float128;
> > +  #endif
> > +  #undef __STDCPP_BFLOAT16_T__
> > +  #ifdef __STDCPP_BFLOAT16_T__
> > +  using bfloat16_t = __bf16; // ???
> > +  #endif
> > +  template<typename T, T v> struct integral_constant {
> > +    static constexpr T value = v;
> > +  };
> > +  typedef integral_constant<bool, false> false_type;
> > +  typedef integral_constant<bool, true> true_type;
> > +  template<class T, class U>
> > +  struct is_same : std::false_type {};
> > +  template <class T>
> > +  struct is_same<T, T> : std::true_type {};
> > +}
> > --- gcc/testsuite/g++.target/i386/float16-1.C.jj        2021-12-30 15:12:43.315149146 +0100
> > +++ gcc/testsuite/g++.target/i386/float16-1.C   2022-09-12 08:49:38.178955414 +0200
> > @@ -1,8 +1,8 @@
> >  /* { dg-do compile } */
> >  /* { dg-options "-O2 -mno-sse2" } */
> >
> > -_Float16/* { dg-error "does not name a type" } */
> > +_Float16       /* { dg-error "expected unqualified-id before '_Float16'" } */
> >  foo (_Float16 x)
> >  {
> >    return x;
> > -}
> > +}              /* { dg-error "'_Float16' is not supported on this target" } */
> > --- libcpp/expr.cc.jj   2022-09-08 13:01:19.837771596 +0200
> > +++ libcpp/expr.cc      2022-09-09 09:52:46.533798139 +0200
> > @@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfil
> >         case 'f': case 'F':
> >           f++;
> >           if (len > 0
> > -             && !CPP_OPTION (pfile, cplusplus)
> >               && s[1] >= '1'
> >               && s[1] <= '9'
> >               && fn_bits == 0)
> > @@ -230,7 +229,9 @@ interpret_float_suffix (cpp_reader *pfil
> >                   len--;
> >                   s++;
> >                 }
> > -             if (len > 0 && s[1] == 'x')
> > +             if (len > 0
> > +                 && s[1] == 'x'
> > +                 && !CPP_OPTION (pfile, cplusplus))
> >                 {
> >                   fnx++;
> >                   len--;
> > --- include/demangle.h.jj       2022-08-26 09:23:37.788064821 +0200
> > +++ include/demangle.h  2022-09-09 09:52:46.533798139 +0200
> > @@ -457,6 +457,11 @@ enum demangle_component_type
> >    DEMANGLE_COMPONENT_MODULE_PARTITION,
> >    DEMANGLE_COMPONENT_MODULE_ENTITY,
> >    DEMANGLE_COMPONENT_MODULE_INIT,
> > +
> > +  /* A builtin type with argument.  This holds the builtin type
> > +     information.  */
> > +  DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
> > +
> >  };
> >
> >  /* Types which are only used internally.  */
> > @@ -543,6 +548,14 @@ struct demangle_component
> >        const struct demangle_builtin_type_info *type;
> >      } s_builtin;
> >
> > +    /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  */
> > +    struct
> > +    {
> > +      /* Builtin type.  */
> > +      const struct demangle_builtin_type_info *type;
> > +      int arg;
> > +    } s_extended_builtin;
> > +
> >      /* For DEMANGLE_COMPONENT_SUB_STD.  */
> >      struct
> >      {
> > --- libiberty/cp-demangle.c.jj  2022-08-26 09:23:37.788064821 +0200
> > +++ libiberty/cp-demangle.c     2022-09-09 09:52:46.957792397 +0200
> > @@ -648,6 +648,10 @@ d_dump (struct demangle_component *dc, i
> >      case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> >        printf ("builtin type %s\n", dc->u.s_builtin.type->name);
> >        return;
> > +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> > +      printf ("builtin type %s%d\n", dc->u.s_extended_builtin.type->name,
> > +             dc->u.s_extended_builtin.type->arg);
> > +      return;
> >      case DEMANGLE_COMPONENT_OPERATOR:
> >        printf ("operator %s\n", dc->u.s_operator.op->name);
> >        return;
> > @@ -771,11 +775,6 @@ d_dump (struct demangle_component *dc, i
> >      case DEMANGLE_COMPONENT_PTRMEM_TYPE:
> >        printf ("pointer to member type\n");
> >        break;
> > -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> > -      printf ("fixed-point type, accum? %d, sat? %d\n",
> > -              dc->u.s_fixed.accum, dc->u.s_fixed.sat);
> > -      d_dump (dc->u.s_fixed.length, indent + 2);
> > -      break;
> >      case DEMANGLE_COMPONENT_ARGLIST:
> >        printf ("argument list\n");
> >        break;
> > @@ -1109,6 +1108,27 @@ d_make_builtin_type (struct d_info *di,
> >    return p;
> >  }
> >
> > +/* Add a new extended builtin type component.  */
> > +
> > +static struct demangle_component *
> > +d_make_extended_builtin_type (struct d_info *di,
> > +                             const struct demangle_builtin_type_info *type,
> > +                             int arg)
> > +{
> > +  struct demangle_component *p;
> > +
> > +  if (type == NULL)
> > +    return NULL;
> > +  p = d_make_empty (di);
> > +  if (p != NULL)
> > +    {
> > +      p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE;
> > +      p->u.s_extended_builtin.type = type;
> > +      p->u.s_extended_builtin.arg = arg;
> > +    }
> > +  return p;
> > +}
> > +
> >  /* Add a new operator component.  */
> >
> >  static struct demangle_component *
> > @@ -2464,6 +2484,7 @@ cplus_demangle_builtin_types[D_BUILTIN_T
> >    /* 32 */ { NL ("char32_t"),  NL ("char32_t"),        D_PRINT_DEFAULT },
> >    /* 33 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
> >              D_PRINT_DEFAULT },
> > +  /* 34 */ { NL ("_Float"),    NL ("_Float"),          D_PRINT_FLOAT },
> >  };
> >
> >  CP_STATIC_IF_GLIBCPP_V3
> > @@ -2727,19 +2748,22 @@ cplus_demangle_type (struct d_info *di)
> >           break;
> >
> >         case 'F':
> > -         /* Fixed point types. DF<int bits><length><fract bits><sat>  */
> > -         ret = d_make_empty (di);
> > -         ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
> > -         if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
> > -           /* For demangling we don't care about the bits.  */
> > -           d_number (di);
> > -         ret->u.s_fixed.length = cplus_demangle_type (di);
> > -         if (ret->u.s_fixed.length == NULL)
> > -           return NULL;
> > -         d_number (di);
> > -         peek = d_next_char (di);
> > -         ret->u.s_fixed.sat = (peek == 's');
> > -         break;
> > +         /* DF<number>_ - _Float<number>.  */
> > +         {
> > +           int arg = d_number (di);
> > +           char buf[12];
> > +           if (d_peek_char (di) != '_')
> > +             return NULL;
> > +           ret
> > +             = d_make_extended_builtin_type (di,
> > +                                             &cplus_demangle_builtin_types[34],
> > +                                             arg);
> > +           d_advance (di, 1);
> > +           sprintf (buf, "%d", arg);
> > +           di->expansion += ret->u.s_extended_builtin.type->len
> > +                            + strlen (buf);
> > +           break;
> > +         }
> >
> >         case 'v':
> >           ret = d_vector_type (di);
> > @@ -4202,6 +4226,7 @@ d_count_templates_scopes (struct d_print
> >      case DEMANGLE_COMPONENT_FUNCTION_PARAM:
> >      case DEMANGLE_COMPONENT_SUB_STD:
> >      case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> > +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> >      case DEMANGLE_COMPONENT_OPERATOR:
> >      case DEMANGLE_COMPONENT_CHARACTER:
> >      case DEMANGLE_COMPONENT_NUMBER:
> > @@ -4210,6 +4235,7 @@ d_count_templates_scopes (struct d_print
> >      case DEMANGLE_COMPONENT_MODULE_NAME:
> >      case DEMANGLE_COMPONENT_MODULE_PARTITION:
> >      case DEMANGLE_COMPONENT_MODULE_INIT:
> > +    case DEMANGLE_COMPONENT_FIXED_TYPE:
> >        break;
> >
> >      case DEMANGLE_COMPONENT_TEMPLATE:
> > @@ -4309,10 +4335,6 @@ d_count_templates_scopes (struct d_print
> >        d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
> >        break;
> >
> > -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> > -      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
> > -      break;
> > -
> >      case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
> >      case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
> >      case DEMANGLE_COMPONENT_MODULE_ENTITY:
> > @@ -4580,11 +4602,11 @@ d_find_pack (struct d_print_info *dpi,
> >      case DEMANGLE_COMPONENT_TAGGED_NAME:
> >      case DEMANGLE_COMPONENT_OPERATOR:
> >      case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> > +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> >      case DEMANGLE_COMPONENT_SUB_STD:
> >      case DEMANGLE_COMPONENT_CHARACTER:
> >      case DEMANGLE_COMPONENT_FUNCTION_PARAM:
> >      case DEMANGLE_COMPONENT_UNNAMED_TYPE:
> > -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> >      case DEMANGLE_COMPONENT_DEFAULT_ARG:
> >      case DEMANGLE_COMPONENT_NUMBER:
> >        return NULL;
> > @@ -5387,6 +5409,16 @@ d_print_comp_inner (struct d_print_info
> >                          dc->u.s_builtin.type->java_len);
> >        return;
> >
> > +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> > +      if ((options & DMGL_JAVA) == 0)
> > +       d_append_buffer (dpi, dc->u.s_extended_builtin.type->name,
> > +                        dc->u.s_extended_builtin.type->len);
> > +      else
> > +       d_append_buffer (dpi, dc->u.s_extended_builtin.type->java_name,
> > +                        dc->u.s_extended_builtin.type->java_len);
> > +      d_append_num (dpi, dc->u.s_extended_builtin.arg);
> > +      return;
> > +
> >      case DEMANGLE_COMPONENT_VENDOR_TYPE:
> >        d_print_comp (dpi, options, d_left (dc));
> >        return;
> > @@ -5525,22 +5557,6 @@ d_print_comp_inner (struct d_print_info
> >         return;
> >        }
> >
> > -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> > -      if (dc->u.s_fixed.sat)
> > -       d_append_string (dpi, "_Sat ");
> > -      /* Don't print "int _Accum".  */
> > -      if (dc->u.s_fixed.length->u.s_builtin.type
> > -         != &cplus_demangle_builtin_types['i'-'a'])
> > -       {
> > -         d_print_comp (dpi, options, dc->u.s_fixed.length);
> > -         d_append_char (dpi, ' ');
> > -       }
> > -      if (dc->u.s_fixed.accum)
> > -       d_append_string (dpi, "_Accum");
> > -      else
> > -       d_append_string (dpi, "_Fract");
> > -      return;
> > -
> >      case DEMANGLE_COMPONENT_ARGLIST:
> >      case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
> >        if (d_left (dc) != NULL)
> > --- libiberty/cp-demangle.h.jj  2022-08-26 09:23:37.788064821 +0200
> > +++ libiberty/cp-demangle.h     2022-09-09 09:52:46.978792113 +0200
> > @@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i)
> >  extern const struct demangle_operator_info cplus_demangle_operators[];
> >  #endif
> >
> > -#define D_BUILTIN_TYPE_COUNT (34)
> > +#define D_BUILTIN_TYPE_COUNT (35)
> >
> >  CP_STATIC_IF_GLIBCPP_V3
> >  const struct demangle_builtin_type_info
> > --- libiberty/testsuite/demangle-expected.jj    2022-08-26 09:23:37.788064821 +0200
> > +++ libiberty/testsuite/demangle-expected       2022-09-09 09:52:46.993791909 +0200
> > @@ -1242,8 +1242,8 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8fun
> >  post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
> >  #
> >  --format=auto --no-params
> > -_Z3xxxDFyuVb
> > -xxx(unsigned long long _Fract, bool volatile)
> > +_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb
> > +xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile)
> >  xxx
> >  # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
> >  --format=auto --no-params
> > --- fixincludes/inclhack.def.jj 2022-03-01 19:42:39.183264899 +0100
> > +++ fixincludes/inclhack.def    2022-09-11 20:08:07.787691125 +0200
> > @@ -2015,6 +2015,102 @@ fix = {
> >         EOT;
> >  };
> >
> > +/*  glibc-2.27 to 2.36 assume GCC 7 or later supports some or all
> > + *  of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C,
> > + *  but doesn't for C++.
> > + */
> > +fix = {
> > +    hackname  = glibc_cxx_floatn_1;
> > +    files     = bits/floatn.h, bits/floatn-common.h;
> > +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> > +               "(([ \t]*/\\*[^\n]*\\*/\n)?"
> > +               "([ \t]*#[ \t]*if[^\n]*\n)?"
> > +               "[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
> > +    c_fix     = format;
> > +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
> > +    test_text = <<-EOT
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       /* The literal suffix f128 exists only since GCC 7.0.  */
> > +       #   define __f128(x) x##l
> > +       #  else
> > +       #   define __f128(x) x##f128
> > +       #  endif
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       /* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
> > +       #   if __LDBL_MANT_DIG__ == 113
> > +       #    define __f128(x) x##l
> > +       #   else
> > +       #    define __f128(x) x##q
> > +       #   endif
> > +       #  else
> > +       #   define __f128(x) x##f128
> > +       #  endif
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       #   ifdef __NO_LONG_DOUBLE_MATH
> > +       #    define __f64(x) x##l
> > +       #   else
> > +       #    define __f64(x) x
> > +       #   endif
> > +       #  else
> > +       #   define __f64(x) x##f64
> > +       #  endif
> > +       EOT;
> > +};
> > +
> > +fix = {
> > +    hackname  = glibc_cxx_floatn_2;
> > +    files     = bits/floatn.h, bits/floatn-common.h;
> > +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> > +               "(([ \t]*/\\*[^\n]*\\*/\n)?"
> > +               "[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
> > +    c_fix     = format;
> > +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
> > +    test_text = <<-EOT
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
> > +       #  endif
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       typedef __float128 _Float128;
> > +       #  endif
> > +       EOT;
> > +};
> > +
> > +fix = {
> > +    hackname  = glibc_cxx_floatn_3;
> > +    files     = bits/floatn.h, bits/floatn-common.h;
> > +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> > +               "(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?"
> > +               "([ \t]*#[ \t]*if[^\n]*\n)?"
> > +               "([ \t]*typedef[ \t]+[^\n]*;\n)?"
> > +               "[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
> > +    c_fix     = format;
> > +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n%2";
> > +    test_text = <<-EOT
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       #   define __CFLOAT128 _Complex long double
> > +       #  else
> > +       #   define __CFLOAT128 _Complex _Float128
> > +       #  endif
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       /* Add a typedef for older GCC compilers which don't natively support
> > +          _Complex _Float128.  */
> > +       typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
> > +       #   define __CFLOAT128 __cfloat128
> > +       #  else
> > +       #   define __CFLOAT128 _Complex _Float128
> > +       #  endif
> > +       #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> > +       #   ifdef __NO_LONG_DOUBLE_MATH
> > +       #    define __CFLOAT64 _Complex long double
> > +       #   else
> > +       #    define __CFLOAT64 _Complex double
> > +       #   endif
> > +       #  else
> > +       #   define __CFLOAT64 _Complex _Float64
> > +       #  endif
> > +       EOT;
> > +};
> > +
> >  /*  glibc-2.3.5 defines pthread mutex initializers incorrectly,
> >   *  so we replace them with versions that correspond to the
> >   *  definition.
> > --- fixincludes/tests/base/bits/floatn.h.jj     2022-09-11 20:11:34.991962782 +0200
> > +++ fixincludes/tests/base/bits/floatn.h        2022-09-11 20:09:48.323368533 +0200
> > @@ -0,0 +1,74 @@
> > +/*  DO NOT EDIT THIS FILE.
> > +
> > +    It has been auto-edited by fixincludes from:
> > +
> > +       "fixinc/tests/inc/bits/floatn.h"
> > +
> > +    This had to be done to correct non-standard usages in the
> > +    original, manufacturer supplied header file.  */
> > +
> > +
> > +
> > +#if defined( GLIBC_CXX_FLOATN_1_CHECK )
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +/* The literal suffix f128 exists only since GCC 7.0.  */
> > +#   define __f128(x) x##l
> > +#  else
> > +#   define __f128(x) x##f128
> > +#  endif
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
> > +#   if __LDBL_MANT_DIG__ == 113
> > +#    define __f128(x) x##l
> > +#   else
> > +#    define __f128(x) x##q
> > +#   endif
> > +#  else
> > +#   define __f128(x) x##f128
> > +#  endif
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +#   ifdef __NO_LONG_DOUBLE_MATH
> > +#    define __f64(x) x##l
> > +#   else
> > +#    define __f64(x) x
> > +#   endif
> > +#  else
> > +#   define __f64(x) x##f64
> > +#  endif
> > +#endif  /* GLIBC_CXX_FLOATN_1_CHECK */
> > +
> > +
> > +#if defined( GLIBC_CXX_FLOATN_2_CHECK )
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
> > +#  endif
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +typedef __float128 _Float128;
> > +#  endif
> > +#endif  /* GLIBC_CXX_FLOATN_2_CHECK */
> > +
> > +
> > +#if defined( GLIBC_CXX_FLOATN_3_CHECK )
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +#   define __CFLOAT128 _Complex long double
> > +#  else
> > +#   define __CFLOAT128 _Complex _Float128
> > +#  endif
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +/* Add a typedef for older GCC compilers which don't natively support
> > +   _Complex _Float128.  */
> > +typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
> > +#   define __CFLOAT128 __cfloat128
> > +#  else
> > +#   define __CFLOAT128 _Complex _Float128
> > +#  endif
> > +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)
> > +#   ifdef __NO_LONG_DOUBLE_MATH
> > +#    define __CFLOAT64 _Complex long double
> > +#   else
> > +#    define __CFLOAT64 _Complex double
> > +#   endif
> > +#  else
> > +#   define __CFLOAT64 _Complex _Float64
> > +#  endif
> > +#endif  /* GLIBC_CXX_FLOATN_3_CHECK */
> > --- fixincludes/fixincl.x.jj    2022-03-01 19:42:39.169265091 +0100
> > +++ fixincludes/fixincl.x       2022-09-11 20:09:37.668565341 +0200
> > @@ -2,11 +2,11 @@
> >   *
> >   * DO NOT EDIT THIS FILE   (fixincl.x)
> >   *
> > - * It has been AutoGen-ed  February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16
> > + * It has been AutoGen-ed  September 11, 2022 at 08:09:37 PM by AutoGen 5.18.16
> >   * From the definitions    inclhack.def
> >   * and the template file   fixincl
> >   */
> > -/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022
> > +/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Sep 11 20:09:37 CEST 2022
> >   *
> >   * You must regenerate it.  Use the ./genfixes script.
> >   *
> > @@ -15,7 +15,7 @@
> >   * certain ANSI-incompatible system header files which are fixed to work
> >   * correctly with ANSI C and placed in a directory that GNU C will search.
> >   *
> > - * This file contains 267 fixup descriptions.
> > + * This file contains 270 fixup descriptions.
> >   *
> >   * See README for more information.
> >   *
> > @@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4
> >
> >  /* * * * * * * * * * * * * * * * * * * * * * * * * *
> >   *
> > + *  Description of Glibc_Cxx_Floatn_1 fix
> > + */
> > +tSCC zGlibc_Cxx_Floatn_1Name[] =
> > +     "glibc_cxx_floatn_1";
> > +
> > +/*
> > + *  File name selection pattern
> > + */
> > +tSCC zGlibc_Cxx_Floatn_1List[] =
> > +  "bits/floatn.h\0bits/floatn-common.h\0";
> > +/*
> > + *  Machine/OS name selection pattern
> > + */
> > +#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL
> > +
> > +/*
> > + *  content selection pattern - do fix if pattern found
> > + */
> > +tSCC zGlibc_Cxx_Floatn_1Select0[] =
> > +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> > +(([ \t]*/\\*[^\n\
> > +]*\\*/\n\
> > +)?([ \t]*#[ \t]*if[^\n\
> > +]*\n\
> > +)?[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
> > +
> > +#define    GLIBC_CXX_FLOATN_1_TEST_CT  1
> > +static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = {
> > +  { TT_EGREP,    zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, };
> > +
> > +/*
> > + *  Fix Command Arguments for Glibc_Cxx_Floatn_1
> > + */
> > +static const char* apzGlibc_Cxx_Floatn_1Patch[] = {
> > +    "format",
> > +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
> > +%2",
> > +    (char*)NULL };
> > +
> > +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> > + *
> > + *  Description of Glibc_Cxx_Floatn_2 fix
> > + */
> > +tSCC zGlibc_Cxx_Floatn_2Name[] =
> > +     "glibc_cxx_floatn_2";
> > +
> > +/*
> > + *  File name selection pattern
> > + */
> > +tSCC zGlibc_Cxx_Floatn_2List[] =
> > +  "bits/floatn.h\0bits/floatn-common.h\0";
> > +/*
> > + *  Machine/OS name selection pattern
> > + */
> > +#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL
> > +
> > +/*
> > + *  content selection pattern - do fix if pattern found
> > + */
> > +tSCC zGlibc_Cxx_Floatn_2Select0[] =
> > +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> > +(([ \t]*/\\*[^\n\
> > +]*\\*/\n\
> > +)?[ \t]*typedef[ \t]+[^\n\
> > +]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
> > +
> > +#define    GLIBC_CXX_FLOATN_2_TEST_CT  1
> > +static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = {
> > +  { TT_EGREP,    zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, };
> > +
> > +/*
> > + *  Fix Command Arguments for Glibc_Cxx_Floatn_2
> > + */
> > +static const char* apzGlibc_Cxx_Floatn_2Patch[] = {
> > +    "format",
> > +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
> > +%2",
> > +    (char*)NULL };
> > +
> > +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> > + *
> > + *  Description of Glibc_Cxx_Floatn_3 fix
> > + */
> > +tSCC zGlibc_Cxx_Floatn_3Name[] =
> > +     "glibc_cxx_floatn_3";
> > +
> > +/*
> > + *  File name selection pattern
> > + */
> > +tSCC zGlibc_Cxx_Floatn_3List[] =
> > +  "bits/floatn.h\0bits/floatn-common.h\0";
> > +/*
> > + *  Machine/OS name selection pattern
> > + */
> > +#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL
> > +
> > +/*
> > + *  content selection pattern - do fix if pattern found
> > + */
> > +tSCC zGlibc_Cxx_Floatn_3Select0[] =
> > +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> > +(([ \t]*/\\*[^\n\
> > +]*\n\
> > +?[^\n\
> > +]*\\*/\n\
> > +)?([ \t]*#[ \t]*if[^\n\
> > +]*\n\
> > +)?([ \t]*typedef[ \t]+[^\n\
> > +]*;\n\
> > +)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
> > +
> > +#define    GLIBC_CXX_FLOATN_3_TEST_CT  1
> > +static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = {
> > +  { TT_EGREP,    zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, };
> > +
> > +/*
> > + *  Fix Command Arguments for Glibc_Cxx_Floatn_3
> > + */
> > +static const char* apzGlibc_Cxx_Floatn_3Patch[] = {
> > +    "format",
> > +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 1) && defined __FLT32X_MANT_DIG__)\n\
> > +%2",
> > +    (char*)NULL };
> > +
> > +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> > + *
> >   *  Description of Glibc_Mutex_Init fix
> >   */
> >  tSCC zGlibc_Mutex_InitName[] =
> > @@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[]
> >   *
> >   *  List of all fixes
> >   */
> > -#define REGEX_COUNT          305
> > +#define REGEX_COUNT          308
> >  #define MACH_LIST_SIZE_LIMIT 187
> > -#define FIX_COUNT            267
> > +#define FIX_COUNT            270
> >
> >  /*
> >   *  Enumerate the fixes
> > @@ -10977,6 +11103,9 @@ typedef enum {
> >      GLIBC_C99_INLINE_2_FIXIDX,
> >      GLIBC_C99_INLINE_3_FIXIDX,
> >      GLIBC_C99_INLINE_4_FIXIDX,
> > +    GLIBC_CXX_FLOATN_1_FIXIDX,
> > +    GLIBC_CXX_FLOATN_2_FIXIDX,
> > +    GLIBC_CXX_FLOATN_3_FIXIDX,
> >      GLIBC_MUTEX_INIT_FIXIDX,
> >      GLIBC_STDINT_FIXIDX,
> >      GLIBC_STRNCPY_FIXIDX,
> > @@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
> >       GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> >       aGlibc_C99_Inline_4Tests,   apzGlibc_C99_Inline_4Patch, 0 },
> >
> > +  {  zGlibc_Cxx_Floatn_1Name,    zGlibc_Cxx_Floatn_1List,
> > +     apzGlibc_Cxx_Floatn_1Machs,
> > +     GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> > +     aGlibc_Cxx_Floatn_1Tests,   apzGlibc_Cxx_Floatn_1Patch, 0 },
> > +
> > +  {  zGlibc_Cxx_Floatn_2Name,    zGlibc_Cxx_Floatn_2List,
> > +     apzGlibc_Cxx_Floatn_2Machs,
> > +     GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> > +     aGlibc_Cxx_Floatn_2Tests,   apzGlibc_Cxx_Floatn_2Patch, 0 },
> > +
> > +  {  zGlibc_Cxx_Floatn_3Name,    zGlibc_Cxx_Floatn_3List,
> > +     apzGlibc_Cxx_Floatn_3Machs,
> > +     GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> > +     aGlibc_Cxx_Floatn_3Tests,   apzGlibc_Cxx_Floatn_3Patch, 0 },
> > +
> >    {  zGlibc_Mutex_InitName,    zGlibc_Mutex_InitList,
> >       apzGlibc_Mutex_InitMachs,
> >       GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,
> >
> >         Jakub
> >
>
>
> --
> BR,
> Hongtao



-- 
BR,
Hongtao

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-20  3:35 ` Hongtao Liu
  2022-09-20  7:14   ` Hongtao Liu
@ 2022-09-20  8:51   ` Jakub Jelinek
  2022-09-22 15:56     ` [RFC PATCH] __trunc{tf,xf,df,sf,hf}bf2, __truncbfhf2 and __extendbfsf2 Jakub Jelinek
  1 sibling, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-20  8:51 UTC (permalink / raw)
  To: Hongtao Liu
  Cc: Jason Merrill, Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On Tue, Sep 20, 2022 at 11:35:07AM +0800, Hongtao Liu wrote:
> > The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> > shouldn't support it, in the PR there is a partial patch to do so, but
> > the big question is if it should be supported as the __bf16 type those
> > 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> > and add conversions to/from at least SFmode but probably also DFmode, TFmode
> > and XFmode on x86 and implement arithmetics on those through conversion to
> > SFmode, performing arithmetics there and conversion back.
> > Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> > implemented inline, SFmode -> BFmode conversion is harder,
> > I think it is roughly:
> I'm not sure if there should be any floating point exceptions for
> BFmode operation.
> For x86, there's no floating point exceptions for AVX512_BF16 related
> instructions

As long as __bf16 is just an extension, supporting or not supporting
exceptions on sNaNs is just fine I think, but I'm afraid it is different
for std::bfloat16_t.  If we claim we support it (define that type
in <stdfloat>, predefine __STD_BFLOAT16_TYPE__), then it needs to follow
ISO/IEC/IEEE 60559, and I'm afraid that means also exceptions and the like.
While the IEEE spec doesn't cover the exact bfloat16 format, C++ talks about
a format with these and these number of bits here and there that behaves
like in IEEE otherwise.
Whether we support std::bfloat16_t at all is our choice, if we do support
it, whether we support it with __bf16 underlying type or come up with
something different, it is up to us, and with -ffast-math/-Ofast etc.
we can certainly use hw instructions for it which don't raise exceptions.

At least that is my limited understanding of it...

	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [RFC PATCH] __trunc{tf,xf,df,sf,hf}bf2, __truncbfhf2 and __extendbfsf2
  2022-09-20  8:51   ` Jakub Jelinek
@ 2022-09-22 15:56     ` Jakub Jelinek
  2022-09-23  0:44       ` Hongtao Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-22 15:56 UTC (permalink / raw)
  To: Hongtao Liu, Jonathan Wakely, Joseph S. Myers, Richard Earnshaw,
	Kyrylo Tkachov, richard.sandiford
  Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 26865 bytes --]

On Tue, Sep 20, 2022 at 10:51:18AM +0200, Jakub Jelinek via Gcc-patches wrote:
> On Tue, Sep 20, 2022 at 11:35:07AM +0800, Hongtao Liu wrote:
> > > The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> > > shouldn't support it, in the PR there is a partial patch to do so, but
> > > the big question is if it should be supported as the __bf16 type those
> > > 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> > > and add conversions to/from at least SFmode but probably also DFmode, TFmode
> > > and XFmode on x86 and implement arithmetics on those through conversion to
> > > SFmode, performing arithmetics there and conversion back.
> > > Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> > > implemented inline, SFmode -> BFmode conversion is harder,
> > > I think it is roughly:
> > I'm not sure if there should be any floating point exceptions for
> > BFmode operation.
> > For x86, there's no floating point exceptions for AVX512_BF16 related
> > instructions
> 
> As long as __bf16 is just an extension, supporting or not supporting
> exceptions on sNaNs is just fine I think, but I'm afraid it is different
> for std::bfloat16_t.  If we claim we support it (define that type
> in <stdfloat>, predefine __STD_BFLOAT16_TYPE__), then it needs to follow
> ISO/IEC/IEEE 60559, and I'm afraid that means also exceptions and the like.
> While the IEEE spec doesn't cover the exact bfloat16 format, C++ talks about
> a format with these and these number of bits here and there that behaves
> like in IEEE otherwise.
> Whether we support std::bfloat16_t at all is our choice, if we do support
> it, whether we support it with __bf16 underlying type or come up with
> something different, it is up to us, and with -ffast-math/-Ofast etc.
> we can certainly use hw instructions for it which don't raise exceptions.
> 
> At least that is my limited understanding of it...

I've been playing with this a little bit and here is a soft-fp version of
IMHO everything we need for proper bfloat16 support.
In particular, I think we need all the truncating conversions from other
floating formats that a target with BFmode floating point support (currently
arm, aarch64 and x86) has, truncating conversion from BFmode to HFmode
(seems GCC when precision is the same considers conversions truncating)
and an extension from BFmode to SFmode.  Extensions from BFmode to
SF/DF/XF/TFmode are IMHO best implemented inside of GCC by performing
BFmode to SFmode conversion first and then converting SFmode to those
other formats, other arithmetics on BFmode should be implemented simply
by widening to SFmode, doing arithmetics there and then converting back.
The BF to SFmode extension can be also implemented simply by shifting
the VCEd value up by 16 bits and VCEing the result if flags say
sNaNs don't need to be handled, or IMHO if we use the extended result
in some arithmetic operation that will handle the sNaN signaling +
conversion into qNaN, similarly for SFmode to BFmode conversions
we can use hw instructions if available and we don't care about sNaNs.

The C FE has the advantage that it has excess precision support, there
we should arrange for BFmode to be always promoted to SFmode excess
precision, but C++ FE doesn't.

Also, question to ARM/AArch64/x86 maintainers is if it is ok to
add conversion and arithmetic support to the __bf16 type, or if
that type should keep to be useless and there should be another
type (some keyword or just float __attribute__((__mode__ (__BF__))))
that we'd have that support for.  Whatever type we'd use as
std::bfloat16_t should mangle as DFb16_ rather than u6__bf16 that
__bf16 currently mangles to though.

Thoughts on this?

And for Joseph, sure, the libgcc/soft-fp/ part should probably go
into glibc first and be copied from there afterwards.

Perhaps the __truncbfhf2 could be dropped and we could just on
the compiler side emit shift left by 16 before calling __truncsfhf2.

--- libgcc/soft-fp/brain.h.jj	2022-09-22 15:28:04.865171729 +0200
+++ libgcc/soft-fp/brain.h	2022-09-22 15:35:11.970374554 +0200
@@ -0,0 +1,172 @@
+/* Software floating-point emulation.
+   Definitions for Brain Floating Point format (bfloat16).
+   Copyright (C) 1997-2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef SOFT_FP_BRAIN_H
+#define SOFT_FP_BRAIN_H	1
+
+#if _FP_W_TYPE_SIZE < 32
+# error "Here's a nickel kid.  Go buy yourself a real computer."
+#endif
+
+#define _FP_FRACTBITS_B		(_FP_W_TYPE_SIZE)
+
+#define _FP_FRACTBITS_DW_B	(_FP_W_TYPE_SIZE)
+
+#define _FP_FRACBITS_B		8
+#define _FP_FRACXBITS_B		(_FP_FRACTBITS_B - _FP_FRACBITS_B)
+#define _FP_WFRACBITS_B		(_FP_WORKBITS + _FP_FRACBITS_B)
+#define _FP_WFRACXBITS_B	(_FP_FRACTBITS_B - _FP_WFRACBITS_B)
+#define _FP_EXPBITS_B		8
+#define _FP_EXPBIAS_B		127
+#define _FP_EXPMAX_B		255
+
+#define _FP_QNANBIT_B		((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-2))
+#define _FP_QNANBIT_SH_B	((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-2+_FP_WORKBITS))
+#define _FP_IMPLBIT_B		((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-1))
+#define _FP_IMPLBIT_SH_B	((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-1+_FP_WORKBITS))
+#define _FP_OVERFLOW_B		((_FP_W_TYPE) 1 << (_FP_WFRACBITS_B))
+
+#define _FP_WFRACBITS_DW_B	(2 * _FP_WFRACBITS_B)
+#define _FP_WFRACXBITS_DW_B	(_FP_FRACTBITS_DW_B - _FP_WFRACBITS_DW_B)
+#define _FP_HIGHBIT_DW_B	\
+  ((_FP_W_TYPE) 1 << (_FP_WFRACBITS_DW_B - 1) % _FP_W_TYPE_SIZE)
+
+/* The implementation of _FP_MUL_MEAT_B and _FP_DIV_MEAT_B should be
+   chosen by the target machine.  */
+
+typedef float BFtype __attribute__ ((mode (BF)));
+
+union _FP_UNION_B
+{
+  BFtype flt;
+  struct _FP_STRUCT_LAYOUT
+  {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned sign : 1;
+    unsigned exp  : _FP_EXPBITS_B;
+    unsigned frac : _FP_FRACBITS_B - (_FP_IMPLBIT_B != 0);
+#else
+    unsigned frac : _FP_FRACBITS_B - (_FP_IMPLBIT_B != 0);
+    unsigned exp  : _FP_EXPBITS_B;
+    unsigned sign : 1;
+#endif
+  } bits;
+};
+
+#define FP_DECL_B(X)		_FP_DECL (1, X)
+#define FP_UNPACK_RAW_B(X, val)	_FP_UNPACK_RAW_1 (B, X, (val))
+#define FP_UNPACK_RAW_BP(X, val)	_FP_UNPACK_RAW_1_P (B, X, (val))
+#define FP_PACK_RAW_B(val, X)	_FP_PACK_RAW_1 (B, (val), X)
+#define FP_PACK_RAW_BP(val, X)			\
+  do						\
+    {						\
+      if (!FP_INHIBIT_RESULTS)			\
+	_FP_PACK_RAW_1_P (B, (val), X);		\
+    }						\
+  while (0)
+
+#define FP_UNPACK_B(X, val)			\
+  do						\
+    {						\
+      _FP_UNPACK_RAW_1 (B, X, (val));		\
+      _FP_UNPACK_CANONICAL (B, 1, X);		\
+    }						\
+  while (0)
+
+#define FP_UNPACK_BP(X, val)			\
+  do						\
+    {						\
+      _FP_UNPACK_RAW_1_P (B, X, (val));		\
+      _FP_UNPACK_CANONICAL (B, 1, X);		\
+    }						\
+  while (0)
+
+#define FP_UNPACK_SEMIRAW_B(X, val)		\
+  do						\
+    {						\
+      _FP_UNPACK_RAW_1 (B, X, (val));		\
+      _FP_UNPACK_SEMIRAW (B, 1, X);		\
+    }						\
+  while (0)
+
+#define FP_UNPACK_SEMIRAW_BP(X, val)		\
+  do						\
+    {						\
+      _FP_UNPACK_RAW_1_P (B, X, (val));		\
+      _FP_UNPACK_SEMIRAW (B, 1, X);		\
+    }						\
+  while (0)
+
+#define FP_PACK_B(val, X)			\
+  do						\
+    {						\
+      _FP_PACK_CANONICAL (B, 1, X);		\
+      _FP_PACK_RAW_1 (B, (val), X);		\
+    }						\
+  while (0)
+
+#define FP_PACK_BP(val, X)			\
+  do						\
+    {						\
+      _FP_PACK_CANONICAL (B, 1, X);		\
+      if (!FP_INHIBIT_RESULTS)			\
+	_FP_PACK_RAW_1_P (B, (val), X);		\
+    }						\
+  while (0)
+
+#define FP_PACK_SEMIRAW_B(val, X)		\
+  do						\
+    {						\
+      _FP_PACK_SEMIRAW (B, 1, X);		\
+      _FP_PACK_RAW_1 (B, (val), X);		\
+    }						\
+  while (0)
+
+#define FP_PACK_SEMIRAW_BP(val, X)		\
+  do						\
+    {						\
+      _FP_PACK_SEMIRAW (B, 1, X);		\
+      if (!FP_INHIBIT_RESULTS)			\
+	_FP_PACK_RAW_1_P (B, (val), X);		\
+    }						\
+  while (0)
+
+#define FP_TO_INT_B(r, X, rsz, rsg)	_FP_TO_INT (B, 1, (r), X, (rsz), (rsg))
+#define FP_TO_INT_ROUND_B(r, X, rsz, rsg)	\
+  _FP_TO_INT_ROUND (B, 1, (r), X, (rsz), (rsg))
+#define FP_FROM_INT_B(X, r, rs, rt)	_FP_FROM_INT (B, 1, X, (r), (rs), rt)
+
+/* BFmode arithmetic is not implemented.  */
+
+#define _FP_FRAC_HIGH_B(X)	_FP_FRAC_HIGH_1 (X)
+#define _FP_FRAC_HIGH_RAW_B(X)	_FP_FRAC_HIGH_1 (X)
+#define _FP_FRAC_HIGH_DW_B(X)	_FP_FRAC_HIGH_1 (X)
+
+#define FP_CMP_EQ_B(r, X, Y, ex)       _FP_CMP_EQ (B, 1, (r), X, Y, (ex))
+
+#endif /* !SOFT_FP_BRAIN_H */
--- libgcc/soft-fp/truncsfbf2.c.jj	2022-09-22 15:43:46.345386049 +0200
+++ libgcc/soft-fp/truncsfbf2.c	2022-09-22 16:02:19.940226518 +0200
@@ -0,0 +1,48 @@
+/* Software floating-point emulation.
+   Truncate IEEE single into bfloat16.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+#include "single.h"
+
+BFtype
+__truncsfbf2 (SFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_S (A);
+  FP_DECL_B (R);
+  BFtype r;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_SEMIRAW_S (A, a);
+  FP_TRUNC (B, S, 1, 1, R, A);
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/soft-fp/truncbfhf2.c.jj	2022-09-22 16:13:28.894300765 +0200
+++ libgcc/soft-fp/truncbfhf2.c	2022-09-22 17:12:11.459004531 +0200
@@ -0,0 +1,75 @@
+/* Software floating-point emulation.
+   Truncate bfloat16 into IEEE half.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "half.h"
+#include "brain.h"
+#include "single.h"
+
+/* BFtype and HFtype are unordered, neither is a superset or subset
+   of each other.  Convert BFtype to SFtype (lossless) and then
+   truncate to HFtype.  */
+
+HFtype
+__truncbfhf2 (BFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (B);
+  FP_DECL_B (R);
+  SFtype b;
+  HFtype r;
+
+  FP_INIT_ROUNDMODE;
+  /* Optimize BFtype to SFtype conversion to simple left shift
+     by 16 if possible, we don't need to raise exceptions on sNaN
+     here as the SFtype to HFtype truncation should do that too.  */
+  if (sizeof (BFtype) == 2
+      && sizeof (unsigned short) == 2
+      && sizeof (SFtype) == 4
+      && sizeof (unsigned int) == 4)
+    {
+      union { BFtype a; unsigned short b; } u1;
+      union { SFtype a; unsigned int b; } u2;
+      u1.a = a;
+      u2.b = (u1.b << 8) << 8;
+      b = u2.a;
+    }
+  else
+    {
+      FP_UNPACK_RAW_B (A, a);
+      FP_EXTEND (S, B, 1, 1, B, A);
+      FP_PACK_RAW_S (b, B);
+    }
+  FP_UNPACK_SEMIRAW_S (B, b);
+  FP_TRUNC (H, S, 1, 1, R, B);
+  FP_PACK_SEMIRAW_H (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/soft-fp/truncxfbf2.c.jj	2022-09-22 15:45:56.211621629 +0200
+++ libgcc/soft-fp/truncxfbf2.c	2022-09-22 16:02:03.205454405 +0200
@@ -0,0 +1,52 @@
+/* Software floating-point emulation.
+   Truncate IEEE extended into bfloat16.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+#include "extended.h"
+
+BFtype
+__truncxfbf2 (XFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_E (A);
+  FP_DECL_B (R);
+  BFtype r;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_SEMIRAW_E (A, a);
+#if _FP_W_TYPE_SIZE < 64
+  FP_TRUNC (B, E, 1, 4, R, A);
+#else
+  FP_TRUNC (B, E, 1, 2, R, A);
+#endif
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/soft-fp/trunchfbf2.c.jj	2022-09-22 15:59:01.321931320 +0200
+++ libgcc/soft-fp/trunchfbf2.c	2022-09-22 17:11:28.729588880 +0200
@@ -0,0 +1,58 @@
+/* Software floating-point emulation.
+   Truncate IEEE half into bfloat16.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+#include "half.h"
+#include "single.h"
+
+/* BFtype and HFtype are unordered, neither is a superset or subset
+   of each other.  Convert HFtype to SFtype (lossless) and then
+   truncate to BFtype.  */
+
+BFtype
+__trunchfbf2 (HFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_H (A);
+  FP_DECL_S (B);
+  FP_DECL_B (R);
+  SFtype b;
+  BFtype r;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_RAW_H (A, a);
+  FP_EXTEND (S, H, 1, 1, B, A);
+  FP_PACK_RAW_S (b, B);
+  FP_UNPACK_SEMIRAW_S (B, b);
+  FP_TRUNC (B, S, 1, 1, R, B);
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/soft-fp/truncdfbf2.c.jj	2022-09-22 15:40:15.303253337 +0200
+++ libgcc/soft-fp/truncdfbf2.c	2022-09-22 15:41:55.083897689 +0200
@@ -0,0 +1,52 @@
+/* Software floating-point emulation.
+   Truncate IEEE double into bfloat16.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+#include "double.h"
+
+BFtype
+__truncdfbf2 (DFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_D (A);
+  FP_DECL_B (R);
+  BFtype r;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_SEMIRAW_D (A, a);
+#if _FP_W_TYPE_SIZE < _FP_FRACBITS_D
+  FP_TRUNC (B, D, 1, 2, R, A);
+#else
+  FP_TRUNC (B, D, 1, 1, R, A);
+#endif
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/soft-fp/trunctfbf2.c.jj	2022-09-22 15:44:14.924997754 +0200
+++ libgcc/soft-fp/trunctfbf2.c	2022-09-22 15:44:45.694579708 +0200
@@ -0,0 +1,52 @@
+/* Software floating-point emulation.
+   Truncate IEEE quad into bfloat16.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "soft-fp.h"
+#include "brain.h"
+#include "quad.h"
+
+BFtype
+__trunctfbf2 (TFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_Q (A);
+  FP_DECL_B (R);
+  BFtype r;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_SEMIRAW_Q (A, a);
+#if _FP_W_TYPE_SIZE < 64
+  FP_TRUNC (B, Q, 1, 4, R, A);
+#else
+  FP_TRUNC (B, Q, 1, 2, R, A);
+#endif
+  FP_PACK_SEMIRAW_B (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/soft-fp/extendbfsf2.c.jj	2022-09-22 16:27:01.378339625 +0200
+++ libgcc/soft-fp/extendbfsf2.c	2022-09-22 16:27:46.379725593 +0200
@@ -0,0 +1,49 @@
+/* Software floating-point emulation.
+   Return an bfloat16 converted to IEEE single
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define FP_NO_EXACT_UNDERFLOW
+#include "soft-fp.h"
+#include "brain.h"
+#include "single.h"
+
+SFtype
+__extendbfsf2 (BFtype a)
+{
+  FP_DECL_EX;
+  FP_DECL_B (A);
+  FP_DECL_S (R);
+  SFtype r;
+
+  FP_INIT_EXCEPTIONS;
+  FP_UNPACK_RAW_B (A, a);
+  FP_EXTEND (S, B, 1, 1, R, A);
+  FP_PACK_RAW_S (r, R);
+  FP_HANDLE_EXCEPTIONS;
+
+  return r;
+}
--- libgcc/config/i386/t-softfp.jj	2021-12-30 15:12:44.111138056 +0100
+++ libgcc/config/i386/t-softfp	2022-09-22 16:38:31.639921214 +0200
@@ -6,8 +6,9 @@ LIB2FUNCS_EXCLUDE += $(libgcc2-hf-functi
 libgcc2-hf-extras = $(addsuffix .c, $(libgcc2-hf-functions))
 LIB2ADD += $(addprefix $(srcdir)/config/i386/, $(libgcc2-hf-extras))
 
-softfp_extensions := hfsf hfdf hftf hfxf sfdf sftf dftf xftf
-softfp_truncations := tfhf xfhf dfhf sfhf tfsf dfsf tfdf tfxf
+softfp_extensions := hfsf hfdf hftf hfxf sfdf sftf dftf xftf bfsf
+softfp_truncations := tfhf xfhf dfhf sfhf tfsf dfsf tfdf tfxf \
+		      tfbf xfbf dfbf sfbf hfbf bfhf
 
 softfp_extras += eqhf2
 
@@ -20,6 +21,8 @@ CFLAGS-truncsfhf2.c += -msse2
 CFLAGS-truncdfhf2.c += -msse2
 CFLAGS-truncxfhf2.c += -msse2
 CFLAGS-trunctfhf2.c += -msse2
+CFLAGS-truncbfhf2.c += -msse2
+CFLAGS-trunchfbf2.c += -msse2
 
 CFLAGS-eqhf2.c += -msse2
 CFLAGS-_divhc3.c += -msse2
--- libgcc/config/i386/libgcc-glibc.ver.jj	2022-01-11 23:11:23.723271422 +0100
+++ libgcc/config/i386/libgcc-glibc.ver	2022-09-22 16:41:26.599448819 +0200
@@ -214,3 +214,14 @@ GCC_12.0.0 {
   __trunctfhf2
   __truncxfhf2
 }
+
+%inherit GCC_13.0.0 GCC_12.0.0
+GCC_13.0.0 {
+  __extendbfsf2
+  __truncdfbf2
+  __truncsfbf2
+  __trunctfbf2
+  __truncxfbf2
+  __trunchfbf2
+  __truncbfhf2
+}
--- libgcc/config/i386/64/sfp-machine.h.jj	2021-12-30 15:12:44.111138056 +0100
+++ libgcc/config/i386/64/sfp-machine.h	2022-09-22 16:44:45.897627866 +0200
@@ -14,6 +14,7 @@ typedef unsigned int UTItype __attribute
 #define _FP_DIV_MEAT_Q(R,X,Y)   _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
 
 #define _FP_NANFRAC_H		_FP_QNANBIT_H
+#define _FP_NANFRAC_B		_FP_QNANBIT_B
 #define _FP_NANFRAC_S		_FP_QNANBIT_S
 #define _FP_NANFRAC_D		_FP_QNANBIT_D
 #define _FP_NANFRAC_E		_FP_QNANBIT_E, 0
--- libgcc/config/i386/sfp-machine.h.jj	2021-12-30 15:12:44.111138056 +0100
+++ libgcc/config/i386/sfp-machine.h	2022-09-22 16:46:16.130350681 +0200
@@ -18,6 +18,7 @@ typedef int __gcc_CMPtype __attribute__
 #define _FP_QNANNEGATEDP 0
 
 #define _FP_NANSIGN_H		1
+#define _FP_NANSIGN_B		1
 #define _FP_NANSIGN_S		1
 #define _FP_NANSIGN_D		1
 #define _FP_NANSIGN_E		1
--- libgcc/config/i386/32/sfp-machine.h.jj	2021-12-30 15:12:44.110138070 +0100
+++ libgcc/config/i386/32/sfp-machine.h	2022-09-22 16:44:26.786898371 +0200
@@ -87,6 +87,7 @@
 #define _FP_DIV_MEAT_Q(R,X,Y)   _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
 
 #define _FP_NANFRAC_H		_FP_QNANBIT_H
+#define _FP_NANFRAC_B		_FP_QNANBIT_B
 #define _FP_NANFRAC_S		_FP_QNANBIT_S
 #define _FP_NANFRAC_D		_FP_QNANBIT_D, 0
 /* Even if XFmode is 12byte,  we have to pad it to


	Jakub

[-- Attachment #2: a.c --]
[-- Type: text/plain, Size: 2359 bytes --]

extern __bf16 __trunctfbf2 (_Float128);
extern __bf16 __truncxfbf2 (__float80);
extern __bf16 __truncdfbf2 (_Float64);
extern __bf16 __truncsfbf2 (_Float32);
extern __bf16 __trunchfbf2 (_Float16);
extern _Float16 __truncbfhf2 (__bf16);
extern _Float32 __extendbfsf2 (__bf16);

int
main ()
{
  volatile _Float128 tf;
  volatile __float80 xf;
  volatile _Float64 df;
  volatile _Float32 sf;
  volatile _Float16 hf;
  union { _Float32 f; unsigned int i; } u1;
  union { __bf16 f; unsigned short i; } u2;
  tf = 2.718281828459045235360287471352662498F128;
  u1.f = tf; u2.f = __trunctfbf2 (tf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  xf = 2.718281828459045235360287471352662498W;
  u1.f = xf; u2.f = __truncxfbf2 (xf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  df = 2.718281828459045235360287471352662498F64;
  u1.f = df; u2.f = __truncdfbf2 (df);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  sf = 2.718281828459045235360287471352662498F32;
  u1.f = sf; u2.f = __truncsfbf2 (sf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  hf = 2.718281828459045235360287471352662498F16;
  u1.f = hf; u2.f = __trunchfbf2 (hf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  tf = __builtin_inff128 ();
  u1.f = tf; u2.f = __trunctfbf2 (tf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  xf = -__builtin_infl ();
  u1.f = xf; u2.f = __truncxfbf2 (xf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  df = __builtin_inff64 ();
  u1.f = df; u2.f = __truncdfbf2 (df);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  sf = -__builtin_inff32 ();
  u1.f = sf; u2.f = __truncsfbf2 (sf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  hf = __builtin_inff16 ();
  u1.f = hf; u2.f = __trunchfbf2 (hf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  tf = __builtin_nanf128 ("");
  u1.f = tf; u2.f = __trunctfbf2 (tf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  xf = __builtin_nanl ("");
  u1.f = xf; u2.f = __truncxfbf2 (xf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  df = __builtin_nanf64 ("");
  u1.f = df; u2.f = __truncdfbf2 (df);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  sf = __builtin_nanf32 ("");
  u1.f = sf; u2.f = __truncsfbf2 (sf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  hf = __builtin_nanf16 ("");
  u1.f = hf; u2.f = __trunchfbf2 (hf);
  __builtin_printf ("%08x %04x\n", u1.i, u2.i);
  return 0;
}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH] __trunc{tf,xf,df,sf,hf}bf2, __truncbfhf2 and __extendbfsf2
  2022-09-22 15:56     ` [RFC PATCH] __trunc{tf,xf,df,sf,hf}bf2, __truncbfhf2 and __extendbfsf2 Jakub Jelinek
@ 2022-09-23  0:44       ` Hongtao Liu
  0 siblings, 0 replies; 16+ messages in thread
From: Hongtao Liu @ 2022-09-23  0:44 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jonathan Wakely, Joseph S. Myers, Richard Earnshaw,
	Kyrylo Tkachov, richard.sandiford, gcc-patches

On Thu, Sep 22, 2022 at 11:56 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Tue, Sep 20, 2022 at 10:51:18AM +0200, Jakub Jelinek via Gcc-patches wrote:
> > On Tue, Sep 20, 2022 at 11:35:07AM +0800, Hongtao Liu wrote:
> > > > The question is (mainly for aarch64, arm and x86 backend maintainers) if we
> > > > shouldn't support it, in the PR there is a partial patch to do so, but
> > > > the big question is if it should be supported as the __bf16 type those
> > > > 3 targets use with u6__bf16 mangling and remove those *_invalid_* cases
> > > > and add conversions to/from at least SFmode but probably also DFmode, TFmode
> > > > and XFmode on x86 and implement arithmetics on those through conversion to
> > > > SFmode, performing arithmetics there and conversion back.
> > > > Conversion from BFmode to SFmode is easy, left shift by 16 and ought to be
> > > > implemented inline, SFmode -> BFmode conversion is harder,
> > > > I think it is roughly:
> > > I'm not sure if there should be any floating point exceptions for
> > > BFmode operation.
> > > For x86, there's no floating point exceptions for AVX512_BF16 related
> > > instructions
> >
> > As long as __bf16 is just an extension, supporting or not supporting
> > exceptions on sNaNs is just fine I think, but I'm afraid it is different
> > for std::bfloat16_t.  If we claim we support it (define that type
> > in <stdfloat>, predefine __STD_BFLOAT16_TYPE__), then it needs to follow
> > ISO/IEC/IEEE 60559, and I'm afraid that means also exceptions and the like.
> > While the IEEE spec doesn't cover the exact bfloat16 format, C++ talks about
> > a format with these and these number of bits here and there that behaves
> > like in IEEE otherwise.
> > Whether we support std::bfloat16_t at all is our choice, if we do support
> > it, whether we support it with __bf16 underlying type or come up with
> > something different, it is up to us, and with -ffast-math/-Ofast etc.
> > we can certainly use hw instructions for it which don't raise exceptions.
> >
> > At least that is my limited understanding of it...
>
> I've been playing with this a little bit and here is a soft-fp version of
> IMHO everything we need for proper bfloat16 support.
> In particular, I think we need all the truncating conversions from other
> floating formats that a target with BFmode floating point support (currently
> arm, aarch64 and x86) has, truncating conversion from BFmode to HFmode
> (seems GCC when precision is the same considers conversions truncating)
> and an extension from BFmode to SFmode.  Extensions from BFmode to
> SF/DF/XF/TFmode are IMHO best implemented inside of GCC by performing
> BFmode to SFmode conversion first and then converting SFmode to those
> other formats, other arithmetics on BFmode should be implemented simply
> by widening to SFmode, doing arithmetics there and then converting back.
> The BF to SFmode extension can be also implemented simply by shifting
> the VCEd value up by 16 bits and VCEing the result if flags say
> sNaNs don't need to be handled, or IMHO if we use the extended result
> in some arithmetic operation that will handle the sNaN signaling +
> conversion into qNaN, similarly for SFmode to BFmode conversions
> we can use hw instructions if available and we don't care about sNaNs.
>
> The C FE has the advantage that it has excess precision support, there
> we should arrange for BFmode to be always promoted to SFmode excess
> precision, but C++ FE doesn't.
>
> Also, question to ARM/AArch64/x86 maintainers is if it is ok to
> add conversion and arithmetic support to the __bf16 type, or if
> that type should keep to be useless and there should be another
> type (some keyword or just float __attribute__((__mode__ (__BF__))))
> that we'd have that support for.  Whatever type we'd use as
> std::bfloat16_t should mangle as DFb16_ rather than u6__bf16 that
> __bf16 currently mangles to though.
>
> Thoughts on this?
x86 is ok to add conversion and arithmetic support, also for mange as DFb16_.
>
> And for Joseph, sure, the libgcc/soft-fp/ part should probably go
> into glibc first and be copied from there afterwards.
>
> Perhaps the __truncbfhf2 could be dropped and we could just on
> the compiler side emit shift left by 16 before calling __truncsfhf2.
>
> --- libgcc/soft-fp/brain.h.jj   2022-09-22 15:28:04.865171729 +0200
> +++ libgcc/soft-fp/brain.h      2022-09-22 15:35:11.970374554 +0200
> @@ -0,0 +1,172 @@
> +/* Software floating-point emulation.
> +   Definitions for Brain Floating Point format (bfloat16).
> +   Copyright (C) 1997-2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef SOFT_FP_BRAIN_H
> +#define SOFT_FP_BRAIN_H        1
> +
> +#if _FP_W_TYPE_SIZE < 32
> +# error "Here's a nickel kid.  Go buy yourself a real computer."
> +#endif
> +
> +#define _FP_FRACTBITS_B                (_FP_W_TYPE_SIZE)
> +
> +#define _FP_FRACTBITS_DW_B     (_FP_W_TYPE_SIZE)
> +
> +#define _FP_FRACBITS_B         8
> +#define _FP_FRACXBITS_B                (_FP_FRACTBITS_B - _FP_FRACBITS_B)
> +#define _FP_WFRACBITS_B                (_FP_WORKBITS + _FP_FRACBITS_B)
> +#define _FP_WFRACXBITS_B       (_FP_FRACTBITS_B - _FP_WFRACBITS_B)
> +#define _FP_EXPBITS_B          8
> +#define _FP_EXPBIAS_B          127
> +#define _FP_EXPMAX_B           255
> +
> +#define _FP_QNANBIT_B          ((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-2))
> +#define _FP_QNANBIT_SH_B       ((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-2+_FP_WORKBITS))
> +#define _FP_IMPLBIT_B          ((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-1))
> +#define _FP_IMPLBIT_SH_B       ((_FP_W_TYPE) 1 << (_FP_FRACBITS_B-1+_FP_WORKBITS))
> +#define _FP_OVERFLOW_B         ((_FP_W_TYPE) 1 << (_FP_WFRACBITS_B))
> +
> +#define _FP_WFRACBITS_DW_B     (2 * _FP_WFRACBITS_B)
> +#define _FP_WFRACXBITS_DW_B    (_FP_FRACTBITS_DW_B - _FP_WFRACBITS_DW_B)
> +#define _FP_HIGHBIT_DW_B       \
> +  ((_FP_W_TYPE) 1 << (_FP_WFRACBITS_DW_B - 1) % _FP_W_TYPE_SIZE)
> +
> +/* The implementation of _FP_MUL_MEAT_B and _FP_DIV_MEAT_B should be
> +   chosen by the target machine.  */
> +
> +typedef float BFtype __attribute__ ((mode (BF)));
> +
> +union _FP_UNION_B
> +{
> +  BFtype flt;
> +  struct _FP_STRUCT_LAYOUT
> +  {
> +#if __BYTE_ORDER == __BIG_ENDIAN
> +    unsigned sign : 1;
> +    unsigned exp  : _FP_EXPBITS_B;
> +    unsigned frac : _FP_FRACBITS_B - (_FP_IMPLBIT_B != 0);
> +#else
> +    unsigned frac : _FP_FRACBITS_B - (_FP_IMPLBIT_B != 0);
> +    unsigned exp  : _FP_EXPBITS_B;
> +    unsigned sign : 1;
> +#endif
> +  } bits;
> +};
> +
> +#define FP_DECL_B(X)           _FP_DECL (1, X)
> +#define FP_UNPACK_RAW_B(X, val)        _FP_UNPACK_RAW_1 (B, X, (val))
> +#define FP_UNPACK_RAW_BP(X, val)       _FP_UNPACK_RAW_1_P (B, X, (val))
> +#define FP_PACK_RAW_B(val, X)  _FP_PACK_RAW_1 (B, (val), X)
> +#define FP_PACK_RAW_BP(val, X)                 \
> +  do                                           \
> +    {                                          \
> +      if (!FP_INHIBIT_RESULTS)                 \
> +       _FP_PACK_RAW_1_P (B, (val), X);         \
> +    }                                          \
> +  while (0)
> +
> +#define FP_UNPACK_B(X, val)                    \
> +  do                                           \
> +    {                                          \
> +      _FP_UNPACK_RAW_1 (B, X, (val));          \
> +      _FP_UNPACK_CANONICAL (B, 1, X);          \
> +    }                                          \
> +  while (0)
> +
> +#define FP_UNPACK_BP(X, val)                   \
> +  do                                           \
> +    {                                          \
> +      _FP_UNPACK_RAW_1_P (B, X, (val));                \
> +      _FP_UNPACK_CANONICAL (B, 1, X);          \
> +    }                                          \
> +  while (0)
> +
> +#define FP_UNPACK_SEMIRAW_B(X, val)            \
> +  do                                           \
> +    {                                          \
> +      _FP_UNPACK_RAW_1 (B, X, (val));          \
> +      _FP_UNPACK_SEMIRAW (B, 1, X);            \
> +    }                                          \
> +  while (0)
> +
> +#define FP_UNPACK_SEMIRAW_BP(X, val)           \
> +  do                                           \
> +    {                                          \
> +      _FP_UNPACK_RAW_1_P (B, X, (val));                \
> +      _FP_UNPACK_SEMIRAW (B, 1, X);            \
> +    }                                          \
> +  while (0)
> +
> +#define FP_PACK_B(val, X)                      \
> +  do                                           \
> +    {                                          \
> +      _FP_PACK_CANONICAL (B, 1, X);            \
> +      _FP_PACK_RAW_1 (B, (val), X);            \
> +    }                                          \
> +  while (0)
> +
> +#define FP_PACK_BP(val, X)                     \
> +  do                                           \
> +    {                                          \
> +      _FP_PACK_CANONICAL (B, 1, X);            \
> +      if (!FP_INHIBIT_RESULTS)                 \
> +       _FP_PACK_RAW_1_P (B, (val), X);         \
> +    }                                          \
> +  while (0)
> +
> +#define FP_PACK_SEMIRAW_B(val, X)              \
> +  do                                           \
> +    {                                          \
> +      _FP_PACK_SEMIRAW (B, 1, X);              \
> +      _FP_PACK_RAW_1 (B, (val), X);            \
> +    }                                          \
> +  while (0)
> +
> +#define FP_PACK_SEMIRAW_BP(val, X)             \
> +  do                                           \
> +    {                                          \
> +      _FP_PACK_SEMIRAW (B, 1, X);              \
> +      if (!FP_INHIBIT_RESULTS)                 \
> +       _FP_PACK_RAW_1_P (B, (val), X);         \
> +    }                                          \
> +  while (0)
> +
> +#define FP_TO_INT_B(r, X, rsz, rsg)    _FP_TO_INT (B, 1, (r), X, (rsz), (rsg))
> +#define FP_TO_INT_ROUND_B(r, X, rsz, rsg)      \
> +  _FP_TO_INT_ROUND (B, 1, (r), X, (rsz), (rsg))
> +#define FP_FROM_INT_B(X, r, rs, rt)    _FP_FROM_INT (B, 1, X, (r), (rs), rt)
> +
> +/* BFmode arithmetic is not implemented.  */
> +
> +#define _FP_FRAC_HIGH_B(X)     _FP_FRAC_HIGH_1 (X)
> +#define _FP_FRAC_HIGH_RAW_B(X) _FP_FRAC_HIGH_1 (X)
> +#define _FP_FRAC_HIGH_DW_B(X)  _FP_FRAC_HIGH_1 (X)
> +
> +#define FP_CMP_EQ_B(r, X, Y, ex)       _FP_CMP_EQ (B, 1, (r), X, Y, (ex))
> +
> +#endif /* !SOFT_FP_BRAIN_H */
> --- libgcc/soft-fp/truncsfbf2.c.jj      2022-09-22 15:43:46.345386049 +0200
> +++ libgcc/soft-fp/truncsfbf2.c 2022-09-22 16:02:19.940226518 +0200
> @@ -0,0 +1,48 @@
> +/* Software floating-point emulation.
> +   Truncate IEEE single into bfloat16.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "soft-fp.h"
> +#include "brain.h"
> +#include "single.h"
> +
> +BFtype
> +__truncsfbf2 (SFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_S (A);
> +  FP_DECL_B (R);
> +  BFtype r;
> +
> +  FP_INIT_ROUNDMODE;
> +  FP_UNPACK_SEMIRAW_S (A, a);
> +  FP_TRUNC (B, S, 1, 1, R, A);
> +  FP_PACK_SEMIRAW_B (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/soft-fp/truncbfhf2.c.jj      2022-09-22 16:13:28.894300765 +0200
> +++ libgcc/soft-fp/truncbfhf2.c 2022-09-22 17:12:11.459004531 +0200
> @@ -0,0 +1,75 @@
> +/* Software floating-point emulation.
> +   Truncate bfloat16 into IEEE half.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "soft-fp.h"
> +#include "half.h"
> +#include "brain.h"
> +#include "single.h"
> +
> +/* BFtype and HFtype are unordered, neither is a superset or subset
> +   of each other.  Convert BFtype to SFtype (lossless) and then
> +   truncate to HFtype.  */
> +
> +HFtype
> +__truncbfhf2 (BFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_H (A);
> +  FP_DECL_S (B);
> +  FP_DECL_B (R);
> +  SFtype b;
> +  HFtype r;
> +
> +  FP_INIT_ROUNDMODE;
> +  /* Optimize BFtype to SFtype conversion to simple left shift
> +     by 16 if possible, we don't need to raise exceptions on sNaN
> +     here as the SFtype to HFtype truncation should do that too.  */
> +  if (sizeof (BFtype) == 2
> +      && sizeof (unsigned short) == 2
> +      && sizeof (SFtype) == 4
> +      && sizeof (unsigned int) == 4)
> +    {
> +      union { BFtype a; unsigned short b; } u1;
> +      union { SFtype a; unsigned int b; } u2;
> +      u1.a = a;
> +      u2.b = (u1.b << 8) << 8;
> +      b = u2.a;
> +    }
> +  else
> +    {
> +      FP_UNPACK_RAW_B (A, a);
> +      FP_EXTEND (S, B, 1, 1, B, A);
> +      FP_PACK_RAW_S (b, B);
> +    }
> +  FP_UNPACK_SEMIRAW_S (B, b);
> +  FP_TRUNC (H, S, 1, 1, R, B);
> +  FP_PACK_SEMIRAW_H (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/soft-fp/truncxfbf2.c.jj      2022-09-22 15:45:56.211621629 +0200
> +++ libgcc/soft-fp/truncxfbf2.c 2022-09-22 16:02:03.205454405 +0200
> @@ -0,0 +1,52 @@
> +/* Software floating-point emulation.
> +   Truncate IEEE extended into bfloat16.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "soft-fp.h"
> +#include "brain.h"
> +#include "extended.h"
> +
> +BFtype
> +__truncxfbf2 (XFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_E (A);
> +  FP_DECL_B (R);
> +  BFtype r;
> +
> +  FP_INIT_ROUNDMODE;
> +  FP_UNPACK_SEMIRAW_E (A, a);
> +#if _FP_W_TYPE_SIZE < 64
> +  FP_TRUNC (B, E, 1, 4, R, A);
> +#else
> +  FP_TRUNC (B, E, 1, 2, R, A);
> +#endif
> +  FP_PACK_SEMIRAW_B (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/soft-fp/trunchfbf2.c.jj      2022-09-22 15:59:01.321931320 +0200
> +++ libgcc/soft-fp/trunchfbf2.c 2022-09-22 17:11:28.729588880 +0200
> @@ -0,0 +1,58 @@
> +/* Software floating-point emulation.
> +   Truncate IEEE half into bfloat16.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "soft-fp.h"
> +#include "brain.h"
> +#include "half.h"
> +#include "single.h"
> +
> +/* BFtype and HFtype are unordered, neither is a superset or subset
> +   of each other.  Convert HFtype to SFtype (lossless) and then
> +   truncate to BFtype.  */
> +
> +BFtype
> +__trunchfbf2 (HFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_H (A);
> +  FP_DECL_S (B);
> +  FP_DECL_B (R);
> +  SFtype b;
> +  BFtype r;
> +
> +  FP_INIT_ROUNDMODE;
> +  FP_UNPACK_RAW_H (A, a);
> +  FP_EXTEND (S, H, 1, 1, B, A);
> +  FP_PACK_RAW_S (b, B);
> +  FP_UNPACK_SEMIRAW_S (B, b);
> +  FP_TRUNC (B, S, 1, 1, R, B);
> +  FP_PACK_SEMIRAW_B (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/soft-fp/truncdfbf2.c.jj      2022-09-22 15:40:15.303253337 +0200
> +++ libgcc/soft-fp/truncdfbf2.c 2022-09-22 15:41:55.083897689 +0200
> @@ -0,0 +1,52 @@
> +/* Software floating-point emulation.
> +   Truncate IEEE double into bfloat16.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include "soft-fp.h"
> +#include "brain.h"
> +#include "double.h"
> +
> +BFtype
> +__truncdfbf2 (DFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_D (A);
> +  FP_DECL_B (R);
> +  BFtype r;
> +
> +  FP_INIT_ROUNDMODE;
> +  FP_UNPACK_SEMIRAW_D (A, a);
> +#if _FP_W_TYPE_SIZE < _FP_FRACBITS_D
> +  FP_TRUNC (B, D, 1, 2, R, A);
> +#else
> +  FP_TRUNC (B, D, 1, 1, R, A);
> +#endif
> +  FP_PACK_SEMIRAW_B (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/soft-fp/trunctfbf2.c.jj      2022-09-22 15:44:14.924997754 +0200
> +++ libgcc/soft-fp/trunctfbf2.c 2022-09-22 15:44:45.694579708 +0200
> @@ -0,0 +1,52 @@
> +/* Software floating-point emulation.
> +   Truncate IEEE quad into bfloat16.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include "soft-fp.h"
> +#include "brain.h"
> +#include "quad.h"
> +
> +BFtype
> +__trunctfbf2 (TFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_Q (A);
> +  FP_DECL_B (R);
> +  BFtype r;
> +
> +  FP_INIT_ROUNDMODE;
> +  FP_UNPACK_SEMIRAW_Q (A, a);
> +#if _FP_W_TYPE_SIZE < 64
> +  FP_TRUNC (B, Q, 1, 4, R, A);
> +#else
> +  FP_TRUNC (B, Q, 1, 2, R, A);
> +#endif
> +  FP_PACK_SEMIRAW_B (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/soft-fp/extendbfsf2.c.jj     2022-09-22 16:27:01.378339625 +0200
> +++ libgcc/soft-fp/extendbfsf2.c        2022-09-22 16:27:46.379725593 +0200
> @@ -0,0 +1,49 @@
> +/* Software floating-point emulation.
> +   Return an bfloat16 converted to IEEE single
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   In addition to the permissions in the GNU Lesser General Public
> +   License, the Free Software Foundation gives you unlimited
> +   permission to link the compiled version of this file into
> +   combinations with other programs, and to distribute those
> +   combinations without any restriction coming from the use of this
> +   file.  (The Lesser General Public License restrictions do apply in
> +   other respects; for example, they cover modification of the file,
> +   and distribution when not linked into a combine executable.)
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#define FP_NO_EXACT_UNDERFLOW
> +#include "soft-fp.h"
> +#include "brain.h"
> +#include "single.h"
> +
> +SFtype
> +__extendbfsf2 (BFtype a)
> +{
> +  FP_DECL_EX;
> +  FP_DECL_B (A);
> +  FP_DECL_S (R);
> +  SFtype r;
> +
> +  FP_INIT_EXCEPTIONS;
> +  FP_UNPACK_RAW_B (A, a);
> +  FP_EXTEND (S, B, 1, 1, R, A);
> +  FP_PACK_RAW_S (r, R);
> +  FP_HANDLE_EXCEPTIONS;
> +
> +  return r;
> +}
> --- libgcc/config/i386/t-softfp.jj      2021-12-30 15:12:44.111138056 +0100
> +++ libgcc/config/i386/t-softfp 2022-09-22 16:38:31.639921214 +0200
> @@ -6,8 +6,9 @@ LIB2FUNCS_EXCLUDE += $(libgcc2-hf-functi
>  libgcc2-hf-extras = $(addsuffix .c, $(libgcc2-hf-functions))
>  LIB2ADD += $(addprefix $(srcdir)/config/i386/, $(libgcc2-hf-extras))
>
> -softfp_extensions := hfsf hfdf hftf hfxf sfdf sftf dftf xftf
> -softfp_truncations := tfhf xfhf dfhf sfhf tfsf dfsf tfdf tfxf
> +softfp_extensions := hfsf hfdf hftf hfxf sfdf sftf dftf xftf bfsf
> +softfp_truncations := tfhf xfhf dfhf sfhf tfsf dfsf tfdf tfxf \
> +                     tfbf xfbf dfbf sfbf hfbf bfhf
>
>  softfp_extras += eqhf2
>
> @@ -20,6 +21,8 @@ CFLAGS-truncsfhf2.c += -msse2
>  CFLAGS-truncdfhf2.c += -msse2
>  CFLAGS-truncxfhf2.c += -msse2
>  CFLAGS-trunctfhf2.c += -msse2
> +CFLAGS-truncbfhf2.c += -msse2
> +CFLAGS-trunchfbf2.c += -msse2
>
>  CFLAGS-eqhf2.c += -msse2
>  CFLAGS-_divhc3.c += -msse2
> --- libgcc/config/i386/libgcc-glibc.ver.jj      2022-01-11 23:11:23.723271422 +0100
> +++ libgcc/config/i386/libgcc-glibc.ver 2022-09-22 16:41:26.599448819 +0200
> @@ -214,3 +214,14 @@ GCC_12.0.0 {
>    __trunctfhf2
>    __truncxfhf2
>  }
> +
> +%inherit GCC_13.0.0 GCC_12.0.0
> +GCC_13.0.0 {
> +  __extendbfsf2
> +  __truncdfbf2
> +  __truncsfbf2
> +  __trunctfbf2
> +  __truncxfbf2
> +  __trunchfbf2
> +  __truncbfhf2
> +}
> --- libgcc/config/i386/64/sfp-machine.h.jj      2021-12-30 15:12:44.111138056 +0100
> +++ libgcc/config/i386/64/sfp-machine.h 2022-09-22 16:44:45.897627866 +0200
> @@ -14,6 +14,7 @@ typedef unsigned int UTItype __attribute
>  #define _FP_DIV_MEAT_Q(R,X,Y)   _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
>
>  #define _FP_NANFRAC_H          _FP_QNANBIT_H
> +#define _FP_NANFRAC_B          _FP_QNANBIT_B
>  #define _FP_NANFRAC_S          _FP_QNANBIT_S
>  #define _FP_NANFRAC_D          _FP_QNANBIT_D
>  #define _FP_NANFRAC_E          _FP_QNANBIT_E, 0
> --- libgcc/config/i386/sfp-machine.h.jj 2021-12-30 15:12:44.111138056 +0100
> +++ libgcc/config/i386/sfp-machine.h    2022-09-22 16:46:16.130350681 +0200
> @@ -18,6 +18,7 @@ typedef int __gcc_CMPtype __attribute__
>  #define _FP_QNANNEGATEDP 0
>
>  #define _FP_NANSIGN_H          1
> +#define _FP_NANSIGN_B          1
>  #define _FP_NANSIGN_S          1
>  #define _FP_NANSIGN_D          1
>  #define _FP_NANSIGN_E          1
> --- libgcc/config/i386/32/sfp-machine.h.jj      2021-12-30 15:12:44.110138070 +0100
> +++ libgcc/config/i386/32/sfp-machine.h 2022-09-22 16:44:26.786898371 +0200
> @@ -87,6 +87,7 @@
>  #define _FP_DIV_MEAT_Q(R,X,Y)   _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
>
>  #define _FP_NANFRAC_H          _FP_QNANBIT_H
> +#define _FP_NANFRAC_B          _FP_QNANBIT_B
>  #define _FP_NANFRAC_S          _FP_QNANBIT_S
>  #define _FP_NANFRAC_D          _FP_QNANBIT_D, 0
>  /* Even if XFmode is 12byte,  we have to pad it to
>
>
>         Jakub



-- 
BR,
Hongtao

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-19 16:39       ` Jakub Jelinek
@ 2022-09-26 21:15         ` Jason Merrill
  2022-09-26 22:11           ` Jakub Jelinek
  0 siblings, 1 reply; 16+ messages in thread
From: Jason Merrill @ 2022-09-26 21:15 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On 9/19/22 12:39, Jakub Jelinek wrote:
> On Sat, Sep 17, 2022 at 10:58:54AM +0200, Jason Merrill wrote:
>>> I thought it is fairly important because __float128 has been around in GCC
>>> for 19 years already.  To be precise, I think e.g. for x86_64 GCC 3.4
>>> introduced it, but mangling was implemented only in GCC 4.1 (2006), before we ICEd
>>> on those.  Until glibc 2.26 (2017) one had to use libquadmath when
>>> math library functions were needed, but since then one can just use libm.
>>> __float128 is on some targets (e.g. PA) just another name for long double,
>>> not a distinct type.
>>
>> I think we certainly want to continue to support __float128, what I'm
>> wondering is how much changing it to mean _Float128 will affect existing
>> code.  I would guess that a lot of code that just works on __float128 will
>> continue to work without modification.  Does anyone know of significant
>> existing uses of __float128?
> 
> I know boost uses it in its cstdfloat.hpp and stuff that uses it.
> 
>>> Another thing are the PowerPC __ieee128 and __ibm128 type, I think for the
>>> former we can't make it the same type as _Float128, because e.g. libstdc++
>>> code relies on __ieee128 and __ibm128 being long double type of the other
>>> ABI, so they should mangle as long double of the other ABI.  But in that
>>> case they can't act as distinct types when long double should mangle the
>>> same as they do.  And it would be weird if those types in one
>>> -mabi=*longdouble mode worked as standard floating-point type and in another
>>> as extended floating-point type, rather than just types which are neither
>>> standard nor extended as before.
>>
>> Absolutely we don't want to mess with __ieee128 and __ibm128.  And I guess
>> that means that we need to preserve the non-standard type handling for the
>> alternate long double.
>>
>> I think we can still change __float128 to be _Float128 on PPC and other
>> targets where it's currently an alias for long double.
>>
>> It seems to me that it's a question of what provides the better transition
>> path for users.  I imagine we'll want to encourage people to replace
>> __float128 with std::float128_t everywhere.
>>
>> In the existing model, it's not portable whether
>>
>> void f(long double) { }
>> void f(__float128) { }
>>
>> is an overload or an erroneous redefinition.  In the new model, you can
>> portably write
>>
>> void f(long double) { }
>> void f(std::float128_t) { }
>>
>> and existing __float128 code will call the second one.  Old code that had
>> conditional __float128 overloads when it's different from long double will
>> need to change to have unconditional _Float128 overloads.
>>
>> If we don't change __float128 to mean _Float128, we require fewer immediate
>> changes for a library that does try to support all floating-point types, but
>> it will need changes to support _Float128 and will need to keep around
>> conditional __float128 overloads indefinitely.
> 
> I agree that we should judge on what makes the forward path for users
> better.
> I just think we serve users better if we keep __float128 as is, it will be
> then better consistent with other weird types like __float80 (on x86/ia64,
> same representation/mode as long double, but distinct with separate
> mangling), __fpreg on ia64 etc.  It is true that whether __float128 is
> distinct or same type as other standard or non-standard types right now
> differs from target to target (on x86 obviously it is distinct from all
> other currently supported types because we didn't have other IEEE quad
> type but __float80 was distinct even if we had one, ia64 has distinct
> __float128 unless it is HP-UX where it is same type as long double,
> on PA it is same as long double if __float128 exists at all, on powerpc
> it is a define to __ieee128 right now where __ieee128 is same type as long
> double in the -mabi=ieeelongdouble, and distinct type otherwise (but only
> with -mvsx, otherwise it isn't supported (on by default for ppc64le but not
> the others)).  So, code that wants to overload with __float128 or use
> __float128 in template arguments needs to do some ifdefs to find out
> what it should do.  But, if we make __float128 the same as _Float128,
> I think it will mean people actually need to make the conditions even more
> complex, because what __float128 will be and how it will behave will depend
> on the compiler version.
> I believe libraries with floating point stuff will want to add
> std::{float{16,32,64,128},bfloat16}_t overloads eventually, not just
> std::float128_t overloads, and it will be better if it uses the standard
> f{16,32,64,128} literal suffixes, builtins, library functions etc. rather
> than Q suffixes, *q builtins, libquadmath functions etc.
> Say on x86 it would be inconsistent if __float80 remains to be some
> non-standard type, but __float128 is now extended type.  And when
> __float128 and _Float128 is distinct, we can keep clean DF128_ mangling
> for the latter.

Fair enough.  And the other responders on the ABI PR seem to agree with you.

> Anyway, here is an updated patch that adds also _Float{32,64,128}x support
> with DF{32,64,128}x mangling and demangling and the conv->bad_p + pedwarn
> change.  __float128 is still distinct from _Float128.

Looks good with the minor adjustments below.

Will you also add the <stdfloat> header and the changes to <limits>?

> 2022-09-19  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/106652
> 	PR c++/85518
> gcc/
> 	* tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE
> 	enumerator.
> 	* tree.h (float128t_type_node): Define.
> 	* tree.cc (build_common_tree_nodes): Initialize float128t_type_node.
> 	* builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that
> 	_Float<N> is supported in C++ too.
> 	* config/i386/i386.cc (ix86_mangle_type): Only mangle as "g"
> 	float128t_type_node.
> 	* config/i386/i386-builtins.cc (ix86_init_builtin_types): Use
> 	float128t_type_node for __float128 instead of float128_type_node
> 	and create it if NULL.
> 	* config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph,
> 	_mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of
> 	0.0f.
> 	* config/ia64/ia64.cc (ia64_init_builtins): Use
> 	float128t_type_node for __float128 instead of float128_type_node
> 	and create it if NULL.
> 	* config/rs6000/rs6000-c.cc (is_float128_p): Also return true
> 	for float128t_type_node if non-NULL.
> 	* config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle
> 	float128_type_node as "u9__ieee128".
> 	* config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use
> 	float128t_type_node for __float128 instead of float128_type_node
> 	and create it if NULL.
> gcc/c-family/
> 	* c-common.cc (c_common_reswords): Change _Float{16,32,64,128} and
> 	_Float{32,64,128}x flags from D_CONLY to 0.
> 	(shorten_binary_op): Punt if common_type returns error_mark_node.
> 	(shorten_compare): Likewise.
> 	(c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128}
> 	and _Float{32,64,128}x builtin types if available.  For C++
> 	clear float128t_type_node.
> 	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
> 	__STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported.
> 	* c-lex.cc (interpret_float): For q/Q suffixes prefer
> 	float128t_type_node over float128_type_node.  Allow
> 	{f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn
> 	for C++20 and older.  Allow {f,F}{32,64,128}x suffixes for C++
> 	with pedwarn.  Don't call excess_precision_type for C++.
> gcc/cp/
> 	* cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement
> 	P1467R9 - Extended floating-point types and standard names except
> 	for std::bfloat16_t for now.  Declare.
> 	(extended_float_type_p): New inline function.
> 	* mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node
> 	as DF{16,32,64,128}_.  Mangle float{32,64,128}x_type_node as
> 	DF{32,64,128}x.  Remove FIXED_POINT_TYPE mangling that conflicts
> 	with that.
> 	* typeck2.cc (check_narrowing): If one of ftype or type is extended
> 	floating-point type, compare floating-point conversion ranks.
> 	* parser.cc (cp_keyword_starts_decl_specifier_p): Handle
> 	CASE_RID_FLOATN_NX.
> 	(cp_parser_simple_type_specifier): Likewise and diagnose missing
> 	_Float<N> or _Float<N>x support if not supported by target.
> 	* typeck.cc (cp_compare_floating_point_conversion_ranks): New function.
> 	(cp_common_type): If both types are REAL_TYPE and one or both are
> 	extended floating-point types, select common type based on comparison
> 	of floating-point conversion ranks and subranks.
> 	(cp_build_binary_op): Diagnose operation with floating point arguments
> 	with unordered conversion ranks.
> 	* call.cc (standard_conversion): For floating-point conversion, if
> 	either from or to are extended floating-point types, set conv->bad_p
> 	for implicit conversion from larger to smaller conversion rank or
> 	with unordered conversion ranks.
> 	(convert_like_internal): Emit a pedwarn on such conversions.
> 	(build_conditional_expr): Diagnose operation with floating point
> 	arguments with unordered conversion ranks.
> 	(convert_arg_to_ellipsis): Don't promote extended floating-point types
> 	narrower than double to double.
> 	(compare_ics): Implement P1467R9 [over.ics.rank]/4 changes.
> gcc/testsuite/
> 	* g++.dg/cpp23/ext-floating1.C: New test.
> 	* g++.dg/cpp23/ext-floating2.C: New test.
> 	* g++.dg/cpp23/ext-floating3.C: New test.
> 	* g++.dg/cpp23/ext-floating4.C: New test.
> 	* g++.dg/cpp23/ext-floating5.C: New test.
> 	* g++.dg/cpp23/ext-floating6.C: New test.
> 	* g++.dg/cpp23/ext-floating7.C: New test.
> 	* g++.dg/cpp23/ext-floating8.C: New test.
> 	* g++.dg/cpp23/ext-floating9.C: New test.
> 	* g++.dg/cpp23/ext-floating10.C: New test.
> 	* g++.dg/cpp23/ext-floating.h: New file.
> 	* g++.target/i386/float16-1.C: Adjust expected diagnostics.
> libcpp/
> 	* expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} and
> 	{f,F}{32,64,128}x suffixes for C++.
> include/
> 	* demangle.h (enum demangle_component_type): Add
> 	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
> 	(struct demangle_component): Add u.s_extended_builtin member.
> libiberty/
> 	* cp-demangle.c (d_dump): Handle
> 	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Don't handle
> 	DEMANGLE_COMPONENT_FIXED_TYPE.
> 	(d_make_extended_builtin_type): New function.
> 	(cplus_demangle_builtin_types): Add _Float entry.
> 	(cplus_demangle_type): For DF demangle it as _Float<N> or
> 	_Float<N>x rather than fixed point which conflicts with it.
> 	(d_count_templates_scopes): Handle
> 	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Just break; for
> 	DEMANGLE_COMPONENT_FIXED_TYPE.
> 	(d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
> 	Don't handle DEMANGLE_COMPONENT_FIXED_TYPE.
> 	(d_print_comp_inner): Likewise.
> 	* cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump.
> 	* testsuite/demangle-expected: Replace _Z3xxxDFyuVb test
> 	with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb.  Add
> 	_Z3xxxDF32xDF64xDF128xCDF32xVb test.
> fixincludes/
> 	* inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2,
> 	glibc_cxx_floatn_3): New fixes.
> 	* tests/base/bits/floatn.h: New file.
> 	* fixincl.x: Regenerated.
> 
> --- gcc/tree-core.h.jj	2022-09-12 10:31:28.082541926 +0200
> +++ gcc/tree-core.h	2022-09-19 15:13:26.501132289 +0200
> @@ -690,6 +690,10 @@ enum tree_index {
>   			     - TI_FLOATN_NX_TYPE_FIRST		\
>   			     + 1)
>   
> +  /* Type used by certain backends for __float128, which in C++ should be
> +     distinct type from _Float128 for backwards compatibility reasons.  */
> +  TI_FLOAT128T_TYPE,
> +
>     /* Put the complex types after their component types, so that in (sequential)
>        tree streaming we can assert that their component types have already been
>        handled (see tree-streamer.cc:record_common_node).  */
> --- gcc/tree.h.jj	2022-09-12 10:31:28.206540208 +0200
> +++ gcc/tree.h	2022-09-19 15:13:26.502132276 +0200
> @@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree ex
>   #define float64x_type_node		global_trees[TI_FLOAT64X_TYPE]
>   #define float128x_type_node		global_trees[TI_FLOAT128X_TYPE]
>   
> +/* Type used by certain backends for __float128, which in C++ should be
> +   distinct type from _Float128 for backwards compatibility reasons.  */
> +#define float128t_type_node		global_trees[TI_FLOAT128T_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]
> --- gcc/tree.cc.jj	2022-09-16 20:40:14.075827838 +0200
> +++ gcc/tree.cc	2022-09-19 15:13:26.504132248 +0200
> @@ -9461,6 +9461,7 @@ build_common_tree_nodes (bool signed_cha
>         layout_type (FLOATN_NX_TYPE_NODE (i));
>         SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
>       }
> +  float128t_type_node = float128_type_node;
>   
>     float_ptr_type_node = build_pointer_type (float_type_node);
>     double_ptr_type_node = build_pointer_type (double_type_node);
> --- gcc/builtins.def.jj	2022-09-12 10:31:27.055556152 +0200
> +++ gcc/builtins.def	2022-09-19 15:13:26.505132234 +0200
> @@ -115,8 +115,8 @@ along with GCC; see the file COPYING3.
>      we are compiling for the C language with GNU extensions, we enable the name
>      without the __builtin_ prefix as well as the name with the __builtin_
>      prefix.  C++ does not enable these names by default because they don't have
> -   the _Float<N> and _Float<N>X keywords, and a class based library should use
> -   the __builtin_ names.  */
> +   the _Float<N>x keywords, and a class based library should use the __builtin_

This comment needs further adjustment now that you've added _Float<N>x 
support.

> +   names.  */
>   #undef DEF_FLOATN_BUILTIN
>   #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS)	\
>     DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,	\
> --- gcc/config/i386/i386.cc.jj	2022-09-12 10:31:27.422551068 +0200
> +++ gcc/config/i386/i386.cc	2022-09-19 15:13:26.508132193 +0200
> @@ -22711,7 +22711,10 @@ ix86_mangle_type (const_tree type)
>         return "DF16_";
>       case E_TFmode:
>         /* __float128 is "g".  */
> -      return "g";
> +      if (type == float128t_type_node)
> +	return "g";
> +      /* _Float128 should mangle as "DF128_" done in generic code.  */
> +      return NULL;
>       case E_XFmode:
>         /* "long double" or __float80 is "e".  */
>         return "e";
> --- gcc/config/i386/i386-builtins.cc.jj	2022-09-16 20:40:13.546835024 +0200
> +++ gcc/config/i386/i386-builtins.cc	2022-09-19 15:13:26.508132193 +0200
> @@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void)
>     lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
>   
>     /* 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");
> +     _Float128, so for C we only need to register the __float128 name for
> +     it.  For C++, we create a distinct type which will mangle differently
> +     (g) vs. _Float128 (DF128_) and behave backwards compatibly.  */
> +  if (float128t_type_node == NULL_TREE)
> +    {
> +      float128t_type_node = make_node (REAL_TYPE);
> +      TYPE_PRECISION (float128t_type_node)
> +	= TYPE_PRECISION (float128_type_node);
> +      SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
> +      layout_type (float128t_type_node);
> +    }
> +  lang_hooks.types.register_builtin_type (float128t_type_node, "__float128");
>   
>     ix86_register_float16_builtin_type ();
>   
> --- gcc/config/i386/avx512fp16intrin.h.jj	2022-01-11 23:11:21.760299007 +0100
> +++ gcc/config/i386/avx512fp16intrin.h	2022-09-19 15:13:26.509132179 +0200
> @@ -183,21 +183,21 @@ extern __inline __m128h
>   __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>   _mm_setzero_ph (void)
>   {
> -  return _mm_set1_ph (0.0f);
> +  return _mm_set1_ph (0.0f16);
>   }
>   
>   extern __inline __m256h
>   __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>   _mm256_setzero_ph (void)
>   {
> -  return _mm256_set1_ph (0.0f);
> +  return _mm256_set1_ph (0.0f16);
>   }
>   
>   extern __inline __m512h
>   __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>   _mm512_setzero_ph (void)
>   {
> -  return _mm512_set1_ph (0.0f);
> +  return _mm512_set1_ph (0.0f16);
>   }
>   
>   extern __inline __m128h
> @@ -358,7 +358,8 @@ extern __inline __m128h
>   __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>   _mm_set_sh (_Float16 __F)
>   {
> -  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F);
> +  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
> +		     __F);
>   }
>   
>   /* Create a vector with element 0 as *P and the rest zero.  */
> @@ -366,7 +367,7 @@ extern __inline __m128h
>   __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
>   _mm_load_sh (void const *__P)
>   {
> -  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
> +  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
>   		     *(_Float16 const *) __P);
>   }
>   
> --- gcc/config/ia64/ia64.cc.jj	2022-09-12 10:31:27.436550875 +0200
> +++ gcc/config/ia64/ia64.cc	2022-09-19 15:13:26.510132166 +0200
> @@ -10466,11 +10466,19 @@ ia64_init_builtins (void)
>   	= build_pointer_type (build_qualified_type
>   			      (char_type_node, TYPE_QUAL_CONST));
>   
> -      (*lang_hooks.types.register_builtin_type) (float128_type_node,
> +      if (float128t_type_node == NULL_TREE)
> +	{
> +	  float128t_type_node = make_node (REAL_TYPE);
> +	  TYPE_PRECISION (float128t_type_node)
> +	    = TYPE_PRECISION (float128_type_node);
> +	  layout_type (float128t_type_node);
> +	  SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
> +	}
> +      (*lang_hooks.types.register_builtin_type) (float128t_type_node,
>   						 "__float128");
>   
>         /* TFmode support builtins.  */
> -      ftype = build_function_type_list (float128_type_node, NULL_TREE);
> +      ftype = build_function_type_list (float128t_type_node, NULL_TREE);
>         decl = add_builtin_function ("__builtin_infq", ftype,
>   				   IA64_BUILTIN_INFQ, BUILT_IN_MD,
>   				   NULL, NULL_TREE);
> @@ -10481,7 +10489,7 @@ ia64_init_builtins (void)
>   				   NULL, NULL_TREE);
>         ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
>   
> -      ftype = build_function_type_list (float128_type_node,
> +      ftype = build_function_type_list (float128t_type_node,
>   					const_string_type,
>   					NULL_TREE);
>         decl = add_builtin_function ("__builtin_nanq", ftype,
> @@ -10496,8 +10504,8 @@ ia64_init_builtins (void)
>         TREE_READONLY (decl) = 1;
>         ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
>   
> -      ftype = build_function_type_list (float128_type_node,
> -					float128_type_node,
> +      ftype = build_function_type_list (float128t_type_node,
> +					float128t_type_node,
>   					NULL_TREE);
>         decl = add_builtin_function ("__builtin_fabsq", ftype,
>   				   IA64_BUILTIN_FABSQ, BUILT_IN_MD,
> @@ -10505,9 +10513,9 @@ ia64_init_builtins (void)
>         TREE_READONLY (decl) = 1;
>         ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
>   
> -      ftype = build_function_type_list (float128_type_node,
> -					float128_type_node,
> -					float128_type_node,
> +      ftype = build_function_type_list (float128t_type_node,
> +					float128t_type_node,
> +					float128t_type_node,
>   					NULL_TREE);
>         decl = add_builtin_function ("__builtin_copysignq", ftype,
>   				   IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
> --- gcc/config/rs6000/rs6000-c.cc.jj	2022-09-13 18:57:29.326969961 +0200
> +++ gcc/config/rs6000/rs6000-c.cc	2022-09-19 15:13:26.511132152 +0200
> @@ -808,6 +808,7 @@ static inline bool
>   is_float128_p (tree t)
>   {
>     return (t == float128_type_node
> +	  || (t && t == float128t_type_node)
>   	  || (TARGET_IEEEQUAD
>   	      && TARGET_LONG_DOUBLE_128
>   	      && t == long_double_type_node));
> --- gcc/config/rs6000/rs6000.cc.jj	2022-09-16 20:40:13.572834671 +0200
> +++ gcc/config/rs6000/rs6000.cc	2022-09-19 15:13:26.514132111 +0200
> @@ -20272,7 +20272,11 @@ rs6000_mangle_type (const_tree type)
>   
>     if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type)))
>       return "g";
> -  if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type)))
> +  if (SCALAR_FLOAT_TYPE_P (type)
> +      && FLOAT128_IEEE_P (TYPE_MODE (type))
> +      /* _Float128 should mangle as DF128_ (done in generic code)
> +	 rather than u9__ieee128 (used for __ieee128 and __float128).  */
> +      && type != float128_type_node)
>       return "u9__ieee128";
>   
>     if (type == vector_pair_type_node)
> --- gcc/config/rs6000/rs6000-builtin.cc.jj	2022-09-13 18:57:29.325969975 +0200
> +++ gcc/config/rs6000/rs6000-builtin.cc	2022-09-19 15:13:26.514132111 +0200
> @@ -733,7 +733,22 @@ rs6000_init_builtins (void)
>         if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
>   	ieee128_float_type_node = long_double_type_node;
>         else
> -	ieee128_float_type_node = float128_type_node;
> +	{
> +	  /* For C we only need to register the __ieee128 name for
> +	     it.  For C++, we create a distinct type which will mangle
> +	     differently (u9__ieee128) vs. _Float128 (DF128_) and behave
> +	     backwards compatibly.  */
> +	  if (float128t_type_node == NULL_TREE)
> +	    {
> +	      float128t_type_node = make_node (REAL_TYPE);
> +	      TYPE_PRECISION (float128t_type_node)
> +		= TYPE_PRECISION (float128_type_node);
> +	      layout_type (float128t_type_node);
> +	      SET_TYPE_MODE (float128t_type_node,
> +			     TYPE_MODE (float128_type_node));
> +	    }
> +	  ieee128_float_type_node = float128t_type_node;
> +	}
>         t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
>         lang_hooks.types.register_builtin_type (ieee128_float_type_node,
>   					      "__ieee128");
> --- gcc/c-family/c-common.cc.jj	2022-09-16 20:40:13.507835554 +0200
> +++ gcc/c-family/c-common.cc	2022-09-19 15:17:07.408105952 +0200
> @@ -352,13 +352,13 @@ const struct c_common_resword c_common_r
>     { "_Bool",		RID_BOOL,      D_CONLY },
>     { "_Complex",		RID_COMPLEX,	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 },
> +  { "_Float16",         RID_FLOAT16,    0 },
> +  { "_Float32",         RID_FLOAT32,    0 },
> +  { "_Float64",         RID_FLOAT64,    0 },
> +  { "_Float128",        RID_FLOAT128,   0 },
> +  { "_Float32x",        RID_FLOAT32X,   0 },
> +  { "_Float64x",        RID_FLOAT64X,   0 },
> +  { "_Float128x",       RID_FLOAT128X,  0 },
>     { "_Decimal32",       RID_DFLOAT32,  D_CONLY },
>     { "_Decimal64",       RID_DFLOAT64,  D_CONLY },
>     { "_Decimal128",      RID_DFLOAT128, D_CONLY },
> @@ -1429,8 +1429,11 @@ shorten_binary_op (tree result_type, tre
>   	  == TYPE_PRECISION (TREE_TYPE (arg0)))
>         && unsigned0 == unsigned1
>         && (unsigned0 || !uns))
> -    return c_common_signed_or_unsigned_type
> -      (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
> +    {
> +      tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
> +      if (ctype != error_mark_node)
> +	return c_common_signed_or_unsigned_type (unsigned0, ctype);
> +    }
>   
>     else if (TREE_CODE (arg0) == INTEGER_CST
>   	   && (unsigned1 || !uns)
> @@ -3202,9 +3205,10 @@ shorten_compare (location_t loc, tree *o
>   
>     else if (unsignedp0 == unsignedp1 && real1 == real2
>   	   && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
> -	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
> +	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)
> +	   && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)))
> +	      != error_mark_node)
>       {
> -      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
>         type = c_common_signed_or_unsigned_type (unsignedp0
>   					       || TYPE_UNSIGNED (*restype_ptr),
>   					       type);
> @@ -4378,11 +4382,18 @@ 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++)
> +  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));
> +    }
> +
> +  /* For C, let float128t_type_node (__float128 in some backends) be the
> +     same type as float128_type_node (_Float128), for C++ let those
> +     be distinct types that mangle and behave differently.  */
> +  if (c_dialect_cxx ())
> +    float128t_type_node = NULL_TREE;
>   
>     /* Only supported decimal floating point extension if the target
>        actually supports underlying modes. */
> --- gcc/c-family/c-cppbuiltin.cc.jj	2022-09-19 11:53:19.873593647 +0200
> +++ gcc/c-family/c-cppbuiltin.cc	2022-09-19 15:19:38.939030140 +0200
> @@ -1247,6 +1247,14 @@ c_cpp_builtins (cpp_reader *pfile)
>       {
>         if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
>   	continue;
> +      if (c_dialect_cxx ()
> +	  && cxx_dialect > cxx20
> +	  && !floatn_nx_types[i].extended)
> +	{
> +	  char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
> +	  sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
> +	  cpp_define (pfile, name);
> +	}
>         char prefix[20], csuffix[20];
>         sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
>   	       floatn_nx_types[i].extended ? "X" : "");
> --- gcc/c-family/c-lex.cc.jj	2022-09-12 10:31:27.254553396 +0200
> +++ gcc/c-family/c-lex.cc	2022-09-19 15:20:48.373078972 +0200
> @@ -960,6 +960,10 @@ interpret_float (const cpp_token *token,
>   	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
>   
>   	type = c_common_type_for_mode (mode, 0);
> +	/* For Q suffix, prefer float128t_type_node (__float128) type
> +	   over float128_type_node (_Float128) type if they are distinct.  */
> +	if (type == float128_type_node && float128t_type_node)
> +	  type = float128t_type_node;
>   	gcc_assert (type);
>         }
>       else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
> @@ -979,8 +983,17 @@ interpret_float (const cpp_token *token,
>   	    error ("unsupported non-standard suffix on floating constant");
>   	    return error_mark_node;
>   	  }
> +	else if (c_dialect_cxx () && !extended)
> +	  {
> +	    if (cxx_dialect < cxx23)
> +	      pedwarn (input_location, OPT_Wpedantic,
> +		       "%<f%d%> or %<F%d%> suffix on floating constant only "
> +		       "available with %<-std=c++2b%> or %<-std=gnu++2b%>",
> +		       n, n);
> +	  }
>   	else
> -	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
> +	  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;
> @@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token,
>       else
>         type = double_type_node;
>   
> -  const_type = excess_precision_type (type);
> +  if (c_dialect_cxx ())
> +    const_type = NULL_TREE;
> +  else
> +    const_type = excess_precision_type (type);
>     if (!const_type)
>       const_type = type;
>   
> --- gcc/cp/cp-tree.h.jj	2022-09-19 11:53:19.780594924 +0200
> +++ gcc/cp/cp-tree.h	2022-09-19 15:38:36.820475429 +0200
> @@ -7947,6 +7947,7 @@ extern tree require_complete_type		(tree
>   extern tree complete_type			(tree);
>   extern tree complete_type_or_else		(tree, tree);
>   extern tree complete_type_or_maybe_complain	(tree, tree, tsubst_flags_t);
> +extern int cp_compare_floating_point_conversion_ranks (tree, tree);
>   inline bool type_unknown_p			(const_tree);
>   enum { ce_derived, ce_type, ce_normal, ce_exact };
>   extern bool comp_except_specs			(const_tree, const_tree, int);
> @@ -8689,6 +8690,18 @@ struct push_access_scope_guard
>     }
>   };
>   
> +/* True if TYPE is an extended floating-point type.  */
> +
> +inline bool
> +extended_float_type_p (tree type)
> +{
> +  type = TYPE_MAIN_VARIANT (type);
> +  for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i)
> +    if (type == FLOATN_TYPE_NODE (i))
> +      return true;
> +  return false;
> +}
> +
>   #if CHECKING_P
>   namespace selftest {
>     extern void run_cp_tests (void);
> --- gcc/cp/mangle.cc.jj	2022-09-12 10:31:27.754546470 +0200
> +++ gcc/cp/mangle.cc	2022-09-19 15:39:17.863916098 +0200
> @@ -2648,63 +2648,24 @@ write_builtin_type (tree type)
>   	write_string ("Dd");
>         else if (type == dfloat128_type_node || type == fallback_dfloat128_type)
>   	write_string ("De");
> +      else if (type == float16_type_node)
> +	write_string ("DF16_");
> +      else if (type == float32_type_node)
> +	write_string ("DF32_");
> +      else if (type == float64_type_node)
> +	write_string ("DF64_");
> +      else if (type == float128_type_node)
> +	write_string ("DF128_");
> +      else if (type == float32x_type_node)
> +	write_string ("DF32x");
> +      else if (type == float64x_type_node)
> +	write_string ("DF64x");
> +      else if (type == float128x_type_node)
> +	write_string ("DF128x");
>         else
>   	gcc_unreachable ();
>         break;
>   
> -    case FIXED_POINT_TYPE:
> -      write_string ("DF");
> -      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
> -	write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
> -      if (type == fract_type_node
> -	  || type == sat_fract_type_node
> -	  || type == accum_type_node
> -	  || type == sat_accum_type_node)
> -	write_char ('i');
> -      else if (type == unsigned_fract_type_node
> -	       || type == sat_unsigned_fract_type_node
> -	       || type == unsigned_accum_type_node
> -	       || type == sat_unsigned_accum_type_node)
> -	write_char ('j');
> -      else if (type == short_fract_type_node
> -	       || type == sat_short_fract_type_node
> -	       || type == short_accum_type_node
> -	       || type == sat_short_accum_type_node)
> -	write_char ('s');
> -      else if (type == unsigned_short_fract_type_node
> -	       || type == sat_unsigned_short_fract_type_node
> -	       || type == unsigned_short_accum_type_node
> -	       || type == sat_unsigned_short_accum_type_node)
> -	write_char ('t');
> -      else if (type == long_fract_type_node
> -	       || type == sat_long_fract_type_node
> -	       || type == long_accum_type_node
> -	       || type == sat_long_accum_type_node)
> -	write_char ('l');
> -      else if (type == unsigned_long_fract_type_node
> -	       || type == sat_unsigned_long_fract_type_node
> -	       || type == unsigned_long_accum_type_node
> -	       || type == sat_unsigned_long_accum_type_node)
> -	write_char ('m');
> -      else if (type == long_long_fract_type_node
> -	       || type == sat_long_long_fract_type_node
> -	       || type == long_long_accum_type_node
> -	       || type == sat_long_long_accum_type_node)
> -	write_char ('x');
> -      else if (type == unsigned_long_long_fract_type_node
> -	       || type == sat_unsigned_long_long_fract_type_node
> -	       || type == unsigned_long_long_accum_type_node
> -	       || type == sat_unsigned_long_long_accum_type_node)
> -	write_char ('y');
> -      else
> -	sorry ("mangling unknown fixed point type");
> -      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
> -      if (TYPE_SATURATING (type))
> -	write_char ('s');
> -      else
> -	write_char ('n');
> -      break;
> -
>       default:
>         gcc_unreachable ();
>       }
> --- gcc/cp/typeck2.cc.jj	2022-09-13 09:21:28.197539576 +0200
> +++ gcc/cp/typeck2.cc	2022-09-19 15:13:26.518132056 +0200
> @@ -997,12 +997,25 @@ check_narrowing (tree type, tree init, t
>     else if (TREE_CODE (ftype) == REAL_TYPE
>   	   && TREE_CODE (type) == REAL_TYPE)
>       {
> -      if ((same_type_p (ftype, long_double_type_node)
> -	   && (same_type_p (type, double_type_node)
> -	       || same_type_p (type, float_type_node)))
> -	  || (same_type_p (ftype, double_type_node)
> -	      && same_type_p (type, float_type_node))
> -	  || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
> +      if ((extended_float_type_p (ftype) || extended_float_type_p (type))
> +	  ? /* "from a floating-point type T to another floating-point type
> +	       whose floating-point conversion rank is neither greater than
> +	       nor equal to that of T".
> +	       So, it is ok if
> +	       cp_compare_floating_point_conversion_ranks (ftype, type)
> +	       returns -2 (type has greater conversion rank than ftype)
> +	       or [-1..1] (type has equal conversion rank as ftype, possibly
> +	       different subrank.  Only do this if at least one of the
> +	       types is extended floating-point type, otherwise keep doing
> +	       what we did before (for the sake of non-standard
> +	       backend types).  */
> +	    cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
> +	  : ((same_type_p (ftype, long_double_type_node)
> +	      && (same_type_p (type, double_type_node)
> +		  || same_type_p (type, float_type_node)))
> +	     || (same_type_p (ftype, double_type_node)
> +		 && same_type_p (type, float_type_node))
> +	     || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
>   	{
>   	  if (TREE_CODE (init) == REAL_CST)
>   	    {
> --- gcc/cp/parser.cc.jj	2022-09-19 12:11:15.891823798 +0200
> +++ gcc/cp/parser.cc	2022-09-19 15:43:13.816700641 +0200
> @@ -1129,6 +1129,7 @@ cp_keyword_starts_decl_specifier_p (enum
>       case RID_UNSIGNED:
>       case RID_FLOAT:
>       case RID_DOUBLE:
> +    CASE_RID_FLOATN_NX:
>       case RID_VOID:
>         /* CV qualifiers.  */
>       case RID_CONST:
> @@ -19746,6 +19747,14 @@ cp_parser_simple_type_specifier (cp_pars
>       case RID_DOUBLE:
>         type = double_type_node;
>         break;
> +    CASE_RID_FLOATN_NX:
> +      type = FLOATN_NX_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST);
> +      if (type == NULL_TREE)
> +	error ("%<_Float%d%s%> is not supported on this target",
> +	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n,
> +	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].extended
> +	       ? "x" : "");
> +      break;
>       case RID_VOID:
>         type = void_type_node;
>         break;
> --- gcc/cp/typeck.cc.jj	2022-09-16 20:40:13.650833611 +0200
> +++ gcc/cp/typeck.cc	2022-09-19 15:55:31.143706567 +0200
> @@ -267,6 +267,132 @@ merge_type_attributes_from (tree type, t
>     return cp_build_type_attribute_variant (type, attrs);
>   }
>   
> +/* Compare floating point conversion ranks and subranks of T1 and T2
> +   types.  If T1 and T2 have unordered conversion ranks, return 3.
> +   If T1 has greater conversion rank than T2, return 2.
> +   If T2 has greater conversion rank than T1, return -2.
> +   If T1 has equal conversion rank as T2, return -1, 0 or 1 depending
> +   on if T1 has smaller, equal or greater conversion subrank than
> +   T2.  */
> +
> +int
> +cp_compare_floating_point_conversion_ranks (tree t1, tree t2)
> +{
> +  tree mv1 = TYPE_MAIN_VARIANT (t1);
> +  tree mv2 = TYPE_MAIN_VARIANT (t2);
> +  int extended1 = 0;
> +  int extended2 = 0;
> +
> +  if (mv1 == mv2)
> +    return 0;
> +
> +  for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i)
> +    {
> +      if (mv1 == FLOATN_NX_TYPE_NODE (i))
> +	extended1 = i + 1;
> +      if (mv2 == FLOATN_NX_TYPE_NODE (i))
> +	extended2 = i + 1;
> +    }
> +  if (extended2 && !extended1)
> +    {
> +      int ret = cp_compare_floating_point_conversion_ranks (t2, t1);
> +      return ret == 3 ? 3 : -ret;
> +    }
> +
> +  const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
> +  const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
> +  gcc_assert (fmt1->b == 2 && fmt2->b == 2);
> +  /* For {ibm,mips}_extended_format formats, the type has variable
> +     precision up to ~2150 bits when the first double is around maximum
> +     representable double and second double is subnormal minimum.
> +     So, e.g. for __ibm128 vs. std::float128_t, they have unordered
> +     ranks.  */
> +  int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1))
> +	    ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p);
> +  int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2))
> +	    ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p);
> +  /* The rank of a floating point type T is greater than the rank of
> +     any floating-point type whose set of values is a proper subset
> +     of the set of values of T.  */
> +  if ((p1 > p2 && fmt1->emax >= fmt2->emax)
> +       || (p1 == p2 && fmt1->emax > fmt2->emax))
> +    return 2;
> +  if ((p1 < p2 && fmt1->emax <= fmt2->emax)
> +       || (p1 == p2 && fmt1->emax < fmt2->emax))
> +    return -2;
> +  if ((p1 > p2 && fmt1->emax < fmt2->emax)
> +       || (p1 < p2 && fmt1->emax > fmt2->emax))
> +    return 3;
> +  if (!extended1 && !extended2)
> +    {
> +      /* The rank of long double is greater than the rank of double, which
> +	 is greater than the rank of float.  */
> +      if (t1 == long_double_type_node)
> +	return 2;
> +      else if (t2 == long_double_type_node)
> +	return -2;
> +      if (t1 == double_type_node)
> +	return 2;
> +      else if (t2 == double_type_node)
> +	return -2;
> +      if (t1 == float_type_node)
> +	return 2;
> +      else if (t2 == float_type_node)
> +	return -2;
> +      return 0;
> +    }
> +  /* Two extended floating-point types with the same set of values have equal
> +     ranks.  */
> +  if (extended1 && extended2)
> +    {
> +      if ((extended1 <= NUM_FLOATN_TYPES) == (extended2 <= NUM_FLOATN_TYPES))
> +	{
> +	  /* Prefer higher extendedN value.  */
> +	  if (extended1 > extended2)
> +	    return 1;
> +	  else if (extended1 < extended2)
> +	    return -1;
> +	  else
> +	    return 0;
> +	}
> +      else if (extended1 <= NUM_FLOATN_TYPES)
> +	/* Prefer _FloatN type over _FloatMx type.  */
> +	return 1;
> +      else if (extended2 <= NUM_FLOATN_TYPES)
> +	return -1;
> +      else
> +	return 0;
> +    }

/* extended1 && !extended2 */

> +  tree *p;
> +  int cnt = 0;
> +  for (p = &float_type_node; p <= &long_double_type_node; ++p)
> +    {
> +      const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p));
> +      gcc_assert (fmt3->b == 2);
> +      int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p))
> +		? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p);
> +      if (p1 == p3 && fmt1->emax == fmt3->emax)
> +	++cnt;
> +    }
> +  /* An extended floating-point type with the same set of values
> +     as exactly one cv-unqualified standard floating-point type
> +     has a rank equal to the rank of that standard floating-point
> +     type.
> +
> +     An extended floating-point type with the same set of values
> +     as more than one cv-unqualified standard floating-point type
> +     has a rank equal to the rank of double.
> +
> +     Thus, if the latter is true and t2 is long double, t2
> +     has higher rank.  */
> +  if (cnt > 1 && mv2 == long_double_type_node)
> +    return -2;
> +  /* Otherwise, they have equal rank, but extended types
> +     (other than std::bfloat16_t) have higher subrank.  */
> +  return 1;
> +}
> +
>   /* Return the common type for two arithmetic types T1 and T2 under the
>      usual arithmetic conversions.  The default conversions have already
>      been applied, and enumerated types converted to their compatible
> @@ -337,6 +463,23 @@ cp_common_type (tree t1, tree t2)
>     if (code2 == REAL_TYPE && code1 != REAL_TYPE)
>       return build_type_attribute_variant (t2, attributes);
>   
> +  if (code1 == REAL_TYPE
> +      && (extended_float_type_p (t1) || extended_float_type_p (t2)))
> +    {
> +      tree mv1 = TYPE_MAIN_VARIANT (t1);
> +      tree mv2 = TYPE_MAIN_VARIANT (t2);
> +      if (mv1 == mv2)
> +	return build_type_attribute_variant (t1, attributes);
> +
> +      int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2);
> +      if (cmpret == 3)
> +	return error_mark_node;
> +      else if (cmpret >= 0)
> +	return build_type_attribute_variant (t1, attributes);
> +      else
> +	return build_type_attribute_variant (t2, attributes);
> +    }
> +
>     /* Both real or both integers; use the one with greater precision.  */
>     if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
>       return build_type_attribute_variant (t1, attributes);
> @@ -5037,7 +5180,20 @@ cp_build_binary_op (const op_location_t
>          = targetm.invalid_binary_op (code, type0, type1)))
>       {
>         if (complain & tf_error)
> -	error (invalid_op_diag);
> +	{
> +	  if (code0 == REAL_TYPE
> +	      && code1 == REAL_TYPE
> +	      && (extended_float_type_p (type0)
> +		  || extended_float_type_p (type1))
> +	      && cp_compare_floating_point_conversion_ranks (type0,
> +							     type1) == 3)
> +	    {
> +	      rich_location richloc (line_table, location);
> +	      binary_op_error (&richloc, code, type0, type1);
> +	    }
> +	  else
> +	    error (invalid_op_diag);
> +	}
>         return error_mark_node;
>       }
>   
> @@ -5907,6 +6063,19 @@ cp_build_binary_op (const op_location_t
>         && (shorten || common || short_compare))
>       {
>         result_type = cp_common_type (type0, type1);
> +      if (result_type == error_mark_node
> +	  && code0 == REAL_TYPE
> +	  && code1 == REAL_TYPE
> +	  && (extended_float_type_p (type0) || extended_float_type_p (type1))
> +	  && cp_compare_floating_point_conversion_ranks (type0, type1) == 3)
> +	{
> +	  if (complain & tf_error)
> +	    {
> +	      rich_location richloc (line_table, location);
> +	      binary_op_error (&richloc, code, type0, type1);
> +	    }
> +	  return error_mark_node;
> +	}
>         if (complain & tf_warning)
>   	{
>   	  do_warn_double_promotion (result_type, type0, type1,
> --- gcc/cp/call.cc.jj	2022-09-19 13:28:53.511058032 +0200
> +++ gcc/cp/call.cc	2022-09-19 17:03:19.280237553 +0200
> @@ -1541,6 +1541,22 @@ standard_conversion (tree to, tree from,
>   	   || (underlying_type && same_type_p (to, underlying_type)))
>   	  && next_conversion (conv)->rank <= cr_promotion)
>   	conv->rank = cr_promotion;
> +
> +      /* A prvalue of floating-point type can be converted to a prvalue of
> +	 another floating-point type with a greater or equal conversion
> +	 rank ([conv.rank]).  A prvalue of standard floating-point type can
> +	 be converted to a prvalue of another standard floating-point type.
> +	 For backwards compatibility with handling __float128 and other
> +	 non-standard floating point types, allow all implicit floating
> +	 point conversions if neither type is extended floating-point
> +	 type and if at least one of them is, fail if they have unordered
> +	 conversion rank or from has higher conversion rank.  */
> +      if (fcode == REAL_TYPE
> +	  && tcode == REAL_TYPE
> +	  && (extended_float_type_p (from)
> +	      || extended_float_type_p (to))
> +	  && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
> +	conv->bad_p = true;
>       }
>     else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
>   	   && vector_types_convertible_p (from, to, false))
> @@ -5842,6 +5858,21 @@ build_conditional_expr (const op_locatio
>         /* In this case, there is always a common type.  */
>         result_type = type_after_usual_arithmetic_conversions (arg2_type,
>   							     arg3_type);
> +      if (result_type == error_mark_node
> +	  && TREE_CODE (arg2_type) == REAL_TYPE
> +	  && TREE_CODE (arg3_type) == REAL_TYPE
> +	  && (extended_float_type_p (arg2_type)
> +	      || extended_float_type_p (arg3_type))
> +	  && cp_compare_floating_point_conversion_ranks (arg2_type,
> +							 arg3_type) == 3)
> +	{
> +	  if (complain & tf_error)
> +	    error_at (loc, "operands to %<?:%> have unordered conversion rank "
> +			   "of types %qT and %qT",

Let's swap "of types..." and "have unordered..."

> +		      arg2_type, arg3_type);
> +	  return error_mark_node;
> +	}
> +
>         if (complain & tf_warning)
>   	do_warn_double_promotion (result_type, arg2_type, arg3_type,
>   				  "implicit conversion from %qH to %qI to "
> @@ -7906,6 +7937,27 @@ convert_like_internal (conversion *convs
>   				"direct-initialization",
>   				totype, TREE_TYPE (expr));
>   
> +      if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
> +	  && TREE_CODE (totype) == REAL_TYPE
> +	  && (extended_float_type_p (TREE_TYPE (expr))
> +	      || extended_float_type_p (totype)))
> +	switch (cp_compare_floating_point_conversion_ranks (TREE_TYPE (expr),
> +							    totype))
> +	  {
> +	  case 2:
> +	    pedwarn (loc, 0, "converting to %qH from %qI with greater "
> +			     "conversion rank", totype, TREE_TYPE (expr));
> +	    complained = true;
> +	    break;
> +	  case 3:
> +	    pedwarn (loc, 0, "converting to %qH from %qI with unordered "
> +			     "conversion ranks", totype, TREE_TYPE (expr));
> +	    complained = true;
> +	    break;
> +	  default:
> +	    break;
> +	  }
> +
>         for (; t ; t = next_conversion (t))
>   	{
>   	  if (t->kind == ck_user && t->cand->reason)
> @@ -8531,7 +8583,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
>     if (TREE_CODE (arg_type) == REAL_TYPE
>         && (TYPE_PRECISION (arg_type)
>   	  < TYPE_PRECISION (double_type_node))
> -      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
> +      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))
> +      && !extended_float_type_p (arg_type))
>       {
>         if ((complain & tf_warning)
>   	  && warn_double_promotion && !c_inhibit_evaluation_warnings)
> @@ -11719,6 +11772,75 @@ compare_ics (conversion *ics1, conversio
>   	return 1;
>       }
>   
> +  {
> +    /* A conversion in either direction between floating-point type FP1 and
> +       floating-point type FP2 is better than a conversion in the same
> +       direction between FP1 and arithmetic type T3 if
> +       - the floating-point conversion rank of FP1 is equal to the rank of
> +	 FP2, and
> +       - T3 is not a floating-point type, or T3 is a floating-point type
> +	 whose rank is not equal to the rank of FP1, or the floating-point
> +	 conversion subrank of FP2 is greater than the subrank of T3.  */
> +    tree fp1 = from_type1;
> +    tree fp2 = to_type1;
> +    tree fp3 = from_type2;
> +    tree t3 = to_type2;
> +    int ret = 1;
> +    if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3))
> +      {
> +	std::swap (fp1, fp2);
> +	std::swap (fp3, t3);
> +      }
> +    if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3)
> +	&& TREE_CODE (fp1) == REAL_TYPE
> +	/* Only apply this rule if at least one of the 3 types is
> +	   extended floating-point type, otherwise keep them as
> +	   before for compatibility reasons with types like __float128.
> +	   float, double and long double alone have different conversion
> +	   ranks and so when just those 3 types are involved, this
> +	   rule doesn't trigger.  */
> +	&& (extended_float_type_p (fp1)
> +	    || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2))
> +	    || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3))))
> +      {
> +	if (TREE_CODE (fp2) != REAL_TYPE)
> +	  {
> +	    ret = -ret;
> +	    std::swap (fp2, t3);
> +	  }
> +	if (TREE_CODE (fp2) == REAL_TYPE)
> +	  {

Please add a comment to explain what you're doing with signed/unsigned 
arithmetic here.

> +	    if (cp_compare_floating_point_conversion_ranks (fp1, fp2) + 1U
> +		<= 2U)
> +	      {
> +		/* Conversion ranks of FP1 and FP2 are equal.  */
> +		if (TREE_CODE (t3) != REAL_TYPE
> +		    || (cp_compare_floating_point_conversion_ranks (fp1, t3)
> +			+ 1U > 2U))
> +		  /* FP1 <-> FP2 conversion is better.  */
> +		  return ret;
> +		int c = cp_compare_floating_point_conversion_ranks (fp2, t3);
> +		gcc_assert (c + 1U <= 2U);
> +		if (c == 1)
> +		  /* Conversion subrank of FP2 is greater than subrank of T3.
> +		     FP1 <-> FP2 conversion is better.  */
> +		  return ret;
> +		else if (c == -1)
> +		  /* Conversion subrank of FP2 is less than subrank of T3.
> +		     FP1 <-> T3 conversion is better.  */
> +		  return -ret;
> +	      }
> +	    else if (TREE_CODE (t3) == REAL_TYPE
> +		     && (cp_compare_floating_point_conversion_ranks (fp1, t3)
> +			 + 1U <= 2U))
> +	      /* Conversion ranks of FP1 and FP2 are not equal, conversion
> +		 ranks of FP1 and T3 are equal.
> +		 FP1 <-> T3 conversion is better.  */
> +	      return -ret;
> +	  }
> +      }
> +  }
> +
>     if (TYPE_PTR_P (from_type1)
>         && TYPE_PTR_P (from_type2)
>         && TYPE_PTR_P (to_type1)
> --- gcc/testsuite/g++.dg/cpp23/ext-floating1.C.jj	2022-09-19 15:13:26.526131946 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C	2022-09-19 18:10:04.270447220 +0200
> @@ -0,0 +1,447 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do compile { target c++23 } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#ifdef __STRICT_ANSI__
> +#undef __SIZEOF_FLOAT128__
> +#endif
> +
> +using namespace std;
> +
> +static_assert (!is_same<float, double>::value);
> +static_assert (!is_same<float, long double>::value);
> +static_assert (!is_same<double, long double>::value);
> +static_assert (is_same<decltype (0.0f), float>::value);
> +static_assert (is_same<decltype (0.0F), float>::value);
> +static_assert (is_same<decltype (0.0), double>::value);
> +static_assert (is_same<decltype (0.0l), long double>::value);
> +static_assert (is_same<decltype (0.0L), long double>::value);
> +static_assert (is_same<decltype (0.0f + 0.0F), float>::value);
> +static_assert (is_same<decltype (0.0F + 0.0f), float>::value);
> +static_assert (is_same<decltype (0.0 + 0.0), double>::value);
> +static_assert (is_same<decltype (0.0l + 0.0L), long double>::value);
> +static_assert (is_same<decltype (0.0L + 0.0l), long double>::value);
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (is_same<decltype (0.0q), __float128>::value);
> +static_assert (is_same<decltype (0.0Q), __float128>::value);
> +static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value);
> +static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT16_T__
> +static_assert (!is_same<float, float16_t>::value);
> +static_assert (!is_same<double, float16_t>::value);
> +static_assert (!is_same<long double, float16_t>::value);
> +static_assert (is_same<decltype (0.0f16), float16_t>::value);
> +static_assert (is_same<decltype (0.0F16), float16_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +static_assert (!is_same<float, float32_t>::value);
> +static_assert (!is_same<double, float32_t>::value);
> +static_assert (!is_same<long double, float32_t>::value);
> +static_assert (!is_same<decltype (0.0f), float32_t>::value);
> +static_assert (!is_same<decltype (0.0F), float32_t>::value);
> +static_assert (is_same<decltype (0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32), float32_t>::value);
> +static_assert (!is_same<decltype (0.0f32), float>::value);
> +static_assert (!is_same<decltype (0.0F32), float>::value);
> +static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +static_assert (!is_same<float, float64_t>::value);
> +static_assert (!is_same<double, float64_t>::value);
> +static_assert (!is_same<long double, float64_t>::value);
> +static_assert (!is_same<decltype (0.0), float64_t>::value);
> +static_assert (is_same<decltype (0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64), float64_t>::value);
> +static_assert (!is_same<decltype (0.0f64), double>::value);
> +static_assert (!is_same<decltype (0.0F64), double>::value);
> +static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +static_assert (!is_same<float, float128_t>::value);
> +static_assert (!is_same<double, float128_t>::value);
> +static_assert (!is_same<long double, float128_t>::value);
> +static_assert (!is_same<decltype (0.0l), float128_t>::value);
> +static_assert (!is_same<decltype (0.0L), float128_t>::value);
> +static_assert (is_same<decltype (0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128), float128_t>::value);
> +static_assert (!is_same<decltype (0.0f128), long double>::value);
> +static_assert (!is_same<decltype (0.0F128), long double>::value);
> +static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value);
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (!is_same<float128_t, __float128>::value);
> +static_assert (!is_same<decltype (0.0q), float128_t>::value);
> +static_assert (!is_same<decltype (0.0Q), float128_t>::value);
> +static_assert (!is_same<decltype (0.0f128), __float128>::value);
> +static_assert (!is_same<decltype (0.0F128), __float128>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +static_assert (!is_same<float, bfloat16_t>::value);
> +static_assert (!is_same<double, bfloat16_t>::value);
> +static_assert (!is_same<long double, bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value);
> +#endif
> +#ifdef __FLT32X_MANT_DIG__
> +static_assert (!is_same<float, _Float32x>::value);
> +static_assert (!is_same<double, _Float32x>::value);
> +static_assert (!is_same<long double, _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0F), _Float32x>::value);
> +static_assert (is_same<decltype (0.0f32x), _Float32x>::value);
> +static_assert (is_same<decltype (0.0F32x), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f32x), float>::value);
> +static_assert (!is_same<decltype (0.0F32x), float>::value);
> +static_assert (is_same<decltype (0.0f32x + 0.0f32x), _Float32x>::value);
> +static_assert (is_same<decltype (0.0F32x + 0.0F32x), _Float32x>::value);
> +#ifdef __STDCPP_FLOAT16_T__
> +static_assert (!is_same<float16_t, _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f16), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0F16), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f32x), float16_t>::value);
> +static_assert (!is_same<decltype (0.0F32x), float16_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +static_assert (!is_same<float32_t, _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f32), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0F32), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f32x), float32_t>::value);
> +static_assert (!is_same<decltype (0.0F32x), float32_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +static_assert (!is_same<float64_t, _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f64), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0F64), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f32x), float64_t>::value);
> +static_assert (!is_same<decltype (0.0F32x), float64_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +static_assert (!is_same<float128_t, _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f128), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0F128), _Float32x>::value);
> +static_assert (!is_same<decltype (0.0f32x), float128_t>::value);
> +static_assert (!is_same<decltype (0.0F32x), float128_t>::value);
> +#endif
> +#endif
> +#ifdef __FLT64X_MANT_DIG__
> +static_assert (!is_same<float, _Float64x>::value);
> +static_assert (!is_same<double, _Float64x>::value);
> +static_assert (!is_same<long double, _Float64x>::value);
> +static_assert (!is_same<decltype (0.0), _Float64x>::value);
> +static_assert (is_same<decltype (0.0f64x), _Float64x>::value);
> +static_assert (is_same<decltype (0.0F64x), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64x), double>::value);
> +static_assert (!is_same<decltype (0.0F64x), double>::value);
> +static_assert (is_same<decltype (0.0f64x + 0.0f64x), _Float64x>::value);
> +static_assert (is_same<decltype (0.0F64x + 0.0F64x), _Float64x>::value);
> +#ifdef __STDCPP_FLOAT16_T__
> +static_assert (!is_same<float16_t, _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f16), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0F16), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64x), float16_t>::value);
> +static_assert (!is_same<decltype (0.0F64x), float16_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +static_assert (!is_same<float32_t, _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f32), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0F32), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64x), float32_t>::value);
> +static_assert (!is_same<decltype (0.0F64x), float32_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +static_assert (!is_same<float64_t, _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0F64), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64x), float64_t>::value);
> +static_assert (!is_same<decltype (0.0F64x), float64_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +static_assert (!is_same<float128_t, _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f128), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0F128), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64x), float128_t>::value);
> +static_assert (!is_same<decltype (0.0F64x), float128_t>::value);
> +#endif
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (!is_same<_Float64x, __float128>::value);
> +static_assert (!is_same<decltype (0.0q), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0Q), _Float64x>::value);
> +static_assert (!is_same<decltype (0.0f64x), __float128>::value);
> +static_assert (!is_same<decltype (0.0F64x), __float128>::value);
> +#endif
> +#endif
> +#ifdef __FLT128X_MANT_DIG__
> +static_assert (!is_same<float, _Float128x>::value);
> +static_assert (!is_same<double, _Float128x>::value);
> +static_assert (!is_same<long double, _Float128x>::value);
> +static_assert (!is_same<decltype (0.0l), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0L), _Float128x>::value);
> +static_assert (is_same<decltype (0.0f128x), _Float128x>::value);
> +static_assert (is_same<decltype (0.0F128x), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128x), long double>::value);
> +static_assert (!is_same<decltype (0.0F128x), long double>::value);
> +static_assert (is_same<decltype (0.0f128x + 0.0f128x), _Float128x>::value);
> +static_assert (is_same<decltype (0.0F128x + 0.0F128x), _Float128x>::value);
> +#ifdef __STDCPP_FLOAT16_T__
> +static_assert (!is_same<float16_t, _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f16), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0F16), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128x), float16_t>::value);
> +static_assert (!is_same<decltype (0.0F128x), float16_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +static_assert (!is_same<float32_t, _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f32), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0F32), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128x), float32_t>::value);
> +static_assert (!is_same<decltype (0.0F128x), float32_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +static_assert (!is_same<float64_t, _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f64), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0F64), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128x), float64_t>::value);
> +static_assert (!is_same<decltype (0.0F128x), float64_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +static_assert (!is_same<float128_t, _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0F128), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128x), float128_t>::value);
> +static_assert (!is_same<decltype (0.0F128x), float128_t>::value);
> +#endif
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (!is_same<_Float128x, __float128>::value);
> +static_assert (!is_same<decltype (0.0q), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0Q), _Float128x>::value);
> +static_assert (!is_same<decltype (0.0f128x), __float128>::value);
> +static_assert (!is_same<decltype (0.0F128x), __float128>::value);
> +#endif
> +#endif
> +static_assert (is_same<decltype (0.0f + 0.0), double>::value);
> +static_assert (is_same<decltype (0.0 + 0.0F), double>::value);
> +static_assert (is_same<decltype (0.0L + 0.0), long double>::value);
> +static_assert (is_same<decltype (0.0 + 0.0L), long double>::value);
> +static_assert (is_same<decltype (0.0L + 0.0f), long double>::value);
> +static_assert (is_same<decltype (0.0F + 0.0l), long double>::value);
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
> +static_assert (!is_same<float16_t, float32_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
> +static_assert (!is_same<float16_t, float64_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<float16_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT32X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f16 + 0.0f32x), _Float32x>::value);
> +static_assert (is_same<decltype (0.0F32x + 0.0F16), _Float32x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT64X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f16 + 0.0f64x), _Float64x>::value);
> +static_assert (is_same<decltype (0.0F64x + 0.0F16), _Float64x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT128X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f16 + 0.0f128x), _Float128x>::value);
> +static_assert (is_same<decltype (0.0F128x + 0.0F16), _Float128x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__)
> +static_assert (!is_same<float32_t, float64_t>::value);
> +static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<float32_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT32X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f32 + 0.0f32x), _Float32x>::value);
> +static_assert (is_same<decltype (0.0F32x + 0.0F32), _Float32x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT64X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f32 + 0.0f64x), _Float64x>::value);
> +static_assert (is_same<decltype (0.0F64x + 0.0F32), _Float64x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT128X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f32 + 0.0f128x), _Float128x>::value);
> +static_assert (is_same<decltype (0.0F128x + 0.0F32), _Float128x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<float64_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT32X_MANT_DIG__) \
> +    && __FLT64_MAX_EXP__ == __FLT32X_MAX_EXP__ \
> +    && __FLT64_MANT_DIG__ == __FLT32X_MANT_DIG__
> +static_assert (is_same<decltype (0.0f64 + 0.0f32x), float64_t>::value);
> +static_assert (is_same<decltype (0.0F32x + 0.0F64), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT64X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f64 + 0.0f64x), _Float64x>::value);
> +static_assert (is_same<decltype (0.0F64x + 0.0F64), _Float64x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT128X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f64 + 0.0f128x), _Float128x>::value);
> +static_assert (is_same<decltype (0.0F128x + 0.0F64), _Float128x>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT32X_MANT_DIG__) \
> +    && __FLT128_MAX_EXP__ >= __FLT32X_MAX_EXP__ \
> +    && __FLT128_MANT_DIG__ >= __FLT32X_MANT_DIG__
> +static_assert (is_same<decltype (0.0f128 + 0.0f32x), float128_t>::value);
> +static_assert (is_same<decltype (0.0F32x + 0.0F128), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT64X_MANT_DIG__) \
> +    && __FLT128_MAX_EXP__ >= __FLT64X_MAX_EXP__ \
> +    && __FLT128_MANT_DIG__ >= __FLT64X_MANT_DIG__
> +static_assert (is_same<decltype (0.0f128 + 0.0f64x), float128_t>::value);
> +static_assert (is_same<decltype (0.0F64x + 0.0F128), float128_t>::value);
> +#endif
> +#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT128X_MANT_DIG__)
> +static_assert (is_same<decltype (0.0f128 + 0.0f128x), _Float128>::value);
> +static_assert (is_same<decltype (0.0F128x + 0.0F128), _Float128>::value);
> +#endif
> +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
> +static_assert (!is_same<bfloat16_t, float32_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value);
> +#endif
> +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
> +static_assert (!is_same<bfloat16_t, float64_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value);
> +#endif
> +#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
> +static_assert (!is_same<bfloat16_t, float128_t>::value);
> +static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value);
> +#endif
> +#ifdef __STDCPP_FLOAT16_T__
> +#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f16), float>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value);
> +#endif
> +#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f16), double>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0), double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value);
> +static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value);
> +#endif
> +#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f32), double>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0), double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value);
> +static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value);
> +#endif
> +#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \
> +    && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
> +// An extended floating-point type with the same set of values as more than one
> +// cv-unqualified standard floating-point type has a rank equal to the rank of
> +// double.
> +// Then long double will have higher rank than float64_t.
> +static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
> +static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value);
> +#endif
> +#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \
> +    && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered.
> +static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value);
> +#endif
> +#ifdef __SIZEOF_FLOAT128__
> +static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value);
> +static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value);
> +#endif
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value);
> +#endif
> +#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value);
> +#endif
> +#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__
> +static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value);
> +static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value);
> +#endif
> +#endif
> +
> +void foo (float) {}
> +void foo (double) {}
> +void foo (long double) {}
> +#ifdef __STDCPP_FLOAT16_T__
> +void foo (float16_t) {}
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +void foo (float32_t) {}
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +void foo (float64_t) {}
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +void foo (float128_t) {}
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +void foo (bfloat16_t) {}
> +#endif
> +#ifdef __FLT32X_MANT_DIG__
> +void foo (_Float32x) {}
> +#endif
> +#ifdef __FLT64X_MANT_DIG__
> +void foo (_Float64x) {}
> +#endif
> +#ifdef __FLT128X_MANT_DIG__
> +void foo (_Float128x) {}
> +#endif
> --- gcc/testsuite/g++.dg/cpp23/ext-floating2.C.jj	2022-09-19 15:13:26.526131946 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating2.C	2022-09-19 17:30:32.400901278 +0200
> @@ -0,0 +1,157 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do compile { target c++23 } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#ifdef __STRICT_ANSI__
> +#undef __SIZEOF_FLOAT128__
> +#endif
> +
> +using namespace std;
> +
> +float fa = 1.0f;
> +float fb = (float) 1.0f;
> +float fc = 1.0;
> +float fd = (float) 1.0;
> +float fe = 1.0L;
> +float ff = (float) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float fg = 1.0Q;
> +float fh = (float) 1.0Q;
> +#endif
> +double da = 1.0f;
> +double db = (double) 1.0f;
> +double dc = 1.0;
> +double dd = (double) 1.0;
> +double de = 1.0L;
> +double df = (double) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +double dg = 1.0Q;
> +double dh = (double) 1.0Q;
> +#endif
> +long double lda = 1.0f;
> +long double ldb = (long double) 1.0f;
> +long double ldc = 1.0;
> +long double ldd = (long double) 1.0;
> +long double lde = 1.0L;
> +long double ldf = (long double) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +long double ldg = 1.0Q;
> +long double ldh = (long double) 1.0Q;
> +__float128 qa = 1.0f;
> +__float128 qb = (__float128) 1.0f;
> +__float128 qc = 1.0;
> +__float128 qd = (__float128) 1.0;
> +__float128 qe = 1.0L;
> +__float128 qf = (__float128) 1.0L;
> +__float128 qg = 1.0Q;
> +__float128 qh = (__float128) 1.0Q;
> +#endif
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t f16a = 1.0F16;
> +float16_t f16b = (float16_t) 1.0F16;
> +#ifdef __STDCPP_FLOAT32_T__
> +float16_t f16c = 1.0F32;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float32' with greater conversion rank" "" { target { float16 && float32 } } }
> +float16_t f16d = (float16_t) 1.0F32;
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +float16_t f16e = 1.0F64;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float64' with greater conversion rank" "" { target { float16 && float64 } } }
> +float16_t f16f = (float16_t) 1.0F64;
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +float16_t f16g = 1.0F128;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float128' with greater conversion rank" "" { target { float16 && float128 } } }
> +float16_t f16h = (float16_t) 1.0F128;
> +#endif
> +float16_t f16j = (float16_t) 1.0f;
> +float16_t f16l = (float16_t) 1.0;
> +float16_t f16n = (float16_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float16_t f16p = (float16_t) 1.0Q;
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +#ifdef __STDCPP_FLOAT16_T__
> +float32_t f32a = 1.0F16;
> +float32_t f32b = (float32_t) 1.0F16;
> +#endif
> +float32_t f32c = 1.0F32;
> +float32_t f32d = (float32_t) 1.0F32;
> +#ifdef __STDCPP_FLOAT64_T__
> +float32_t f32e = 1.0F64;		// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float64' with greater conversion rank" "" { target { float32 && float64 } } }
> +float32_t f32f = (float32_t) 1.0F64;
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +float32_t f32g = 1.0F128;		// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float128' with greater conversion rank" "" { target { float32 && float128 } } }
> +float32_t f32h = (float32_t) 1.0F128;
> +#endif
> +#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__
> +float32_t f32i = 1.0f;
> +#endif
> +float32_t f32j = (float32_t) 1.0f;
> +float32_t f32l = (float32_t) 1.0;
> +float32_t f32n = (float32_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float32_t f32p = (float32_t) 1.0Q;
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +#ifdef __STDCPP_FLOAT16_T__
> +float64_t f64a = 1.0F16;
> +float64_t f64b = (float64_t) 1.0F16;
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +float64_t f64c = 1.0F32;
> +float64_t f64d = (float64_t) 1.0F32;
> +#endif
> +float64_t f64e = 1.0F64;
> +float64_t f64f = (float64_t) 1.0F64;
> +#ifdef __STDCPP_FLOAT128_T__
> +float64_t f64g = 1.0F128;		// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '_Float128' with greater conversion rank" "" { target { float64 && float128 } } }
> +float64_t f64h = (float64_t) 1.0F128;
> +#endif
> +#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__
> +float64_t f64i = 1.0f;
> +#endif
> +float64_t f64j = (float64_t) 1.0f;
> +#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__
> +float64_t f64k = 1.0;
> +#endif
> +float64_t f64l = (float64_t) 1.0;
> +float64_t f64n = (float64_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float64_t f64p = (float64_t) 1.0Q;
> +#endif
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +#ifdef __STDCPP_FLOAT16_T__
> +float128_t f128a = 1.0F16;
> +float128_t f128b = (float128_t) 1.0F16;
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +float128_t f128c = 1.0F32;
> +float128_t f128d = (float128_t) 1.0F32;
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +float128_t f128e = 1.0F64;
> +float128_t f128f = (float128_t) 1.0F64;
> +#endif
> +float128_t f128g = 1.0F128;
> +float128_t f128h = (float128_t) 1.0F128;
> +#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__
> +float128_t f128i = 1.0f;
> +#endif
> +float128_t f128j = (float128_t) 1.0f;
> +#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__
> +float128_t f128k = 1.0;
> +#endif
> +float128_t f128l = (float128_t) 1.0;
> +#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106
> +float128_t f128m = 1.0L;
> +#endif
> +float128_t f128n = (float128_t) 1.0L;
> +#ifdef __SIZEOF_FLOAT128__
> +float128_t f128o = 1.0Q;
> +float128_t f128p = (float128_t) 1.0Q;
> +#endif
> +#endif
> --- gcc/testsuite/g++.dg/cpp23/ext-floating3.C.jj	2022-09-19 15:13:26.526131946 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C	2022-09-19 17:33:51.274179774 +0200
> @@ -0,0 +1,134 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// Variant of ext-floating2.C test with x86 specific assumptions
> +// about float, double, long double and existence of __float128.
> +// And some further tests.
> +// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#if !defined(__STDCPP_FLOAT32_T__) \
> +    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
> +    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
> +    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
> +    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
> +    || !defined(__SIZEOF_FLOAT128__)
> +#error Unexpected set of floating point types
> +#endif
> +
> +using namespace std;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t f16i = 1.0f;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } }
> +float16_t f16k = 1.0;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } }
> +float16_t f16m = 1.0L;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } }
> +float16_t f16o = 1.0Q;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '__float128' with greater conversion rank" "" { target float16 } }
> +#endif
> +float32_t f32i = 1.0f;
> +float32_t f32k = 1.0;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" }
> +float32_t f32m = 1.0L;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" }
> +float32_t f32o = 1.0Q;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '__float128' with greater conversion rank" }
> +float64_t f64i = 1.0f;
> +float64_t f64k = 1.0;
> +float64_t f64m = 1.0L;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" }
> +float64_t f64o = 1.0Q;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '__float128' with greater conversion rank" }
> +float128_t f128i = 1.0f;
> +float128_t f128k = 1.0;
> +float128_t f128m = 1.0L;
> +float128_t f128o = 1.0Q;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +constexpr float16_t f16x = 1.0F16;
> +#endif
> +constexpr float32_t f32x = 2.0F32;
> +constexpr float64_t f64x = 3.0F64;
> +constexpr float128_t f128x = 4.0F128;
> +constexpr float fx = 5.0f;
> +constexpr double dx = 6.0;
> +constexpr long double ldx = 7.0L;
> +
> +constexpr int foo (float32_t) { return 1; }
> +constexpr int foo (float64_t) { return 2; }
> +constexpr int bar (float) { return 3; }
> +constexpr int bar (double) { return 4; }
> +constexpr int bar (long double) { return 5; }
> +constexpr int baz (float32_t) { return 6; }
> +constexpr int baz (float64_t) { return 7; }
> +constexpr int baz (float128_t) { return 8; }
> +constexpr int qux (float64_t) { return 9; }
> +constexpr int qux (float32_t) { return 10; }
> +constexpr int fred (long double) { return 11; }
> +constexpr int fred (double) { return 12; }
> +constexpr int fred (float) { return 13; }
> +constexpr int thud (float128_t) { return 14; }
> +constexpr int thud (float64_t) { return 15; }
> +constexpr int thud (float32_t) { return 16; }
> +struct S {
> +  constexpr operator float32_t () const { return 1.0f32; }
> +  constexpr operator float64_t () const { return 2.0f64; }
> +};
> +struct T {
> +  constexpr operator float64_t () const { return 3.0f64; }
> +  constexpr operator float32_t () const { return 4.0f32; }
> +};
> +
> +void
> +test (S s, T t)
> +{
> +#ifdef __STDCPP_FLOAT16_T__
> +  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (foo (float (2.0)) == 1);
> +  static_assert (foo (double (3.0)) == 2);
> +  constexpr double x (s);
> +  static_assert (x == 2.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (bar (f32x) == 3);
> +  static_assert (bar (f64x) == 4);
> +  bar (f128x);					// { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" }
> +						// { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 }
> +						// { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 }
> +						// { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 }
> +  static_assert (bar (fx) == 3);
> +  static_assert (bar (dx) == 4);
> +  static_assert (bar (ldx) == 5);
> +#ifdef __STDCPP_FLOAT16_T__
> +  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (baz (f32x) == 6);
> +  static_assert (baz (f64x) == 7);
> +  static_assert (baz (f128x) == 8);
> +  static_assert (baz (fx) == 6);
> +  static_assert (baz (dx) == 7);
> +  static_assert (baz (ldx) == 8);
> +#ifdef __STDCPP_FLOAT16_T__
> +  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (qux (float (2.0)) == 10);
> +  static_assert (qux (double (3.0)) == 9);
> +  constexpr double y (t);
> +  static_assert (y == 3.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (fred (f32x) == 13);
> +  static_assert (fred (f64x) == 12);
> +  fred (f128x);					// { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" }
> +						// { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 }
> +						// { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 }
> +						// { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 }
> +  static_assert (fred (fx) == 13);
> +  static_assert (fred (dx) == 12);
> +  static_assert (fred (ldx) == 11);
> +#ifdef __STDCPP_FLOAT16_T__
> +  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (thud (f32x) == 16);
> +  static_assert (thud (f64x) == 15);
> +  static_assert (thud (f128x) == 14);
> +  static_assert (thud (fx) == 16);
> +  static_assert (thud (dx) == 15);
> +  static_assert (thud (ldx) == 14);
> +}
> --- gcc/testsuite/g++.dg/cpp23/ext-floating4.C.jj	2022-09-19 15:13:26.540131753 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C	2022-09-19 17:31:01.429503718 +0200
> @@ -0,0 +1,126 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// Variant of ext-floating3.C test with different specific assumptions
> +// about float, double, long double.
> +// float, double and long double are assumed to be IEEE 754 single, double
> +// and quad.
> +// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } }
> +// { dg-options "" }
> +// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } }
> +// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } }
> +
> +#include "ext-floating.h"
> +
> +#if !defined(__STDCPP_FLOAT32_T__) \
> +    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
> +    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
> +    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
> +    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__
> +#error Unexpected set of floating point types
> +#endif
> +
> +using namespace std;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t f16i = 1.0f;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } }
> +float16_t f16k = 1.0;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } }
> +float16_t f16m = 1.0L;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } }
> +#endif
> +float32_t f32i = 1.0f;
> +float32_t f32k = 1.0;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" }
> +float32_t f32m = 1.0L;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" }
> +float64_t f64i = 1.0f;
> +float64_t f64k = 1.0;
> +float64_t f64m = 1.0L;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" }
> +float128_t f128i = 1.0f;
> +float128_t f128k = 1.0;
> +float128_t f128m = 1.0L;
> +
> +#ifdef __STDCPP_FLOAT16_T__
> +constexpr float16_t f16x = 1.0F16;
> +#endif
> +constexpr float32_t f32x = 2.0F32;
> +constexpr float64_t f64x = 3.0F64;
> +constexpr float128_t f128x = 4.0F128;
> +constexpr float fx = 5.0f;
> +constexpr double dx = 6.0;
> +constexpr long double ldx = 7.0L;
> +
> +constexpr int foo (float32_t) { return 1; }
> +constexpr int foo (float64_t) { return 2; }
> +constexpr int bar (float) { return 3; }
> +constexpr int bar (double) { return 4; }
> +constexpr int bar (long double) { return 5; }
> +constexpr int baz (float32_t) { return 6; }
> +constexpr int baz (float64_t) { return 7; }
> +constexpr int baz (float128_t) { return 8; }
> +constexpr int qux (float64_t) { return 9; }
> +constexpr int qux (float32_t) { return 10; }
> +constexpr int fred (long double) { return 11; }
> +constexpr int fred (double) { return 12; }
> +constexpr int fred (float) { return 13; }
> +constexpr int thud (float128_t) { return 14; }
> +constexpr int thud (float64_t) { return 15; }
> +constexpr int thud (float32_t) { return 16; }
> +struct S {
> +  constexpr operator float32_t () const { return 1.0f32; }
> +  constexpr operator float64_t () const { return 2.0f64; }
> +};
> +struct T {
> +  constexpr operator float64_t () const { return 3.0f64; }
> +  constexpr operator float32_t () const { return 4.0f32; }
> +};
> +
> +void
> +test (S s, T t)
> +{
> +#ifdef __STDCPP_FLOAT16_T__
> +  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (foo (float (2.0)) == 1);
> +  static_assert (foo (double (3.0)) == 2);
> +  constexpr double x (s);
> +  static_assert (x == 2.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (bar (f32x) == 3);
> +  static_assert (bar (f64x) == 4);
> +  static_assert (bar (f128x) == 5);
> +  static_assert (bar (fx) == 3);
> +  static_assert (bar (dx) == 4);
> +  static_assert (bar (ldx) == 5);
> +#ifdef __STDCPP_FLOAT16_T__
> +  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (baz (f32x) == 6);
> +  static_assert (baz (f64x) == 7);
> +  static_assert (baz (f128x) == 8);
> +  static_assert (baz (fx) == 6);
> +  static_assert (baz (dx) == 7);
> +  static_assert (baz (ldx) == 8);
> +#ifdef __STDCPP_FLOAT16_T__
> +  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (qux (float (2.0)) == 10);
> +  static_assert (qux (double (3.0)) == 9);
> +  constexpr double y (t);
> +  static_assert (y == 3.0);
> +#ifdef __STDCPP_FLOAT16_T__
> +  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (fred (f32x) == 13);
> +  static_assert (fred (f64x) == 12);
> +  static_assert (fred (f128x) == 11);
> +  static_assert (fred (fx) == 13);
> +  static_assert (fred (dx) == 12);
> +  static_assert (fred (ldx) == 11);
> +#ifdef __STDCPP_FLOAT16_T__
> +  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
> +#endif
> +  static_assert (thud (f32x) == 16);
> +  static_assert (thud (f64x) == 15);
> +  static_assert (thud (f128x) == 14);
> +  static_assert (thud (fx) == 16);
> +  static_assert (thud (dx) == 15);
> +  static_assert (thud (ldx) == 14);
> +}
> --- gcc/testsuite/g++.dg/cpp23/ext-floating5.C.jj	2022-09-19 15:13:26.540131753 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C	2022-09-19 15:13:26.540131753 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// IBM extended long double and _Float128 should have unordered conversion
> +// ranks as IBM extended long double has variable precision from 53 bits
> +// for denormals to more than 2150 bits for certain numbers.
> +// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } }
> +// { dg-require-effective-target ppc_float128_sw }
> +// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" }
> +
> +auto a = 1.0F128 + 1.0L;	// { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" }
> +auto b = 1.0L + 1.0F128;	// { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" }
> +bool c;
> +auto d = c ? 1.0F128 : 1.0L;	// { dg-error "operands to '\\\?:' have unordered conversion rank of types '_Float128' and 'long double'" }
> +auto e = c ? 1.0L : 1.0F128;	// { dg-error "operands to '\\\?:' have unordered conversion rank of types 'long double' and '_Float128'" }
> --- gcc/testsuite/g++.dg/cpp23/ext-floating6.C.jj	2022-09-19 15:13:26.540131753 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating6.C	2022-09-19 15:13:26.540131753 +0200
> @@ -0,0 +1,30 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do compile { target c++23 } }
> +// { dg-options "" }
> +
> +#include "ext-floating.h"
> +
> +#ifdef __STRICT_ANSI__
> +#undef __SIZEOF_FLOAT128__
> +#endif
> +
> +using namespace std;
> +
> +float foo (float x, float y, float z) { return x * y + z; }
> +double foo (double x, double y, double z) { return x * y + z; }
> +long double foo (long double x, long double y, long double z) { return x * y + z; }
> +#ifdef __STDCPP_FLOAT16_T__
> +float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_FLOAT32_T__
> +float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_FLOAT64_T__
> +float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_FLOAT128_T__
> +float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; }
> +#endif
> +#ifdef __STDCPP_BFLOAT16_T__
> +bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; }
> +#endif
> --- gcc/testsuite/g++.dg/cpp23/ext-floating7.C.jj	2022-09-19 15:13:26.540131753 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C	2022-09-19 15:13:26.540131753 +0200
> @@ -0,0 +1,119 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float16_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float16 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT16_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 16
> +#endif
> +
> +#include <stdarg.h>
> +#include "ext-floating.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 TYPE CONCAT (_Float, WIDTH)
> +#define CST(C) CONCAT3 (C, f, WIDTH)
> +#define CSTU(C) CONCAT3 (C, F, WIDTH)
> +
> +extern "C" void abort ();
> +
> +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
> +fn (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 = fn (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 ();
> +}
> --- gcc/testsuite/g++.dg/cpp23/ext-floating8.C.jj	2022-09-19 15:13:26.540131753 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C	2022-09-19 15:13:26.540131753 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float32_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float32 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT32_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 32
> +#endif
> +
> +#include "ext-floating7.C"
> --- gcc/testsuite/g++.dg/cpp23/ext-floating9.C.jj	2022-09-19 15:13:26.541131739 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating9.C	2022-09-19 15:13:26.540131753 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float64_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float64 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT64_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 64
> +#endif
> +
> +#include "ext-floating7.C"
> --- gcc/testsuite/g++.dg/cpp23/ext-floating10.C.jj	2022-09-19 15:13:26.541131739 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C	2022-09-19 15:13:26.541131739 +0200
> @@ -0,0 +1,13 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +// { dg-do run { target { c++23 && float128_runtime } } }
> +// { dg-options "" }
> +// { dg-add-options float128 }
> +
> +#ifndef WIDTH
> +#ifndef __STDCPP_FLOAT128_T__
> +#error Unexpected
> +#endif
> +#define WIDTH 128
> +#endif
> +
> +#include "ext-floating7.C"
> --- gcc/testsuite/g++.dg/cpp23/ext-floating.h.jj	2022-09-19 15:13:26.541131739 +0200
> +++ gcc/testsuite/g++.dg/cpp23/ext-floating.h	2022-09-19 15:13:26.541131739 +0200
> @@ -0,0 +1,30 @@
> +// P1467R9 - Extended floating-point types and standard names.
> +
> +namespace std
> +{
> +  #ifdef __STDCPP_FLOAT16_T__
> +  using float16_t = _Float16;
> +  #endif
> +  #ifdef __STDCPP_FLOAT32_T__
> +  using float32_t = _Float32;
> +  #endif
> +  #ifdef __STDCPP_FLOAT64_T__
> +  using float64_t = _Float64;
> +  #endif
> +  #ifdef __STDCPP_FLOAT128_T__
> +  using float128_t = _Float128;
> +  #endif
> +  #undef __STDCPP_BFLOAT16_T__
> +  #ifdef __STDCPP_BFLOAT16_T__
> +  using bfloat16_t = __bf16; // ???
> +  #endif
> +  template<typename T, T v> struct integral_constant {
> +    static constexpr T value = v;
> +  };
> +  typedef integral_constant<bool, false> false_type;
> +  typedef integral_constant<bool, true> true_type;
> +  template<class T, class U>
> +  struct is_same : std::false_type {};
> +  template <class T>
> +  struct is_same<T, T> : std::true_type {};
> +}
> --- gcc/testsuite/g++.target/i386/float16-1.C.jj	2022-09-12 10:31:28.051542356 +0200
> +++ gcc/testsuite/g++.target/i386/float16-1.C	2022-09-19 15:13:26.546131671 +0200
> @@ -1,8 +1,8 @@
>   /* { dg-do compile } */
>   /* { dg-options "-O2 -mno-sse2" } */
>   
> -_Float16/* { dg-error "does not name a type" } */
> +_Float16	/* { dg-error "expected unqualified-id before '_Float16'" } */
>   foo (_Float16 x)
>   {
>     return x;
> -}
> +}		/* { dg-error "'_Float16' is not supported on this target" } */
> --- libcpp/expr.cc.jj	2022-09-12 10:31:28.298538934 +0200
> +++ libcpp/expr.cc	2022-09-19 15:13:59.664677834 +0200
> @@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfil
>   	case 'f': case 'F':
>   	  f++;
>   	  if (len > 0
> -	      && !CPP_OPTION (pfile, cplusplus)
>   	      && s[1] >= '1'
>   	      && s[1] <= '9'
>   	      && fn_bits == 0)
> --- include/demangle.h.jj	2022-09-12 10:31:28.254539543 +0200
> +++ include/demangle.h	2022-09-19 16:53:01.285662293 +0200
> @@ -457,6 +457,11 @@ enum demangle_component_type
>     DEMANGLE_COMPONENT_MODULE_PARTITION,
>     DEMANGLE_COMPONENT_MODULE_ENTITY,
>     DEMANGLE_COMPONENT_MODULE_INIT,
> +
> +  /* A builtin type with argument.  This holds the builtin type
> +     information.  */
> +  DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
> +
>   };
>   
>   /* Types which are only used internally.  */
> @@ -543,6 +548,15 @@ struct demangle_component
>         const struct demangle_builtin_type_info *type;
>       } s_builtin;
>   
> +    /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  */
> +    struct
> +    {
> +      /* Builtin type.  */
> +      const struct demangle_builtin_type_info *type;
> +      short arg;
> +      char suffix;
> +    } s_extended_builtin;
> +
>       /* For DEMANGLE_COMPONENT_SUB_STD.  */
>       struct
>       {
> --- libiberty/cp-demangle.c.jj	2022-09-12 10:31:28.350538214 +0200
> +++ libiberty/cp-demangle.c	2022-09-19 16:59:22.568468901 +0200
> @@ -648,6 +648,13 @@ d_dump (struct demangle_component *dc, i
>       case DEMANGLE_COMPONENT_BUILTIN_TYPE:
>         printf ("builtin type %s\n", dc->u.s_builtin.type->name);
>         return;
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> +      {
> +	char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 };
> +	printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name,
> +		dc->u.s_extended_builtin.type->arg, suffix);
> +      }
> +      return;
>       case DEMANGLE_COMPONENT_OPERATOR:
>         printf ("operator %s\n", dc->u.s_operator.op->name);
>         return;
> @@ -771,11 +778,6 @@ d_dump (struct demangle_component *dc, i
>       case DEMANGLE_COMPONENT_PTRMEM_TYPE:
>         printf ("pointer to member type\n");
>         break;
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> -      printf ("fixed-point type, accum? %d, sat? %d\n",
> -              dc->u.s_fixed.accum, dc->u.s_fixed.sat);
> -      d_dump (dc->u.s_fixed.length, indent + 2);
> -      break;
>       case DEMANGLE_COMPONENT_ARGLIST:
>         printf ("argument list\n");
>         break;
> @@ -1109,6 +1111,28 @@ d_make_builtin_type (struct d_info *di,
>     return p;
>   }
>   
> +/* Add a new extended builtin type component.  */
> +
> +static struct demangle_component *
> +d_make_extended_builtin_type (struct d_info *di,
> +			      const struct demangle_builtin_type_info *type,
> +			      short arg, char suffix)
> +{
> +  struct demangle_component *p;
> +
> +  if (type == NULL)
> +    return NULL;
> +  p = d_make_empty (di);
> +  if (p != NULL)
> +    {
> +      p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE;
> +      p->u.s_extended_builtin.type = type;
> +      p->u.s_extended_builtin.arg = arg;
> +      p->u.s_extended_builtin.suffix = suffix;
> +    }
> +  return p;
> +}
> +
>   /* Add a new operator component.  */
>   
>   static struct demangle_component *
> @@ -2464,6 +2488,7 @@ cplus_demangle_builtin_types[D_BUILTIN_T
>     /* 32 */ { NL ("char32_t"),	NL ("char32_t"),	D_PRINT_DEFAULT },
>     /* 33 */ { NL ("decltype(nullptr)"),	NL ("decltype(nullptr)"),
>   	     D_PRINT_DEFAULT },
> +  /* 34 */ { NL ("_Float"),	NL ("_Float"),		D_PRINT_FLOAT },
>   };
>   
>   CP_STATIC_IF_GLIBCPP_V3
> @@ -2727,19 +2752,26 @@ cplus_demangle_type (struct d_info *di)
>   	  break;
>   
>   	case 'F':
> -	  /* Fixed point types. DF<int bits><length><fract bits><sat>  */
> -	  ret = d_make_empty (di);
> -	  ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
> -	  if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
> -	    /* For demangling we don't care about the bits.  */
> -	    d_number (di);
> -	  ret->u.s_fixed.length = cplus_demangle_type (di);
> -	  if (ret->u.s_fixed.length == NULL)
> -	    return NULL;
> -	  d_number (di);
> -	  peek = d_next_char (di);
> -	  ret->u.s_fixed.sat = (peek == 's');
> -	  break;
> +	  /* DF<number>_ - _Float<number>.
> +	     DF<number>x - _Float<number>x.  */
> +	  {
> +	    int arg = d_number (di);
> +	    char buf[12];
> +	    char suffix = 0;
> +	    if (d_peek_char (di) == 'x')
> +	      suffix = 'x';
> +	    if (!suffix && d_peek_char (di) != '_')
> +	      return NULL;
> +	    ret
> +	      = d_make_extended_builtin_type (di,
> +					      &cplus_demangle_builtin_types[34],
> +					      arg, suffix);
> +	    d_advance (di, 1);
> +	    sprintf (buf, "%d", arg);
> +	    di->expansion += ret->u.s_extended_builtin.type->len
> +			     + strlen (buf) + (suffix != 0);
> +	    break;
> +	  }
>   
>   	case 'v':
>   	  ret = d_vector_type (di);
> @@ -4202,6 +4234,7 @@ d_count_templates_scopes (struct d_print
>       case DEMANGLE_COMPONENT_FUNCTION_PARAM:
>       case DEMANGLE_COMPONENT_SUB_STD:
>       case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
>       case DEMANGLE_COMPONENT_OPERATOR:
>       case DEMANGLE_COMPONENT_CHARACTER:
>       case DEMANGLE_COMPONENT_NUMBER:
> @@ -4210,6 +4243,7 @@ d_count_templates_scopes (struct d_print
>       case DEMANGLE_COMPONENT_MODULE_NAME:
>       case DEMANGLE_COMPONENT_MODULE_PARTITION:
>       case DEMANGLE_COMPONENT_MODULE_INIT:
> +    case DEMANGLE_COMPONENT_FIXED_TYPE:
>         break;
>   
>       case DEMANGLE_COMPONENT_TEMPLATE:
> @@ -4309,10 +4343,6 @@ d_count_templates_scopes (struct d_print
>         d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
>         break;
>   
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> -      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
> -      break;
> -
>       case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
>       case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
>       case DEMANGLE_COMPONENT_MODULE_ENTITY:
> @@ -4580,11 +4610,11 @@ d_find_pack (struct d_print_info *dpi,
>       case DEMANGLE_COMPONENT_TAGGED_NAME:
>       case DEMANGLE_COMPONENT_OPERATOR:
>       case DEMANGLE_COMPONENT_BUILTIN_TYPE:
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
>       case DEMANGLE_COMPONENT_SUB_STD:
>       case DEMANGLE_COMPONENT_CHARACTER:
>       case DEMANGLE_COMPONENT_FUNCTION_PARAM:
>       case DEMANGLE_COMPONENT_UNNAMED_TYPE:
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
>       case DEMANGLE_COMPONENT_DEFAULT_ARG:
>       case DEMANGLE_COMPONENT_NUMBER:
>         return NULL;
> @@ -5387,6 +5417,18 @@ d_print_comp_inner (struct d_print_info
>   			 dc->u.s_builtin.type->java_len);
>         return;
>   
> +    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
> +      if ((options & DMGL_JAVA) == 0)
> +	d_append_buffer (dpi, dc->u.s_extended_builtin.type->name,
> +			 dc->u.s_extended_builtin.type->len);

I don't think we need to handle DMGL_JAVA in new code.

> +      else
> +	d_append_buffer (dpi, dc->u.s_extended_builtin.type->java_name,
> +			 dc->u.s_extended_builtin.type->java_len);
> +      d_append_num (dpi, dc->u.s_extended_builtin.arg);
> +      if (dc->u.s_extended_builtin.suffix)
> +	d_append_buffer (dpi, &dc->u.s_extended_builtin.suffix, 1);
> +      return;
> +
>       case DEMANGLE_COMPONENT_VENDOR_TYPE:
>         d_print_comp (dpi, options, d_left (dc));
>         return;
> @@ -5525,22 +5567,6 @@ d_print_comp_inner (struct d_print_info
>   	return;
>         }
>   
> -    case DEMANGLE_COMPONENT_FIXED_TYPE:
> -      if (dc->u.s_fixed.sat)
> -	d_append_string (dpi, "_Sat ");
> -      /* Don't print "int _Accum".  */
> -      if (dc->u.s_fixed.length->u.s_builtin.type
> -	  != &cplus_demangle_builtin_types['i'-'a'])
> -	{
> -	  d_print_comp (dpi, options, dc->u.s_fixed.length);
> -	  d_append_char (dpi, ' ');
> -	}
> -      if (dc->u.s_fixed.accum)
> -	d_append_string (dpi, "_Accum");
> -      else
> -	d_append_string (dpi, "_Fract");
> -      return;
> -
>       case DEMANGLE_COMPONENT_ARGLIST:
>       case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
>         if (d_left (dc) != NULL)
> --- libiberty/cp-demangle.h.jj	2022-09-12 10:31:28.399537535 +0200
> +++ libiberty/cp-demangle.h	2022-09-19 15:13:26.635130450 +0200
> @@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i)
>   extern const struct demangle_operator_info cplus_demangle_operators[];
>   #endif
>   
> -#define D_BUILTIN_TYPE_COUNT (34)
> +#define D_BUILTIN_TYPE_COUNT (35)
>   
>   CP_STATIC_IF_GLIBCPP_V3
>   const struct demangle_builtin_type_info
> --- libiberty/testsuite/demangle-expected.jj	2022-09-12 10:31:28.436537023 +0200
> +++ libiberty/testsuite/demangle-expected	2022-09-19 17:00:51.603253497 +0200
> @@ -1242,8 +1242,12 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8fun
>   post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
>   #
>   --format=auto --no-params
> -_Z3xxxDFyuVb
> -xxx(unsigned long long _Fract, bool volatile)
> +_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb
> +xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile)
> +xxx
> +--format=auto --no-params
> +_Z3xxxDF32xDF64xDF128xCDF32xVb
> +xxx(_Float32x, _Float64x, _Float128x, _Float32x _Complex, bool volatile)
>   xxx
>   # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
>   --format=auto --no-params
> --- fixincludes/inclhack.def.jj	2022-09-12 10:37:19.145679055 +0200
> +++ fixincludes/inclhack.def	2022-09-19 18:14:45.768595397 +0200
> @@ -2015,6 +2015,102 @@ fix = {
>   	EOT;
>   };
>   
> +/*  glibc-2.27 to 2.36 assume GCC 7 or later supports some or all
> + *  of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C,
> + *  but doesn't for C++.
> + */
> +fix = {
> +    hackname  = glibc_cxx_floatn_1;
> +    files     = bits/floatn.h, bits/floatn-common.h;
> +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> +		"(([ \t]*/\\*[^\n]*\\*/\n)?"
> +		"([ \t]*#[ \t]*if[^\n]*\n)?"
> +		"[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
> +    c_fix     = format;
> +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
> +    test_text = <<-EOT
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	/* The literal suffix f128 exists only since GCC 7.0.  */
> +	#   define __f128(x) x##l
> +	#  else
> +	#   define __f128(x) x##f128
> +	#  endif
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
> +	#   if __LDBL_MANT_DIG__ == 113
> +	#    define __f128(x) x##l
> +	#   else
> +	#    define __f128(x) x##q
> +	#   endif
> +	#  else
> +	#   define __f128(x) x##f128
> +	#  endif
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	#   ifdef __NO_LONG_DOUBLE_MATH
> +	#    define __f64(x) x##l
> +	#   else
> +	#    define __f64(x) x
> +	#   endif
> +	#  else
> +	#   define __f64(x) x##f64
> +	#  endif
> +	EOT;
> +};
> +
> +fix = {
> +    hackname  = glibc_cxx_floatn_2;
> +    files     = bits/floatn.h, bits/floatn-common.h;
> +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> +		"(([ \t]*/\\*[^\n]*\\*/\n)?"
> +		"[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
> +    c_fix     = format;
> +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
> +    test_text = <<-EOT
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
> +	#  endif
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	typedef __float128 _Float128;
> +	#  endif
> +	EOT;
> +};
> +
> +fix = {
> +    hackname  = glibc_cxx_floatn_3;
> +    files     = bits/floatn.h, bits/floatn-common.h;
> +    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
> +		"(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?"
> +		"([ \t]*#[ \t]*if[^\n]*\n)?"
> +		"([ \t]*typedef[ \t]+[^\n]*;\n)?"
> +		"[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
> +    c_fix     = format;
> +    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
> +    test_text = <<-EOT
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	#   define __CFLOAT128 _Complex long double
> +	#  else
> +	#   define __CFLOAT128 _Complex _Float128
> +	#  endif
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	/* Add a typedef for older GCC compilers which don't natively support
> +	   _Complex _Float128.  */
> +	typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
> +	#   define __CFLOAT128 __cfloat128
> +	#  else
> +	#   define __CFLOAT128 _Complex _Float128
> +	#  endif
> +	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
> +	#   ifdef __NO_LONG_DOUBLE_MATH
> +	#    define __CFLOAT64 _Complex long double
> +	#   else
> +	#    define __CFLOAT64 _Complex double
> +	#   endif
> +	#  else
> +	#   define __CFLOAT64 _Complex _Float64
> +	#  endif
> +	EOT;
> +};
> +
>   /*  glibc-2.3.5 defines pthread mutex initializers incorrectly,
>    *  so we replace them with versions that correspond to the
>    *  definition.
> --- fixincludes/tests/base/bits/floatn.h.jj	2022-09-19 15:13:26.673129929 +0200
> +++ fixincludes/tests/base/bits/floatn.h	2022-09-19 18:16:10.934430067 +0200
> @@ -0,0 +1,74 @@
> +/*  DO NOT EDIT THIS FILE.
> +
> +    It has been auto-edited by fixincludes from:
> +
> +	"fixinc/tests/inc/bits/floatn.h"
> +
> +    This had to be done to correct non-standard usages in the
> +    original, manufacturer supplied header file.  */
> +
> +
> +
> +#if defined( GLIBC_CXX_FLOATN_1_CHECK )
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +/* The literal suffix f128 exists only since GCC 7.0.  */
> +#   define __f128(x) x##l
> +#  else
> +#   define __f128(x) x##f128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
> +#   if __LDBL_MANT_DIG__ == 113
> +#    define __f128(x) x##l
> +#   else
> +#    define __f128(x) x##q
> +#   endif
> +#  else
> +#   define __f128(x) x##f128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +#   ifdef __NO_LONG_DOUBLE_MATH
> +#    define __f64(x) x##l
> +#   else
> +#    define __f64(x) x
> +#   endif
> +#  else
> +#   define __f64(x) x##f64
> +#  endif
> +#endif  /* GLIBC_CXX_FLOATN_1_CHECK */
> +
> +
> +#if defined( GLIBC_CXX_FLOATN_2_CHECK )
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +typedef __float128 _Float128;
> +#  endif
> +#endif  /* GLIBC_CXX_FLOATN_2_CHECK */
> +
> +
> +#if defined( GLIBC_CXX_FLOATN_3_CHECK )
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +#   define __CFLOAT128 _Complex long double
> +#  else
> +#   define __CFLOAT128 _Complex _Float128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +/* Add a typedef for older GCC compilers which don't natively support
> +   _Complex _Float128.  */
> +typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
> +#   define __CFLOAT128 __cfloat128
> +#  else
> +#   define __CFLOAT128 _Complex _Float128
> +#  endif
> +#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
> +#   ifdef __NO_LONG_DOUBLE_MATH
> +#    define __CFLOAT64 _Complex long double
> +#   else
> +#    define __CFLOAT64 _Complex double
> +#   endif
> +#  else
> +#   define __CFLOAT64 _Complex _Float64
> +#  endif
> +#endif  /* GLIBC_CXX_FLOATN_3_CHECK */
> --- fixincludes/fixincl.x.jj	2022-09-12 10:37:19.144679069 +0200
> +++ fixincludes/fixincl.x	2022-09-19 18:15:18.850142748 +0200
> @@ -2,11 +2,11 @@
>    *
>    * DO NOT EDIT THIS FILE   (fixincl.x)
>    *
> - * It has been AutoGen-ed  February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16
> + * It has been AutoGen-ed  September 11, 2022 at 08:09:37 PM by AutoGen 5.18.16
>    * From the definitions    inclhack.def
>    * and the template file   fixincl
>    */
> -/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022
> +/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Sep 11 20:09:37 CEST 2022
>    *
>    * You must regenerate it.  Use the ./genfixes script.
>    *
> @@ -15,7 +15,7 @@
>    * certain ANSI-incompatible system header files which are fixed to work
>    * correctly with ANSI C and placed in a directory that GNU C will search.
>    *
> - * This file contains 267 fixup descriptions.
> + * This file contains 270 fixup descriptions.
>    *
>    * See README for more information.
>    *
> @@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4
>   
>   /* * * * * * * * * * * * * * * * * * * * * * * * * *
>    *
> + *  Description of Glibc_Cxx_Floatn_1 fix
> + */
> +tSCC zGlibc_Cxx_Floatn_1Name[] =
> +     "glibc_cxx_floatn_1";
> +
> +/*
> + *  File name selection pattern
> + */
> +tSCC zGlibc_Cxx_Floatn_1List[] =
> +  "bits/floatn.h\0bits/floatn-common.h\0";
> +/*
> + *  Machine/OS name selection pattern
> + */
> +#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL
> +
> +/*
> + *  content selection pattern - do fix if pattern found
> + */
> +tSCC zGlibc_Cxx_Floatn_1Select0[] =
> +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> +(([ \t]*/\\*[^\n\
> +]*\\*/\n\
> +)?([ \t]*#[ \t]*if[^\n\
> +]*\n\
> +)?[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
> +
> +#define    GLIBC_CXX_FLOATN_1_TEST_CT  1
> +static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = {
> +  { TT_EGREP,    zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, };
> +
> +/*
> + *  Fix Command Arguments for Glibc_Cxx_Floatn_1
> + */
> +static const char* apzGlibc_Cxx_Floatn_1Patch[] = {
> +    "format",
> +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
> +%2",
> +    (char*)NULL };
> +
> +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> + *
> + *  Description of Glibc_Cxx_Floatn_2 fix
> + */
> +tSCC zGlibc_Cxx_Floatn_2Name[] =
> +     "glibc_cxx_floatn_2";
> +
> +/*
> + *  File name selection pattern
> + */
> +tSCC zGlibc_Cxx_Floatn_2List[] =
> +  "bits/floatn.h\0bits/floatn-common.h\0";
> +/*
> + *  Machine/OS name selection pattern
> + */
> +#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL
> +
> +/*
> + *  content selection pattern - do fix if pattern found
> + */
> +tSCC zGlibc_Cxx_Floatn_2Select0[] =
> +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> +(([ \t]*/\\*[^\n\
> +]*\\*/\n\
> +)?[ \t]*typedef[ \t]+[^\n\
> +]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
> +
> +#define    GLIBC_CXX_FLOATN_2_TEST_CT  1
> +static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = {
> +  { TT_EGREP,    zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, };
> +
> +/*
> + *  Fix Command Arguments for Glibc_Cxx_Floatn_2
> + */
> +static const char* apzGlibc_Cxx_Floatn_2Patch[] = {
> +    "format",
> +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
> +%2",
> +    (char*)NULL };
> +
> +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> + *
> + *  Description of Glibc_Cxx_Floatn_3 fix
> + */
> +tSCC zGlibc_Cxx_Floatn_3Name[] =
> +     "glibc_cxx_floatn_3";
> +
> +/*
> + *  File name selection pattern
> + */
> +tSCC zGlibc_Cxx_Floatn_3List[] =
> +  "bits/floatn.h\0bits/floatn-common.h\0";
> +/*
> + *  Machine/OS name selection pattern
> + */
> +#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL
> +
> +/*
> + *  content selection pattern - do fix if pattern found
> + */
> +tSCC zGlibc_Cxx_Floatn_3Select0[] =
> +       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
> +(([ \t]*/\\*[^\n\
> +]*\n\
> +?[^\n\
> +]*\\*/\n\
> +)?([ \t]*#[ \t]*if[^\n\
> +]*\n\
> +)?([ \t]*typedef[ \t]+[^\n\
> +]*;\n\
> +)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
> +
> +#define    GLIBC_CXX_FLOATN_3_TEST_CT  1
> +static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = {
> +  { TT_EGREP,    zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, };
> +
> +/*
> + *  Fix Command Arguments for Glibc_Cxx_Floatn_3
> + */
> +static const char* apzGlibc_Cxx_Floatn_3Patch[] = {
> +    "format",
> +    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
> +%2",
> +    (char*)NULL };
> +
> +/* * * * * * * * * * * * * * * * * * * * * * * * * *
> + *
>    *  Description of Glibc_Mutex_Init fix
>    */
>   tSCC zGlibc_Mutex_InitName[] =
> @@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[]
>    *
>    *  List of all fixes
>    */
> -#define REGEX_COUNT          305
> +#define REGEX_COUNT          308
>   #define MACH_LIST_SIZE_LIMIT 187
> -#define FIX_COUNT            267
> +#define FIX_COUNT            270
>   
>   /*
>    *  Enumerate the fixes
> @@ -10977,6 +11103,9 @@ typedef enum {
>       GLIBC_C99_INLINE_2_FIXIDX,
>       GLIBC_C99_INLINE_3_FIXIDX,
>       GLIBC_C99_INLINE_4_FIXIDX,
> +    GLIBC_CXX_FLOATN_1_FIXIDX,
> +    GLIBC_CXX_FLOATN_2_FIXIDX,
> +    GLIBC_CXX_FLOATN_3_FIXIDX,
>       GLIBC_MUTEX_INIT_FIXIDX,
>       GLIBC_STDINT_FIXIDX,
>       GLIBC_STRNCPY_FIXIDX,
> @@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
>        GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
>        aGlibc_C99_Inline_4Tests,   apzGlibc_C99_Inline_4Patch, 0 },
>   
> +  {  zGlibc_Cxx_Floatn_1Name,    zGlibc_Cxx_Floatn_1List,
> +     apzGlibc_Cxx_Floatn_1Machs,
> +     GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> +     aGlibc_Cxx_Floatn_1Tests,   apzGlibc_Cxx_Floatn_1Patch, 0 },
> +
> +  {  zGlibc_Cxx_Floatn_2Name,    zGlibc_Cxx_Floatn_2List,
> +     apzGlibc_Cxx_Floatn_2Machs,
> +     GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> +     aGlibc_Cxx_Floatn_2Tests,   apzGlibc_Cxx_Floatn_2Patch, 0 },
> +
> +  {  zGlibc_Cxx_Floatn_3Name,    zGlibc_Cxx_Floatn_3List,
> +     apzGlibc_Cxx_Floatn_3Machs,
> +     GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
> +     aGlibc_Cxx_Floatn_3Tests,   apzGlibc_Cxx_Floatn_3Patch, 0 },
> +
>     {  zGlibc_Mutex_InitName,    zGlibc_Mutex_InitList,
>        apzGlibc_Mutex_InitMachs,
>        GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,
> 
> 
> 	Jakub
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
  2022-09-26 21:15         ` Jason Merrill
@ 2022-09-26 22:11           ` Jakub Jelinek
  0 siblings, 0 replies; 16+ messages in thread
From: Jakub Jelinek @ 2022-09-26 22:11 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, Joseph S. Myers, Bruce Korb, gcc-patches

On Mon, Sep 26, 2022 at 05:15:12PM -0400, Jason Merrill wrote:
> > Anyway, here is an updated patch that adds also _Float{32,64,128}x support
> > with DF{32,64,128}x mangling and demangling and the conv->bad_p + pedwarn
> > change.  __float128 is still distinct from _Float128.
> 
> Looks good with the minor adjustments below.

Thanks for the review.  Below is updated patch that I'll now retest
on x86_64-linux, i686-linux and powerpc64{,le}-linux before committing.

> Will you also add the <stdfloat> header and the changes to <limits>?

I have a partial patch that I'll perhaps make some progress on and will
incrementally regtest it, but there are parts which I'd prefer
to defer to Jonathan.

> Please add a comment to explain what you're doing with signed/unsigned
> arithmetic here.
> 
> > +	    if (cp_compare_floating_point_conversion_ranks (fp1, fp2) + 1U
> > +		<= 2U)

While I've added a comment, it occurred to me that these would be more
readable using the IN_RANGE macro (above is IN_RANGE (cp_compare..., -1, 1))
which under the hood does the same thing.

> > +	      {
> > +		/* Conversion ranks of FP1 and FP2 are equal.  */
> > +		if (TREE_CODE (t3) != REAL_TYPE
> > +		    || (cp_compare_floating_point_conversion_ranks (fp1, t3)
> > +			+ 1U > 2U))

and this is !IN_RANGE (cp_compare..., -1, 1),
so I've changed that in the patch too.

2022-09-27  Jakub Jelinek  <jakub@redhat.com>

	PR c++/106652
	PR c++/85518
gcc/
	* tree-core.h (enum tree_index): Add TI_FLOAT128T_TYPE
	enumerator.
	* tree.h (float128t_type_node): Define.
	* tree.cc (build_common_tree_nodes): Initialize float128t_type_node.
	* builtins.def (DEF_FLOATN_BUILTIN): Adjust comment now that
	_Float<N> is supported in C++ too.
	* config/i386/i386.cc (ix86_mangle_type): Only mangle as "g"
	float128t_type_node.
	* config/i386/i386-builtins.cc (ix86_init_builtin_types): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
	* config/i386/avx512fp16intrin.h (_mm_setzero_ph, _mm256_setzero_ph,
	_mm512_setzero_ph, _mm_set_sh, _mm_load_sh): Use 0.0f16 instead of
	0.0f.
	* config/ia64/ia64.cc (ia64_init_builtins): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
	* config/rs6000/rs6000-c.cc (is_float128_p): Also return true
	for float128t_type_node if non-NULL.
	* config/rs6000/rs6000.cc (rs6000_mangle_type): Don't mangle
	float128_type_node as "u9__ieee128".
	* config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Use
	float128t_type_node for __float128 instead of float128_type_node
	and create it if NULL.
gcc/c-family/
	* c-common.cc (c_common_reswords): Change _Float{16,32,64,128} and
	_Float{32,64,128}x flags from D_CONLY to 0.
	(shorten_binary_op): Punt if common_type returns error_mark_node.
	(shorten_compare): Likewise.
	(c_common_nodes_and_builtins): For C++ record _Float{16,32,64,128}
	and _Float{32,64,128}x builtin types if available.  For C++
	clear float128t_type_node.
	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
	__STDCPP_FLOAT{16,32,64,128}_T__ for C++23 if supported.
	* c-lex.cc (interpret_float): For q/Q suffixes prefer
	float128t_type_node over float128_type_node.  Allow
	{f,F}{16,32,64,128} suffixes for C++ if supported with pedwarn
	for C++20 and older.  Allow {f,F}{32,64,128}x suffixes for C++
	with pedwarn.  Don't call excess_precision_type for C++.
gcc/cp/
	* cp-tree.h (cp_compare_floating_point_conversion_ranks): Implement
	P1467R9 - Extended floating-point types and standard names except
	for std::bfloat16_t for now.  Declare.
	(extended_float_type_p): New inline function.
	* mangle.cc (write_builtin_type): Mangle float{16,32,64,128}_type_node
	as DF{16,32,64,128}_.  Mangle float{32,64,128}x_type_node as
	DF{32,64,128}x.  Remove FIXED_POINT_TYPE mangling that conflicts
	with that.
	* typeck2.cc (check_narrowing): If one of ftype or type is extended
	floating-point type, compare floating-point conversion ranks.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Handle
	CASE_RID_FLOATN_NX.
	(cp_parser_simple_type_specifier): Likewise and diagnose missing
	_Float<N> or _Float<N>x support if not supported by target.
	* typeck.cc (cp_compare_floating_point_conversion_ranks): New function.
	(cp_common_type): If both types are REAL_TYPE and one or both are
	extended floating-point types, select common type based on comparison
	of floating-point conversion ranks and subranks.
	(cp_build_binary_op): Diagnose operation with floating point arguments
	with unordered conversion ranks.
	* call.cc (standard_conversion): For floating-point conversion, if
	either from or to are extended floating-point types, set conv->bad_p
	for implicit conversion from larger to smaller conversion rank or
	with unordered conversion ranks.
	(convert_like_internal): Emit a pedwarn on such conversions.
	(build_conditional_expr): Diagnose operation with floating point
	arguments with unordered conversion ranks.
	(convert_arg_to_ellipsis): Don't promote extended floating-point types
	narrower than double to double.
	(compare_ics): Implement P1467R9 [over.ics.rank]/4 changes.
gcc/testsuite/
	* g++.dg/cpp23/ext-floating1.C: New test.
	* g++.dg/cpp23/ext-floating2.C: New test.
	* g++.dg/cpp23/ext-floating3.C: New test.
	* g++.dg/cpp23/ext-floating4.C: New test.
	* g++.dg/cpp23/ext-floating5.C: New test.
	* g++.dg/cpp23/ext-floating6.C: New test.
	* g++.dg/cpp23/ext-floating7.C: New test.
	* g++.dg/cpp23/ext-floating8.C: New test.
	* g++.dg/cpp23/ext-floating9.C: New test.
	* g++.dg/cpp23/ext-floating10.C: New test.
	* g++.dg/cpp23/ext-floating.h: New file.
	* g++.target/i386/float16-1.C: Adjust expected diagnostics.
libcpp/
	* expr.cc (interpret_float_suffix): Allow {f,F}{16,32,64,128} and
	{f,F}{32,64,128}x suffixes for C++.
include/
	* demangle.h (enum demangle_component_type): Add
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
	(struct demangle_component): Add u.s_extended_builtin member.
libiberty/
	* cp-demangle.c (d_dump): Handle
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Don't handle
	DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_make_extended_builtin_type): New function.
	(cplus_demangle_builtin_types): Add _Float entry.
	(cplus_demangle_type): For DF demangle it as _Float<N> or
	_Float<N>x rather than fixed point which conflicts with it.
	(d_count_templates_scopes): Handle
	DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  Just break; for
	DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_find_pack): Handle DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.
	Don't handle DEMANGLE_COMPONENT_FIXED_TYPE.
	(d_print_comp_inner): Likewise.
	* cp-demangle.h (D_BUILTIN_TYPE_COUNT): Bump.
	* testsuite/demangle-expected: Replace _Z3xxxDFyuVb test
	with _Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb.  Add
	_Z3xxxDF32xDF64xDF128xCDF32xVb test.
fixincludes/
	* inclhack.def (glibc_cxx_floatn_1, glibc_cxx_floatn_2,
	glibc_cxx_floatn_3): New fixes.
	* tests/base/bits/floatn.h: New file.
	* fixincl.x: Regenerated.

--- gcc/tree-core.h.jj	2022-09-20 11:21:29.928213666 +0200
+++ gcc/tree-core.h	2022-09-26 23:29:20.099534299 +0200
@@ -690,6 +690,10 @@ enum tree_index {
 			     - TI_FLOATN_NX_TYPE_FIRST		\
 			     + 1)
 
+  /* Type used by certain backends for __float128, which in C++ should be
+     distinct type from _Float128 for backwards compatibility reasons.  */
+  TI_FLOAT128T_TYPE,
+
   /* Put the complex types after their component types, so that in (sequential)
      tree streaming we can assert that their component types have already been
      handled (see tree-streamer.cc:record_common_node).  */
--- gcc/tree.h.jj	2022-09-20 11:21:29.963213186 +0200
+++ gcc/tree.h	2022-09-26 23:29:20.128533912 +0200
@@ -4302,6 +4302,10 @@ tree_strip_any_location_wrapper (tree ex
 #define float64x_type_node		global_trees[TI_FLOAT64X_TYPE]
 #define float128x_type_node		global_trees[TI_FLOAT128X_TYPE]
 
+/* Type used by certain backends for __float128, which in C++ should be
+   distinct type from _Float128 for backwards compatibility reasons.  */
+#define float128t_type_node		global_trees[TI_FLOAT128T_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]
--- gcc/tree.cc.jj	2022-09-20 11:21:29.952213336 +0200
+++ gcc/tree.cc	2022-09-26 23:29:20.164533432 +0200
@@ -9461,6 +9461,7 @@ build_common_tree_nodes (bool signed_cha
       layout_type (FLOATN_NX_TYPE_NODE (i));
       SET_TYPE_MODE (FLOATN_NX_TYPE_NODE (i), mode);
     }
+  float128t_type_node = float128_type_node;
 
   float_ptr_type_node = build_pointer_type (float_type_node);
   double_ptr_type_node = build_pointer_type (double_type_node);
--- gcc/builtins.def.jj	2022-09-20 11:21:29.554218794 +0200
+++ gcc/builtins.def	2022-09-26 23:33:36.160125086 +0200
@@ -114,9 +114,8 @@ along with GCC; see the file COPYING3.
    with an argument such as FLOAT32 to produce the enum value for the type.  If
    we are compiling for the C language with GNU extensions, we enable the name
    without the __builtin_ prefix as well as the name with the __builtin_
-   prefix.  C++ does not enable these names by default because they don't have
-   the _Float<N> and _Float<N>X keywords, and a class based library should use
-   the __builtin_ names.  */
+   prefix.  C++ does not enable these names by default because a class based
+   library should use the __builtin_ names.  */
 #undef DEF_FLOATN_BUILTIN
 #define DEF_FLOATN_BUILTIN(ENUM, NAME, TYPE, ATTRS)	\
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,	\
--- gcc/config/i386/i386.cc.jj	2022-09-23 09:02:56.555317948 +0200
+++ gcc/config/i386/i386.cc	2022-09-26 23:29:20.260532152 +0200
@@ -22735,7 +22735,10 @@ ix86_mangle_type (const_tree type)
       return "DF16_";
     case E_TFmode:
       /* __float128 is "g".  */
-      return "g";
+      if (type == float128t_type_node)
+	return "g";
+      /* _Float128 should mangle as "DF128_" done in generic code.  */
+      return NULL;
     case E_XFmode:
       /* "long double" or __float80 is "e".  */
       return "e";
--- gcc/config/i386/i386-builtins.cc.jj	2022-09-20 11:21:29.612217998 +0200
+++ gcc/config/i386/i386-builtins.cc	2022-09-26 23:29:20.314531431 +0200
@@ -1409,9 +1409,18 @@ ix86_init_builtin_types (void)
   lang_hooks.types.register_builtin_type (float80_type_node, "__float80");
 
   /* 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");
+     _Float128, so for C we only need to register the __float128 name for
+     it.  For C++, we create a distinct type which will mangle differently
+     (g) vs. _Float128 (DF128_) and behave backwards compatibly.  */
+  if (float128t_type_node == NULL_TREE)
+    {
+      float128t_type_node = make_node (REAL_TYPE);
+      TYPE_PRECISION (float128t_type_node)
+	= TYPE_PRECISION (float128_type_node);
+      SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
+      layout_type (float128t_type_node);
+    }
+  lang_hooks.types.register_builtin_type (float128t_type_node, "__float128");
 
   ix86_register_float16_builtin_type ();
 
--- gcc/config/i386/avx512fp16intrin.h.jj	2022-09-20 11:21:29.591218286 +0200
+++ gcc/config/i386/avx512fp16intrin.h	2022-09-26 23:29:20.337531125 +0200
@@ -183,21 +183,21 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_setzero_ph (void)
 {
-  return _mm_set1_ph (0.0f);
+  return _mm_set1_ph (0.0f16);
 }
 
 extern __inline __m256h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm256_setzero_ph (void)
 {
-  return _mm256_set1_ph (0.0f);
+  return _mm256_set1_ph (0.0f16);
 }
 
 extern __inline __m512h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm512_setzero_ph (void)
 {
-  return _mm512_set1_ph (0.0f);
+  return _mm512_set1_ph (0.0f16);
 }
 
 extern __inline __m128h
@@ -358,7 +358,8 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_set_sh (_Float16 __F)
 {
-  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, __F);
+  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
+		     __F);
 }
 
 /* Create a vector with element 0 as *P and the rest zero.  */
@@ -366,7 +367,7 @@ extern __inline __m128h
 __attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
 _mm_load_sh (void const *__P)
 {
-  return _mm_set_ph (0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+  return _mm_set_ph (0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16, 0.0f16,
 		     *(_Float16 const *) __P);
 }
 
--- gcc/config/ia64/ia64.cc.jj	2022-09-20 11:21:29.656217395 +0200
+++ gcc/config/ia64/ia64.cc	2022-09-26 23:29:20.370530685 +0200
@@ -10466,11 +10466,19 @@ ia64_init_builtins (void)
 	= build_pointer_type (build_qualified_type
 			      (char_type_node, TYPE_QUAL_CONST));
 
-      (*lang_hooks.types.register_builtin_type) (float128_type_node,
+      if (float128t_type_node == NULL_TREE)
+	{
+	  float128t_type_node = make_node (REAL_TYPE);
+	  TYPE_PRECISION (float128t_type_node)
+	    = TYPE_PRECISION (float128_type_node);
+	  layout_type (float128t_type_node);
+	  SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node));
+	}
+      (*lang_hooks.types.register_builtin_type) (float128t_type_node,
 						 "__float128");
 
       /* TFmode support builtins.  */
-      ftype = build_function_type_list (float128_type_node, NULL_TREE);
+      ftype = build_function_type_list (float128t_type_node, NULL_TREE);
       decl = add_builtin_function ("__builtin_infq", ftype,
 				   IA64_BUILTIN_INFQ, BUILT_IN_MD,
 				   NULL, NULL_TREE);
@@ -10481,7 +10489,7 @@ ia64_init_builtins (void)
 				   NULL, NULL_TREE);
       ia64_builtins[IA64_BUILTIN_HUGE_VALQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
 					const_string_type,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_nanq", ftype,
@@ -10496,8 +10504,8 @@ ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_NANSQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
-					float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
+					float128t_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_fabsq", ftype,
 				   IA64_BUILTIN_FABSQ, BUILT_IN_MD,
@@ -10505,9 +10513,9 @@ ia64_init_builtins (void)
       TREE_READONLY (decl) = 1;
       ia64_builtins[IA64_BUILTIN_FABSQ] = decl;
 
-      ftype = build_function_type_list (float128_type_node,
-					float128_type_node,
-					float128_type_node,
+      ftype = build_function_type_list (float128t_type_node,
+					float128t_type_node,
+					float128t_type_node,
 					NULL_TREE);
       decl = add_builtin_function ("__builtin_copysignq", ftype,
 				   IA64_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
--- gcc/config/rs6000/rs6000-c.cc.jj	2022-09-20 11:21:29.668217230 +0200
+++ gcc/config/rs6000/rs6000-c.cc	2022-09-26 23:29:20.395530351 +0200
@@ -808,6 +808,7 @@ static inline bool
 is_float128_p (tree t)
 {
   return (t == float128_type_node
+	  || (t && t == float128t_type_node)
 	  || (TARGET_IEEEQUAD
 	      && TARGET_LONG_DOUBLE_128
 	      && t == long_double_type_node));
--- gcc/config/rs6000/rs6000.cc.jj	2022-09-20 11:21:29.691216915 +0200
+++ gcc/config/rs6000/rs6000.cc	2022-09-26 23:29:20.416530071 +0200
@@ -20272,7 +20272,11 @@ rs6000_mangle_type (const_tree type)
 
   if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IBM_P (TYPE_MODE (type)))
     return "g";
-  if (SCALAR_FLOAT_TYPE_P (type) && FLOAT128_IEEE_P (TYPE_MODE (type)))
+  if (SCALAR_FLOAT_TYPE_P (type)
+      && FLOAT128_IEEE_P (TYPE_MODE (type))
+      /* _Float128 should mangle as DF128_ (done in generic code)
+	 rather than u9__ieee128 (used for __ieee128 and __float128).  */
+      && type != float128_type_node)
     return "u9__ieee128";
 
   if (type == vector_pair_type_node)
--- gcc/config/rs6000/rs6000-builtin.cc.jj	2022-09-20 11:21:29.666217258 +0200
+++ gcc/config/rs6000/rs6000-builtin.cc	2022-09-26 23:29:20.438529778 +0200
@@ -733,7 +733,22 @@ rs6000_init_builtins (void)
       if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128)
 	ieee128_float_type_node = long_double_type_node;
       else
-	ieee128_float_type_node = float128_type_node;
+	{
+	  /* For C we only need to register the __ieee128 name for
+	     it.  For C++, we create a distinct type which will mangle
+	     differently (u9__ieee128) vs. _Float128 (DF128_) and behave
+	     backwards compatibly.  */
+	  if (float128t_type_node == NULL_TREE)
+	    {
+	      float128t_type_node = make_node (REAL_TYPE);
+	      TYPE_PRECISION (float128t_type_node)
+		= TYPE_PRECISION (float128_type_node);
+	      layout_type (float128t_type_node);
+	      SET_TYPE_MODE (float128t_type_node,
+			     TYPE_MODE (float128_type_node));
+	    }
+	  ieee128_float_type_node = float128t_type_node;
+	}
       t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST);
       lang_hooks.types.register_builtin_type (ieee128_float_type_node,
 					      "__ieee128");
--- gcc/c-family/c-common.cc.jj	2022-09-24 09:07:50.533450215 +0200
+++ gcc/c-family/c-common.cc	2022-09-26 23:29:20.453529578 +0200
@@ -352,13 +352,13 @@ const struct c_common_resword c_common_r
   { "_Bool",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	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 },
+  { "_Float16",         RID_FLOAT16,    0 },
+  { "_Float32",         RID_FLOAT32,    0 },
+  { "_Float64",         RID_FLOAT64,    0 },
+  { "_Float128",        RID_FLOAT128,   0 },
+  { "_Float32x",        RID_FLOAT32X,   0 },
+  { "_Float64x",        RID_FLOAT64X,   0 },
+  { "_Float128x",       RID_FLOAT128X,  0 },
   { "_Decimal32",       RID_DFLOAT32,  D_CONLY },
   { "_Decimal64",       RID_DFLOAT64,  D_CONLY },
   { "_Decimal128",      RID_DFLOAT128, D_CONLY },
@@ -1431,8 +1431,11 @@ shorten_binary_op (tree result_type, tre
 	  == TYPE_PRECISION (TREE_TYPE (arg0)))
       && unsigned0 == unsigned1
       && (unsigned0 || !uns))
-    return c_common_signed_or_unsigned_type
-      (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+    {
+      tree ctype = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
+      if (ctype != error_mark_node)
+	return c_common_signed_or_unsigned_type (unsigned0, ctype);
+    }
 
   else if (TREE_CODE (arg0) == INTEGER_CST
 	   && (unsigned1 || !uns)
@@ -3204,9 +3207,10 @@ shorten_compare (location_t loc, tree *o
 
   else if (unsignedp0 == unsignedp1 && real1 == real2
 	   && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
-	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
+	   && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)
+	   && (type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1)))
+	      != error_mark_node)
     {
-      type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
       type = c_common_signed_or_unsigned_type (unsignedp0
 					       || TYPE_UNSIGNED (*restype_ptr),
 					       type);
@@ -4380,11 +4384,18 @@ 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++)
+  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));
+    }
+
+  /* For C, let float128t_type_node (__float128 in some backends) be the
+     same type as float128_type_node (_Float128), for C++ let those
+     be distinct types that mangle and behave differently.  */
+  if (c_dialect_cxx ())
+    float128t_type_node = NULL_TREE;
 
   /* Only supported decimal floating point extension if the target
      actually supports underlying modes. */
--- gcc/c-family/c-cppbuiltin.cc.jj	2022-09-26 20:02:45.871351509 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2022-09-26 23:29:20.454529565 +0200
@@ -1246,6 +1246,14 @@ c_cpp_builtins (cpp_reader *pfile)
     {
       if (FLOATN_NX_TYPE_NODE (i) == NULL_TREE)
 	continue;
+      if (c_dialect_cxx ()
+	  && cxx_dialect > cxx20
+	  && !floatn_nx_types[i].extended)
+	{
+	  char name[sizeof ("__STDCPP_FLOAT128_T__=1")];
+	  sprintf (name, "__STDCPP_FLOAT%d_T__=1", floatn_nx_types[i].n);
+	  cpp_define (pfile, name);
+	}
       char prefix[20], csuffix[20];
       sprintf (prefix, "FLT%d%s", floatn_nx_types[i].n,
 	       floatn_nx_types[i].extended ? "X" : "");
--- gcc/c-family/c-lex.cc.jj	2022-09-23 09:02:30.787672865 +0200
+++ gcc/c-family/c-lex.cc	2022-09-26 23:29:20.495529018 +0200
@@ -960,6 +960,10 @@ interpret_float (const cpp_token *token,
 	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
 
 	type = c_common_type_for_mode (mode, 0);
+	/* For Q suffix, prefer float128t_type_node (__float128) type
+	   over float128_type_node (_Float128) type if they are distinct.  */
+	if (type == float128_type_node && float128t_type_node)
+	  type = float128t_type_node;
 	gcc_assert (type);
       }
     else if ((flags & (CPP_N_FLOATN | CPP_N_FLOATNX)) != 0)
@@ -979,8 +983,17 @@ interpret_float (const cpp_token *token,
 	    error ("unsupported non-standard suffix on floating constant");
 	    return error_mark_node;
 	  }
+	else if (c_dialect_cxx () && !extended)
+	  {
+	    if (cxx_dialect < cxx23)
+	      pedwarn (input_location, OPT_Wpedantic,
+		       "%<f%d%> or %<F%d%> suffix on floating constant only "
+		       "available with %<-std=c++2b%> or %<-std=gnu++2b%>",
+		       n, n);
+	  }
 	else
-	  pedwarn (input_location, OPT_Wpedantic, "non-standard suffix on floating constant");
+	  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;
@@ -990,7 +1003,10 @@ interpret_float (const cpp_token *token,
     else
       type = double_type_node;
 
-  const_type = excess_precision_type (type);
+  if (c_dialect_cxx ())
+    const_type = NULL_TREE;
+  else
+    const_type = excess_precision_type (type);
   if (!const_type)
     const_type = type;
 
--- gcc/cp/cp-tree.h.jj	2022-09-26 18:39:50.509459099 +0200
+++ gcc/cp/cp-tree.h	2022-09-26 23:29:20.523528645 +0200
@@ -7946,6 +7946,7 @@ extern tree require_complete_type		(tree
 extern tree complete_type			(tree);
 extern tree complete_type_or_else		(tree, tree);
 extern tree complete_type_or_maybe_complain	(tree, tree, tsubst_flags_t);
+extern int cp_compare_floating_point_conversion_ranks (tree, tree);
 inline bool type_unknown_p			(const_tree);
 enum { ce_derived, ce_type, ce_normal, ce_exact };
 extern bool comp_except_specs			(const_tree, const_tree, int);
@@ -8688,6 +8689,18 @@ struct push_access_scope_guard
   }
 };
 
+/* True if TYPE is an extended floating-point type.  */
+
+inline bool
+extended_float_type_p (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i)
+    if (type == FLOATN_TYPE_NODE (i))
+      return true;
+  return false;
+}
+
 #if CHECKING_P
 namespace selftest {
   extern void run_cp_tests (void);
--- gcc/cp/mangle.cc.jj	2022-09-20 11:21:29.773215791 +0200
+++ gcc/cp/mangle.cc	2022-09-26 23:29:20.544528365 +0200
@@ -2648,63 +2648,24 @@ write_builtin_type (tree type)
 	write_string ("Dd");
       else if (type == dfloat128_type_node || type == fallback_dfloat128_type)
 	write_string ("De");
+      else if (type == float16_type_node)
+	write_string ("DF16_");
+      else if (type == float32_type_node)
+	write_string ("DF32_");
+      else if (type == float64_type_node)
+	write_string ("DF64_");
+      else if (type == float128_type_node)
+	write_string ("DF128_");
+      else if (type == float32x_type_node)
+	write_string ("DF32x");
+      else if (type == float64x_type_node)
+	write_string ("DF64x");
+      else if (type == float128x_type_node)
+	write_string ("DF128x");
       else
 	gcc_unreachable ();
       break;
 
-    case FIXED_POINT_TYPE:
-      write_string ("DF");
-      if (GET_MODE_IBIT (TYPE_MODE (type)) > 0)
-	write_unsigned_number (GET_MODE_IBIT (TYPE_MODE (type)));
-      if (type == fract_type_node
-	  || type == sat_fract_type_node
-	  || type == accum_type_node
-	  || type == sat_accum_type_node)
-	write_char ('i');
-      else if (type == unsigned_fract_type_node
-	       || type == sat_unsigned_fract_type_node
-	       || type == unsigned_accum_type_node
-	       || type == sat_unsigned_accum_type_node)
-	write_char ('j');
-      else if (type == short_fract_type_node
-	       || type == sat_short_fract_type_node
-	       || type == short_accum_type_node
-	       || type == sat_short_accum_type_node)
-	write_char ('s');
-      else if (type == unsigned_short_fract_type_node
-	       || type == sat_unsigned_short_fract_type_node
-	       || type == unsigned_short_accum_type_node
-	       || type == sat_unsigned_short_accum_type_node)
-	write_char ('t');
-      else if (type == long_fract_type_node
-	       || type == sat_long_fract_type_node
-	       || type == long_accum_type_node
-	       || type == sat_long_accum_type_node)
-	write_char ('l');
-      else if (type == unsigned_long_fract_type_node
-	       || type == sat_unsigned_long_fract_type_node
-	       || type == unsigned_long_accum_type_node
-	       || type == sat_unsigned_long_accum_type_node)
-	write_char ('m');
-      else if (type == long_long_fract_type_node
-	       || type == sat_long_long_fract_type_node
-	       || type == long_long_accum_type_node
-	       || type == sat_long_long_accum_type_node)
-	write_char ('x');
-      else if (type == unsigned_long_long_fract_type_node
-	       || type == sat_unsigned_long_long_fract_type_node
-	       || type == unsigned_long_long_accum_type_node
-	       || type == sat_unsigned_long_long_accum_type_node)
-	write_char ('y');
-      else
-	sorry ("mangling unknown fixed point type");
-      write_unsigned_number (GET_MODE_FBIT (TYPE_MODE (type)));
-      if (TYPE_SATURATING (type))
-	write_char ('s');
-      else
-	write_char ('n');
-      break;
-
     default:
       gcc_unreachable ();
     }
--- gcc/cp/typeck2.cc.jj	2022-09-26 20:02:45.881351375 +0200
+++ gcc/cp/typeck2.cc	2022-09-26 23:29:20.000000000 +0200
@@ -997,12 +997,25 @@ check_narrowing (tree type, tree init, t
   else if (TREE_CODE (ftype) == REAL_TYPE
 	   && TREE_CODE (type) == REAL_TYPE)
     {
-      if ((same_type_p (ftype, long_double_type_node)
-	   && (same_type_p (type, double_type_node)
-	       || same_type_p (type, float_type_node)))
-	  || (same_type_p (ftype, double_type_node)
-	      && same_type_p (type, float_type_node))
-	  || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype)))
+      if ((extended_float_type_p (ftype) || extended_float_type_p (type))
+	  ? /* "from a floating-point type T to another floating-point type
+	       whose floating-point conversion rank is neither greater than
+	       nor equal to that of T".
+	       So, it is ok if
+	       cp_compare_floating_point_conversion_ranks (ftype, type)
+	       returns -2 (type has greater conversion rank than ftype)
+	       or [-1..1] (type has equal conversion rank as ftype, possibly
+	       different subrank.  Only do this if at least one of the
+	       types is extended floating-point type, otherwise keep doing
+	       what we did before (for the sake of non-standard
+	       backend types).  */
+	    cp_compare_floating_point_conversion_ranks (ftype, type) >= 2
+	  : ((same_type_p (ftype, long_double_type_node)
+	      && (same_type_p (type, double_type_node)
+		  || same_type_p (type, float_type_node)))
+	     || (same_type_p (ftype, double_type_node)
+		 && same_type_p (type, float_type_node))
+	     || (TYPE_PRECISION (type) < TYPE_PRECISION (ftype))))
 	{
 	  if (TREE_CODE (init) == REAL_CST)
 	    {
--- gcc/cp/parser.cc.jj	2022-09-26 18:39:50.531458805 +0200
+++ gcc/cp/parser.cc	2022-09-26 23:29:20.593527711 +0200
@@ -1129,6 +1129,7 @@ cp_keyword_starts_decl_specifier_p (enum
     case RID_UNSIGNED:
     case RID_FLOAT:
     case RID_DOUBLE:
+    CASE_RID_FLOATN_NX:
     case RID_VOID:
       /* CV qualifiers.  */
     case RID_CONST:
@@ -19716,6 +19717,14 @@ cp_parser_simple_type_specifier (cp_pars
     case RID_DOUBLE:
       type = double_type_node;
       break;
+    CASE_RID_FLOATN_NX:
+      type = FLOATN_NX_TYPE_NODE (token->keyword - RID_FLOATN_NX_FIRST);
+      if (type == NULL_TREE)
+	error ("%<_Float%d%s%> is not supported on this target",
+	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].n,
+	       floatn_nx_types[token->keyword - RID_FLOATN_NX_FIRST].extended
+	       ? "x" : "");
+      break;
     case RID_VOID:
       type = void_type_node;
       break;
--- gcc/cp/typeck.cc.jj	2022-09-20 11:21:29.825215078 +0200
+++ gcc/cp/typeck.cc	2022-09-26 23:35:54.647283995 +0200
@@ -267,6 +267,133 @@ merge_type_attributes_from (tree type, t
   return cp_build_type_attribute_variant (type, attrs);
 }
 
+/* Compare floating point conversion ranks and subranks of T1 and T2
+   types.  If T1 and T2 have unordered conversion ranks, return 3.
+   If T1 has greater conversion rank than T2, return 2.
+   If T2 has greater conversion rank than T1, return -2.
+   If T1 has equal conversion rank as T2, return -1, 0 or 1 depending
+   on if T1 has smaller, equal or greater conversion subrank than
+   T2.  */
+
+int
+cp_compare_floating_point_conversion_ranks (tree t1, tree t2)
+{
+  tree mv1 = TYPE_MAIN_VARIANT (t1);
+  tree mv2 = TYPE_MAIN_VARIANT (t2);
+  int extended1 = 0;
+  int extended2 = 0;
+
+  if (mv1 == mv2)
+    return 0;
+
+  for (int i = 0; i < NUM_FLOATN_NX_TYPES; ++i)
+    {
+      if (mv1 == FLOATN_NX_TYPE_NODE (i))
+	extended1 = i + 1;
+      if (mv2 == FLOATN_NX_TYPE_NODE (i))
+	extended2 = i + 1;
+    }
+  if (extended2 && !extended1)
+    {
+      int ret = cp_compare_floating_point_conversion_ranks (t2, t1);
+      return ret == 3 ? 3 : -ret;
+    }
+
+  const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1));
+  const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2));
+  gcc_assert (fmt1->b == 2 && fmt2->b == 2);
+  /* For {ibm,mips}_extended_format formats, the type has variable
+     precision up to ~2150 bits when the first double is around maximum
+     representable double and second double is subnormal minimum.
+     So, e.g. for __ibm128 vs. std::float128_t, they have unordered
+     ranks.  */
+  int p1 = (MODE_COMPOSITE_P (TYPE_MODE (t1))
+	    ? fmt1->emax - fmt1->emin + fmt1->p - 1 : fmt1->p);
+  int p2 = (MODE_COMPOSITE_P (TYPE_MODE (t2))
+	    ? fmt2->emax - fmt2->emin + fmt2->p - 1 : fmt2->p);
+  /* The rank of a floating point type T is greater than the rank of
+     any floating-point type whose set of values is a proper subset
+     of the set of values of T.  */
+  if ((p1 > p2 && fmt1->emax >= fmt2->emax)
+       || (p1 == p2 && fmt1->emax > fmt2->emax))
+    return 2;
+  if ((p1 < p2 && fmt1->emax <= fmt2->emax)
+       || (p1 == p2 && fmt1->emax < fmt2->emax))
+    return -2;
+  if ((p1 > p2 && fmt1->emax < fmt2->emax)
+       || (p1 < p2 && fmt1->emax > fmt2->emax))
+    return 3;
+  if (!extended1 && !extended2)
+    {
+      /* The rank of long double is greater than the rank of double, which
+	 is greater than the rank of float.  */
+      if (t1 == long_double_type_node)
+	return 2;
+      else if (t2 == long_double_type_node)
+	return -2;
+      if (t1 == double_type_node)
+	return 2;
+      else if (t2 == double_type_node)
+	return -2;
+      if (t1 == float_type_node)
+	return 2;
+      else if (t2 == float_type_node)
+	return -2;
+      return 0;
+    }
+  /* Two extended floating-point types with the same set of values have equal
+     ranks.  */
+  if (extended1 && extended2)
+    {
+      if ((extended1 <= NUM_FLOATN_TYPES) == (extended2 <= NUM_FLOATN_TYPES))
+	{
+	  /* Prefer higher extendedN value.  */
+	  if (extended1 > extended2)
+	    return 1;
+	  else if (extended1 < extended2)
+	    return -1;
+	  else
+	    return 0;
+	}
+      else if (extended1 <= NUM_FLOATN_TYPES)
+	/* Prefer _FloatN type over _FloatMx type.  */
+	return 1;
+      else if (extended2 <= NUM_FLOATN_TYPES)
+	return -1;
+      else
+	return 0;
+    }
+
+  /* gcc_assert (extended1 && !extended2);  */
+  tree *p;
+  int cnt = 0;
+  for (p = &float_type_node; p <= &long_double_type_node; ++p)
+    {
+      const struct real_format *fmt3 = REAL_MODE_FORMAT (TYPE_MODE (*p));
+      gcc_assert (fmt3->b == 2);
+      int p3 = (MODE_COMPOSITE_P (TYPE_MODE (*p))
+		? fmt3->emax - fmt3->emin + fmt3->p - 1 : fmt3->p);
+      if (p1 == p3 && fmt1->emax == fmt3->emax)
+	++cnt;
+    }
+  /* An extended floating-point type with the same set of values
+     as exactly one cv-unqualified standard floating-point type
+     has a rank equal to the rank of that standard floating-point
+     type.
+
+     An extended floating-point type with the same set of values
+     as more than one cv-unqualified standard floating-point type
+     has a rank equal to the rank of double.
+
+     Thus, if the latter is true and t2 is long double, t2
+     has higher rank.  */
+  if (cnt > 1 && mv2 == long_double_type_node)
+    return -2;
+  /* Otherwise, they have equal rank, but extended types
+     (other than std::bfloat16_t) have higher subrank.  */
+  return 1;
+}
+
 /* Return the common type for two arithmetic types T1 and T2 under the
    usual arithmetic conversions.  The default conversions have already
    been applied, and enumerated types converted to their compatible
@@ -337,6 +464,23 @@ cp_common_type (tree t1, tree t2)
   if (code2 == REAL_TYPE && code1 != REAL_TYPE)
     return build_type_attribute_variant (t2, attributes);
 
+  if (code1 == REAL_TYPE
+      && (extended_float_type_p (t1) || extended_float_type_p (t2)))
+    {
+      tree mv1 = TYPE_MAIN_VARIANT (t1);
+      tree mv2 = TYPE_MAIN_VARIANT (t2);
+      if (mv1 == mv2)
+	return build_type_attribute_variant (t1, attributes);
+
+      int cmpret = cp_compare_floating_point_conversion_ranks (mv1, mv2);
+      if (cmpret == 3)
+	return error_mark_node;
+      else if (cmpret >= 0)
+	return build_type_attribute_variant (t1, attributes);
+      else
+	return build_type_attribute_variant (t2, attributes);
+    }
+
   /* Both real or both integers; use the one with greater precision.  */
   if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
     return build_type_attribute_variant (t1, attributes);
@@ -5037,7 +5181,20 @@ cp_build_binary_op (const op_location_t
        = targetm.invalid_binary_op (code, type0, type1)))
     {
       if (complain & tf_error)
-	error (invalid_op_diag);
+	{
+	  if (code0 == REAL_TYPE
+	      && code1 == REAL_TYPE
+	      && (extended_float_type_p (type0)
+		  || extended_float_type_p (type1))
+	      && cp_compare_floating_point_conversion_ranks (type0,
+							     type1) == 3)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  else
+	    error (invalid_op_diag);
+	}
       return error_mark_node;
     }
 
@@ -5907,6 +6064,19 @@ cp_build_binary_op (const op_location_t
       && (shorten || common || short_compare))
     {
       result_type = cp_common_type (type0, type1);
+      if (result_type == error_mark_node
+	  && code0 == REAL_TYPE
+	  && code1 == REAL_TYPE
+	  && (extended_float_type_p (type0) || extended_float_type_p (type1))
+	  && cp_compare_floating_point_conversion_ranks (type0, type1) == 3)
+	{
+	  if (complain & tf_error)
+	    {
+	      rich_location richloc (line_table, location);
+	      binary_op_error (&richloc, code, type0, type1);
+	    }
+	  return error_mark_node;
+	}
       if (complain & tf_warning)
 	{
 	  do_warn_double_promotion (result_type, type0, type1,
--- gcc/cp/call.cc.jj	2022-09-20 11:21:29.725216449 +0200
+++ gcc/cp/call.cc	2022-09-26 23:56:49.834586261 +0200
@@ -1541,6 +1541,22 @@ standard_conversion (tree to, tree from,
 	   || (underlying_type && same_type_p (to, underlying_type)))
 	  && next_conversion (conv)->rank <= cr_promotion)
 	conv->rank = cr_promotion;
+
+      /* A prvalue of floating-point type can be converted to a prvalue of
+	 another floating-point type with a greater or equal conversion
+	 rank ([conv.rank]).  A prvalue of standard floating-point type can
+	 be converted to a prvalue of another standard floating-point type.
+	 For backwards compatibility with handling __float128 and other
+	 non-standard floating point types, allow all implicit floating
+	 point conversions if neither type is extended floating-point
+	 type and if at least one of them is, fail if they have unordered
+	 conversion rank or from has higher conversion rank.  */
+      if (fcode == REAL_TYPE
+	  && tcode == REAL_TYPE
+	  && (extended_float_type_p (from)
+	      || extended_float_type_p (to))
+	  && cp_compare_floating_point_conversion_ranks (from, to) >= 2)
+	conv->bad_p = true;
     }
   else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
 	   && vector_types_convertible_p (from, to, false))
@@ -5842,6 +5858,21 @@ build_conditional_expr (const op_locatio
       /* In this case, there is always a common type.  */
       result_type = type_after_usual_arithmetic_conversions (arg2_type,
 							     arg3_type);
+      if (result_type == error_mark_node
+	  && TREE_CODE (arg2_type) == REAL_TYPE
+	  && TREE_CODE (arg3_type) == REAL_TYPE
+	  && (extended_float_type_p (arg2_type)
+	      || extended_float_type_p (arg3_type))
+	  && cp_compare_floating_point_conversion_ranks (arg2_type,
+							 arg3_type) == 3)
+	{
+	  if (complain & tf_error)
+	    error_at (loc, "operands to %<?:%> of types %qT and %qT "
+			   "have unordered conversion rank",
+		      arg2_type, arg3_type);
+	  return error_mark_node;
+	}
+
       if (complain & tf_warning)
 	do_warn_double_promotion (result_type, arg2_type, arg3_type,
 				  "implicit conversion from %qH to %qI to "
@@ -7906,6 +7937,27 @@ convert_like_internal (conversion *convs
 				"direct-initialization",
 				totype, TREE_TYPE (expr));
 
+      if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
+	  && TREE_CODE (totype) == REAL_TYPE
+	  && (extended_float_type_p (TREE_TYPE (expr))
+	      || extended_float_type_p (totype)))
+	switch (cp_compare_floating_point_conversion_ranks (TREE_TYPE (expr),
+							    totype))
+	  {
+	  case 2:
+	    pedwarn (loc, 0, "converting to %qH from %qI with greater "
+			     "conversion rank", totype, TREE_TYPE (expr));
+	    complained = true;
+	    break;
+	  case 3:
+	    pedwarn (loc, 0, "converting to %qH from %qI with unordered "
+			     "conversion ranks", totype, TREE_TYPE (expr));
+	    complained = true;
+	    break;
+	  default:
+	    break;
+	  }
+
       for (; t ; t = next_conversion (t))
 	{
 	  if (t->kind == ck_user && t->cand->reason)
@@ -8531,7 +8583,8 @@ convert_arg_to_ellipsis (tree arg, tsubs
   if (TREE_CODE (arg_type) == REAL_TYPE
       && (TYPE_PRECISION (arg_type)
 	  < TYPE_PRECISION (double_type_node))
-      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type)))
+      && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (arg_type))
+      && !extended_float_type_p (arg_type))
     {
       if ((complain & tf_warning)
 	  && warn_double_promotion && !c_inhibit_evaluation_warnings)
@@ -11719,6 +11772,81 @@ compare_ics (conversion *ics1, conversio
 	return 1;
     }
 
+  {
+    /* A conversion in either direction between floating-point type FP1 and
+       floating-point type FP2 is better than a conversion in the same
+       direction between FP1 and arithmetic type T3 if
+       - the floating-point conversion rank of FP1 is equal to the rank of
+	 FP2, and
+       - T3 is not a floating-point type, or T3 is a floating-point type
+	 whose rank is not equal to the rank of FP1, or the floating-point
+	 conversion subrank of FP2 is greater than the subrank of T3.  */
+    tree fp1 = from_type1;
+    tree fp2 = to_type1;
+    tree fp3 = from_type2;
+    tree t3 = to_type2;
+    int ret = 1;
+    if (TYPE_MAIN_VARIANT (fp2) == TYPE_MAIN_VARIANT (t3))
+      {
+	std::swap (fp1, fp2);
+	std::swap (fp3, t3);
+      }
+    if (TYPE_MAIN_VARIANT (fp1) == TYPE_MAIN_VARIANT (fp3)
+	&& TREE_CODE (fp1) == REAL_TYPE
+	/* Only apply this rule if at least one of the 3 types is
+	   extended floating-point type, otherwise keep them as
+	   before for compatibility reasons with types like __float128.
+	   float, double and long double alone have different conversion
+	   ranks and so when just those 3 types are involved, this
+	   rule doesn't trigger.  */
+	&& (extended_float_type_p (fp1)
+	    || (TREE_CODE (fp2) == REAL_TYPE && extended_float_type_p (fp2))
+	    || (TREE_CODE (t3) == REAL_TYPE && extended_float_type_p (t3))))
+      {
+	if (TREE_CODE (fp2) != REAL_TYPE)
+	  {
+	    ret = -ret;
+	    std::swap (fp2, t3);
+	  }
+	if (TREE_CODE (fp2) == REAL_TYPE)
+	  {
+	    /* cp_compare_floating_point_conversion_ranks returns -1, 0 or 1
+	       if the conversion rank is equal (-1 or 1 if the subrank is
+	       different).  */
+	    if (IN_RANGE (cp_compare_floating_point_conversion_ranks (fp1,
+								      fp2),
+			  -1, 1))
+	      {
+		/* Conversion ranks of FP1 and FP2 are equal.  */
+		if (TREE_CODE (t3) != REAL_TYPE
+		    || !IN_RANGE (cp_compare_floating_point_conversion_ranks
+								(fp1, t3),
+				  -1, 1))
+		  /* FP1 <-> FP2 conversion is better.  */
+		  return ret;
+		int c = cp_compare_floating_point_conversion_ranks (fp2, t3);
+		gcc_assert (IN_RANGE (c, -1, 1));
+		if (c == 1)
+		  /* Conversion subrank of FP2 is greater than subrank of T3.
+		     FP1 <-> FP2 conversion is better.  */
+		  return ret;
+		else if (c == -1)
+		  /* Conversion subrank of FP2 is less than subrank of T3.
+		     FP1 <-> T3 conversion is better.  */
+		  return -ret;
+	      }
+	    else if (TREE_CODE (t3) == REAL_TYPE
+		     && IN_RANGE (cp_compare_floating_point_conversion_ranks
+								(fp1, t3),
+				  -1, 1))
+	      /* Conversion ranks of FP1 and FP2 are not equal, conversion
+		 ranks of FP1 and T3 are equal.
+		 FP1 <-> T3 conversion is better.  */
+	      return -ret;
+	  }
+      }
+  }
+
   if (TYPE_PTR_P (from_type1)
       && TYPE_PTR_P (from_type2)
       && TYPE_PTR_P (to_type1)
--- gcc/testsuite/g++.dg/cpp23/ext-floating1.C.jj	2022-09-26 23:29:20.677526591 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating1.C	2022-09-26 23:29:20.677526591 +0200
@@ -0,0 +1,447 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+static_assert (!is_same<float, double>::value);
+static_assert (!is_same<float, long double>::value);
+static_assert (!is_same<double, long double>::value);
+static_assert (is_same<decltype (0.0f), float>::value);
+static_assert (is_same<decltype (0.0F), float>::value);
+static_assert (is_same<decltype (0.0), double>::value);
+static_assert (is_same<decltype (0.0l), long double>::value);
+static_assert (is_same<decltype (0.0L), long double>::value);
+static_assert (is_same<decltype (0.0f + 0.0F), float>::value);
+static_assert (is_same<decltype (0.0F + 0.0f), float>::value);
+static_assert (is_same<decltype (0.0 + 0.0), double>::value);
+static_assert (is_same<decltype (0.0l + 0.0L), long double>::value);
+static_assert (is_same<decltype (0.0L + 0.0l), long double>::value);
+#ifdef __SIZEOF_FLOAT128__
+static_assert (is_same<decltype (0.0q), __float128>::value);
+static_assert (is_same<decltype (0.0Q), __float128>::value);
+static_assert (is_same<decltype (0.0q + 0.0q), __float128>::value);
+static_assert (is_same<decltype (0.0Q + 0.0Q), __float128>::value);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float, float16_t>::value);
+static_assert (!is_same<double, float16_t>::value);
+static_assert (!is_same<long double, float16_t>::value);
+static_assert (is_same<decltype (0.0f16), float16_t>::value);
+static_assert (is_same<decltype (0.0F16), float16_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f16), float16_t>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0F16), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float, float32_t>::value);
+static_assert (!is_same<double, float32_t>::value);
+static_assert (!is_same<long double, float32_t>::value);
+static_assert (!is_same<decltype (0.0f), float32_t>::value);
+static_assert (!is_same<decltype (0.0F), float32_t>::value);
+static_assert (is_same<decltype (0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32), float32_t>::value);
+static_assert (!is_same<decltype (0.0f32), float>::value);
+static_assert (!is_same<decltype (0.0F32), float>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F32), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float, float64_t>::value);
+static_assert (!is_same<double, float64_t>::value);
+static_assert (!is_same<long double, float64_t>::value);
+static_assert (!is_same<decltype (0.0), float64_t>::value);
+static_assert (is_same<decltype (0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64), float64_t>::value);
+static_assert (!is_same<decltype (0.0f64), double>::value);
+static_assert (!is_same<decltype (0.0F64), double>::value);
+static_assert (is_same<decltype (0.0f64 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F64), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float, float128_t>::value);
+static_assert (!is_same<double, float128_t>::value);
+static_assert (!is_same<long double, float128_t>::value);
+static_assert (!is_same<decltype (0.0l), float128_t>::value);
+static_assert (!is_same<decltype (0.0L), float128_t>::value);
+static_assert (is_same<decltype (0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128), float128_t>::value);
+static_assert (!is_same<decltype (0.0f128), long double>::value);
+static_assert (!is_same<decltype (0.0F128), long double>::value);
+static_assert (is_same<decltype (0.0f128 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F128), float128_t>::value);
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<float128_t, __float128>::value);
+static_assert (!is_same<decltype (0.0q), float128_t>::value);
+static_assert (!is_same<decltype (0.0Q), float128_t>::value);
+static_assert (!is_same<decltype (0.0f128), __float128>::value);
+static_assert (!is_same<decltype (0.0F128), __float128>::value);
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+static_assert (!is_same<float, bfloat16_t>::value);
+static_assert (!is_same<double, bfloat16_t>::value);
+static_assert (!is_same<long double, bfloat16_t>::value);
+static_assert (is_same<decltype (0.0bf16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0BF16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0bf16), bfloat16_t>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0BF16), bfloat16_t>::value);
+#endif
+#ifdef __FLT32X_MANT_DIG__
+static_assert (!is_same<float, _Float32x>::value);
+static_assert (!is_same<double, _Float32x>::value);
+static_assert (!is_same<long double, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F), _Float32x>::value);
+static_assert (is_same<decltype (0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float>::value);
+static_assert (!is_same<decltype (0.0F32x), float>::value);
+static_assert (is_same<decltype (0.0f32x + 0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F32x), _Float32x>::value);
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float16_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f16), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F16), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float16_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float32_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F32), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float32_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float64_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f64), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F64), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float64_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float128_t, _Float32x>::value);
+static_assert (!is_same<decltype (0.0f128), _Float32x>::value);
+static_assert (!is_same<decltype (0.0F128), _Float32x>::value);
+static_assert (!is_same<decltype (0.0f32x), float128_t>::value);
+static_assert (!is_same<decltype (0.0F32x), float128_t>::value);
+#endif
+#endif
+#ifdef __FLT64X_MANT_DIG__
+static_assert (!is_same<float, _Float64x>::value);
+static_assert (!is_same<double, _Float64x>::value);
+static_assert (!is_same<long double, _Float64x>::value);
+static_assert (!is_same<decltype (0.0), _Float64x>::value);
+static_assert (is_same<decltype (0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), double>::value);
+static_assert (!is_same<decltype (0.0F64x), double>::value);
+static_assert (is_same<decltype (0.0f64x + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F64x), _Float64x>::value);
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float16_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f16), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F16), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float16_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float32_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f32), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F32), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float32_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float64_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F64), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float64_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float128_t, _Float64x>::value);
+static_assert (!is_same<decltype (0.0f128), _Float64x>::value);
+static_assert (!is_same<decltype (0.0F128), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), float128_t>::value);
+static_assert (!is_same<decltype (0.0F64x), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<_Float64x, __float128>::value);
+static_assert (!is_same<decltype (0.0q), _Float64x>::value);
+static_assert (!is_same<decltype (0.0Q), _Float64x>::value);
+static_assert (!is_same<decltype (0.0f64x), __float128>::value);
+static_assert (!is_same<decltype (0.0F64x), __float128>::value);
+#endif
+#endif
+#ifdef __FLT128X_MANT_DIG__
+static_assert (!is_same<float, _Float128x>::value);
+static_assert (!is_same<double, _Float128x>::value);
+static_assert (!is_same<long double, _Float128x>::value);
+static_assert (!is_same<decltype (0.0l), _Float128x>::value);
+static_assert (!is_same<decltype (0.0L), _Float128x>::value);
+static_assert (is_same<decltype (0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), long double>::value);
+static_assert (!is_same<decltype (0.0F128x), long double>::value);
+static_assert (is_same<decltype (0.0f128x + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F128x), _Float128x>::value);
+#ifdef __STDCPP_FLOAT16_T__
+static_assert (!is_same<float16_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f16), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F16), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float16_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float16_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+static_assert (!is_same<float32_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f32), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F32), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float32_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float32_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+static_assert (!is_same<float64_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f64), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F64), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float64_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float64_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+static_assert (!is_same<float128_t, _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128), _Float128x>::value);
+static_assert (!is_same<decltype (0.0F128), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), float128_t>::value);
+static_assert (!is_same<decltype (0.0F128x), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (!is_same<_Float128x, __float128>::value);
+static_assert (!is_same<decltype (0.0q), _Float128x>::value);
+static_assert (!is_same<decltype (0.0Q), _Float128x>::value);
+static_assert (!is_same<decltype (0.0f128x), __float128>::value);
+static_assert (!is_same<decltype (0.0F128x), __float128>::value);
+#endif
+#endif
+static_assert (is_same<decltype (0.0f + 0.0), double>::value);
+static_assert (is_same<decltype (0.0 + 0.0F), double>::value);
+static_assert (is_same<decltype (0.0L + 0.0), long double>::value);
+static_assert (is_same<decltype (0.0 + 0.0L), long double>::value);
+static_assert (is_same<decltype (0.0L + 0.0f), long double>::value);
+static_assert (is_same<decltype (0.0F + 0.0l), long double>::value);
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
+static_assert (!is_same<float16_t, float32_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F16), float32_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<float16_t, float64_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F16), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float16_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f16 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F16), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT32X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f16 + 0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F16), _Float32x>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT64X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f16 + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F16), _Float64x>::value);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f16 + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F16), _Float128x>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<float32_t, float64_t>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F32), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float32_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f32 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F32), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT32X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f32 + 0.0f32x), _Float32x>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F32), _Float32x>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT64X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f32 + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F32), _Float64x>::value);
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f32 + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F32), _Float128x>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<float64_t, float128_t>::value);
+static_assert (is_same<decltype (0.0f64 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT32X_MANT_DIG__) \
+    && __FLT64_MAX_EXP__ == __FLT32X_MAX_EXP__ \
+    && __FLT64_MANT_DIG__ == __FLT32X_MANT_DIG__
+static_assert (is_same<decltype (0.0f64 + 0.0f32x), float64_t>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F64), float64_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT64X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f64 + 0.0f64x), _Float64x>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F64), _Float64x>::value);
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f64 + 0.0f128x), _Float128x>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F64), _Float128x>::value);
+#endif
+#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT32X_MANT_DIG__) \
+    && __FLT128_MAX_EXP__ >= __FLT32X_MAX_EXP__ \
+    && __FLT128_MANT_DIG__ >= __FLT32X_MANT_DIG__
+static_assert (is_same<decltype (0.0f128 + 0.0f32x), float128_t>::value);
+static_assert (is_same<decltype (0.0F32x + 0.0F128), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT64X_MANT_DIG__) \
+    && __FLT128_MAX_EXP__ >= __FLT64X_MAX_EXP__ \
+    && __FLT128_MANT_DIG__ >= __FLT64X_MANT_DIG__
+static_assert (is_same<decltype (0.0f128 + 0.0f64x), float128_t>::value);
+static_assert (is_same<decltype (0.0F64x + 0.0F128), float128_t>::value);
+#endif
+#if defined(__STDCPP_FLOAT128_T__) && defined(__FLT128X_MANT_DIG__)
+static_assert (is_same<decltype (0.0f128 + 0.0f128x), _Float128>::value);
+static_assert (is_same<decltype (0.0F128x + 0.0F128), _Float128>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT32_T__)
+static_assert (!is_same<bfloat16_t, float32_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0BF16), float32_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT64_T__)
+static_assert (!is_same<bfloat16_t, float64_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0BF16), float64_t>::value);
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(__STDCPP_FLOAT128_T__)
+static_assert (!is_same<bfloat16_t, float128_t>::value);
+static_assert (is_same<decltype (0.0bf16 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0BF16), float128_t>::value);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+#if __FLT_MAX_EXP__ > __FLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f16), float>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0F), float>::value);
+#endif
+#if __DBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f16), double>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f16), long double>::value);
+static_assert (is_same<decltype (0.0F16 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+#if __FLT_MAX_EXP__ == __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ == __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f32), float32_t>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0F), float32_t>::value);
+#endif
+#if __DBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __DBL_MANT_DIG__ > __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f32), double>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT32_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT32_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f32), long double>::value);
+static_assert (is_same<decltype (0.0F32 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+#if __FLT_MAX_EXP__ < __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0F), float64_t>::value);
+#endif
+#if __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f64), float64_t>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0), float64_t>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ > __FLT64_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
+#endif
+#if __LDBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __LDBL_MANT_DIG__ == __FLT64_MANT_DIG__ \
+    && __DBL_MAX_EXP__ == __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ == __FLT64_MANT_DIG__
+// An extended floating-point type with the same set of values as more than one
+// cv-unqualified standard floating-point type has a rank equal to the rank of
+// double.
+// Then long double will have higher rank than float64_t.
+static_assert (is_same<decltype (0.0L + 0.0f64), long double>::value);
+static_assert (is_same<decltype (0.0F64 + 0.0l), long double>::value);
+#endif
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+#if __FLT_MAX_EXP__ < __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ < __FLT128_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0F), float128_t>::value);
+#endif
+#if __DBL_MAX_EXP__ < __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ < __FLT128_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0), float128_t>::value);
+#endif
+#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ \
+    && __LDBL_MANT_DIG__ != 106 // IBM extended long double and IEEE quad are unordered.
+static_assert (is_same<decltype (0.0L + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0l), float128_t>::value);
+#endif
+#ifdef __SIZEOF_FLOAT128__
+static_assert (is_same<decltype (0.0Q + 0.0f128), float128_t>::value);
+static_assert (is_same<decltype (0.0F128 + 0.0q), float128_t>::value);
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+#if __FLT_MAX_EXP__ > __BFLT16_MAX_EXP__ && __FLT_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0f + 0.0bf16), float>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0F), float>::value);
+#endif
+#if __DBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __DBL_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0 + 0.0bf16), double>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0), double>::value);
+#endif
+#if __LDBL_MAX_EXP__ > __BFLT16_MAX_EXP__ && __LDBL_MANT_DIG__ > __BFLT16_MANT_DIG__
+static_assert (is_same<decltype (0.0L + 0.0bf16), long double>::value);
+static_assert (is_same<decltype (0.0BF16 + 0.0l), long double>::value);
+#endif
+#endif
+
+void foo (float) {}
+void foo (double) {}
+void foo (long double) {}
+#ifdef __STDCPP_FLOAT16_T__
+void foo (float16_t) {}
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+void foo (float32_t) {}
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+void foo (float64_t) {}
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+void foo (float128_t) {}
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+void foo (bfloat16_t) {}
+#endif
+#ifdef __FLT32X_MANT_DIG__
+void foo (_Float32x) {}
+#endif
+#ifdef __FLT64X_MANT_DIG__
+void foo (_Float64x) {}
+#endif
+#ifdef __FLT128X_MANT_DIG__
+void foo (_Float128x) {}
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating2.C.jj	2022-09-26 23:29:20.677526591 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating2.C	2022-09-26 23:29:20.677526591 +0200
@@ -0,0 +1,157 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+float fa = 1.0f;
+float fb = (float) 1.0f;
+float fc = 1.0;
+float fd = (float) 1.0;
+float fe = 1.0L;
+float ff = (float) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float fg = 1.0Q;
+float fh = (float) 1.0Q;
+#endif
+double da = 1.0f;
+double db = (double) 1.0f;
+double dc = 1.0;
+double dd = (double) 1.0;
+double de = 1.0L;
+double df = (double) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+double dg = 1.0Q;
+double dh = (double) 1.0Q;
+#endif
+long double lda = 1.0f;
+long double ldb = (long double) 1.0f;
+long double ldc = 1.0;
+long double ldd = (long double) 1.0;
+long double lde = 1.0L;
+long double ldf = (long double) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+long double ldg = 1.0Q;
+long double ldh = (long double) 1.0Q;
+__float128 qa = 1.0f;
+__float128 qb = (__float128) 1.0f;
+__float128 qc = 1.0;
+__float128 qd = (__float128) 1.0;
+__float128 qe = 1.0L;
+__float128 qf = (__float128) 1.0L;
+__float128 qg = 1.0Q;
+__float128 qh = (__float128) 1.0Q;
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16a = 1.0F16;
+float16_t f16b = (float16_t) 1.0F16;
+#ifdef __STDCPP_FLOAT32_T__
+float16_t f16c = 1.0F32;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float32' with greater conversion rank" "" { target { float16 && float32 } } }
+float16_t f16d = (float16_t) 1.0F32;
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float16_t f16e = 1.0F64;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float64' with greater conversion rank" "" { target { float16 && float64 } } }
+float16_t f16f = (float16_t) 1.0F64;
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float16_t f16g = 1.0F128;		// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '_Float128' with greater conversion rank" "" { target { float16 && float128 } } }
+float16_t f16h = (float16_t) 1.0F128;
+#endif
+float16_t f16j = (float16_t) 1.0f;
+float16_t f16l = (float16_t) 1.0;
+float16_t f16n = (float16_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float16_t f16p = (float16_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+#ifdef __STDCPP_FLOAT16_T__
+float32_t f32a = 1.0F16;
+float32_t f32b = (float32_t) 1.0F16;
+#endif
+float32_t f32c = 1.0F32;
+float32_t f32d = (float32_t) 1.0F32;
+#ifdef __STDCPP_FLOAT64_T__
+float32_t f32e = 1.0F64;		// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float64' with greater conversion rank" "" { target { float32 && float64 } } }
+float32_t f32f = (float32_t) 1.0F64;
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float32_t f32g = 1.0F128;		// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '_Float128' with greater conversion rank" "" { target { float32 && float128 } } }
+float32_t f32h = (float32_t) 1.0F128;
+#endif
+#if __FLT_MAX_EXP__ <= __FLT32_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT32_MANT_DIG__
+float32_t f32i = 1.0f;
+#endif
+float32_t f32j = (float32_t) 1.0f;
+float32_t f32l = (float32_t) 1.0;
+float32_t f32n = (float32_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float32_t f32p = (float32_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+#ifdef __STDCPP_FLOAT16_T__
+float64_t f64a = 1.0F16;
+float64_t f64b = (float64_t) 1.0F16;
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float64_t f64c = 1.0F32;
+float64_t f64d = (float64_t) 1.0F32;
+#endif
+float64_t f64e = 1.0F64;
+float64_t f64f = (float64_t) 1.0F64;
+#ifdef __STDCPP_FLOAT128_T__
+float64_t f64g = 1.0F128;		// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '_Float128' with greater conversion rank" "" { target { float64 && float128 } } }
+float64_t f64h = (float64_t) 1.0F128;
+#endif
+#if __FLT_MAX_EXP__ <= __FLT64_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT64_MANT_DIG__
+float64_t f64i = 1.0f;
+#endif
+float64_t f64j = (float64_t) 1.0f;
+#if __DBL_MAX_EXP__ <= __FLT64_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT64_MANT_DIG__
+float64_t f64k = 1.0;
+#endif
+float64_t f64l = (float64_t) 1.0;
+float64_t f64n = (float64_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float64_t f64p = (float64_t) 1.0Q;
+#endif
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+#ifdef __STDCPP_FLOAT16_T__
+float128_t f128a = 1.0F16;
+float128_t f128b = (float128_t) 1.0F16;
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float128_t f128c = 1.0F32;
+float128_t f128d = (float128_t) 1.0F32;
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float128_t f128e = 1.0F64;
+float128_t f128f = (float128_t) 1.0F64;
+#endif
+float128_t f128g = 1.0F128;
+float128_t f128h = (float128_t) 1.0F128;
+#if __FLT_MAX_EXP__ <= __FLT128_MAX_EXP__ && __FLT_MANT_DIG__ <= __FLT128_MANT_DIG__
+float128_t f128i = 1.0f;
+#endif
+float128_t f128j = (float128_t) 1.0f;
+#if __DBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __DBL_MANT_DIG__ <= __FLT128_MANT_DIG__
+float128_t f128k = 1.0;
+#endif
+float128_t f128l = (float128_t) 1.0;
+#if __LDBL_MAX_EXP__ <= __FLT128_MAX_EXP__ && __LDBL_MANT_DIG__ <= __FLT128_MANT_DIG__ && __LDBL_MANT_DIG__ != 106
+float128_t f128m = 1.0L;
+#endif
+float128_t f128n = (float128_t) 1.0L;
+#ifdef __SIZEOF_FLOAT128__
+float128_t f128o = 1.0Q;
+float128_t f128p = (float128_t) 1.0Q;
+#endif
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating3.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating3.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,134 @@
+// P1467R9 - Extended floating-point types and standard names.
+// Variant of ext-floating2.C test with x86 specific assumptions
+// about float, double, long double and existence of __float128.
+// And some further tests.
+// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
+    || !defined(__SIZEOF_FLOAT128__)
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16i = 1.0f;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } }
+float16_t f16k = 1.0;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } }
+float16_t f16m = 1.0L;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } }
+float16_t f16o = 1.0Q;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from '__float128' with greater conversion rank" "" { target float16 } }
+#endif
+float32_t f32i = 1.0f;
+float32_t f32k = 1.0;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" }
+float32_t f32m = 1.0L;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" }
+float32_t f32o = 1.0Q;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from '__float128' with greater conversion rank" }
+float64_t f64i = 1.0f;
+float64_t f64k = 1.0;
+float64_t f64m = 1.0L;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" }
+float64_t f64o = 1.0Q;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from '__float128' with greater conversion rank" }
+float128_t f128i = 1.0f;
+float128_t f128k = 1.0;
+float128_t f128m = 1.0L;
+float128_t f128o = 1.0Q;
+
+#ifdef __STDCPP_FLOAT16_T__
+constexpr float16_t f16x = 1.0F16;
+#endif
+constexpr float32_t f32x = 2.0F32;
+constexpr float64_t f64x = 3.0F64;
+constexpr float128_t f128x = 4.0F128;
+constexpr float fx = 5.0f;
+constexpr double dx = 6.0;
+constexpr long double ldx = 7.0L;
+
+constexpr int foo (float32_t) { return 1; }
+constexpr int foo (float64_t) { return 2; }
+constexpr int bar (float) { return 3; }
+constexpr int bar (double) { return 4; }
+constexpr int bar (long double) { return 5; }
+constexpr int baz (float32_t) { return 6; }
+constexpr int baz (float64_t) { return 7; }
+constexpr int baz (float128_t) { return 8; }
+constexpr int qux (float64_t) { return 9; }
+constexpr int qux (float32_t) { return 10; }
+constexpr int fred (long double) { return 11; }
+constexpr int fred (double) { return 12; }
+constexpr int fred (float) { return 13; }
+constexpr int thud (float128_t) { return 14; }
+constexpr int thud (float64_t) { return 15; }
+constexpr int thud (float32_t) { return 16; }
+struct S {
+  constexpr operator float32_t () const { return 1.0f32; }
+  constexpr operator float64_t () const { return 2.0f64; }
+};
+struct T {
+  constexpr operator float64_t () const { return 3.0f64; }
+  constexpr operator float32_t () const { return 4.0f32; }
+};
+
+void
+test (S s, T t)
+{
+#ifdef __STDCPP_FLOAT16_T__
+  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (foo (float (2.0)) == 1);
+  static_assert (foo (double (3.0)) == 2);
+  constexpr double x (s);
+  static_assert (x == 2.0);
+#ifdef __STDCPP_FLOAT16_T__
+  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (bar (f32x) == 3);
+  static_assert (bar (f64x) == 4);
+  bar (f128x);					// { dg-error "no matching function for call to 'bar\\\(const std::float128_t\\\&\\\)'" }
+						// { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 }
+						// { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 }
+						// { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 }
+  static_assert (bar (fx) == 3);
+  static_assert (bar (dx) == 4);
+  static_assert (bar (ldx) == 5);
+#ifdef __STDCPP_FLOAT16_T__
+  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (baz (f32x) == 6);
+  static_assert (baz (f64x) == 7);
+  static_assert (baz (f128x) == 8);
+  static_assert (baz (fx) == 6);
+  static_assert (baz (dx) == 7);
+  static_assert (baz (ldx) == 8);
+#ifdef __STDCPP_FLOAT16_T__
+  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (qux (float (2.0)) == 10);
+  static_assert (qux (double (3.0)) == 9);
+  constexpr double y (t);
+  static_assert (y == 3.0);
+#ifdef __STDCPP_FLOAT16_T__
+  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (fred (f32x) == 13);
+  static_assert (fred (f64x) == 12);
+  fred (f128x);					// { dg-error "no matching function for call to 'fred\\\(const std::float128_t\\\&\\\)'" }
+						// { dg-warning "converting to 'float' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-1 }
+						// { dg-warning "converting to 'double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-2 }
+						// { dg-warning "converting to 'long double' from 'const std::float128_t' \\\{aka 'const _Float128'\\\} with greater conversion rank" "" { target *-*-* } .-3 }
+  static_assert (fred (fx) == 13);
+  static_assert (fred (dx) == 12);
+  static_assert (fred (ldx) == 11);
+#ifdef __STDCPP_FLOAT16_T__
+  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (thud (f32x) == 16);
+  static_assert (thud (f64x) == 15);
+  static_assert (thud (f128x) == 14);
+  static_assert (thud (fx) == 16);
+  static_assert (thud (dx) == 15);
+  static_assert (thud (ldx) == 14);
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating4.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating4.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,126 @@
+// P1467R9 - Extended floating-point types and standard names.
+// Variant of ext-floating3.C test with different specific assumptions
+// about float, double, long double.
+// float, double and long double are assumed to be IEEE 754 single, double
+// and quad.
+// { dg-do compile { target { c++23 && { aarch64*-*-* powerpc64le*-*-linux* riscv*-*-* s390*-*-* sparc*-*-linux* } } } }
+// { dg-options "" }
+// { dg-additional-options "-mlong-double-128" { target s390*-*-* sparc*-*-linux* } }
+// { dg-additional-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ieeelongdouble -Wno-psabi" { target powerpc64le*-*-linux* } }
+
+#include "ext-floating.h"
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ != __FLT128_MANT_DIG__
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+#ifdef __STDCPP_FLOAT16_T__
+float16_t f16i = 1.0f;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'float' with greater conversion rank" "" { target float16 } }
+float16_t f16k = 1.0;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'double' with greater conversion rank" "" { target float16 } }
+float16_t f16m = 1.0L;			// { dg-warning "converting to 'std::float16_t' \\\{aka '_Float16'\\\} from 'long double' with greater conversion rank" "" { target float16 } }
+#endif
+float32_t f32i = 1.0f;
+float32_t f32k = 1.0;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'double' with greater conversion rank" }
+float32_t f32m = 1.0L;			// { dg-warning "converting to 'std::float32_t' \\\{aka '_Float32'\\\} from 'long double' with greater conversion rank" }
+float64_t f64i = 1.0f;
+float64_t f64k = 1.0;
+float64_t f64m = 1.0L;			// { dg-warning "converting to 'std::float64_t' \\\{aka '_Float64'\\\} from 'long double' with greater conversion rank" }
+float128_t f128i = 1.0f;
+float128_t f128k = 1.0;
+float128_t f128m = 1.0L;
+
+#ifdef __STDCPP_FLOAT16_T__
+constexpr float16_t f16x = 1.0F16;
+#endif
+constexpr float32_t f32x = 2.0F32;
+constexpr float64_t f64x = 3.0F64;
+constexpr float128_t f128x = 4.0F128;
+constexpr float fx = 5.0f;
+constexpr double dx = 6.0;
+constexpr long double ldx = 7.0L;
+
+constexpr int foo (float32_t) { return 1; }
+constexpr int foo (float64_t) { return 2; }
+constexpr int bar (float) { return 3; }
+constexpr int bar (double) { return 4; }
+constexpr int bar (long double) { return 5; }
+constexpr int baz (float32_t) { return 6; }
+constexpr int baz (float64_t) { return 7; }
+constexpr int baz (float128_t) { return 8; }
+constexpr int qux (float64_t) { return 9; }
+constexpr int qux (float32_t) { return 10; }
+constexpr int fred (long double) { return 11; }
+constexpr int fred (double) { return 12; }
+constexpr int fred (float) { return 13; }
+constexpr int thud (float128_t) { return 14; }
+constexpr int thud (float64_t) { return 15; }
+constexpr int thud (float32_t) { return 16; }
+struct S {
+  constexpr operator float32_t () const { return 1.0f32; }
+  constexpr operator float64_t () const { return 2.0f64; }
+};
+struct T {
+  constexpr operator float64_t () const { return 3.0f64; }
+  constexpr operator float32_t () const { return 4.0f32; }
+};
+
+void
+test (S s, T t)
+{
+#ifdef __STDCPP_FLOAT16_T__
+  foo (float16_t (1.0));			// { dg-error "call of overloaded 'foo\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (foo (float (2.0)) == 1);
+  static_assert (foo (double (3.0)) == 2);
+  constexpr double x (s);
+  static_assert (x == 2.0);
+#ifdef __STDCPP_FLOAT16_T__
+  bar (f16x);					// { dg-error "call of overloaded 'bar\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (bar (f32x) == 3);
+  static_assert (bar (f64x) == 4);
+  static_assert (bar (f128x) == 5);
+  static_assert (bar (fx) == 3);
+  static_assert (bar (dx) == 4);
+  static_assert (bar (ldx) == 5);
+#ifdef __STDCPP_FLOAT16_T__
+  baz (f16x);					// { dg-error "call of overloaded 'baz\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (baz (f32x) == 6);
+  static_assert (baz (f64x) == 7);
+  static_assert (baz (f128x) == 8);
+  static_assert (baz (fx) == 6);
+  static_assert (baz (dx) == 7);
+  static_assert (baz (ldx) == 8);
+#ifdef __STDCPP_FLOAT16_T__
+  qux (float16_t (1.0));			// { dg-error "call of overloaded 'qux\\\(std::float16_t\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (qux (float (2.0)) == 10);
+  static_assert (qux (double (3.0)) == 9);
+  constexpr double y (t);
+  static_assert (y == 3.0);
+#ifdef __STDCPP_FLOAT16_T__
+  fred (f16x);					// { dg-error "call of overloaded 'fred\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (fred (f32x) == 13);
+  static_assert (fred (f64x) == 12);
+  static_assert (fred (f128x) == 11);
+  static_assert (fred (fx) == 13);
+  static_assert (fred (dx) == 12);
+  static_assert (fred (ldx) == 11);
+#ifdef __STDCPP_FLOAT16_T__
+  thud (f16x);					// { dg-error "call of overloaded 'thud\\\(const std::float16_t\\\&\\\)' is ambiguous" "" { target float16 } }
+#endif
+  static_assert (thud (f32x) == 16);
+  static_assert (thud (f64x) == 15);
+  static_assert (thud (f128x) == 14);
+  static_assert (thud (fx) == 16);
+  static_assert (thud (dx) == 15);
+  static_assert (thud (ldx) == 14);
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating5.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating5.C	2022-09-26 23:38:08.599503194 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// IBM extended long double and _Float128 should have unordered conversion
+// ranks as IBM extended long double has variable precision from 53 bits
+// for denormals to more than 2150 bits for certain numbers.
+// { dg-do compile { target { c++23 && { powerpc*-*-linux* } } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -mlong-double-128 -mabi=ibmlongdouble" }
+
+auto a = 1.0F128 + 1.0L;	// { dg-error "invalid operands to binary \\\+ \\\(have '_Float128' and 'long double'\\\)" }
+auto b = 1.0L + 1.0F128;	// { dg-error "invalid operands to binary \\\+ \\\(have 'long double' and '_Float128'\\\)" }
+bool c;
+auto d = c ? 1.0F128 : 1.0L;	// { dg-error "operands to '\\\?:' of types '_Float128' and 'long double' have unordered conversion rank" }
+auto e = c ? 1.0L : 1.0F128;	// { dg-error "operands to '\\\?:' of types 'long double' and '_Float128' have unordered conversion rank" }
--- gcc/testsuite/g++.dg/cpp23/ext-floating6.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating6.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,30 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target c++23 } }
+// { dg-options "" }
+
+#include "ext-floating.h"
+
+#ifdef __STRICT_ANSI__
+#undef __SIZEOF_FLOAT128__
+#endif
+
+using namespace std;
+
+float foo (float x, float y, float z) { return x * y + z; }
+double foo (double x, double y, double z) { return x * y + z; }
+long double foo (long double x, long double y, long double z) { return x * y + z; }
+#ifdef __STDCPP_FLOAT16_T__
+float16_t foo (float16_t x, float16_t y, float16_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+float32_t foo (float32_t x, float32_t y, float32_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+float64_t foo (float64_t x, float64_t y, float64_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+float128_t foo (float128_t x, float128_t y, float128_t z) { return x * y + z; }
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+bfloat16_t foo (bfloat16_t x, bfloat16_t y, bfloat16_t z) { return x * y + z; }
+#endif
--- gcc/testsuite/g++.dg/cpp23/ext-floating7.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating7.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,119 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float16_runtime } } }
+// { dg-options "" }
+// { dg-add-options float16 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT16_T__
+#error Unexpected
+#endif
+#define WIDTH 16
+#endif
+
+#include <stdarg.h>
+#include "ext-floating.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 TYPE CONCAT (_Float, WIDTH)
+#define CST(C) CONCAT3 (C, f, WIDTH)
+#define CSTU(C) CONCAT3 (C, F, WIDTH)
+
+extern "C" void abort ();
+
+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
+fn (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 = fn (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 ();
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating8.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating8.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float32_runtime } } }
+// { dg-options "" }
+// { dg-add-options float32 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT32_T__
+#error Unexpected
+#endif
+#define WIDTH 32
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating9.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating9.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float64_runtime } } }
+// { dg-options "" }
+// { dg-add-options float64 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT64_T__
+#error Unexpected
+#endif
+#define WIDTH 64
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating10.C.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating10.C	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,13 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do run { target { c++23 && float128_runtime } } }
+// { dg-options "" }
+// { dg-add-options float128 }
+
+#ifndef WIDTH
+#ifndef __STDCPP_FLOAT128_T__
+#error Unexpected
+#endif
+#define WIDTH 128
+#endif
+
+#include "ext-floating7.C"
--- gcc/testsuite/g++.dg/cpp23/ext-floating.h.jj	2022-09-26 23:29:20.678526578 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating.h	2022-09-26 23:29:20.678526578 +0200
@@ -0,0 +1,30 @@
+// P1467R9 - Extended floating-point types and standard names.
+
+namespace std
+{
+  #ifdef __STDCPP_FLOAT16_T__
+  using float16_t = _Float16;
+  #endif
+  #ifdef __STDCPP_FLOAT32_T__
+  using float32_t = _Float32;
+  #endif
+  #ifdef __STDCPP_FLOAT64_T__
+  using float64_t = _Float64;
+  #endif
+  #ifdef __STDCPP_FLOAT128_T__
+  using float128_t = _Float128;
+  #endif
+  #undef __STDCPP_BFLOAT16_T__
+  #ifdef __STDCPP_BFLOAT16_T__
+  using bfloat16_t = __bf16; // ???
+  #endif
+  template<typename T, T v> struct integral_constant {
+    static constexpr T value = v;
+  };
+  typedef integral_constant<bool, false> false_type;
+  typedef integral_constant<bool, true> true_type;
+  template<class T, class U>
+  struct is_same : std::false_type {};
+  template <class T>
+  struct is_same<T, T> : std::true_type {};
+}
--- gcc/testsuite/g++.target/i386/float16-1.C.jj	2022-09-20 11:21:29.904213995 +0200
+++ gcc/testsuite/g++.target/i386/float16-1.C	2022-09-26 23:29:20.692526391 +0200
@@ -1,8 +1,8 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -mno-sse2" } */
 
-_Float16/* { dg-error "does not name a type" } */
+_Float16	/* { dg-error "expected unqualified-id before '_Float16'" } */
 foo (_Float16 x) 
 {
   return x;
-}
+}		/* { dg-error "'_Float16' is not supported on this target" } */
--- libcpp/expr.cc.jj	2022-09-20 11:21:29.988212843 +0200
+++ libcpp/expr.cc	2022-09-26 23:29:20.707526191 +0200
@@ -215,7 +215,6 @@ interpret_float_suffix (cpp_reader *pfil
 	case 'f': case 'F':
 	  f++;
 	  if (len > 0
-	      && !CPP_OPTION (pfile, cplusplus)
 	      && s[1] >= '1'
 	      && s[1] <= '9'
 	      && fn_bits == 0)
--- include/demangle.h.jj	2022-09-20 11:21:29.974213035 +0200
+++ include/demangle.h	2022-09-26 23:29:20.729525898 +0200
@@ -457,6 +457,11 @@ enum demangle_component_type
   DEMANGLE_COMPONENT_MODULE_PARTITION,
   DEMANGLE_COMPONENT_MODULE_ENTITY,
   DEMANGLE_COMPONENT_MODULE_INIT,
+
+  /* A builtin type with argument.  This holds the builtin type
+     information.  */
+  DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
+
 };
 
 /* Types which are only used internally.  */
@@ -543,6 +548,15 @@ struct demangle_component
       const struct demangle_builtin_type_info *type;
     } s_builtin;
 
+    /* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE.  */
+    struct
+    {
+      /* Builtin type.  */
+      const struct demangle_builtin_type_info *type;
+      short arg;
+      char suffix;
+    } s_extended_builtin;
+
     /* For DEMANGLE_COMPONENT_SUB_STD.  */
     struct
     {
--- libiberty/cp-demangle.c.jj	2022-09-20 11:21:30.010212541 +0200
+++ libiberty/cp-demangle.c	2022-09-26 23:42:10.514287102 +0200
@@ -648,6 +648,13 @@ d_dump (struct demangle_component *dc, i
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
       printf ("builtin type %s\n", dc->u.s_builtin.type->name);
       return;
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
+      {
+	char suffix[2] = { dc->u.s_extended_builtin.type->suffix, 0 };
+	printf ("builtin type %s%d%s\n", dc->u.s_extended_builtin.type->name,
+		dc->u.s_extended_builtin.type->arg, suffix);
+      }
+      return;
     case DEMANGLE_COMPONENT_OPERATOR:
       printf ("operator %s\n", dc->u.s_operator.op->name);
       return;
@@ -771,11 +778,6 @@ d_dump (struct demangle_component *dc, i
     case DEMANGLE_COMPONENT_PTRMEM_TYPE:
       printf ("pointer to member type\n");
       break;
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      printf ("fixed-point type, accum? %d, sat? %d\n",
-              dc->u.s_fixed.accum, dc->u.s_fixed.sat);
-      d_dump (dc->u.s_fixed.length, indent + 2);
-      break;
     case DEMANGLE_COMPONENT_ARGLIST:
       printf ("argument list\n");
       break;
@@ -1109,6 +1111,28 @@ d_make_builtin_type (struct d_info *di,
   return p;
 }
 
+/* Add a new extended builtin type component.  */
+
+static struct demangle_component *
+d_make_extended_builtin_type (struct d_info *di,
+			      const struct demangle_builtin_type_info *type,
+			      short arg, char suffix)
+{
+  struct demangle_component *p;
+
+  if (type == NULL)
+    return NULL;
+  p = d_make_empty (di);
+  if (p != NULL)
+    {
+      p->type = DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE;
+      p->u.s_extended_builtin.type = type;
+      p->u.s_extended_builtin.arg = arg;
+      p->u.s_extended_builtin.suffix = suffix;
+    }
+  return p;
+}
+
 /* Add a new operator component.  */
 
 static struct demangle_component *
@@ -2464,6 +2488,7 @@ cplus_demangle_builtin_types[D_BUILTIN_T
   /* 32 */ { NL ("char32_t"),	NL ("char32_t"),	D_PRINT_DEFAULT },
   /* 33 */ { NL ("decltype(nullptr)"),	NL ("decltype(nullptr)"),
 	     D_PRINT_DEFAULT },
+  /* 34 */ { NL ("_Float"),	NL ("_Float"),		D_PRINT_FLOAT },
 };
 
 CP_STATIC_IF_GLIBCPP_V3
@@ -2727,19 +2752,26 @@ cplus_demangle_type (struct d_info *di)
 	  break;
 
 	case 'F':
-	  /* Fixed point types. DF<int bits><length><fract bits><sat>  */
-	  ret = d_make_empty (di);
-	  ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
-	  if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
-	    /* For demangling we don't care about the bits.  */
-	    d_number (di);
-	  ret->u.s_fixed.length = cplus_demangle_type (di);
-	  if (ret->u.s_fixed.length == NULL)
-	    return NULL;
-	  d_number (di);
-	  peek = d_next_char (di);
-	  ret->u.s_fixed.sat = (peek == 's');
-	  break;
+	  /* DF<number>_ - _Float<number>.
+	     DF<number>x - _Float<number>x.  */
+	  {
+	    int arg = d_number (di);
+	    char buf[12];
+	    char suffix = 0;
+	    if (d_peek_char (di) == 'x')
+	      suffix = 'x';
+	    if (!suffix && d_peek_char (di) != '_')
+	      return NULL;
+	    ret
+	      = d_make_extended_builtin_type (di,
+					      &cplus_demangle_builtin_types[34],
+					      arg, suffix);
+	    d_advance (di, 1);
+	    sprintf (buf, "%d", arg);
+	    di->expansion += ret->u.s_extended_builtin.type->len
+			     + strlen (buf) + (suffix != 0);
+	    break;
+	  }
 
 	case 'v':
 	  ret = d_vector_type (di);
@@ -4202,6 +4234,7 @@ d_count_templates_scopes (struct d_print
     case DEMANGLE_COMPONENT_FUNCTION_PARAM:
     case DEMANGLE_COMPONENT_SUB_STD:
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
     case DEMANGLE_COMPONENT_OPERATOR:
     case DEMANGLE_COMPONENT_CHARACTER:
     case DEMANGLE_COMPONENT_NUMBER:
@@ -4210,6 +4243,7 @@ d_count_templates_scopes (struct d_print
     case DEMANGLE_COMPONENT_MODULE_NAME:
     case DEMANGLE_COMPONENT_MODULE_PARTITION:
     case DEMANGLE_COMPONENT_MODULE_INIT:
+    case DEMANGLE_COMPONENT_FIXED_TYPE:
       break;
 
     case DEMANGLE_COMPONENT_TEMPLATE:
@@ -4309,10 +4343,6 @@ d_count_templates_scopes (struct d_print
       d_count_templates_scopes (dpi, dc->u.s_extended_operator.name);
       break;
 
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      d_count_templates_scopes (dpi, dc->u.s_fixed.length);
-      break;
-
     case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
     case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
     case DEMANGLE_COMPONENT_MODULE_ENTITY:
@@ -4580,11 +4610,11 @@ d_find_pack (struct d_print_info *dpi,
     case DEMANGLE_COMPONENT_TAGGED_NAME:
     case DEMANGLE_COMPONENT_OPERATOR:
     case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
     case DEMANGLE_COMPONENT_SUB_STD:
     case DEMANGLE_COMPONENT_CHARACTER:
     case DEMANGLE_COMPONENT_FUNCTION_PARAM:
     case DEMANGLE_COMPONENT_UNNAMED_TYPE:
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
     case DEMANGLE_COMPONENT_DEFAULT_ARG:
     case DEMANGLE_COMPONENT_NUMBER:
       return NULL;
@@ -5387,6 +5417,14 @@ d_print_comp_inner (struct d_print_info
 			 dc->u.s_builtin.type->java_len);
       return;
 
+    case DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE:
+      d_append_buffer (dpi, dc->u.s_extended_builtin.type->name,
+		       dc->u.s_extended_builtin.type->len);
+      d_append_num (dpi, dc->u.s_extended_builtin.arg);
+      if (dc->u.s_extended_builtin.suffix)
+	d_append_buffer (dpi, &dc->u.s_extended_builtin.suffix, 1);
+      return;
+
     case DEMANGLE_COMPONENT_VENDOR_TYPE:
       d_print_comp (dpi, options, d_left (dc));
       return;
@@ -5525,22 +5563,6 @@ d_print_comp_inner (struct d_print_info
 	return;
       }
 
-    case DEMANGLE_COMPONENT_FIXED_TYPE:
-      if (dc->u.s_fixed.sat)
-	d_append_string (dpi, "_Sat ");
-      /* Don't print "int _Accum".  */
-      if (dc->u.s_fixed.length->u.s_builtin.type
-	  != &cplus_demangle_builtin_types['i'-'a'])
-	{
-	  d_print_comp (dpi, options, dc->u.s_fixed.length);
-	  d_append_char (dpi, ' ');
-	}
-      if (dc->u.s_fixed.accum)
-	d_append_string (dpi, "_Accum");
-      else
-	d_append_string (dpi, "_Fract");
-      return;
-
     case DEMANGLE_COMPONENT_ARGLIST:
     case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
       if (d_left (dc) != NULL)
--- libiberty/cp-demangle.h.jj	2022-09-20 11:21:30.010212541 +0200
+++ libiberty/cp-demangle.h	2022-09-26 23:29:20.777525258 +0200
@@ -180,7 +180,7 @@ d_advance (struct d_info *di, int i)
 extern const struct demangle_operator_info cplus_demangle_operators[];
 #endif
 
-#define D_BUILTIN_TYPE_COUNT (34)
+#define D_BUILTIN_TYPE_COUNT (35)
 
 CP_STATIC_IF_GLIBCPP_V3
 const struct demangle_builtin_type_info
--- libiberty/testsuite/demangle-expected.jj	2022-09-20 11:21:30.020212404 +0200
+++ libiberty/testsuite/demangle-expected	2022-09-26 23:29:20.794525031 +0200
@@ -1242,8 +1242,12 @@ _ZNSt9_Any_data9_M_accessIPZ4postISt8fun
 post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
 #
 --format=auto --no-params
-_Z3xxxDFyuVb
-xxx(unsigned long long _Fract, bool volatile)
+_Z3xxxDF16_DF32_DF64_DF128_CDF16_Vb
+xxx(_Float16, _Float32, _Float64, _Float128, _Float16 _Complex, bool volatile)
+xxx
+--format=auto --no-params
+_Z3xxxDF32xDF64xDF128xCDF32xVb
+xxx(_Float32x, _Float64x, _Float128x, _Float32x _Complex, bool volatile)
 xxx
 # https://sourceware.org/bugzilla/show_bug.cgi?id=16817
 --format=auto --no-params
--- fixincludes/inclhack.def.jj	2022-09-20 11:21:29.527219165 +0200
+++ fixincludes/inclhack.def	2022-09-26 23:29:20.815524751 +0200
@@ -2015,6 +2015,102 @@ fix = {
 	EOT;
 };
 
+/*  glibc-2.27 to 2.36 assume GCC 7 or later supports some or all
+ *  of _Float{16,32,64,128} and _Float{32,64,128}x keywords for C,
+ *  but doesn't for C++.
+ */
+fix = {
+    hackname  = glibc_cxx_floatn_1;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\\*/\n)?"
+		"([ \t]*#[ \t]*if[^\n]*\n)?"
+		"[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* The literal suffix f128 exists only since GCC 7.0.  */
+	#   define __f128(x) x##l
+	#  else
+	#   define __f128(x) x##f128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
+	#   if __LDBL_MANT_DIG__ == 113
+	#    define __f128(x) x##l
+	#   else
+	#    define __f128(x) x##q
+	#   endif
+	#  else
+	#   define __f128(x) x##f128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   ifdef __NO_LONG_DOUBLE_MATH
+	#    define __f64(x) x##l
+	#   else
+	#    define __f64(x) x
+	#   endif
+	#  else
+	#   define __f64(x) x##f64
+	#  endif
+	EOT;
+};
+
+fix = {
+    hackname  = glibc_cxx_floatn_2;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\\*/\n)?"
+		"[ \t]*typedef[ \t]+[^\n]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	typedef __float128 _Float128;
+	#  endif
+	EOT;
+};
+
+fix = {
+    hackname  = glibc_cxx_floatn_3;
+    files     = bits/floatn.h, bits/floatn-common.h;
+    select    = "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n"
+		"(([ \t]*/\\*[^\n]*\n?[^\n]*\\*/\n)?"
+		"([ \t]*#[ \t]*if[^\n]*\n)?"
+		"([ \t]*typedef[ \t]+[^\n]*;\n)?"
+		"[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
+    c_fix     = format;
+    c_fix_arg = "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n%2";
+    test_text = <<-EOT
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   define __CFLOAT128 _Complex long double
+	#  else
+	#   define __CFLOAT128 _Complex _Float128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	/* Add a typedef for older GCC compilers which don't natively support
+	   _Complex _Float128.  */
+	typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
+	#   define __CFLOAT128 __cfloat128
+	#  else
+	#   define __CFLOAT128 _Complex _Float128
+	#  endif
+	#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
+	#   ifdef __NO_LONG_DOUBLE_MATH
+	#    define __CFLOAT64 _Complex long double
+	#   else
+	#    define __CFLOAT64 _Complex double
+	#   endif
+	#  else
+	#   define __CFLOAT64 _Complex _Float64
+	#  endif
+	EOT;
+};
+
 /*  glibc-2.3.5 defines pthread mutex initializers incorrectly,
  *  so we replace them with versions that correspond to the
  *  definition.
--- fixincludes/tests/base/bits/floatn.h.jj	2022-09-26 23:29:20.815524751 +0200
+++ fixincludes/tests/base/bits/floatn.h	2022-09-26 23:29:20.815524751 +0200
@@ -0,0 +1,74 @@
+/*  DO NOT EDIT THIS FILE.
+
+    It has been auto-edited by fixincludes from:
+
+	"fixinc/tests/inc/bits/floatn.h"
+
+    This had to be done to correct non-standard usages in the
+    original, manufacturer supplied header file.  */
+
+
+
+#if defined( GLIBC_CXX_FLOATN_1_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+/* The literal suffix f128 exists only since GCC 7.0.  */
+#   define __f128(x) x##l
+#  else
+#   define __f128(x) x##f128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+/* The literal suffix (f128) exist for powerpc only since GCC 7.0.  */
+#   if __LDBL_MANT_DIG__ == 113
+#    define __f128(x) x##l
+#   else
+#    define __f128(x) x##q
+#   endif
+#  else
+#   define __f128(x) x##f128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+#   ifdef __NO_LONG_DOUBLE_MATH
+#    define __f64(x) x##l
+#   else
+#    define __f64(x) x
+#   endif
+#  else
+#   define __f64(x) x##f64
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_1_CHECK */
+
+
+#if defined( GLIBC_CXX_FLOATN_2_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+typedef __float128 _Float128;
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_2_CHECK */
+
+
+#if defined( GLIBC_CXX_FLOATN_3_CHECK )
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+#   define __CFLOAT128 _Complex long double
+#  else
+#   define __CFLOAT128 _Complex _Float128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+/* Add a typedef for older GCC compilers which don't natively support
+   _Complex _Float128.  */
+typedef _Complex float __cfloat128 __attribute__ ((__mode__ (__TC__)));
+#   define __CFLOAT128 __cfloat128
+#  else
+#   define __CFLOAT128 _Complex _Float128
+#  endif
+#  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
+#   ifdef __NO_LONG_DOUBLE_MATH
+#    define __CFLOAT64 _Complex long double
+#   else
+#    define __CFLOAT64 _Complex double
+#   endif
+#  else
+#   define __CFLOAT64 _Complex _Float64
+#  endif
+#endif  /* GLIBC_CXX_FLOATN_3_CHECK */
--- fixincludes/fixincl.x.jj	2022-09-20 11:21:29.526219179 +0200
+++ fixincludes/fixincl.x	2022-09-26 23:29:20.840524418 +0200
@@ -2,11 +2,11 @@
  *
  * DO NOT EDIT THIS FILE   (fixincl.x)
  *
- * It has been AutoGen-ed  February 27, 2022 at 07:47:03 PM by AutoGen 5.18.16
+ * It has been AutoGen-ed  September 11, 2022 at 08:09:37 PM by AutoGen 5.18.16
  * From the definitions    inclhack.def
  * and the template file   fixincl
  */
-/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Feb 27 19:47:03 UTC 2022
+/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Sep 11 20:09:37 CEST 2022
  *
  * You must regenerate it.  Use the ./genfixes script.
  *
@@ -15,7 +15,7 @@
  * certain ANSI-incompatible system header files which are fixed to work
  * correctly with ANSI C and placed in a directory that GNU C will search.
  *
- * This file contains 267 fixup descriptions.
+ * This file contains 270 fixup descriptions.
  *
  * See README for more information.
  *
@@ -4107,6 +4107,132 @@ static const char* apzGlibc_C99_Inline_4
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * *
  *
+ *  Description of Glibc_Cxx_Floatn_1 fix
+ */
+tSCC zGlibc_Cxx_Floatn_1Name[] =
+     "glibc_cxx_floatn_1";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_1List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_1Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_1Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\\*/\n\
+)?([ \t]*#[ \t]*if[^\n\
+]*\n\
+)?[ \t]*#[ \t]*define __f(16|32|64|128)\\()";
+
+#define    GLIBC_CXX_FLOATN_1_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_1Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_1Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_1
+ */
+static const char* apzGlibc_Cxx_Floatn_1Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Glibc_Cxx_Floatn_2 fix
+ */
+tSCC zGlibc_Cxx_Floatn_2Name[] =
+     "glibc_cxx_floatn_2";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_2List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_2Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_2Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\\*/\n\
+)?[ \t]*typedef[ \t]+[^\n\
+]*[ \t]+_Float(16|32|64|128)([ \t]+__attribute__ \\(\\(__mode__ \\(__HF__\\)\\)\\))?;)";
+
+#define    GLIBC_CXX_FLOATN_2_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_2Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_2Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_2
+ */
+static const char* apzGlibc_Cxx_Floatn_2Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Glibc_Cxx_Floatn_3 fix
+ */
+tSCC zGlibc_Cxx_Floatn_3Name[] =
+     "glibc_cxx_floatn_3";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zGlibc_Cxx_Floatn_3List[] =
+  "bits/floatn.h\0bits/floatn-common.h\0";
+/*
+ *  Machine/OS name selection pattern
+ */
+#define apzGlibc_Cxx_Floatn_3Machs (const char**)NULL
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zGlibc_Cxx_Floatn_3Select0[] =
+       "^([ \t]*#[ \t]*if !__GNUC_PREREQ \\(7, 0\\) \\|\\| )defined __cplusplus\n\
+(([ \t]*/\\*[^\n\
+]*\n\
+?[^\n\
+]*\\*/\n\
+)?([ \t]*#[ \t]*if[^\n\
+]*\n\
+)?([ \t]*typedef[ \t]+[^\n\
+]*;\n\
+)?[ \t]*#[ \t]*define __CFLOAT(16|32|64|128)[ \t]+)";
+
+#define    GLIBC_CXX_FLOATN_3_TEST_CT  1
+static tTestDesc aGlibc_Cxx_Floatn_3Tests[] = {
+  { TT_EGREP,    zGlibc_Cxx_Floatn_3Select0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Glibc_Cxx_Floatn_3
+ */
+static const char* apzGlibc_Cxx_Floatn_3Patch[] = {
+    "format",
+    "%1(defined __cplusplus && !__GNUC_PREREQ (13, 0))\n\
+%2",
+    (char*)NULL };
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
  *  Description of Glibc_Mutex_Init fix
  */
 tSCC zGlibc_Mutex_InitName[] =
@@ -10872,9 +10998,9 @@ static const char* apzX11_SprintfPatch[]
  *
  *  List of all fixes
  */
-#define REGEX_COUNT          305
+#define REGEX_COUNT          308
 #define MACH_LIST_SIZE_LIMIT 187
-#define FIX_COUNT            267
+#define FIX_COUNT            270
 
 /*
  *  Enumerate the fixes
@@ -10977,6 +11103,9 @@ typedef enum {
     GLIBC_C99_INLINE_2_FIXIDX,
     GLIBC_C99_INLINE_3_FIXIDX,
     GLIBC_C99_INLINE_4_FIXIDX,
+    GLIBC_CXX_FLOATN_1_FIXIDX,
+    GLIBC_CXX_FLOATN_2_FIXIDX,
+    GLIBC_CXX_FLOATN_3_FIXIDX,
     GLIBC_MUTEX_INIT_FIXIDX,
     GLIBC_STDINT_FIXIDX,
     GLIBC_STRNCPY_FIXIDX,
@@ -11635,6 +11764,21 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
      GLIBC_C99_INLINE_4_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
      aGlibc_C99_Inline_4Tests,   apzGlibc_C99_Inline_4Patch, 0 },
 
+  {  zGlibc_Cxx_Floatn_1Name,    zGlibc_Cxx_Floatn_1List,
+     apzGlibc_Cxx_Floatn_1Machs,
+     GLIBC_CXX_FLOATN_1_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_1Tests,   apzGlibc_Cxx_Floatn_1Patch, 0 },
+
+  {  zGlibc_Cxx_Floatn_2Name,    zGlibc_Cxx_Floatn_2List,
+     apzGlibc_Cxx_Floatn_2Machs,
+     GLIBC_CXX_FLOATN_2_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_2Tests,   apzGlibc_Cxx_Floatn_2Patch, 0 },
+
+  {  zGlibc_Cxx_Floatn_3Name,    zGlibc_Cxx_Floatn_3List,
+     apzGlibc_Cxx_Floatn_3Machs,
+     GLIBC_CXX_FLOATN_3_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aGlibc_Cxx_Floatn_3Tests,   apzGlibc_Cxx_Floatn_3Patch, 0 },
+
   {  zGlibc_Mutex_InitName,    zGlibc_Mutex_InitList,
      apzGlibc_Mutex_InitMachs,
      GLIBC_MUTEX_INIT_TEST_CT, FD_MACH_ONLY,


	Jakub


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2022-09-26 23:23 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-12  8:05 [PATCH] c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652] Jakub Jelinek
2022-09-12 19:36 ` Joseph Myers
2022-09-12 20:52   ` Jakub Jelinek
2022-09-12 21:00     ` Jakub Jelinek
2022-09-13 17:50     ` Joseph Myers
2022-09-16 11:48 ` Jason Merrill
2022-09-16 17:34   ` Jakub Jelinek
2022-09-17  8:58     ` Jason Merrill
2022-09-19 16:39       ` Jakub Jelinek
2022-09-26 21:15         ` Jason Merrill
2022-09-26 22:11           ` Jakub Jelinek
2022-09-20  3:35 ` Hongtao Liu
2022-09-20  7:14   ` Hongtao Liu
2022-09-20  8:51   ` Jakub Jelinek
2022-09-22 15:56     ` [RFC PATCH] __trunc{tf,xf,df,sf,hf}bf2, __truncbfhf2 and __extendbfsf2 Jakub Jelinek
2022-09-23  0:44       ` Hongtao Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).