//===-- 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/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/common.h" #include "src/errno/libc_errno.h" #include #include namespace __llvm_libc { LIBC_INLINE uint32_t as_uint32_bits(float x) { return cpp::bit_cast(x); } LIBC_INLINE uint64_t as_uint64_bits(double x) { return cpp::bit_cast(x); } LIBC_INLINE float as_float(uint32_t x) { return cpp::bit_cast(x); } LIBC_INLINE double as_double(uint64_t x) { return cpp::bit_cast(x); } LIBC_INLINE uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; } LIBC_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 LIBC_INLINE T with_errno(T x, int err) { if (math_errhandling & MATH_ERRNO) libc_errno = err; return x; } template LIBC_INLINE void force_eval(T x) { volatile T y LIBC_UNUSED = x; } template LIBC_INLINE T opt_barrier(T x) { volatile T y = x; return y; } template struct IsFloatOrDouble { static constexpr bool Value = // NOLINT so that this Value can match the ones for IsSame cpp::is_same_v || cpp::is_same_v; }; template using EnableIfFloatOrDouble = cpp::enable_if_t::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> LIBC_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