blob: 4d394889c392af8d15ea51b7ad35b026488cc5ed [file] [log] [blame]
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +01001/*
Matthew Bentham7d9a78e2023-05-31 13:18:33 +00002 * Copyright (c) 2017-2023 Arm Limited.
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
Matthew Bentham758b5ba2020-03-05 23:37:48 +000024#ifndef ARM_COMPUTE_SUPPORT_TOOLCHAINSUPPORT
25#define ARM_COMPUTE_SUPPORT_TOOLCHAINSUPPORT
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010026
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010027#include "support/Bfloat16.h"
28#include "support/Half.h"
29
Pablo Tello65f99822018-05-24 11:40:15 +010030#include <cassert>
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010031#include <cmath>
32#include <cstddef>
33#include <limits>
34#include <memory>
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010035#include <sstream>
36#include <string>
37#include <type_traits>
38
SiCongLi410e21e2020-12-11 15:07:53 +000039#ifndef M_PI
40#define M_PI (3.14159265358979323846)
41#endif // M_PI
42
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010043namespace arm_compute
44{
Matthew Bentham7d9a78e2023-05-31 13:18:33 +000045#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
46typedef __fp16 float16_t;
47#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
48
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010049namespace support
50{
51namespace cpp11
52{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010053#if (__ANDROID__ || BARE_METAL)
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +010054template <typename T>
55inline T nearbyint(T value)
56{
Michalis Spyrou748a7c82019-10-07 13:00:44 +010057 return static_cast<T>(::nearbyint(value));
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +010058}
59
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010060/** Round floating-point value with half value rounding away from zero.
61 *
62 * @note This function implements the same behaviour as std::round except that it doesn't
63 * support Integral type. The latter is not in the namespace std in some Android toolchains.
64 *
65 * @param[in] value floating-point value to be rounded.
66 *
67 * @return Floating-point value of rounded @p value.
68 */
69template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
70inline T round(T value)
71{
72 return ::round(value);
73}
74
Giorgio Arena433ea492021-05-26 15:32:50 +010075/** Round floating-point value with half value rounding away from zero and cast to long
76 *
77 * @note This function implements the same behaviour as std::lround except that it doesn't
78 * support Integral type. The latter is not in the namespace std in some Android toolchains.
79 *
80 * @param[in] value floating-point value to be rounded.
81 *
82 * @return Floating-point value of rounded @p value casted to long
83 */
84template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
85inline long lround(T value)
86{
87 return ::lround(value);
88}
89
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +010090/** Truncate floating-point value.
91 *
92 * @note This function implements the same behaviour as std::truncate except that it doesn't
93 * support Integral type. The latter is not in the namespace std in some Android toolchains.
94 *
95 * @param[in] value floating-point value to be truncated.
96 *
97 * @return Floating-point value of truncated @p value.
98 */
99template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
100inline T trunc(T value)
101{
102 return ::trunc(value);
103}
104
105/** Composes a floating point value with the magnitude of @p x and the sign of @p y.
106 *
107 * @note This function implements the same behaviour as std::copysign except that it doesn't
108 * support Integral type. The latter is not in the namespace std in some Android toolchains.
109 *
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100110 * @param[in] x value that contains the magnitude to be used in constructing the result.
111 * @param[in] y value that contains the sign to be used in construct in the result.
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100112 *
113 * @return Floating-point value with magnitude of @p x and sign of @p y.
114 */
115template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
116inline T copysign(T x, T y)
117{
118 return ::copysign(x, y);
119}
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100120
Georgios Pinitas1c29ffc2019-08-01 15:03:00 +0100121/** Computes (x*y) + z as if to infinite precision and rounded only once to fit the result type.
122 *
123 * @note This function implements the same behaviour as std::fma except that it doesn't
124 * support Integral type. The latter is not in the namespace std in some Android toolchains.
125 *
126 * @param[in] x floating-point value
127 * @param[in] y floating-point value
128 * @param[in] z floating-point value
129 *
130 * @return Result floating point value equal to (x*y) + z.c
131 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100132template <typename T,
133 typename = typename std::enable_if<std::is_floating_point<T>::value
Giorgio Arenad93e2632019-10-15 11:09:33 +0100134#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100135 || std::is_same<T, float16_t>::value
Giorgio Arenad93e2632019-10-15 11:09:33 +0100136#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100137 >::type>
Georgios Pinitas1c29ffc2019-08-01 15:03:00 +0100138inline T fma(T x, T y, T z)
139{
140 return ::fma(x, y, z);
141}
142
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100143/** Loads the data from the given location, converts them to character string equivalents
144 * and writes the result to a character string buffer.
145 *
146 * @param[in] s Pointer to a character string to write to
ramelg01b2eba7f2021-12-23 08:32:08 +0000147 * @param[in] n Up to buf_size - 1 characters may be written, plus the null ending character
148 * @param[in] fmt Pointer to a null-ended multibyte string specifying how to interpret the data.
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100149 * @param[in] args Arguments forwarded to snprintf.
150 *
151 * @return Number of characters that would have been written for a sufficiently large buffer
ramelg01b2eba7f2021-12-23 08:32:08 +0000152 * if successful (not including the ending null character), or a negative value if an error occurred.
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100153 */
154template <typename... Ts>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100155inline int snprintf(char *s, size_t n, const char *fmt, Ts &&...args)
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100156{
157 return ::snprintf(s, n, fmt, std::forward<Ts>(args)...);
158}
Giorgio Arenad93e2632019-10-15 11:09:33 +0100159#else /* (__ANDROID__ || BARE_METAL) */
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +0100160/** Rounds the floating-point argument arg to an integer value in floating-point format, using the current rounding mode.
161 *
162 * @note This function acts as a convenience wrapper around std::nearbyint. The
163 * latter is missing in some Android toolchains.
164 *
165 * @param[in] value Value to be rounded.
166 *
167 * @return The rounded value.
168 */
169template <typename T>
170inline T nearbyint(T value)
171{
Michalis Spyrou748a7c82019-10-07 13:00:44 +0100172 return static_cast<T>(std::nearbyint(value));
Michalis Spyroue6bcb5b2019-06-07 11:47:16 +0100173}
174
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100175/** Round floating-point value with half value rounding away from zero.
176 *
177 * @note This function implements the same behaviour as std::round except that it doesn't
178 * support Integral type. The latter is not in the namespace std in some Android toolchains.
179 *
180 * @param[in] value floating-point value to be rounded.
181 *
182 * @return Floating-point value of rounded @p value.
183 */
184template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
185inline T round(T value)
186{
Pablo Tello826c7692018-01-16 11:41:12 +0000187 //Workaround Valgrind's mismatches: when running from Valgrind the call to std::round(-4.500000) == -4.000000 instead of 5.00000
188 return (value < 0.f) ? static_cast<int>(value - 0.5f) : static_cast<int>(value + 0.5f);
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100189}
190
Giorgio Arena433ea492021-05-26 15:32:50 +0100191/** Round floating-point value with half value rounding away from zero and cast to long
192 *
193 * @note This function implements the same behaviour as std::lround except that it doesn't
194 * support Integral type. The latter is not in the namespace std in some Android toolchains.
195 *
196 * @param[in] value floating-point value to be rounded.
197 *
198 * @return Floating-point value of rounded @p value casted to long
199 */
200template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
201inline long lround(T value)
202{
203 return std::lround(value);
204}
205
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100206/** Truncate floating-point value.
207 *
208 * @note This function implements the same behaviour as std::truncate except that it doesn't
209 * support Integral type. The latter is not in the namespace std in some Android toolchains.
210 *
211 * @param[in] value floating-point value to be truncated.
212 *
213 * @return Floating-point value of truncated @p value.
214 */
215template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
216inline T trunc(T value)
217{
218 return std::trunc(value);
219}
220
221/** Composes a floating point value with the magnitude of @p x and the sign of @p y.
222 *
223 * @note This function implements the same behaviour as std::copysign except that it doesn't
224 * support Integral type. The latter is not in the namespace std in some Android toolchains.
225 *
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100226 * @param[in] x value that contains the magnitude to be used in constructing the result.
227 * @param[in] y value that contains the sign to be used in construct in the result.
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100228 *
229 * @return Floating-point value with magnitude of @p x and sign of @p y.
230 */
231template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
232inline T copysign(T x, T y)
233{
234 return std::copysign(x, y);
235}
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100236
Georgios Pinitas1c29ffc2019-08-01 15:03:00 +0100237/** Computes (x*y) + z as if to infinite precision and rounded only once to fit the result type.
238 *
239 * @note This function implements the same behaviour as std::fma except that it doesn't
240 * support Integral type. The latter is not in the namespace std in some Android toolchains.
241 *
242 * @param[in] x floating-point value
243 * @param[in] y floating-point value
244 * @param[in] z floating-point value
245 *
246 * @return Result floating point value equal to (x*y) + z.
247 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100248template <typename T,
249 typename = typename std::enable_if<std::is_floating_point<T>::value
Giorgio Arenad93e2632019-10-15 11:09:33 +0100250#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100251 || std::is_same<T, float16_t>::value
Giorgio Arenad93e2632019-10-15 11:09:33 +0100252#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100253 >::type>
Georgios Pinitas1c29ffc2019-08-01 15:03:00 +0100254inline T fma(T x, T y, T z)
255{
256 return std::fma(x, y, z);
257}
258
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100259/** Loads the data from the given location, converts them to character string equivalents
260 * and writes the result to a character string buffer.
261 *
262 * @param[in] s Pointer to a character string to write to
ramelg01b2eba7f2021-12-23 08:32:08 +0000263 * @param[in] n Up to buf_size - 1 characters may be written, plus the null ending character
264 * @param[in] fmt Pointer to a null-ended multibyte string specifying how to interpret the data.
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100265 * @param[in] args Arguments forwarded to std::snprintf.
266 *
267 * @return Number of characters that would have been written for a sufficiently large buffer
ramelg01b2eba7f2021-12-23 08:32:08 +0000268 * if successful (not including the ending null character), or a negative value if an error occurred.
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100269 */
270template <typename... Ts>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100271inline int snprintf(char *s, std::size_t n, const char *fmt, Ts &&...args)
Georgios Pinitas7d3d1b92017-10-12 17:34:20 +0100272{
273 return std::snprintf(s, n, fmt, std::forward<Ts>(args)...);
274}
Michalis Spyrou07781ac2017-08-31 15:11:41 +0100275#endif /* (__ANDROID__ || BARE_METAL) */
Moritz Pflanzer572ade72017-07-21 17:36:33 +0100276
Anthony Barbier3a6163e2018-08-10 17:36:36 +0100277// std::numeric_limits<T>::lowest
278template <typename T>
279inline T lowest()
280{
281 return std::numeric_limits<T>::lowest();
282}
283
284#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
285template <>
286inline __fp16 lowest<__fp16>()
287{
288 return std::numeric_limits<half_float::half>::lowest();
289}
290#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Ioan-Cristian Szabo33fd07b2017-10-26 15:42:24 +0100291
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000292template <>
293inline bfloat16 lowest<bfloat16>()
294{
295 return bfloat16::lowest();
296}
297
Ioan-Cristian Szabo33fd07b2017-10-26 15:42:24 +0100298// std::isfinite
299template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
300inline bool isfinite(T value)
301{
Pablo Tello29cab362022-03-10 17:05:34 +0000302 return std::isfinite(static_cast<double>(value));
Ioan-Cristian Szabo33fd07b2017-10-26 15:42:24 +0100303}
304
305inline bool isfinite(half_float::half value)
306{
307 return half_float::isfinite(value);
308}
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000309
310inline bool isfinite(bfloat16 value)
311{
312 return std::isfinite(float(value));
313}
SiCongLib99e54e2022-01-05 12:18:03 +0000314
315// std::signbit
316template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
317inline bool signbit(T value)
318{
Pablo Tello29cab362022-03-10 17:05:34 +0000319 return std::signbit(static_cast<double>(value));
SiCongLib99e54e2022-01-05 12:18:03 +0000320}
321
322inline bool signbit(half_float::half value)
323{
324 return half_float::signbit(value);
325}
326
327inline bool signbit(bfloat16 value)
328{
329 return std::signbit(float(value));
330}
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100331} // namespace cpp11
Moritz Pflanzerd0ae8b82017-06-29 14:51:57 +0100332} // namespace support
333} // namespace arm_compute
Matthew Bentham758b5ba2020-03-05 23:37:48 +0000334#endif /* ARM_COMPUTE_SUPPORT_TOOLCHAINSUPPORT */