aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/c_global
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2022-10-19 11:25:03 +0200
committerJakub Jelinek <jakub@redhat.com>2022-10-19 11:26:17 +0200
commitba281da28d34f9a78a07f6ee56ad2c754447966e (patch)
tree138b87b22ce59fc64ded5d445160605eda5c22fd /libstdc++-v3/include/c_global
parent8f7df3338c16471a38784983531e57aa2dba1d03 (diff)
downloadgcc-ba281da28d34f9a78a07f6ee56ad2c754447966e.zip
gcc-ba281da28d34f9a78a07f6ee56ad2c754447966e.tar.gz
gcc-ba281da28d34f9a78a07f6ee56ad2c754447966e.tar.bz2
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.
Diffstat (limited to 'libstdc++-v3/include/c_global')
-rw-r--r--libstdc++-v3/include/c_global/cmath94
1 files changed, 92 insertions, 2 deletions
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 81635a0..555d644 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -2755,7 +2755,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
nearbyint(_Float16 __x)
{ return _Float16(__builtin_nearbyintf(__x)); }
- // nextafter not implemented so far.
+ inline _Float16
+ nextafter(_Float16 __x, _Float16 __y)
+ {
+#ifdef __INT16_TYPE__
+ using __float16_int_type = __INT16_TYPE__;
+#else
+ using __float16_int_type = short int;
+#endif
+ __float16_int_type __hx, __hy, __ix, __iy;
+ __builtin_memcpy(&__hx, &__x, sizeof(__x));
+ __builtin_memcpy(&__hy, &__y, sizeof(__x));
+ __ix = __hx & 0x7fff; // |x|
+ __iy = __hy & 0x7fff; // |y|
+ if (__ix > 0x7c00 || __iy > 0x7c00) // x or y is NaN
+ return __x + __y;
+ if (__x == __y)
+ return __y; // x == y, return y
+ if (__ix == 0) // x == 0
+ {
+ __hy = (__hy & 0x8000) | 1; // return +-__FLT16_DENORM_MIN__
+ __builtin_memcpy(&__x, &__hy, sizeof(__x));
+ __builtin_nextafterf(0.0f, 1.0f); // raise underflow
+ return __x;
+ }
+ if (__hx >= 0) // x > 0
+ {
+ if (__hx > __hy) // x > y, x -= ulp
+ --__hx;
+ else // x < y, x += ulp
+ ++__hx;
+ }
+ else // x < 0
+ {
+ if (__hy >= 0 || __hx > __hy) // x < y, x -= ulp
+ --__hx;
+ else // x > y, x += ulp
+ ++__hx;
+ }
+ __hy = __hx & 0x7c00;
+ if (__hy >= 0x7c00)
+ __builtin_nextafterf(__FLT_MAX__, __builtin_inff()); // overflow
+ else if (__hy < 0x0400)
+ __builtin_nextafterf(__FLT_MIN__, 0.0f); // underflow
+ __builtin_memcpy(&__x, &__hx, sizeof(__x));
+ return __x;
+ }
constexpr _Float16
remainder(_Float16 __x, _Float16 __y)
@@ -3426,7 +3471,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
nearbyint(__gnu_cxx::__bfloat16_t __x)
{ return __gnu_cxx::__bfloat16_t(__builtin_nearbyintf(__x)); }
- // nextafter not implemented so far.
+ inline __gnu_cxx::__bfloat16_t
+ nextafter(__gnu_cxx::__bfloat16_t __x, __gnu_cxx::__bfloat16_t __y)
+ {
+#ifdef __INT16_TYPE__
+ using __bfloat16_int_type = __INT16_TYPE__;
+#else
+ using __bfloat16_int_type = short int;
+#endif
+ __bfloat16_int_type __hx, __hy, __ix, __iy;
+ __builtin_memcpy(&__hx, &__x, sizeof(__x));
+ __builtin_memcpy(&__hy, &__y, sizeof(__x));
+ __ix = __hx & 0x7fff; // |x|
+ __iy = __hy & 0x7fff; // |y|
+ if (__ix > 0x7f80 || __iy > 0x7f80) // x or y is NaN
+ return __x + __y;
+ if (__x == __y)
+ return __y; // x == y, return y
+ if (__ix == 0) // x == 0
+ {
+ __hy = (__hy & 0x8000) | 1; // return +-__BFLT16_DENORM_MIN__
+ __builtin_memcpy(&__x, &__hy, sizeof(__x));
+ __builtin_nextafterf(0.0f, 1.0f); // raise underflow
+ return __x;
+ }
+ if (__hx >= 0) // x > 0
+ {
+ if (__hx > __hy) // x > y, x -= ulp
+ --__hx;
+ else // x < y, x += ulp
+ ++__hx;
+ }
+ else // x < 0
+ {
+ if (__hy >= 0 || __hx > __hy) // x < y, x -= ulp
+ --__hx;
+ else // x > y, x += ulp
+ ++__hx;
+ }
+ __hy = __hx & 0x7f80;
+ if (__hy >= 0x7f80)
+ __builtin_nextafterf(__FLT_MAX__, __builtin_inff()); // overflow
+ else if (__hy < 0x0080)
+ __builtin_nextafterf(__FLT_MIN__, 0.0f); // underflow
+ __builtin_memcpy(&__x, &__hx, sizeof(__x));
+ return __x;
+ }
constexpr __gnu_cxx::__bfloat16_t
remainder(__gnu_cxx::__bfloat16_t __x, __gnu_cxx::__bfloat16_t __y)