blob: 11c2bd1f0a4ae568f4a1dc8ce533d5567b8e5a90 [file] [log] [blame]
 //===-- Collection of utils for implementing math functions -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC_MATH_MATH_UTILS_H #define LLVM_LIBC_SRC_MATH_MATH_UTILS_H #include "src/__support/CPP/TypeTraits.h" #include "src/__support/common.h" #include #include #include namespace __llvm_libc { static inline uint32_t as_uint32_bits(float x) { return *reinterpret_cast(&x); } static inline uint64_t as_uint64_bits(double x) { return *reinterpret_cast(&x); } static inline float as_float(uint32_t x) { return *reinterpret_cast(&x); } static inline double as_double(uint64_t x) { return *reinterpret_cast(&x); } static inline uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; } static inline uint32_t top12_bits(double x) { return as_uint64_bits(x) >> 52; } // Values to trigger underflow and overflow. template struct XFlowValues; template <> struct XFlowValues { static const float overflow_value; static const float underflow_value; static const float may_underflow_value; }; template <> struct XFlowValues { static const double overflow_value; static const double underflow_value; static const double may_underflow_value; }; template static inline T with_errno(T x, int err) { if (math_errhandling & MATH_ERRNO) errno = err; return x; } template static inline void force_eval(T x) { volatile T y UNUSED = x; } template static inline T opt_barrier(T x) { volatile T y = x; return y; } template struct IsFloatOrDouble { static constexpr bool Value = cpp::IsSame::Value || cpp::IsSame::Value; }; template using EnableIfFloatOrDouble = cpp::EnableIfType::Value, int>; template = 0> T xflow(uint32_t sign, T y) { // Underflow happens when two extremely small values are multiplied. // Likewise, overflow happens when two large values are multiplied. y = opt_barrier(sign ? -y : y) * y; return with_errno(y, ERANGE); } template = 0> T overflow(uint32_t sign) { return xflow(sign, XFlowValues::overflow_value); } template = 0> T underflow(uint32_t sign) { return xflow(sign, XFlowValues::underflow_value); } template = 0> T may_underflow(uint32_t sign) { return xflow(sign, XFlowValues::may_underflow_value); } template = 0> static inline constexpr float invalid(T x) { T y = (x - x) / (x - x); return isnan(x) ? y : with_errno(y, EDOM); } } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_MATH_MATH_UTILS_H