1 | //===-- runtime/Float128Math/math-entries.h ---------------------*- 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 FORTRAN_RUNTIME_FLOAT128MATH_MATH_ENTRIES_H_ |
10 | #define FORTRAN_RUNTIME_FLOAT128MATH_MATH_ENTRIES_H_ |
11 | #include "terminator.h" |
12 | #include "tools.h" |
13 | #include "flang/Common/float128.h" |
14 | #include "flang/Runtime/entry-names.h" |
15 | #include <cfloat> |
16 | #include <cmath> |
17 | #include <type_traits> |
18 | |
19 | namespace { |
20 | using namespace Fortran::runtime; |
21 | using F128RetType = CppTypeFor<TypeCategory::Real, 16>; |
22 | using I32RetType = CppTypeFor<TypeCategory::Integer, 4>; |
23 | using I64RetType = CppTypeFor<TypeCategory::Integer, 8>; |
24 | } // namespace |
25 | |
26 | namespace Fortran::runtime { |
27 | |
28 | // Define a class template to gracefully fail, when |
29 | // there is no specialized template that implements |
30 | // the required function via using the third-party |
31 | // implementation. |
32 | #define DEFINE_FALLBACK(caller, ret_type) \ |
33 | template <bool = false, typename RT = ret_type> struct caller { \ |
34 | template <typename... ATs> [[noreturn]] static RT invoke(ATs... args) { \ |
35 | Terminator terminator{__FILE__, __LINE__}; \ |
36 | terminator.Crash("Float128 variant of '%s' is unsupported", #caller); \ |
37 | } \ |
38 | }; |
39 | |
40 | // Define template specialization that is calling the third-party |
41 | // implementation. |
42 | // |
43 | // Defining the specialization for any target library requires |
44 | // adding the generic template via DEFINE_FALLBACK, so that |
45 | // a build with another target library that does not define |
46 | // the same alias can gracefully fail in runtime. |
47 | #define DEFINE_SIMPLE_ALIAS(caller, callee) \ |
48 | template <typename RT> struct caller<true, RT> { \ |
49 | template <typename... ATs> static RT invoke(ATs... args) { \ |
50 | static_assert(std::is_invocable_r_v<RT, \ |
51 | decltype(callee(std::declval<ATs>()...))(ATs...), ATs...>); \ |
52 | if constexpr (std::is_same_v<RT, void>) { \ |
53 | callee(args...); \ |
54 | } else { \ |
55 | return callee(args...); \ |
56 | } \ |
57 | } \ |
58 | }; |
59 | |
60 | // Define fallback callers. |
61 | #define DEFINE_FALLBACK_F128(caller) DEFINE_FALLBACK(caller, ::F128RetType) |
62 | #define DEFINE_FALLBACK_I32(caller) DEFINE_FALLBACK(caller, ::I32RetType) |
63 | #define DEFINE_FALLBACK_I64(caller) DEFINE_FALLBACK(caller, ::I64RetType) |
64 | |
65 | DEFINE_FALLBACK_F128(Abs) |
66 | DEFINE_FALLBACK_F128(Acos) |
67 | DEFINE_FALLBACK_F128(Acosh) |
68 | DEFINE_FALLBACK_F128(Asin) |
69 | DEFINE_FALLBACK_F128(Asinh) |
70 | DEFINE_FALLBACK_F128(Atan) |
71 | DEFINE_FALLBACK_F128(Atan2) |
72 | DEFINE_FALLBACK_F128(Atanh) |
73 | DEFINE_FALLBACK_F128(Ceil) |
74 | DEFINE_FALLBACK_F128(Cos) |
75 | DEFINE_FALLBACK_F128(Cosh) |
76 | DEFINE_FALLBACK_F128(Erf) |
77 | DEFINE_FALLBACK_F128(Erfc) |
78 | DEFINE_FALLBACK_F128(Exp) |
79 | DEFINE_FALLBACK_F128(Floor) |
80 | DEFINE_FALLBACK_F128(Fma) |
81 | DEFINE_FALLBACK_F128(Frexp) |
82 | DEFINE_FALLBACK_F128(Hypot) |
83 | DEFINE_FALLBACK_I32(Ilogb) |
84 | DEFINE_FALLBACK_I32(Isinf) |
85 | DEFINE_FALLBACK_I32(Isnan) |
86 | DEFINE_FALLBACK_F128(J0) |
87 | DEFINE_FALLBACK_F128(J1) |
88 | DEFINE_FALLBACK_F128(Jn) |
89 | DEFINE_FALLBACK_F128(Ldexp) |
90 | DEFINE_FALLBACK_F128(Lgamma) |
91 | DEFINE_FALLBACK_I64(Llround) |
92 | DEFINE_FALLBACK_F128(Log) |
93 | DEFINE_FALLBACK_F128(Log10) |
94 | DEFINE_FALLBACK_I32(Lround) |
95 | DEFINE_FALLBACK_F128(Nextafter) |
96 | DEFINE_FALLBACK_F128(Pow) |
97 | DEFINE_FALLBACK_F128(Qnan) |
98 | DEFINE_FALLBACK_F128(Round) |
99 | DEFINE_FALLBACK_F128(Sin) |
100 | DEFINE_FALLBACK_F128(Sinh) |
101 | DEFINE_FALLBACK_F128(Sqrt) |
102 | DEFINE_FALLBACK_F128(Tan) |
103 | DEFINE_FALLBACK_F128(Tanh) |
104 | DEFINE_FALLBACK_F128(Tgamma) |
105 | DEFINE_FALLBACK_F128(Trunc) |
106 | DEFINE_FALLBACK_F128(Y0) |
107 | DEFINE_FALLBACK_F128(Y1) |
108 | DEFINE_FALLBACK_F128(Yn) |
109 | |
110 | #if HAS_QUADMATHLIB |
111 | // Define wrapper callers for libquadmath. |
112 | #include "quadmath.h" |
113 | DEFINE_SIMPLE_ALIAS(Abs, fabsq) |
114 | DEFINE_SIMPLE_ALIAS(Acos, acosq) |
115 | DEFINE_SIMPLE_ALIAS(Acosh, acoshq) |
116 | DEFINE_SIMPLE_ALIAS(Asin, asinq) |
117 | DEFINE_SIMPLE_ALIAS(Asinh, asinhq) |
118 | DEFINE_SIMPLE_ALIAS(Atan, atanq) |
119 | DEFINE_SIMPLE_ALIAS(Atan2, atan2q) |
120 | DEFINE_SIMPLE_ALIAS(Atanh, atanhq) |
121 | DEFINE_SIMPLE_ALIAS(Ceil, ceilq) |
122 | DEFINE_SIMPLE_ALIAS(Cos, cosq) |
123 | DEFINE_SIMPLE_ALIAS(Cosh, coshq) |
124 | DEFINE_SIMPLE_ALIAS(Erf, erfq) |
125 | DEFINE_SIMPLE_ALIAS(Erfc, erfcq) |
126 | DEFINE_SIMPLE_ALIAS(Exp, expq) |
127 | DEFINE_SIMPLE_ALIAS(Floor, floorq) |
128 | DEFINE_SIMPLE_ALIAS(Fma, fmaq) |
129 | DEFINE_SIMPLE_ALIAS(Frexp, frexpq) |
130 | DEFINE_SIMPLE_ALIAS(Hypot, hypotq) |
131 | DEFINE_SIMPLE_ALIAS(Ilogb, ilogbq) |
132 | DEFINE_SIMPLE_ALIAS(Isinf, isinfq) |
133 | DEFINE_SIMPLE_ALIAS(Isnan, isnanq) |
134 | DEFINE_SIMPLE_ALIAS(J0, j0q) |
135 | DEFINE_SIMPLE_ALIAS(J1, j1q) |
136 | DEFINE_SIMPLE_ALIAS(Jn, jnq) |
137 | DEFINE_SIMPLE_ALIAS(Ldexp, ldexpq) |
138 | DEFINE_SIMPLE_ALIAS(Lgamma, lgammaq) |
139 | DEFINE_SIMPLE_ALIAS(Llround, llroundq) |
140 | DEFINE_SIMPLE_ALIAS(Log, logq) |
141 | DEFINE_SIMPLE_ALIAS(Log10, log10q) |
142 | DEFINE_SIMPLE_ALIAS(Lround, lroundq) |
143 | DEFINE_SIMPLE_ALIAS(Nextafter, nextafterq) |
144 | DEFINE_SIMPLE_ALIAS(Pow, powq) |
145 | DEFINE_SIMPLE_ALIAS(Round, roundq) |
146 | DEFINE_SIMPLE_ALIAS(Sin, sinq) |
147 | DEFINE_SIMPLE_ALIAS(Sinh, sinhq) |
148 | DEFINE_SIMPLE_ALIAS(Sqrt, sqrtq) |
149 | DEFINE_SIMPLE_ALIAS(Tan, tanq) |
150 | DEFINE_SIMPLE_ALIAS(Tanh, tanhq) |
151 | DEFINE_SIMPLE_ALIAS(Tgamma, tgammaq) |
152 | DEFINE_SIMPLE_ALIAS(Trunc, truncq) |
153 | DEFINE_SIMPLE_ALIAS(Y0, y0q) |
154 | DEFINE_SIMPLE_ALIAS(Y1, y1q) |
155 | DEFINE_SIMPLE_ALIAS(Yn, ynq) |
156 | |
157 | // Use cmath INFINITY/NAN definition. Rely on C implicit conversions. |
158 | #define F128_RT_INFINITY (INFINITY) |
159 | #define F128_RT_QNAN (NAN) |
160 | #elif LDBL_MANT_DIG == 113 |
161 | // Define wrapper callers for libm. |
162 | #include <limits> |
163 | |
164 | // Use STD math functions. They provide IEEE-754 128-bit float |
165 | // support either via 'long double' or __float128. |
166 | // The Bessel's functions are not present in STD namespace. |
167 | DEFINE_SIMPLE_ALIAS(Abs, std::abs) |
168 | DEFINE_SIMPLE_ALIAS(Acos, std::acos) |
169 | DEFINE_SIMPLE_ALIAS(Acosh, std::acosh) |
170 | DEFINE_SIMPLE_ALIAS(Asin, std::asin) |
171 | DEFINE_SIMPLE_ALIAS(Asinh, std::asinh) |
172 | DEFINE_SIMPLE_ALIAS(Atan, std::atan) |
173 | DEFINE_SIMPLE_ALIAS(Atan2, std::atan2) |
174 | DEFINE_SIMPLE_ALIAS(Atanh, std::atanh) |
175 | DEFINE_SIMPLE_ALIAS(Ceil, std::ceil) |
176 | DEFINE_SIMPLE_ALIAS(Cos, std::cos) |
177 | DEFINE_SIMPLE_ALIAS(Cosh, std::cosh) |
178 | DEFINE_SIMPLE_ALIAS(Erf, std::erf) |
179 | DEFINE_SIMPLE_ALIAS(Erfc, std::erfc) |
180 | DEFINE_SIMPLE_ALIAS(Exp, std::exp) |
181 | DEFINE_SIMPLE_ALIAS(Floor, std::floor) |
182 | DEFINE_SIMPLE_ALIAS(Fma, std::fma) |
183 | DEFINE_SIMPLE_ALIAS(Frexp, std::frexp) |
184 | DEFINE_SIMPLE_ALIAS(Hypot, std::hypot) |
185 | DEFINE_SIMPLE_ALIAS(Ilogb, std::ilogb) |
186 | DEFINE_SIMPLE_ALIAS(Isinf, std::isinf) |
187 | DEFINE_SIMPLE_ALIAS(Isnan, std::isnan) |
188 | DEFINE_SIMPLE_ALIAS(J0, j0l) |
189 | DEFINE_SIMPLE_ALIAS(J1, j1l) |
190 | DEFINE_SIMPLE_ALIAS(Jn, jnl) |
191 | DEFINE_SIMPLE_ALIAS(Ldexp, std::ldexp) |
192 | DEFINE_SIMPLE_ALIAS(Lgamma, std::lgamma) |
193 | DEFINE_SIMPLE_ALIAS(Llround, std::llround) |
194 | DEFINE_SIMPLE_ALIAS(Log, std::log) |
195 | DEFINE_SIMPLE_ALIAS(Log10, std::log10) |
196 | DEFINE_SIMPLE_ALIAS(Lround, std::lround) |
197 | DEFINE_SIMPLE_ALIAS(Nextafter, std::nextafter) |
198 | DEFINE_SIMPLE_ALIAS(Pow, std::pow) |
199 | DEFINE_SIMPLE_ALIAS(Round, std::round) |
200 | DEFINE_SIMPLE_ALIAS(Sin, std::sin) |
201 | DEFINE_SIMPLE_ALIAS(Sinh, std::sinh) |
202 | DEFINE_SIMPLE_ALIAS(Sqrt, std::sqrt) |
203 | DEFINE_SIMPLE_ALIAS(Tan, std::tan) |
204 | DEFINE_SIMPLE_ALIAS(Tanh, std::tanh) |
205 | DEFINE_SIMPLE_ALIAS(Tgamma, std::tgamma) |
206 | DEFINE_SIMPLE_ALIAS(Trunc, std::trunc) |
207 | DEFINE_SIMPLE_ALIAS(Y0, y0l) |
208 | DEFINE_SIMPLE_ALIAS(Y1, y1l) |
209 | DEFINE_SIMPLE_ALIAS(Yn, ynl) |
210 | |
211 | // Use numeric_limits to produce infinity of the right type. |
212 | #define F128_RT_INFINITY \ |
213 | (std::numeric_limits<CppTypeFor<TypeCategory::Real, 16>>::infinity()) |
214 | #define F128_RT_QNAN \ |
215 | (std::numeric_limits<CppTypeFor<TypeCategory::Real, 16>>::quiet_NaN()) |
216 | #elif HAS_LIBMF128 |
217 | // We can use __float128 versions of libm functions. |
218 | // __STDC_WANT_IEC_60559_TYPES_EXT__ needs to be defined |
219 | // before including cmath to enable the *f128 prototypes. |
220 | #error "Float128Math build with glibc>=2.26 is unsupported yet" |
221 | #endif |
222 | |
223 | } // namespace Fortran::runtime |
224 | |
225 | #endif // FORTRAN_RUNTIME_FLOAT128MATH_MATH_ENTRIES_H_ |
226 | |