Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libc / src / math / generic / math_utils.h
blob38a14a47e88fa531fba36a4428996c19c2d35c57
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 //===----------------------------------------------------------------------===//
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"
17 #include <math.h>
19 #include <stdint.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)
56 libc_errno = err;
57 return x;
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) {
65 volatile T y = x;
66 return y;
69 template <typename T> struct IsFloatOrDouble {
70 static constexpr bool
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>;
75 template <typename T>
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