1 //===-- Collection of utils for implementing math functions -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_MATH_GENERIC_MATH_UTILS_H
10 #define LLVM_LIBC_SRC_MATH_GENERIC_MATH_UTILS_H
12 #include "src/__support/CPP/bit.h"
13 #include "src/__support/CPP/type_traits.h"
14 #include "src/__support/common.h"
15 #include "src/errno/libc_errno.h"
21 namespace LIBC_NAMESPACE
{
23 LIBC_INLINE
uint32_t as_uint32_bits(float x
) {
24 return cpp::bit_cast
<uint32_t>(x
);
27 LIBC_INLINE
uint64_t as_uint64_bits(double x
) {
28 return cpp::bit_cast
<uint64_t>(x
);
31 LIBC_INLINE
float as_float(uint32_t x
) { return cpp::bit_cast
<float>(x
); }
33 LIBC_INLINE
double as_double(uint64_t x
) { return cpp::bit_cast
<double>(x
); }
35 LIBC_INLINE
uint32_t top12_bits(float x
) { return as_uint32_bits(x
) >> 20; }
37 LIBC_INLINE
uint32_t top12_bits(double x
) { return as_uint64_bits(x
) >> 52; }
39 // Values to trigger underflow and overflow.
40 template <typename T
> struct XFlowValues
;
42 template <> struct XFlowValues
<float> {
43 static const float OVERFLOW_VALUE
;
44 static const float UNDERFLOW_VALUE
;
45 static const float MAY_UNDERFLOW_VALUE
;
48 template <> struct XFlowValues
<double> {
49 static const double OVERFLOW_VALUE
;
50 static const double UNDERFLOW_VALUE
;
51 static const double MAY_UNDERFLOW_VALUE
;
54 template <typename T
> LIBC_INLINE T
with_errno(T x
, int err
) {
55 if (math_errhandling
& MATH_ERRNO
)
60 template <typename T
> LIBC_INLINE
void force_eval(T x
) {
61 volatile T y LIBC_UNUSED
= x
;
64 template <typename T
> LIBC_INLINE T
opt_barrier(T x
) {
69 template <typename T
> struct IsFloatOrDouble
{
71 Value
= // NOLINT so that this Value can match the ones for IsSame
72 cpp::is_same_v
<T
, float> || cpp::is_same_v
<T
, double>;
76 using EnableIfFloatOrDouble
= cpp::enable_if_t
<IsFloatOrDouble
<T
>::Value
, int>;
78 template <typename T
, EnableIfFloatOrDouble
<T
> = 0>
79 T
xflow(uint32_t sign
, T y
) {
80 // Underflow happens when two extremely small values are multiplied.
81 // Likewise, overflow happens when two large values are multiplied.
82 y
= opt_barrier(sign
? -y
: y
) * y
;
83 return with_errno(y
, ERANGE
);
86 template <typename T
, EnableIfFloatOrDouble
<T
> = 0> T
overflow(uint32_t sign
) {
87 return xflow(sign
, XFlowValues
<T
>::OVERFLOW_VALUE
);
90 template <typename T
, EnableIfFloatOrDouble
<T
> = 0> T
underflow(uint32_t sign
) {
91 return xflow(sign
, XFlowValues
<T
>::UNDERFLOW_VALUE
);
94 template <typename T
, EnableIfFloatOrDouble
<T
> = 0>
95 T
may_underflow(uint32_t sign
) {
96 return xflow(sign
, XFlowValues
<T
>::MAY_UNDERFLOW_VALUE
);
99 template <typename T
, EnableIfFloatOrDouble
<T
> = 0>
100 LIBC_INLINE
constexpr float invalid(T x
) {
101 T y
= (x
- x
) / (x
- x
);
102 return isnan(x
) ? y
: with_errno(y
, EDOM
);
105 } // namespace LIBC_NAMESPACE
107 #endif // LLVM_LIBC_SRC_MATH_GENERIC_MATH_UTILS_H