1 //===-- Collection of utils for implementing math functions -----*- 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_MATH_MATH_UTILS_H 10 #define LLVM_LIBC_SRC_MATH_MATH_UTILS_H 11 12 #include "src/__support/CPP/TypeTraits.h" 13 #include "src/__support/common.h" 14 #include <errno.h> 15 #include <math.h> 16 17 #include <stdint.h> 18 19 namespace __llvm_libc { 20 21 static inline uint32_t as_uint32_bits(float x) { 22 return *reinterpret_cast<uint32_t *>(&x); 23 } 24 25 static inline uint64_t as_uint64_bits(double x) { 26 return *reinterpret_cast<uint64_t *>(&x); 27 } 28 29 static inline float as_float(uint32_t x) { 30 return *reinterpret_cast<float *>(&x); 31 } 32 33 static inline double as_double(uint64_t x) { 34 return *reinterpret_cast<double *>(&x); 35 } 36 37 static inline uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; } 38 39 static inline uint32_t top12_bits(double x) { return as_uint64_bits(x) >> 52; } 40 41 // Values to trigger underflow and overflow. 42 template <typename T> struct XFlowValues; 43 44 template <> struct XFlowValues<float> { 45 static const float overflow_value; 46 static const float underflow_value; 47 static const float may_underflow_value; 48 }; 49 50 template <> struct XFlowValues<double> { 51 static const double overflow_value; 52 static const double underflow_value; 53 static const double may_underflow_value; 54 }; 55 56 template <typename T> static inline T with_errno(T x, int err) { 57 if (math_errhandling & MATH_ERRNO) 58 errno = err; 59 return x; 60 } 61 62 template <typename T> static inline void force_eval(T x) { 63 volatile T y UNUSED = x; 64 } 65 66 template <typename T> static inline T opt_barrier(T x) { 67 volatile T y = x; 68 return y; 69 } 70 71 template <typename T> struct IsFloatOrDouble { 72 static constexpr bool Value = 73 cpp::IsSame<T, float>::Value || cpp::IsSame<T, double>::Value; 74 }; 75 76 template <typename T> 77 using EnableIfFloatOrDouble = cpp::EnableIfType<IsFloatOrDouble<T>::Value, int>; 78 79 template <typename T, EnableIfFloatOrDouble<T> = 0> 80 T xflow(uint32_t sign, T y) { 81 // Underflow happens when two extremely small values are multiplied. 82 // Likewise, overflow happens when two large values are multiplied. 83 y = opt_barrier(sign ? -y : y) * y; 84 return with_errno(y, ERANGE); 85 } 86 87 template <typename T, EnableIfFloatOrDouble<T> = 0> T overflow(uint32_t sign) { 88 return xflow(sign, XFlowValues<T>::overflow_value); 89 } 90 91 template <typename T, EnableIfFloatOrDouble<T> = 0> T underflow(uint32_t sign) { 92 return xflow(sign, XFlowValues<T>::underflow_value); 93 } 94 95 template <typename T, EnableIfFloatOrDouble<T> = 0> 96 T may_underflow(uint32_t sign) { 97 return xflow(sign, XFlowValues<T>::may_underflow_value); 98 } 99 100 template <typename T, EnableIfFloatOrDouble<T> = 0> 101 static inline constexpr float invalid(T x) { 102 T y = (x - x) / (x - x); 103 return isnan(x) ? y : with_errno(y, EDOM); 104 } 105 106 } // namespace __llvm_libc 107 108 #endif // LLVM_LIBC_SRC_MATH_MATH_UTILS_H 109