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/TypeTraits.h"
13 #include "src/__support/common.h"
14 #include <errno.h>
15 #include <math.h>
16 
17 #include <stdint.h>
18 
19 namespace __llvm_libc {
20 
21 static inline uint32_t as_uint32_bits(float x) {
22   return *reinterpret_cast<uint32_t *>(&x);
23 }
24 
25 static inline uint64_t as_uint64_bits(double x) {
26   return *reinterpret_cast<uint64_t *>(&x);
27 }
28 
29 static inline float as_float(uint32_t x) {
30   return *reinterpret_cast<float *>(&x);
31 }
32 
33 static inline double as_double(uint64_t x) {
34   return *reinterpret_cast<double *>(&x);
35 }
36 
37 static inline uint32_t top12_bits(float x) { return as_uint32_bits(x) >> 20; }
38 
39 static inline uint32_t top12_bits(double x) { return as_uint64_bits(x) >> 52; }
40 
41 // Values to trigger underflow and overflow.
42 template <typename T> struct XFlowValues;
43 
44 template <> struct XFlowValues<float> {
45   static const float OVERFLOW_VALUE;
46   static const float UNDERFLOW_VALUE;
47   static const float MAY_UNDERFLOW_VALUE;
48 };
49 
50 template <> struct XFlowValues<double> {
51   static const double OVERFLOW_VALUE;
52   static const double UNDERFLOW_VALUE;
53   static const double MAY_UNDERFLOW_VALUE;
54 };
55 
56 template <typename T> static inline T with_errno(T x, int err) {
57   if (math_errhandling & MATH_ERRNO)
58     errno = err;
59   return x;
60 }
61 
62 template <typename T> static inline void force_eval(T x) {
63   volatile T y UNUSED = x;
64 }
65 
66 template <typename T> static inline T opt_barrier(T x) {
67   volatile T y = x;
68   return y;
69 }
70 
71 template <typename T> struct IsFloatOrDouble {
72   static constexpr bool
73       Value = // NOLINT so that this Value can match the ones for IsSame
74       cpp::IsSame<T, float>::Value || cpp::IsSame<T, double>::Value;
75 };
76 
77 template <typename T>
78 using EnableIfFloatOrDouble = cpp::EnableIfType<IsFloatOrDouble<T>::Value, int>;
79 
80 template <typename T, EnableIfFloatOrDouble<T> = 0>
81 T xflow(uint32_t sign, T y) {
82   // Underflow happens when two extremely small values are multiplied.
83   // Likewise, overflow happens when two large values are multiplied.
84   y = opt_barrier(sign ? -y : y) * y;
85   return with_errno(y, ERANGE);
86 }
87 
88 template <typename T, EnableIfFloatOrDouble<T> = 0> T overflow(uint32_t sign) {
89   return xflow(sign, XFlowValues<T>::OVERFLOW_VALUE);
90 }
91 
92 template <typename T, EnableIfFloatOrDouble<T> = 0> T underflow(uint32_t sign) {
93   return xflow(sign, XFlowValues<T>::UNDERFLOW_VALUE);
94 }
95 
96 template <typename T, EnableIfFloatOrDouble<T> = 0>
97 T may_underflow(uint32_t sign) {
98   return xflow(sign, XFlowValues<T>::MAY_UNDERFLOW_VALUE);
99 }
100 
101 template <typename T, EnableIfFloatOrDouble<T> = 0>
102 static inline constexpr float invalid(T x) {
103   T y = (x - x) / (x - x);
104   return isnan(x) ? y : with_errno(y, EDOM);
105 }
106 
107 } // namespace __llvm_libc
108 
109 #endif // LLVM_LIBC_SRC_MATH_MATH_UTILS_H
110