Bug 106652 - [C++23] P1467 - Extended floating-point types and standard names
Summary: [C++23] P1467 - Extended floating-point types and standard names
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: 13.0
Assignee: Jakub Jelinek
URL:
Keywords:
: 105509 (view as bug list)
Depends on:
Blocks: c++23-core c++23-lib
  Show dependency treegraph
 
Reported: 2022-08-16 17:14 UTC by Marek Polacek
Modified: 2023-08-22 14:16 UTC (History)
10 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-09-10 00:00:00


Attachments
gcc13-pr106652-wip.patch (6.59 KB, patch)
2022-08-24 14:27 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652-wip.patch (8.12 KB, patch)
2022-08-25 12:51 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652-bf16.patch (4.70 KB, patch)
2022-08-25 12:55 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652-wip.patch (10.30 KB, patch)
2022-08-25 14:39 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652-wip.patch (11.88 KB, patch)
2022-09-09 09:44 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652-wip.patch (13.12 KB, patch)
2022-09-09 18:12 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652.patch (16.94 KB, patch)
2022-09-10 10:20 UTC, Jakub Jelinek
Details | Diff
gcc13-pr106652-lib.patch (3.34 KB, patch)
2022-09-10 17:28 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Marek Polacek 2022-08-16 17:14:41 UTC
See <https://wg21.link/p1467>.
Comment 1 Jakub Jelinek 2022-08-24 14:27:10 UTC
Created attachment 53504 [details]
gcc13-pr106652-wip.patch

Untested WIP.

The plan is to use _Float{16,32,64,128} types (keywords like in C, so that
_Complex _Float64 etc. works) for underlying types of std::float{16,32,64,128}_t
implementation.
Comment 2 Jakub Jelinek 2022-08-24 14:49:58 UTC
On targets that do have __float128, I believe we want to mangle it as before and also handle usual arithmetic conversions etc. the same we did before unless the
C++23 extended floating-point types are involved.
Which is why I've introduced the float128t_type_node hack, where non-C++ can continue to do what it did before but for C++ __float128 will be a new distinct type.
For mangling of std::float{16,32,64,128}_t I'm using the Itanium ABI _Float{16,32,64,128} mangling, i.e. DF{16,32,64,128}_
This collides with the apparently never really used mangling of FIXED_POINT_TYPEs 
(fixed points are really only supported in C on a few platforms, not in C++,
and at some point they leaked into the C++ FE through 0r and similar literals, but that has been fixed shortly afterwards).
The patch only introduces _Float{16,32,64,128}, not _Float{32,64,128}x that C also supports, so I've removed __FLT{32,64,128}X_* predefined macros.

The patch is still incomplete and I'm getting stuck on it (except I can surely provide testsuite coverage for what is already implemented):

1) there is no bf16/BF16 constant suffix nor underlying type for std::bfloat16_t
   for now; I think we need to come to agreement on how the underlying type
   would be called (__bf16 like aarch64/arm/i386 currently have their extension
   type?) and how to mangle it (all 3 currently mangle it as u6__bf16) and
   if we choose a different keyword for it whether it is distinct from __bf16

2) I haven't implemented the [conv.double] addition:
   "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" - not really sure where it should be done
   (but the new cp_compare_floating_point_conversion_ranks function can be
   used to compare ranks and subranks)

3) for the [expr.static.cast] addition, I wonder if there is anything to do,
   I'd expect it would just work as is

4) for the [expr.arith.conv] changes, I think I've implement those in
   cp_common_type, except for the
   "Otherwise, the expression is ill-formed."
   part where I just return error_mark_node, but cp_common_type doesn't
   emit any diagnostics whatsoever, so I wonder if it should be done
   somewhere in the callers, or if the function and its wrappers should
   get tsubst_flags_t complain argument or what.

5) I've skipped the [over.ics.rank] changes, I'm afraid it is another thing
   I'm not really familiar with

6) the library part is unimplemented altogether, the __FLT* macros can be used
   to implement numerical limits, but e.g. for the <cmath>/<complex> stuff
   not really sure how far can we get for std::float128_t if not on glibc or
   on old glibc (guess the others at least when they match float/double
   which can be tested through preprocessor macros can be handled by casts
   to those types)
Comment 3 Jakub Jelinek 2022-08-24 16:56:49 UTC
Testcase for the already implemented features:
// P1467R9 - Extended floating-point types and standard names.
// { dg-do compile { target c++23 } }
// { dg-options "" }

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
  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 {};
}
#ifdef __STRICT_ANSI__
#undef __SIZEOF_FLOAT128__
#endif

using namespace std;

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<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<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<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<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<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
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<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<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<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<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<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<decltype (0.0f64 + 0.0f128), float128_t>::value);
static_assert (is_same<decltype (0.0F128 + 0.0F64), float128_t>::value);
#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

For e.g. powerpc64le-linux, would be nice to repeat the testcase with
-mlong-double-64
-mlong-double-128 -mabi=ibmlongdouble
-mlong-double-128 -mabi=ieeelongdouble
options.
Also, we should have a mangling testcase, one generic and one for the __float128 target specific mangling etc. and then once [over.ics.rank] is implemented, something to test that.
Comment 4 jsm-csl@polyomino.org.uk 2022-08-24 17:35:05 UTC
Regarding mangling: I expect this change should fix bug 85518.

General: I expect some glibc header changes might be appropriate, where 
they currently assume __FloatN keywords aren't supported in C++.  And 
where glibc headers handle type-generic operations for C++ by defining 
appropriate overloaded functions in the headers, make sure the overloads 
for _Float128 work with both _Float128 and __float128 where supported and 
distinct, or otherwise adjust the headers as needed to handle both types.

(Also, so far we don't have _Float16 support in glibc, and while it would 
be a sensible feature in principle, there would be issues to consider with 
the impact on minimum GCC versions for building glibc on relevant 
architectures, unless some kind of hack is used to allow _Float16 
functions to be built and to get the correct ABI even when built with an 
older compiler.  Requiring GCC 7 to build glibc for AArch64 and Arm might 
well be reasonable now; requiring GCC 12 for x86/x86_64 or GCC 13 for 
RISC-V probably not for a few years.)
Comment 5 Jakub Jelinek 2022-08-25 12:51:50 UTC
Created attachment 53506 [details]
gcc13-pr106652-wip.patch

Slightly updated patch (mostly to add even more extended testcase).
Comment 6 Jakub Jelinek 2022-08-25 12:55:58 UTC
Created attachment 53507 [details]
gcc13-pr106652-bf16.patch

And if the answer to 1) is that it is ok for std::bfloat16_t to be __bf16
with u6__bf16 mangling, incremental patch for that.  This one doesn't work though, because apparently on none of the 3 targets that do support __bf16
we actually support conversions between __bf16 and other floating point types
(most importantly float), nor arithmetic operations (that is quite fatal).
So, the important question is if we are ok to add arithmetic operation support
to __bf16 and ditto conversions (where arithmetic operations presumably would be implemented by cast to float, arithmetic on float and conversion back?), or if that should be done only on some separate type, whether it is _BFloat16 or __bfloat16_t or whatever else.
Comment 7 Jakub Jelinek 2022-08-25 14:39:33 UTC
Created attachment 53508 [details]
gcc13-pr106652-wip.patch

Further updated patch to kill the never actually used fixed type demangling support from demangler and instead implement the _Float{16,32,64,128} demangling.
Comment 8 Jakub Jelinek 2022-09-09 09:44:43 UTC
Created attachment 53555 [details]
gcc13-pr106652-wip.patch

Some further progress.  Introduces a helper extended_float_type_p and uses it
and attempts to implement 2) from above and add some testcase coverage for it
(not complete, because right now there are just float{16,32,64,128} effective
targets and not effective targets for various float/double/long double type
properties (e.g. if they are ieee type), so for the cases where there should be
an error on the conversion I've kept only cases where I know for sure using the
above mentioned effective targets, not where it is sometimes the case and
sometimes it isn't.  From the above list, 1) needs decision what to do about
arithmetics in that type, 4) needs discussion on where to diagnose it, 5) needs
implementation.
Comment 9 Jakub Jelinek 2022-09-09 18:12:40 UTC
Created attachment 53557 [details]
gcc13-pr106652-wip.patch

Further updated patch which implements also the 4) diagnostics, both for binary operations and ?: and punts in c-common.c uses if common_type fails, plus an added x86 specific tests for further errors and a powerpc specific test to test for the long double (IBM extended) vs. _Float128 unordered conversion ranks.
[over.ics.rank] changes are still not implemented and I'm lost there.
Comment 10 Jakub Jelinek 2022-09-10 10:20:55 UTC
Created attachment 53558 [details]
gcc13-pr106652.patch

The other conversion better should use backend support if available, but
could be implemented in libgcc __truncsfbf2 or inline.  I believe Intel docs
document it as
__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;
}
Comment 11 Jakub Jelinek 2022-09-10 10:22:58 UTC
(In reply to Jakub Jelinek from comment #10)

Ouch, sorry for lost start of the comment,
this is full patch with even [conv.ics.rank]/4 changes and extended test coverage, just std::bfloat16_t support isn't in.  And the above comment
is about that support, where conversion from __bf16 to _Float32 can be
done even in generic code just by shifting the bits up by 16.
Comment 12 Jakub Jelinek 2022-09-10 17:28:44 UTC
Created attachment 53559 [details]
gcc13-pr106652-lib.patch

Some unfinished library changes.

Unfortunately, we seem to have a major problem with glibc.
<bits/floatn.h> included from <math.h> etc. on some arches does:
# if __HAVE_FLOAT128

/* The type _Float128 exists only since GCC 7.0.  */
#  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
typedef __float128 _Float128;
#  endif
...
#endif
or
typedef long double _Float128;
etc.
I'm afraid we'll need to fixincludes that and change in glibc.
The question is to what exactly.  I think with the compiler patch _Float<N>
are in C++ generally available as keyword but __STDCPP_FLOAT<N>_T__ that the libstdc++ patch is using is only defined for C++23.  The F<N> or f<N> literal suffixes pedwarn before C++23 but bet not in system headers, so glibc then
could use those for C++ always for __GNUC_PREREQ (13, 0)?
Comment 13 Jakub Jelinek 2022-09-10 17:31:18 UTC
grep finds these problematic spots:
./sysdeps/mips/ieee754/bits/floatn.h:typedef long double _Float128;
./sysdeps/ieee754/ldbl-128/bits/floatn.h:typedef long double _Float128;
./sysdeps/ia64/bits/floatn.h:typedef __float128 _Float128;
./sysdeps/powerpc/bits/floatn.h:typedef long double _Float128;
./sysdeps/powerpc/bits/floatn.h:typedef __float128 _Float128;
./sysdeps/x86/bits/floatn.h:typedef __float128 _Float128;
./bits/floatn-common.h:typedef float _Float16 __attribute__ ((__mode__ (__HF__)));
./bits/floatn-common.h:typedef float _Float32;
./bits/floatn-common.h:typedef long double _Float64;
./bits/floatn-common.h:typedef double _Float64;
Comment 14 Jakub Jelinek 2022-09-10 18:13:15 UTC
What I did in the patch is stop predefining __FLT32X_*__ macros etc. for C++ because C++ doesn't support those, so perhaps the
if !__GNUC_PREREQ (7, 0) || defined __cplusplus
conditions related to _Float<N> (but not _Float<N>x) could be fixincluded
or changed to
if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && defined __FLT32_MANT_DIG__)
or so (to differentiate between C++ doesn't have vs. has _Float<N> keywords.
Comment 15 GCC Commits 2022-09-27 06:18:34 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:b04208895fed34171eac6bafb60c90048eb1cb0c

commit r13-2887-gb04208895fed34171eac6bafb60c90048eb1cb0c
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Sep 27 08:04:06 2022 +0200

    c++: Implement P1467R9 - Extended floating-point types and standard names compiler part except for bfloat16 [PR106652]
    
    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, with DF{16,32,64,128}_
    mangling.
    It also introduces _Float{32,64,128}x for C++ with the
    https://github.com/itanium-cxx-abi/cxx-abi/pull/147
    proposed mangling of DF{32,64,128}x.
    The patch doesn't add anything for bfloat16_t support, as right now
    __bf16 type refuses all conversions and arithmetic operations.
    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,32x,64x,128x} (_FloatNx are
    also treated as extended floating-point types) 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,32x,64x,128x} support nor
    {f,F}{16,32,64,128}{,x} literal suffixes nor _Complex _Float{16,32,64,128,32x,64x,128x}.
    The patch fixincludes this for now and hopefully if this is committed, then
    glibc can change those.  The patch changes those
     #  if !__GNUC_PREREQ (7, 0) || defined __cplusplus
    conditions to
     #  if !__GNUC_PREREQ (7, 0) || (defined __cplusplus && !__GNUC_PREREQ (13, 0))
    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,32x,64x,128x} is
    supported in C++ by
    __GNUC__ >= 13 && defined(__FLT{16,32,64,128,32X,64X,128X}_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.
    
    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.
Comment 16 GCC Commits 2022-10-18 09:43:44 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:a23225fb4f764dfc3e3e729c7d7238f03f282aaa

commit r13-3354-ga23225fb4f764dfc3e3e729c7d7238f03f282aaa
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Oct 18 11:37:13 2022 +0200

    libstdc++: Partial library support for std::float{16,32,64,128}_t and std::bfloat16_t
    
    The following patch is partial support for std::float{16,32,64,128}_t
    and std::bfloat16_t in libstdc++.
    https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1467r9.html
    says that <ostream>, <istream>, <charconv> and <complex>
    need changes toom, but that isn't implemented so far.
    In <cmath> the only thing missing I'm aware of is
    std::nextafter std::float16_t and std::bfloat16_t overloads (I think
    we probably need to implement that out of line somewhere, or inline? - might
    need inline asm barriers) and std::nexttoward overloads (those are
    intentional, you said there is a LWG issue about that).
    Also, this patch has the glibc 2.26+ std::float128_t support for platforms
    where long double isn't IEEE quad format temporarily disabled
    because it depends on
    https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603665.html
    changes which aren't in yet.
    
    The patch also doesn't include any testcases to cover the <type_traits>
    changes, it isn't clear to me where to put that.
    
    2022-10-18  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/106652
            * include/std/stdfloat: New file.
            * include/std/numbers (__glibcxx_numbers): Define and use it
            for __float128 explicit instantiations as well as
            _Float{16,32,64,128} and __gnu_cxx::__bfloat16_t.
            * include/std/atomic (atomic<_Float16>, atomic<_Float32>,
            atomic<_Float64>, atomic<_Float128>, atomic<__gnu_cxx::__bfloat16_t>):
            New explicit instantiations.
            * include/std/type_traits (__is_floating_point_helper<_Float16>,
            __is_floating_point_helper<_Float32>,
            __is_floating_point_helper<_Float64>,
            __is_floating_point_helper<_Float128>,
            __is_floating_point_helper<__gnu_cxx::__bfloat16_t>): Likewise.
            * include/std/limits (__glibcxx_concat3_, __glibcxx_concat3,
            __glibcxx_float_n): Define.
            (numeric_limits<_Float16>, numeric_limits<_Float32>,
            numeric_limits<_Float64>, numeric_limits<_Float128>,
            numeric_limits<__gnu_cxx::__bfloat16_t>): New explicit instantiations.
            * include/bits/std_abs.h (abs): New overloads for
            _Float{16,32,64,128} and __gnu_cxx::__bfloat16_t.
            * include/bits/c++config (_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128): Define
            if long double is IEEE quad.
            (__gnu_cxx::__bfloat16_t): New using.
            * include/c_global/cmath (acos, asin, atan, atan2, ceil, cos, cosh,
            exp, fabs, floor, fmod, frexp, ldexp, log, log10, modf, pow, sin,
            sinh, sqrt, tan, tanh, fpclassify, isfinite, isinf, isnan, isnormal,
            signbit, isgreater, isgreaterequal, isless, islessequal,
            islessgreater, isunordered, acosh, asinh, atanh, cbrt, copysign, erf,
            erfc, exp2, expm1, fdim, fma, fmax, fmin, hypot, ilogb, lgamma,
            llrint, llround, log1p, log2, logb, lrint, lround, nearbyint,
            nextafter, remainder, rint, round, scalbln, scalbn, tgamma, trunc,
            lerp): New overloads with _Float{16,32,64,128} or
            __gnu_cxx::__bfloat16_t types.
            * config/os/gnu-linux/os_defines.h (_GLIBCXX_HAVE_FLOAT128_MATH):
            Prepare for definition if glibc 2.26 and later implements *f128 APIs
            but comment out the actual definition for now.
            * include/ext/type_traits.h (__promote<_Float16>, __promote<_Float32>,
            __promote<_Float64>, __promote<_Float128>,
            __promote<__gnu_cxx::__bfloat16_t>): New specializations.
            * include/Makefile.am (std_headers): Add stdfloat.
            * include/Makefile.in: Regenerated.
            * include/precompiled/stdc++.h: Include stdfloat.
            * testsuite/18_support/headers/stdfloat/types_std.cc: New test.
            * testsuite/18_support/headers/limits/synopsis_cxx23.cc: New test.
            * testsuite/26_numerics/headers/cmath/c99_classification_macros_c++23.cc:
            New test.
            * testsuite/26_numerics/headers/cmath/functions_std_c++23.cc: New test.
            * testsuite/26_numerics/numbers/4.cc: New test.
            * testsuite/29_atomics/atomic_float/requirements_cxx23.cc: New test.
Comment 17 GCC Commits 2022-10-19 09:26:39 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:ba281da28d34f9a78a07f6ee56ad2c754447966e

commit r13-3372-gba281da28d34f9a78a07f6ee56ad2c754447966e
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Oct 19 11:25:03 2022 +0200

    libstdc++-v3: Implement {,b}float16_t nextafter and some fixes [PR106652]
    
    The following patch implements nextafter for std::{,b}float16_t,
    though right now only without constexpr support, and adds a testcase for it.
    The testcase unfortunately relevealed I've screwed up testing of my last
    patch.  I've tested earlier version of the patch with
    --target_board=unix/-std=c++23
    but didn't test the final version with that RUNTESTFLAGS, so missed
    an invalid call to std::sph_neumann (too many arguments) in the test.
    And, I've made a typo in the guard for numeric_limits (the reason
    for the guard is I wanted to avoid defining a large macro that nothing
    will then use because the std::{,b}float*_t types are C++23 only) and
    so numeric_limits wasn't specialized for the types at all but
    testsuite/18_support/headers/limits/synopsis_cxx23.cc test didn't
    detect that.
    In the nextafter implementation I'm calling __builtin_nextafterf
    to get various required side-effects for nextafter from 0/-0, or from max
    to inf or from min to largest subnormal to avoid needing to set errno
    inline, or use inline asm specific for each processor to force math
    evaluation barriers.  Dunno if
      #ifdef __INT16_TYPE__
        using __float16_int_type = __INT16_TYPE__;
      #else
        using __float16_int_type = short int;
      #endif
    isn't too ugly, perhaps we could just blindly use short int and hope
    or even assert it has the same size as _Float16 or __gnu_cxx::__bfloat16_t?
    Only aarch64, arm, csky, gcn, x86, nvptx and riscv support these types
    and all of them have 16-bit short (I think the only target with some
    other short size is avr with certain command line switches where both
    short and int are 8-bit, but such mode isn't compatible with C and C++
    requirements).
    
    2022-10-19  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/106652
            * include/std/limits: Fix a typo, 202202L -> 202002L.
            (numeric_limits::<_Float16>::radix, numeric_limits::<_Float32>::radix,
            numeric_limits::<_Float64>::radix, numeric_limits::<_Float128>::radix,
            numeric_limits::<__gnu_cxx::__bfloat16_t>::radix): Use __FLT_RADIX__
            macro instead of type specific macros.
            * include/c_global/cmath (nextafter(_Float16, _Float16)): New
            overload.
            (nextafter(__gnu_cxx::__bfloat16_t, __gnu_cxx::__bfloat16_t)):
            Likewise.
            * testsuite/26_numerics/headers/cmath/functions_std_c++23.cc
            (test_functions): Uncomment nextafter test.  Fix up sph_neumann call.
            * testsuite/26_numerics/headers/cmath/nextafter_c++23.cc: New test.
Comment 18 Jakub Jelinek 2022-11-19 09:24:18 UTC
This is now implemented.
Comment 19 Andrew Pinski 2022-12-09 15:20:22 UTC
*** Bug 105509 has been marked as a duplicate of this bug. ***
Comment 20 Igor Kushnir 2023-08-21 15:57:20 UTC
(In reply to Jakub Jelinek from comment #18)
> This is now implemented.
Shouldn't the sentence "These types are not supported when compiling C++." be removed from the documentation 
https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Floating-Types.html?
Comment 21 GCC Commits 2023-08-22 14:15:14 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:145da6a8e1ad60f048069012d81e37f84e1585fd

commit r14-3385-g145da6a8e1ad60f048069012d81e37f84e1585fd
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Aug 22 16:13:44 2023 +0200

    doc: Remove obsolete sentence about _Float* not being supported in C++ [PR106652]
    
    As mentioned in the PR, these types are supported in C++ since GCC 13,
    so we shouldn't confuse users.
    
    2023-08-22  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/106652
            * doc/extend.texi (_Float<n>): Drop obsolete sentence that the
            types aren't supported in C++.
Comment 22 GCC Commits 2023-08-22 14:16:19 UTC
The releases/gcc-13 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:e7a097ea72d3295a1a1680ba05c4fc8242bae7f0

commit r13-7743-ge7a097ea72d3295a1a1680ba05c4fc8242bae7f0
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Aug 22 16:13:44 2023 +0200

    doc: Remove obsolete sentence about _Float* not being supported in C++ [PR106652]
    
    As mentioned in the PR, these types are supported in C++ since GCC 13,
    so we shouldn't confuse users.
    
    2023-08-22  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/106652
            * doc/extend.texi (_Float<n>): Drop obsolete sentence that the
            types aren't supported in C++.
    
    (cherry picked from commit 145da6a8e1ad60f048069012d81e37f84e1585fd)