xref: /aosp_15_r20/external/ComputeLibrary/support/ToolchainSupport.h (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1*c217d954SCole Faust /*
2*c217d954SCole Faust  * Copyright (c) 2017-2022 Arm Limited.
3*c217d954SCole Faust  *
4*c217d954SCole Faust  * SPDX-License-Identifier: MIT
5*c217d954SCole Faust  *
6*c217d954SCole Faust  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*c217d954SCole Faust  * of this software and associated documentation files (the "Software"), to
8*c217d954SCole Faust  * deal in the Software without restriction, including without limitation the
9*c217d954SCole Faust  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*c217d954SCole Faust  * sell copies of the Software, and to permit persons to whom the Software is
11*c217d954SCole Faust  * furnished to do so, subject to the following conditions:
12*c217d954SCole Faust  *
13*c217d954SCole Faust  * The above copyright notice and this permission notice shall be included in all
14*c217d954SCole Faust  * copies or substantial portions of the Software.
15*c217d954SCole Faust  *
16*c217d954SCole Faust  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*c217d954SCole Faust  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*c217d954SCole Faust  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*c217d954SCole Faust  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*c217d954SCole Faust  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*c217d954SCole Faust  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*c217d954SCole Faust  * SOFTWARE.
23*c217d954SCole Faust  */
24*c217d954SCole Faust #ifndef ARM_COMPUTE_SUPPORT_TOOLCHAINSUPPORT
25*c217d954SCole Faust #define ARM_COMPUTE_SUPPORT_TOOLCHAINSUPPORT
26*c217d954SCole Faust 
27*c217d954SCole Faust #include <cassert>
28*c217d954SCole Faust #include <cmath>
29*c217d954SCole Faust #include <cstddef>
30*c217d954SCole Faust #include <limits>
31*c217d954SCole Faust #include <memory>
32*c217d954SCole Faust #include <sstream>
33*c217d954SCole Faust #include <string>
34*c217d954SCole Faust #include <type_traits>
35*c217d954SCole Faust 
36*c217d954SCole Faust #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
37*c217d954SCole Faust #include <arm_neon.h>
38*c217d954SCole Faust #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
39*c217d954SCole Faust 
40*c217d954SCole Faust #include "support/Bfloat16.h"
41*c217d954SCole Faust #include "support/Half.h"
42*c217d954SCole Faust 
43*c217d954SCole Faust #ifndef M_PI
44*c217d954SCole Faust #define M_PI (3.14159265358979323846)
45*c217d954SCole Faust #endif // M_PI
46*c217d954SCole Faust 
47*c217d954SCole Faust namespace arm_compute
48*c217d954SCole Faust {
49*c217d954SCole Faust namespace support
50*c217d954SCole Faust {
51*c217d954SCole Faust namespace cpp11
52*c217d954SCole Faust {
53*c217d954SCole Faust #if(__ANDROID__ || BARE_METAL)
54*c217d954SCole Faust template <typename T>
nearbyint(T value)55*c217d954SCole Faust inline T nearbyint(T value)
56*c217d954SCole Faust {
57*c217d954SCole Faust     return static_cast<T>(::nearbyint(value));
58*c217d954SCole Faust }
59*c217d954SCole Faust 
60*c217d954SCole Faust /** Round floating-point value with half value rounding away from zero.
61*c217d954SCole Faust  *
62*c217d954SCole Faust  * @note This function implements the same behaviour as std::round except that it doesn't
63*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
64*c217d954SCole Faust  *
65*c217d954SCole Faust  * @param[in] value floating-point value to be rounded.
66*c217d954SCole Faust  *
67*c217d954SCole Faust  * @return Floating-point value of rounded @p value.
68*c217d954SCole Faust  */
69*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
round(T value)70*c217d954SCole Faust inline T round(T value)
71*c217d954SCole Faust {
72*c217d954SCole Faust     return ::round(value);
73*c217d954SCole Faust }
74*c217d954SCole Faust 
75*c217d954SCole Faust /** Round floating-point value with half value rounding away from zero and cast to long
76*c217d954SCole Faust  *
77*c217d954SCole Faust  * @note This function implements the same behaviour as std::lround except that it doesn't
78*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
79*c217d954SCole Faust  *
80*c217d954SCole Faust  * @param[in] value floating-point value to be rounded.
81*c217d954SCole Faust  *
82*c217d954SCole Faust  * @return Floating-point value of rounded @p value casted to long
83*c217d954SCole Faust  */
84*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
lround(T value)85*c217d954SCole Faust inline long lround(T value)
86*c217d954SCole Faust {
87*c217d954SCole Faust     return ::lround(value);
88*c217d954SCole Faust }
89*c217d954SCole Faust 
90*c217d954SCole Faust /** Truncate floating-point value.
91*c217d954SCole Faust  *
92*c217d954SCole Faust  * @note This function implements the same behaviour as std::truncate except that it doesn't
93*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
94*c217d954SCole Faust  *
95*c217d954SCole Faust  * @param[in] value floating-point value to be truncated.
96*c217d954SCole Faust  *
97*c217d954SCole Faust  * @return Floating-point value of truncated @p value.
98*c217d954SCole Faust  */
99*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
trunc(T value)100*c217d954SCole Faust inline T trunc(T value)
101*c217d954SCole Faust {
102*c217d954SCole Faust     return ::trunc(value);
103*c217d954SCole Faust }
104*c217d954SCole Faust 
105*c217d954SCole Faust /** Composes a floating point value with the magnitude of @p x and the sign of @p y.
106*c217d954SCole Faust  *
107*c217d954SCole Faust  * @note This function implements the same behaviour as std::copysign except that it doesn't
108*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
109*c217d954SCole Faust  *
110*c217d954SCole Faust  * @param[in] x value that contains the magnitude to be used in constructing the result.
111*c217d954SCole Faust  * @param[in] y value that contains the sign to be used in construct in the result.
112*c217d954SCole Faust  *
113*c217d954SCole Faust  * @return Floating-point value with magnitude of @p x and sign of @p y.
114*c217d954SCole Faust  */
115*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
copysign(T x,T y)116*c217d954SCole Faust inline T copysign(T x, T y)
117*c217d954SCole Faust {
118*c217d954SCole Faust     return ::copysign(x, y);
119*c217d954SCole Faust }
120*c217d954SCole Faust 
121*c217d954SCole Faust /** Computes (x*y) + z as if to infinite precision and rounded only once to fit the result type.
122*c217d954SCole Faust  *
123*c217d954SCole Faust  * @note This function implements the same behaviour as std::fma except that it doesn't
124*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
125*c217d954SCole Faust  *
126*c217d954SCole Faust  * @param[in] x floating-point value
127*c217d954SCole Faust  * @param[in] y floating-point value
128*c217d954SCole Faust  * @param[in] z floating-point value
129*c217d954SCole Faust  *
130*c217d954SCole Faust  * @return Result floating point value equal to (x*y) + z.c
131*c217d954SCole Faust  */
132*c217d954SCole Faust template < typename T, typename = typename std::enable_if < std::is_floating_point<T>::value
133*c217d954SCole Faust #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
134*c217d954SCole Faust                                                             || std::is_same<T, float16_t>::value
135*c217d954SCole Faust #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
136*c217d954SCole Faust                                                             >::type >
fma(T x,T y,T z)137*c217d954SCole Faust inline T fma(T x, T y, T z)
138*c217d954SCole Faust {
139*c217d954SCole Faust     return ::fma(x, y, z);
140*c217d954SCole Faust }
141*c217d954SCole Faust 
142*c217d954SCole Faust /** Loads the data from the given location, converts them to character string equivalents
143*c217d954SCole Faust  *  and writes the result to a character string buffer.
144*c217d954SCole Faust  *
145*c217d954SCole Faust  * @param[in] s    Pointer to a character string to write to
146*c217d954SCole Faust  * @param[in] n    Up to buf_size - 1 characters may be written, plus the null ending character
147*c217d954SCole Faust  * @param[in] fmt  Pointer to a null-ended multibyte string specifying how to interpret the data.
148*c217d954SCole Faust  * @param[in] args Arguments forwarded to snprintf.
149*c217d954SCole Faust  *
150*c217d954SCole Faust  * @return  Number of characters that would have been written for a sufficiently large buffer
151*c217d954SCole Faust  *          if successful (not including the ending null character), or a negative value if an error occurred.
152*c217d954SCole Faust  */
153*c217d954SCole Faust template <typename... Ts>
snprintf(char * s,size_t n,const char * fmt,Ts &&...args)154*c217d954SCole Faust inline int snprintf(char *s, size_t n, const char *fmt, Ts &&... args)
155*c217d954SCole Faust {
156*c217d954SCole Faust     return ::snprintf(s, n, fmt, std::forward<Ts>(args)...);
157*c217d954SCole Faust }
158*c217d954SCole Faust #else /* (__ANDROID__ || BARE_METAL) */
159*c217d954SCole Faust /** Rounds the floating-point argument arg to an integer value in floating-point format, using the current rounding mode.
160*c217d954SCole Faust  *
161*c217d954SCole Faust  * @note This function acts as a convenience wrapper around std::nearbyint. The
162*c217d954SCole Faust  *       latter is missing in some Android toolchains.
163*c217d954SCole Faust  *
164*c217d954SCole Faust  * @param[in] value Value to be rounded.
165*c217d954SCole Faust  *
166*c217d954SCole Faust  * @return The rounded value.
167*c217d954SCole Faust  */
168*c217d954SCole Faust template <typename T>
169*c217d954SCole Faust inline T nearbyint(T value)
170*c217d954SCole Faust {
171*c217d954SCole Faust     return static_cast<T>(std::nearbyint(value));
172*c217d954SCole Faust }
173*c217d954SCole Faust 
174*c217d954SCole Faust /** Round floating-point value with half value rounding away from zero.
175*c217d954SCole Faust  *
176*c217d954SCole Faust  * @note This function implements the same behaviour as std::round except that it doesn't
177*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
178*c217d954SCole Faust  *
179*c217d954SCole Faust  * @param[in] value floating-point value to be rounded.
180*c217d954SCole Faust  *
181*c217d954SCole Faust  * @return Floating-point value of rounded @p value.
182*c217d954SCole Faust  */
183*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
184*c217d954SCole Faust inline T round(T value)
185*c217d954SCole Faust {
186*c217d954SCole Faust     //Workaround Valgrind's mismatches: when running from Valgrind the call to std::round(-4.500000) == -4.000000 instead of 5.00000
187*c217d954SCole Faust     return (value < 0.f) ? static_cast<int>(value - 0.5f) : static_cast<int>(value + 0.5f);
188*c217d954SCole Faust }
189*c217d954SCole Faust 
190*c217d954SCole Faust /** Round floating-point value with half value rounding away from zero and cast to long
191*c217d954SCole Faust  *
192*c217d954SCole Faust  * @note This function implements the same behaviour as std::lround except that it doesn't
193*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
194*c217d954SCole Faust  *
195*c217d954SCole Faust  * @param[in] value floating-point value to be rounded.
196*c217d954SCole Faust  *
197*c217d954SCole Faust  * @return Floating-point value of rounded @p value casted to long
198*c217d954SCole Faust  */
199*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
200*c217d954SCole Faust inline long lround(T value)
201*c217d954SCole Faust {
202*c217d954SCole Faust     return std::lround(value);
203*c217d954SCole Faust }
204*c217d954SCole Faust 
205*c217d954SCole Faust /** Truncate floating-point value.
206*c217d954SCole Faust  *
207*c217d954SCole Faust  * @note This function implements the same behaviour as std::truncate except that it doesn't
208*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
209*c217d954SCole Faust  *
210*c217d954SCole Faust  * @param[in] value floating-point value to be truncated.
211*c217d954SCole Faust  *
212*c217d954SCole Faust  * @return Floating-point value of truncated @p value.
213*c217d954SCole Faust  */
214*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
215*c217d954SCole Faust inline T trunc(T value)
216*c217d954SCole Faust {
217*c217d954SCole Faust     return std::trunc(value);
218*c217d954SCole Faust }
219*c217d954SCole Faust 
220*c217d954SCole Faust /** Composes a floating point value with the magnitude of @p x and the sign of @p y.
221*c217d954SCole Faust  *
222*c217d954SCole Faust  * @note This function implements the same behaviour as std::copysign except that it doesn't
223*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
224*c217d954SCole Faust  *
225*c217d954SCole Faust  * @param[in] x value that contains the magnitude to be used in constructing the result.
226*c217d954SCole Faust  * @param[in] y value that contains the sign to be used in construct in the result.
227*c217d954SCole Faust  *
228*c217d954SCole Faust  * @return Floating-point value with magnitude of @p x and sign of @p y.
229*c217d954SCole Faust  */
230*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
231*c217d954SCole Faust inline T copysign(T x, T y)
232*c217d954SCole Faust {
233*c217d954SCole Faust     return std::copysign(x, y);
234*c217d954SCole Faust }
235*c217d954SCole Faust 
236*c217d954SCole Faust /** Computes (x*y) + z as if to infinite precision and rounded only once to fit the result type.
237*c217d954SCole Faust  *
238*c217d954SCole Faust  * @note This function implements the same behaviour as std::fma except that it doesn't
239*c217d954SCole Faust  *       support Integral type. The latter is not in the namespace std in some Android toolchains.
240*c217d954SCole Faust  *
241*c217d954SCole Faust  * @param[in] x floating-point value
242*c217d954SCole Faust  * @param[in] y floating-point value
243*c217d954SCole Faust  * @param[in] z floating-point value
244*c217d954SCole Faust  *
245*c217d954SCole Faust  * @return Result floating point value equal to (x*y) + z.
246*c217d954SCole Faust  */
247*c217d954SCole Faust template < typename T, typename = typename std::enable_if < std::is_floating_point<T>::value
248*c217d954SCole Faust #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
249*c217d954SCole Faust                                                             || std::is_same<T, float16_t>::value
250*c217d954SCole Faust #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
251*c217d954SCole Faust                                                             >::type >
252*c217d954SCole Faust inline T fma(T x, T y, T z)
253*c217d954SCole Faust {
254*c217d954SCole Faust     return std::fma(x, y, z);
255*c217d954SCole Faust }
256*c217d954SCole Faust 
257*c217d954SCole Faust /** Loads the data from the given location, converts them to character string equivalents
258*c217d954SCole Faust  *  and writes the result to a character string buffer.
259*c217d954SCole Faust  *
260*c217d954SCole Faust  * @param[in] s    Pointer to a character string to write to
261*c217d954SCole Faust  * @param[in] n    Up to buf_size - 1 characters may be written, plus the null ending character
262*c217d954SCole Faust  * @param[in] fmt  Pointer to a null-ended multibyte string specifying how to interpret the data.
263*c217d954SCole Faust  * @param[in] args Arguments forwarded to std::snprintf.
264*c217d954SCole Faust  *
265*c217d954SCole Faust  * @return  Number of characters that would have been written for a sufficiently large buffer
266*c217d954SCole Faust  *          if successful (not including the ending null character), or a negative value if an error occurred.
267*c217d954SCole Faust  */
268*c217d954SCole Faust template <typename... Ts>
269*c217d954SCole Faust inline int snprintf(char *s, std::size_t n, const char *fmt, Ts &&... args)
270*c217d954SCole Faust {
271*c217d954SCole Faust     return std::snprintf(s, n, fmt, std::forward<Ts>(args)...);
272*c217d954SCole Faust }
273*c217d954SCole Faust #endif /* (__ANDROID__ || BARE_METAL) */
274*c217d954SCole Faust 
275*c217d954SCole Faust // std::numeric_limits<T>::lowest
276*c217d954SCole Faust template <typename T>
lowest()277*c217d954SCole Faust inline T lowest()
278*c217d954SCole Faust {
279*c217d954SCole Faust     return std::numeric_limits<T>::lowest();
280*c217d954SCole Faust }
281*c217d954SCole Faust 
282*c217d954SCole Faust #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
283*c217d954SCole Faust template <>
284*c217d954SCole Faust inline __fp16 lowest<__fp16>()
285*c217d954SCole Faust {
286*c217d954SCole Faust     return std::numeric_limits<half_float::half>::lowest();
287*c217d954SCole Faust }
288*c217d954SCole Faust #endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
289*c217d954SCole Faust 
290*c217d954SCole Faust template <>
291*c217d954SCole Faust inline bfloat16 lowest<bfloat16>()
292*c217d954SCole Faust {
293*c217d954SCole Faust     return bfloat16::lowest();
294*c217d954SCole Faust }
295*c217d954SCole Faust 
296*c217d954SCole Faust // std::isfinite
297*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
isfinite(T value)298*c217d954SCole Faust inline bool isfinite(T value)
299*c217d954SCole Faust {
300*c217d954SCole Faust     return std::isfinite(static_cast<double>(value));
301*c217d954SCole Faust }
302*c217d954SCole Faust 
isfinite(half_float::half value)303*c217d954SCole Faust inline bool isfinite(half_float::half value)
304*c217d954SCole Faust {
305*c217d954SCole Faust     return half_float::isfinite(value);
306*c217d954SCole Faust }
307*c217d954SCole Faust 
isfinite(bfloat16 value)308*c217d954SCole Faust inline bool isfinite(bfloat16 value)
309*c217d954SCole Faust {
310*c217d954SCole Faust     return std::isfinite(float(value));
311*c217d954SCole Faust }
312*c217d954SCole Faust 
313*c217d954SCole Faust // std::signbit
314*c217d954SCole Faust template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
signbit(T value)315*c217d954SCole Faust inline bool signbit(T value)
316*c217d954SCole Faust {
317*c217d954SCole Faust     return std::signbit(static_cast<double>(value));
318*c217d954SCole Faust }
319*c217d954SCole Faust 
signbit(half_float::half value)320*c217d954SCole Faust inline bool signbit(half_float::half value)
321*c217d954SCole Faust {
322*c217d954SCole Faust     return half_float::signbit(value);
323*c217d954SCole Faust }
324*c217d954SCole Faust 
signbit(bfloat16 value)325*c217d954SCole Faust inline bool signbit(bfloat16 value)
326*c217d954SCole Faust {
327*c217d954SCole Faust     return std::signbit(float(value));
328*c217d954SCole Faust }
329*c217d954SCole Faust } // namespace cpp11
330*c217d954SCole Faust } // namespace support
331*c217d954SCole Faust } // namespace arm_compute
332*c217d954SCole Faust #endif /* ARM_COMPUTE_SUPPORT_TOOLCHAINSUPPORT */
333