See <https://wg21.link/p1467>.
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.
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)
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.
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.)
Created attachment 53506 [details] gcc13-pr106652-wip.patch Slightly updated patch (mostly to add even more extended testcase).
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.
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.
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.
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.
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; }
(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.
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)?
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;
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.
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.
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.
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.
This is now implemented.
*** Bug 105509 has been marked as a duplicate of this bug. ***
(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?
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++.
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)