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