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/Bit.h" 13 #include "src/__support/CPP/TypeTraits.h" 14 #include "src/__support/common.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 __llvm_libc::bit_cast<uint32_t>(x); 24 } 25 26 static inline uint64_t as_uint64_bits(double x) { 27 return __llvm_libc::bit_cast<uint64_t>(x); 28 } 29 30 static inline float as_float(uint32_t x) { 31 return __llvm_libc::bit_cast<float>(x); 32 } 33 34 static inline double as_double(uint64_t x) { 35 return __llvm_libc::bit_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 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 74 Value = // NOLINT so that this Value can match the ones for IsSame 75 cpp::IsSame<T, float>::Value || cpp::IsSame<T, double>::Value; 76 }; 77 78 template <typename T> 79 using EnableIfFloatOrDouble = cpp::EnableIfType<IsFloatOrDouble<T>::Value, int>; 80 81 template <typename T, EnableIfFloatOrDouble<T> = 0> 82 T xflow(uint32_t sign, T y) { 83 // Underflow happens when two extremely small values are multiplied. 84 // Likewise, overflow happens when two large values are multiplied. 85 y = opt_barrier(sign ? -y : y) * y; 86 return with_errno(y, ERANGE); 87 } 88 89 template <typename T, EnableIfFloatOrDouble<T> = 0> T overflow(uint32_t sign) { 90 return xflow(sign, XFlowValues<T>::OVERFLOW_VALUE); 91 } 92 93 template <typename T, EnableIfFloatOrDouble<T> = 0> T underflow(uint32_t sign) { 94 return xflow(sign, XFlowValues<T>::UNDERFLOW_VALUE); 95 } 96 97 template <typename T, EnableIfFloatOrDouble<T> = 0> 98 T may_underflow(uint32_t sign) { 99 return xflow(sign, XFlowValues<T>::MAY_UNDERFLOW_VALUE); 100 } 101 102 template <typename T, EnableIfFloatOrDouble<T> = 0> 103 static inline constexpr float invalid(T x) { 104 T y = (x - x) / (x - x); 105 return isnan(x) ? y : with_errno(y, EDOM); 106 } 107 108 } // namespace __llvm_libc 109 110 #endif // LLVM_LIBC_SRC_MATH_MATH_UTILS_H 111