xref: /freebsd/contrib/llvm-project/libc/src/__support/FPUtil/BasicOperations.h (revision bb722a7d0f1642bff6487f943ad0427799a6e5bf)
1*bb722a7dSDimitry Andric //===-- Basic operations on floating point numbers --------------*- C++ -*-===//
2*bb722a7dSDimitry Andric //
3*bb722a7dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*bb722a7dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*bb722a7dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*bb722a7dSDimitry Andric //
7*bb722a7dSDimitry Andric //===----------------------------------------------------------------------===//
8*bb722a7dSDimitry Andric 
9*bb722a7dSDimitry Andric #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
10*bb722a7dSDimitry Andric #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
11*bb722a7dSDimitry Andric 
12*bb722a7dSDimitry Andric #include "FEnvImpl.h"
13*bb722a7dSDimitry Andric #include "FPBits.h"
14*bb722a7dSDimitry Andric #include "dyadic_float.h"
15*bb722a7dSDimitry Andric 
16*bb722a7dSDimitry Andric #include "src/__support/CPP/type_traits.h"
17*bb722a7dSDimitry Andric #include "src/__support/big_int.h"
18*bb722a7dSDimitry Andric #include "src/__support/common.h"
19*bb722a7dSDimitry Andric #include "src/__support/macros/config.h"
20*bb722a7dSDimitry Andric #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
21*bb722a7dSDimitry Andric #include "src/__support/macros/properties/architectures.h"
22*bb722a7dSDimitry Andric #include "src/__support/macros/properties/types.h"
23*bb722a7dSDimitry Andric #include "src/__support/uint128.h"
24*bb722a7dSDimitry Andric 
25*bb722a7dSDimitry Andric namespace LIBC_NAMESPACE_DECL {
26*bb722a7dSDimitry Andric namespace fputil {
27*bb722a7dSDimitry Andric 
28*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
abs(T x)29*bb722a7dSDimitry Andric LIBC_INLINE T abs(T x) {
30*bb722a7dSDimitry Andric   return FPBits<T>(x).abs().get_val();
31*bb722a7dSDimitry Andric }
32*bb722a7dSDimitry Andric 
33*bb722a7dSDimitry Andric namespace internal {
34*bb722a7dSDimitry Andric 
35*bb722a7dSDimitry Andric template <typename T>
max(T x,T y)36*bb722a7dSDimitry Andric LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> max(T x, T y) {
37*bb722a7dSDimitry Andric   FPBits<T> x_bits(x);
38*bb722a7dSDimitry Andric   FPBits<T> y_bits(y);
39*bb722a7dSDimitry Andric 
40*bb722a7dSDimitry Andric   // To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and y
41*bb722a7dSDimitry Andric   // have different signs and both are not NaNs, we return the number with
42*bb722a7dSDimitry Andric   // positive sign.
43*bb722a7dSDimitry Andric   if (x_bits.sign() != y_bits.sign())
44*bb722a7dSDimitry Andric     return x_bits.is_pos() ? x : y;
45*bb722a7dSDimitry Andric   return x > y ? x : y;
46*bb722a7dSDimitry Andric }
47*bb722a7dSDimitry Andric 
48*bb722a7dSDimitry Andric #ifdef LIBC_TYPES_HAS_FLOAT16
49*bb722a7dSDimitry Andric #if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
max(float16 x,float16 y)50*bb722a7dSDimitry Andric template <> LIBC_INLINE float16 max(float16 x, float16 y) {
51*bb722a7dSDimitry Andric   return __builtin_fmaxf16(x, y);
52*bb722a7dSDimitry Andric }
53*bb722a7dSDimitry Andric #elif !defined(LIBC_TARGET_ARCH_IS_AARCH64)
max(float16 x,float16 y)54*bb722a7dSDimitry Andric template <> LIBC_INLINE float16 max(float16 x, float16 y) {
55*bb722a7dSDimitry Andric   FPBits<float16> x_bits(x);
56*bb722a7dSDimitry Andric   FPBits<float16> y_bits(y);
57*bb722a7dSDimitry Andric 
58*bb722a7dSDimitry Andric   int16_t xi = static_cast<int16_t>(x_bits.uintval());
59*bb722a7dSDimitry Andric   int16_t yi = static_cast<int16_t>(y_bits.uintval());
60*bb722a7dSDimitry Andric   return ((xi > yi) != (xi < 0 && yi < 0)) ? x : y;
61*bb722a7dSDimitry Andric }
62*bb722a7dSDimitry Andric #endif
63*bb722a7dSDimitry Andric #endif // LIBC_TYPES_HAS_FLOAT16
64*bb722a7dSDimitry Andric 
65*bb722a7dSDimitry Andric #if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
max(float x,float y)66*bb722a7dSDimitry Andric template <> LIBC_INLINE float max(float x, float y) {
67*bb722a7dSDimitry Andric   return __builtin_fmaxf(x, y);
68*bb722a7dSDimitry Andric }
69*bb722a7dSDimitry Andric 
max(double x,double y)70*bb722a7dSDimitry Andric template <> LIBC_INLINE double max(double x, double y) {
71*bb722a7dSDimitry Andric   return __builtin_fmax(x, y);
72*bb722a7dSDimitry Andric }
73*bb722a7dSDimitry Andric #endif
74*bb722a7dSDimitry Andric 
75*bb722a7dSDimitry Andric template <typename T>
min(T x,T y)76*bb722a7dSDimitry Andric LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> min(T x, T y) {
77*bb722a7dSDimitry Andric   FPBits<T> x_bits(x);
78*bb722a7dSDimitry Andric   FPBits<T> y_bits(y);
79*bb722a7dSDimitry Andric 
80*bb722a7dSDimitry Andric   // To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and y have
81*bb722a7dSDimitry Andric   // different signs and both are not NaNs, we return the number with negative
82*bb722a7dSDimitry Andric   // sign.
83*bb722a7dSDimitry Andric   if (x_bits.sign() != y_bits.sign())
84*bb722a7dSDimitry Andric     return x_bits.is_neg() ? x : y;
85*bb722a7dSDimitry Andric   return x < y ? x : y;
86*bb722a7dSDimitry Andric }
87*bb722a7dSDimitry Andric 
88*bb722a7dSDimitry Andric #ifdef LIBC_TYPES_HAS_FLOAT16
89*bb722a7dSDimitry Andric #if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
min(float16 x,float16 y)90*bb722a7dSDimitry Andric template <> LIBC_INLINE float16 min(float16 x, float16 y) {
91*bb722a7dSDimitry Andric   return __builtin_fminf16(x, y);
92*bb722a7dSDimitry Andric }
93*bb722a7dSDimitry Andric #elif !defined(LIBC_TARGET_ARCH_IS_AARCH64)
min(float16 x,float16 y)94*bb722a7dSDimitry Andric template <> LIBC_INLINE float16 min(float16 x, float16 y) {
95*bb722a7dSDimitry Andric   FPBits<float16> x_bits(x);
96*bb722a7dSDimitry Andric   FPBits<float16> y_bits(y);
97*bb722a7dSDimitry Andric 
98*bb722a7dSDimitry Andric   int16_t xi = static_cast<int16_t>(x_bits.uintval());
99*bb722a7dSDimitry Andric   int16_t yi = static_cast<int16_t>(y_bits.uintval());
100*bb722a7dSDimitry Andric   return ((xi < yi) != (xi < 0 && yi < 0)) ? x : y;
101*bb722a7dSDimitry Andric }
102*bb722a7dSDimitry Andric #endif
103*bb722a7dSDimitry Andric #endif // LIBC_TYPES_HAS_FLOAT16
104*bb722a7dSDimitry Andric 
105*bb722a7dSDimitry Andric #if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
min(float x,float y)106*bb722a7dSDimitry Andric template <> LIBC_INLINE float min(float x, float y) {
107*bb722a7dSDimitry Andric   return __builtin_fminf(x, y);
108*bb722a7dSDimitry Andric }
109*bb722a7dSDimitry Andric 
min(double x,double y)110*bb722a7dSDimitry Andric template <> LIBC_INLINE double min(double x, double y) {
111*bb722a7dSDimitry Andric   return __builtin_fmin(x, y);
112*bb722a7dSDimitry Andric }
113*bb722a7dSDimitry Andric #endif
114*bb722a7dSDimitry Andric 
115*bb722a7dSDimitry Andric } // namespace internal
116*bb722a7dSDimitry Andric 
117*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fmin(T x,T y)118*bb722a7dSDimitry Andric LIBC_INLINE T fmin(T x, T y) {
119*bb722a7dSDimitry Andric   const FPBits<T> bitx(x), bity(y);
120*bb722a7dSDimitry Andric 
121*bb722a7dSDimitry Andric   if (bitx.is_nan())
122*bb722a7dSDimitry Andric     return y;
123*bb722a7dSDimitry Andric   if (bity.is_nan())
124*bb722a7dSDimitry Andric     return x;
125*bb722a7dSDimitry Andric   return internal::min(x, y);
126*bb722a7dSDimitry Andric }
127*bb722a7dSDimitry Andric 
128*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fmax(T x,T y)129*bb722a7dSDimitry Andric LIBC_INLINE T fmax(T x, T y) {
130*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
131*bb722a7dSDimitry Andric 
132*bb722a7dSDimitry Andric   if (bitx.is_nan())
133*bb722a7dSDimitry Andric     return y;
134*bb722a7dSDimitry Andric   if (bity.is_nan())
135*bb722a7dSDimitry Andric     return x;
136*bb722a7dSDimitry Andric   return internal::max(x, y);
137*bb722a7dSDimitry Andric }
138*bb722a7dSDimitry Andric 
139*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fmaximum(T x,T y)140*bb722a7dSDimitry Andric LIBC_INLINE T fmaximum(T x, T y) {
141*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
142*bb722a7dSDimitry Andric 
143*bb722a7dSDimitry Andric   if (bitx.is_nan())
144*bb722a7dSDimitry Andric     return x;
145*bb722a7dSDimitry Andric   if (bity.is_nan())
146*bb722a7dSDimitry Andric     return y;
147*bb722a7dSDimitry Andric   return internal::max(x, y);
148*bb722a7dSDimitry Andric }
149*bb722a7dSDimitry Andric 
150*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fminimum(T x,T y)151*bb722a7dSDimitry Andric LIBC_INLINE T fminimum(T x, T y) {
152*bb722a7dSDimitry Andric   const FPBits<T> bitx(x), bity(y);
153*bb722a7dSDimitry Andric 
154*bb722a7dSDimitry Andric   if (bitx.is_nan())
155*bb722a7dSDimitry Andric     return x;
156*bb722a7dSDimitry Andric   if (bity.is_nan())
157*bb722a7dSDimitry Andric     return y;
158*bb722a7dSDimitry Andric   return internal::min(x, y);
159*bb722a7dSDimitry Andric }
160*bb722a7dSDimitry Andric 
161*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fmaximum_num(T x,T y)162*bb722a7dSDimitry Andric LIBC_INLINE T fmaximum_num(T x, T y) {
163*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
164*bb722a7dSDimitry Andric   if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
165*bb722a7dSDimitry Andric     fputil::raise_except_if_required(FE_INVALID);
166*bb722a7dSDimitry Andric     if (bitx.is_nan() && bity.is_nan())
167*bb722a7dSDimitry Andric       return FPBits<T>::quiet_nan().get_val();
168*bb722a7dSDimitry Andric   }
169*bb722a7dSDimitry Andric   if (bitx.is_nan())
170*bb722a7dSDimitry Andric     return y;
171*bb722a7dSDimitry Andric   if (bity.is_nan())
172*bb722a7dSDimitry Andric     return x;
173*bb722a7dSDimitry Andric   return internal::max(x, y);
174*bb722a7dSDimitry Andric }
175*bb722a7dSDimitry Andric 
176*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fminimum_num(T x,T y)177*bb722a7dSDimitry Andric LIBC_INLINE T fminimum_num(T x, T y) {
178*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
179*bb722a7dSDimitry Andric   if (bitx.is_signaling_nan() || bity.is_signaling_nan()) {
180*bb722a7dSDimitry Andric     fputil::raise_except_if_required(FE_INVALID);
181*bb722a7dSDimitry Andric     if (bitx.is_nan() && bity.is_nan())
182*bb722a7dSDimitry Andric       return FPBits<T>::quiet_nan().get_val();
183*bb722a7dSDimitry Andric   }
184*bb722a7dSDimitry Andric   if (bitx.is_nan())
185*bb722a7dSDimitry Andric     return y;
186*bb722a7dSDimitry Andric   if (bity.is_nan())
187*bb722a7dSDimitry Andric     return x;
188*bb722a7dSDimitry Andric   return internal::min(x, y);
189*bb722a7dSDimitry Andric }
190*bb722a7dSDimitry Andric 
191*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fmaximum_mag(T x,T y)192*bb722a7dSDimitry Andric LIBC_INLINE T fmaximum_mag(T x, T y) {
193*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
194*bb722a7dSDimitry Andric 
195*bb722a7dSDimitry Andric   if (abs(x) > abs(y))
196*bb722a7dSDimitry Andric     return x;
197*bb722a7dSDimitry Andric   if (abs(y) > abs(x))
198*bb722a7dSDimitry Andric     return y;
199*bb722a7dSDimitry Andric   return fmaximum(x, y);
200*bb722a7dSDimitry Andric }
201*bb722a7dSDimitry Andric 
202*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fminimum_mag(T x,T y)203*bb722a7dSDimitry Andric LIBC_INLINE T fminimum_mag(T x, T y) {
204*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
205*bb722a7dSDimitry Andric 
206*bb722a7dSDimitry Andric   if (abs(x) < abs(y))
207*bb722a7dSDimitry Andric     return x;
208*bb722a7dSDimitry Andric   if (abs(y) < abs(x))
209*bb722a7dSDimitry Andric     return y;
210*bb722a7dSDimitry Andric   return fminimum(x, y);
211*bb722a7dSDimitry Andric }
212*bb722a7dSDimitry Andric 
213*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fmaximum_mag_num(T x,T y)214*bb722a7dSDimitry Andric LIBC_INLINE T fmaximum_mag_num(T x, T y) {
215*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
216*bb722a7dSDimitry Andric 
217*bb722a7dSDimitry Andric   if (abs(x) > abs(y))
218*bb722a7dSDimitry Andric     return x;
219*bb722a7dSDimitry Andric   if (abs(y) > abs(x))
220*bb722a7dSDimitry Andric     return y;
221*bb722a7dSDimitry Andric   return fmaximum_num(x, y);
222*bb722a7dSDimitry Andric }
223*bb722a7dSDimitry Andric 
224*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fminimum_mag_num(T x,T y)225*bb722a7dSDimitry Andric LIBC_INLINE T fminimum_mag_num(T x, T y) {
226*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
227*bb722a7dSDimitry Andric 
228*bb722a7dSDimitry Andric   if (abs(x) < abs(y))
229*bb722a7dSDimitry Andric     return x;
230*bb722a7dSDimitry Andric   if (abs(y) < abs(x))
231*bb722a7dSDimitry Andric     return y;
232*bb722a7dSDimitry Andric   return fminimum_num(x, y);
233*bb722a7dSDimitry Andric }
234*bb722a7dSDimitry Andric 
235*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
fdim(T x,T y)236*bb722a7dSDimitry Andric LIBC_INLINE T fdim(T x, T y) {
237*bb722a7dSDimitry Andric   FPBits<T> bitx(x), bity(y);
238*bb722a7dSDimitry Andric 
239*bb722a7dSDimitry Andric   if (bitx.is_nan()) {
240*bb722a7dSDimitry Andric     return x;
241*bb722a7dSDimitry Andric   }
242*bb722a7dSDimitry Andric 
243*bb722a7dSDimitry Andric   if (bity.is_nan()) {
244*bb722a7dSDimitry Andric     return y;
245*bb722a7dSDimitry Andric   }
246*bb722a7dSDimitry Andric 
247*bb722a7dSDimitry Andric   return (x > y ? x - y : 0);
248*bb722a7dSDimitry Andric }
249*bb722a7dSDimitry Andric 
250*bb722a7dSDimitry Andric // Avoid reusing `issignaling` macro.
251*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
issignaling_impl(const T & x)252*bb722a7dSDimitry Andric LIBC_INLINE int issignaling_impl(const T &x) {
253*bb722a7dSDimitry Andric   FPBits<T> sx(x);
254*bb722a7dSDimitry Andric   return sx.is_signaling_nan();
255*bb722a7dSDimitry Andric }
256*bb722a7dSDimitry Andric 
257*bb722a7dSDimitry Andric template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
canonicalize(T & cx,const T & x)258*bb722a7dSDimitry Andric LIBC_INLINE int canonicalize(T &cx, const T &x) {
259*bb722a7dSDimitry Andric   FPBits<T> sx(x);
260*bb722a7dSDimitry Andric   if constexpr (get_fp_type<T>() == FPType::X86_Binary80) {
261*bb722a7dSDimitry Andric     // All the pseudo and unnormal numbers are not canonical.
262*bb722a7dSDimitry Andric     // More precisely :
263*bb722a7dSDimitry Andric     // Exponent   |       Significand      | Meaning
264*bb722a7dSDimitry Andric     //            | Bits 63-62 | Bits 61-0 |
265*bb722a7dSDimitry Andric     // All Ones   |     00     |    Zero   | Pseudo Infinity, Value = SNaN
266*bb722a7dSDimitry Andric     // All Ones   |     00     |  Non-Zero | Pseudo NaN, Value = SNaN
267*bb722a7dSDimitry Andric     // All Ones   |     01     | Anything  | Pseudo NaN, Value = SNaN
268*bb722a7dSDimitry Andric     //            |   Bit 63   | Bits 62-0 |
269*bb722a7dSDimitry Andric     // All zeroes |   One      | Anything  | Pseudo Denormal, Value =
270*bb722a7dSDimitry Andric     //            |            |           | (−1)**s × m × 2**−16382
271*bb722a7dSDimitry Andric     // All Other  |   Zero     | Anything  | Unnormal, Value = SNaN
272*bb722a7dSDimitry Andric     //  Values    |            |           |
273*bb722a7dSDimitry Andric     bool bit63 = sx.get_implicit_bit();
274*bb722a7dSDimitry Andric     UInt128 mantissa = sx.get_explicit_mantissa();
275*bb722a7dSDimitry Andric     bool bit62 = static_cast<bool>((mantissa & (1ULL << 62)) >> 62);
276*bb722a7dSDimitry Andric     int exponent = sx.get_biased_exponent();
277*bb722a7dSDimitry Andric     if (exponent == 0x7FFF) {
278*bb722a7dSDimitry Andric       if (!bit63 && !bit62) {
279*bb722a7dSDimitry Andric         if (mantissa == 0) {
280*bb722a7dSDimitry Andric           cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
281*bb722a7dSDimitry Andric           raise_except_if_required(FE_INVALID);
282*bb722a7dSDimitry Andric           return 1;
283*bb722a7dSDimitry Andric         }
284*bb722a7dSDimitry Andric         cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
285*bb722a7dSDimitry Andric         raise_except_if_required(FE_INVALID);
286*bb722a7dSDimitry Andric         return 1;
287*bb722a7dSDimitry Andric       } else if (!bit63 && bit62) {
288*bb722a7dSDimitry Andric         cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
289*bb722a7dSDimitry Andric         raise_except_if_required(FE_INVALID);
290*bb722a7dSDimitry Andric         return 1;
291*bb722a7dSDimitry Andric       } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
292*bb722a7dSDimitry Andric         cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa())
293*bb722a7dSDimitry Andric                  .get_val();
294*bb722a7dSDimitry Andric         raise_except_if_required(FE_INVALID);
295*bb722a7dSDimitry Andric         return 1;
296*bb722a7dSDimitry Andric       } else
297*bb722a7dSDimitry Andric         cx = x;
298*bb722a7dSDimitry Andric     } else if (exponent == 0 && bit63)
299*bb722a7dSDimitry Andric       cx = FPBits<T>::make_value(mantissa, 0).get_val();
300*bb722a7dSDimitry Andric     else if (exponent != 0 && !bit63) {
301*bb722a7dSDimitry Andric       cx = FPBits<T>::quiet_nan(sx.sign(), mantissa).get_val();
302*bb722a7dSDimitry Andric       raise_except_if_required(FE_INVALID);
303*bb722a7dSDimitry Andric       return 1;
304*bb722a7dSDimitry Andric     } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
305*bb722a7dSDimitry Andric       cx =
306*bb722a7dSDimitry Andric           FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
307*bb722a7dSDimitry Andric       raise_except_if_required(FE_INVALID);
308*bb722a7dSDimitry Andric       return 1;
309*bb722a7dSDimitry Andric     } else
310*bb722a7dSDimitry Andric       cx = x;
311*bb722a7dSDimitry Andric   } else if (LIBC_UNLIKELY(sx.is_signaling_nan())) {
312*bb722a7dSDimitry Andric     cx = FPBits<T>::quiet_nan(sx.sign(), sx.get_explicit_mantissa()).get_val();
313*bb722a7dSDimitry Andric     raise_except_if_required(FE_INVALID);
314*bb722a7dSDimitry Andric     return 1;
315*bb722a7dSDimitry Andric   } else
316*bb722a7dSDimitry Andric     cx = x;
317*bb722a7dSDimitry Andric   return 0;
318*bb722a7dSDimitry Andric }
319*bb722a7dSDimitry Andric 
320*bb722a7dSDimitry Andric template <typename T>
321*bb722a7dSDimitry Andric LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
totalorder(T x,T y)322*bb722a7dSDimitry Andric totalorder(T x, T y) {
323*bb722a7dSDimitry Andric   using FPBits = FPBits<T>;
324*bb722a7dSDimitry Andric   FPBits x_bits(x);
325*bb722a7dSDimitry Andric   FPBits y_bits(y);
326*bb722a7dSDimitry Andric 
327*bb722a7dSDimitry Andric   using StorageType = typename FPBits::StorageType;
328*bb722a7dSDimitry Andric   StorageType x_u = x_bits.uintval();
329*bb722a7dSDimitry Andric   StorageType y_u = y_bits.uintval();
330*bb722a7dSDimitry Andric 
331*bb722a7dSDimitry Andric   bool has_neg = ((x_u | y_u) & FPBits::SIGN_MASK) != 0;
332*bb722a7dSDimitry Andric   return x_u == y_u || ((x_u < y_u) != has_neg);
333*bb722a7dSDimitry Andric }
334*bb722a7dSDimitry Andric 
335*bb722a7dSDimitry Andric template <typename T>
336*bb722a7dSDimitry Andric LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
totalordermag(T x,T y)337*bb722a7dSDimitry Andric totalordermag(T x, T y) {
338*bb722a7dSDimitry Andric   return FPBits<T>(x).abs().uintval() <= FPBits<T>(y).abs().uintval();
339*bb722a7dSDimitry Andric }
340*bb722a7dSDimitry Andric 
341*bb722a7dSDimitry Andric template <typename T>
getpayload(T x)342*bb722a7dSDimitry Andric LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> getpayload(T x) {
343*bb722a7dSDimitry Andric   using FPBits = FPBits<T>;
344*bb722a7dSDimitry Andric   using StorageType = typename FPBits::StorageType;
345*bb722a7dSDimitry Andric   FPBits x_bits(x);
346*bb722a7dSDimitry Andric 
347*bb722a7dSDimitry Andric   if (!x_bits.is_nan())
348*bb722a7dSDimitry Andric     return T(-1.0);
349*bb722a7dSDimitry Andric 
350*bb722a7dSDimitry Andric   StorageType payload = x_bits.uintval() & (FPBits::FRACTION_MASK >> 1);
351*bb722a7dSDimitry Andric 
352*bb722a7dSDimitry Andric   if constexpr (is_big_int_v<StorageType>) {
353*bb722a7dSDimitry Andric     DyadicFloat<FPBits::STORAGE_LEN> payload_dfloat(Sign::POS, 0, payload);
354*bb722a7dSDimitry Andric 
355*bb722a7dSDimitry Andric     return static_cast<T>(payload_dfloat);
356*bb722a7dSDimitry Andric   } else {
357*bb722a7dSDimitry Andric     return static_cast<T>(payload);
358*bb722a7dSDimitry Andric   }
359*bb722a7dSDimitry Andric }
360*bb722a7dSDimitry Andric 
361*bb722a7dSDimitry Andric template <bool IsSignaling, typename T>
362*bb722a7dSDimitry Andric LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool>
setpayload(T & res,T pl)363*bb722a7dSDimitry Andric setpayload(T &res, T pl) {
364*bb722a7dSDimitry Andric   using FPBits = FPBits<T>;
365*bb722a7dSDimitry Andric   FPBits pl_bits(pl);
366*bb722a7dSDimitry Andric 
367*bb722a7dSDimitry Andric   // Signaling NaNs don't have the mantissa's MSB set to 1, so they need a
368*bb722a7dSDimitry Andric   // non-zero payload to distinguish them from infinities.
369*bb722a7dSDimitry Andric   if (!IsSignaling && pl_bits.is_zero()) {
370*bb722a7dSDimitry Andric     res = FPBits::quiet_nan(Sign::POS).get_val();
371*bb722a7dSDimitry Andric     return false;
372*bb722a7dSDimitry Andric   }
373*bb722a7dSDimitry Andric 
374*bb722a7dSDimitry Andric   int pl_exp = pl_bits.get_exponent();
375*bb722a7dSDimitry Andric 
376*bb722a7dSDimitry Andric   if (pl_bits.is_neg() || pl_exp < 0 || pl_exp >= FPBits::FRACTION_LEN - 1 ||
377*bb722a7dSDimitry Andric       ((pl_bits.get_mantissa() << pl_exp) & FPBits::FRACTION_MASK) != 0) {
378*bb722a7dSDimitry Andric     res = T(0.0);
379*bb722a7dSDimitry Andric     return true;
380*bb722a7dSDimitry Andric   }
381*bb722a7dSDimitry Andric 
382*bb722a7dSDimitry Andric   using StorageType = typename FPBits::StorageType;
383*bb722a7dSDimitry Andric   StorageType v(pl_bits.get_explicit_mantissa() >>
384*bb722a7dSDimitry Andric                 (FPBits::FRACTION_LEN - pl_exp));
385*bb722a7dSDimitry Andric 
386*bb722a7dSDimitry Andric   if constexpr (IsSignaling)
387*bb722a7dSDimitry Andric     res = FPBits::signaling_nan(Sign::POS, v).get_val();
388*bb722a7dSDimitry Andric   else
389*bb722a7dSDimitry Andric     res = FPBits::quiet_nan(Sign::POS, v).get_val();
390*bb722a7dSDimitry Andric   return false;
391*bb722a7dSDimitry Andric }
392*bb722a7dSDimitry Andric 
393*bb722a7dSDimitry Andric } // namespace fputil
394*bb722a7dSDimitry Andric } // namespace LIBC_NAMESPACE_DECL
395*bb722a7dSDimitry Andric 
396*bb722a7dSDimitry Andric #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_BASICOPERATIONS_H
397