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