Zephyr Project API 4.4.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
math_extras_impl.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Facebook.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#ifndef ZEPHYR_INCLUDE_SYS_MATH_EXTRAS_IMPL_H_
8#define ZEPHYR_INCLUDE_SYS_MATH_EXTRAS_IMPL_H_
9
14
15#ifndef ZEPHYR_INCLUDE_SYS_MATH_EXTRAS_H_
16#error "please include <sys/math_extras.h> instead of this file"
17#endif
18
19#include <zephyr/toolchain.h>
20
22
23/*
24 * Force the use of portable C code (no builtins) by defining
25 * PORTABLE_MISC_MATH_EXTRAS before including <misc/math_extras.h>.
26 * This is primarily for use by tests.
27 *
28 * We'll #undef use_builtin again at the end of the file.
29 */
30#ifdef PORTABLE_MISC_MATH_EXTRAS
31#define use_builtin(x) 0
32#define __has_type_128 0
33#else
34#define use_builtin(x) HAS_BUILTIN(x)
35#ifdef __SIZEOF_INT128__
36 #define __has_type_128 1
37#else
38 #define __has_type_128 0
39#endif
40#endif
41
42#if use_builtin(__builtin_add_overflow)
43static inline bool u16_add_overflow(uint16_t a, uint16_t b, uint16_t *result)
44{
45 return __builtin_add_overflow(a, b, result);
46}
47
48static inline bool u32_add_overflow(uint32_t a, uint32_t b, uint32_t *result)
49{
50 return __builtin_add_overflow(a, b, result);
51}
52
53static inline bool u64_add_overflow(uint64_t a, uint64_t b, uint64_t *result)
54{
55 return __builtin_add_overflow(a, b, result);
56}
57
58static inline bool size_add_overflow(size_t a, size_t b, size_t *result)
59{
60 return __builtin_add_overflow(a, b, result);
61}
62#else /* !use_builtin(__builtin_add_overflow) */
63static inline bool u16_add_overflow(uint16_t a, uint16_t b, uint16_t *result)
64{
65 uint16_t c = a + b;
66
67 *result = c;
68
69 return c < a;
70}
71
72static inline bool u32_add_overflow(uint32_t a, uint32_t b, uint32_t *result)
73{
74 uint32_t c = a + b;
75
76 *result = c;
77
78 return c < a;
79}
80
81static inline bool u64_add_overflow(uint64_t a, uint64_t b, uint64_t *result)
82{
83 uint64_t c = a + b;
84
85 *result = c;
86
87 return c < a;
88}
89
90static inline bool size_add_overflow(size_t a, size_t b, size_t *result)
91{
92 size_t c = a + b;
93
94 *result = c;
95
96 return c < a;
97}
98#endif /* use_builtin(__builtin_add_overflow) */
99
100#if use_builtin(__builtin_mul_overflow)
101static inline bool u16_mul_overflow(uint16_t a, uint16_t b, uint16_t *result)
102{
103 return __builtin_mul_overflow(a, b, result);
104}
105
106static inline bool u32_mul_overflow(uint32_t a, uint32_t b, uint32_t *result)
107{
108 return __builtin_mul_overflow(a, b, result);
109}
110
111static inline bool u64_mul_overflow(uint64_t a, uint64_t b, uint64_t *result)
112{
113 return __builtin_mul_overflow(a, b, result);
114}
115
116static inline bool size_mul_overflow(size_t a, size_t b, size_t *result)
117{
118 return __builtin_mul_overflow(a, b, result);
119}
120#else /* !use_builtin(__builtin_mul_overflow) */
121static inline bool u16_mul_overflow(uint16_t a, uint16_t b, uint16_t *result)
122{
123 uint16_t c = a * b;
124
125 *result = c;
126
127 return a != 0 && (c / a) != b;
128}
129
130static inline bool u32_mul_overflow(uint32_t a, uint32_t b, uint32_t *result)
131{
132 uint32_t c = a * b;
133
134 *result = c;
135
136 return a != 0 && (c / a) != b;
137}
138
139static inline bool u64_mul_overflow(uint64_t a, uint64_t b, uint64_t *result)
140{
141 uint64_t c = a * b;
142
143 *result = c;
144
145 return a != 0 && (c / a) != b;
146}
147
148static inline bool size_mul_overflow(size_t a, size_t b, size_t *result)
149{
150 size_t c = a * b;
151
152 *result = c;
153
154 return a != 0 && (c / a) != b;
155}
156#endif /* use_builtin(__builtin_mul_overflow) */
157
158
159/*
160 * The GCC builtins __builtin_clz(), __builtin_ctz(), and 64-bit
161 * variants are described by the GCC documentation as having undefined
162 * behavior when the argument is zero. See
163 * https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
164 *
165 * The undefined behavior applies to all architectures, regardless of
166 * the behavior of the instruction used to implement the builtin.
167 *
168 * We don't want to expose users of this API to the undefined behavior,
169 * so we use a conditional to explicitly provide the correct result when
170 * x=0.
171 *
172 * Most instruction set architectures have a CLZ instruction or similar
173 * that already computes the correct result for x=0. Both GCC and Clang
174 * know this and simply generate a CLZ instruction, optimizing away the
175 * conditional.
176 *
177 * For x86, and for compilers that fail to eliminate the conditional,
178 * there is often another opportunity for optimization since code using
179 * these functions tends to contain a zero check already. For example,
180 * from kernel/sched.c:
181 *
182 * struct k_thread *z_priq_mq_best(struct _priq_mq *pq)
183 * {
184 * if (!pq->bitmask) {
185 * return NULL;
186 * }
187 *
188 * struct k_thread *thread = NULL;
189 * sys_dlist_t *l =
190 * &pq->queues[u32_count_trailing_zeros(pq->bitmask)];
191 *
192 * ...
193 *
194 * The compiler will often be able to eliminate the redundant x == 0
195 * check after inlining the call to u32_count_trailing_zeros().
196 */
197
198#if use_builtin(__builtin_clz)
199static inline int u32_count_leading_zeros(uint32_t x)
200{
201 return (x == 0) ? 32 : __builtin_clz(x);
202}
203#else /* !use_builtin(__builtin_clz) */
204static inline int u32_count_leading_zeros(uint32_t x)
205{
206 int b;
207
208 for (b = 0; b < 32 && (x >> 31) == 0; b++) {
209 x <<= 1;
210 }
211
212 return b;
213}
214#endif /* use_builtin(__builtin_clz) */
215
216#if use_builtin(__builtin_clzll)
217static inline int u64_count_leading_zeros(uint64_t x)
218{
219 return (x == 0) ? 64 : __builtin_clzll(x);
220}
221#else /* !use_builtin(__builtin_clzll) */
222static inline int u64_count_leading_zeros(uint64_t x)
223{
224 if (x == (uint32_t)x) {
225 return 32 + u32_count_leading_zeros((uint32_t)x);
226 } else {
227 return u32_count_leading_zeros(x >> 32);
228 }
229}
230#endif /* use_builtin(__builtin_clzll) */
231
232#if use_builtin(__builtin_ctz)
233static inline int u32_count_trailing_zeros(uint32_t x)
234{
235 return (x == 0) ? 32 : __builtin_ctz(x);
236}
237#else /* !use_builtin(__builtin_ctz) */
238static inline int u32_count_trailing_zeros(uint32_t x)
239{
240 int b;
241
242 for (b = 0; b < 32 && (x & 1) == 0; b++) {
243 x >>= 1;
244 }
245
246 return b;
247}
248#endif /* use_builtin(__builtin_ctz) */
249
250#if use_builtin(__builtin_ctzll)
251static inline int u64_count_trailing_zeros(uint64_t x)
252{
253 return (x == 0) ? 64 : __builtin_ctzll(x);
254}
255#else /* !use_builtin(__builtin_ctzll) */
256static inline int u64_count_trailing_zeros(uint64_t x)
257{
258 if ((uint32_t)x) {
260 } else {
261 return 32 + u32_count_trailing_zeros(x >> 32);
262 }
263}
264#endif /* use_builtin(__builtin_ctzll) */
265
276#if __has_type_128
277static inline void i128_multiply_i64_i64(int64_t a, int64_t b, int128_t *result)
278{
279 __int128 c = (__int128)a * (__int128)b;
280
281 result->low = (uint64_t)c;
282 result->high = (uint64_t)(c >> 64);
283}
284#else
285static inline void i128_multiply_i64_i64(int64_t a, int64_t b, int128_t *result)
286{
287 uint64_t u_a = (a < 0) ? (uint64_t)-a : (uint64_t)a;
288 uint64_t u_b = (b < 0) ? (uint64_t)-b : (uint64_t)b;
289 int sign = (a < 0) ^ (b < 0);
290
291 /* Split to 32-bit values */
292 uint64_t a_lo = u_a & 0xFFFFFFFFULL;
293 uint64_t a_hi = u_a >> 32;
294 uint64_t b_lo = u_b & 0xFFFFFFFFULL;
295 uint64_t b_hi = u_b >> 32;
296
297 /* Calculate product, just like in school */
298 uint64_t res_0 = a_lo * b_lo;
299 uint64_t res_1 = a_hi * b_lo;
300 uint64_t res_2 = a_lo * b_hi;
301 uint64_t res_3 = a_hi * b_hi;
302
303 /* Combine values including carry */
304 uint64_t carry = 0;
305 uint64_t middle = (res_0 >> 32) + (res_1 & 0xFFFFFFFFULL) + (res_2 & 0xFFFFFFFFULL);
306
307 result->low = (res_0 & 0xFFFFFFFFULL) | (middle << 32);
308
309 /* Move the top part */
310 carry = (middle >> 32) + (res_1 >> 32) + (res_2 >> 32) + res_3;
311 result->high = carry;
312
313 /* Calculate two-complement if sign is minus */
314 if (sign) {
315 result->low = ~result->low + 1;
316 result->high = ~result->high + (result->low == 0 ? 1 : 0);
317 }
318}
319#endif /* __has_type_128 */
320
321#undef use_builtin
322
324
325#endif /* ZEPHYR_INCLUDE_SYS_MATH_EXTRAS_IMPL_H_ */
static bool u16_mul_overflow(uint16_t a, uint16_t b, uint16_t *result)
Multiply two unsigned 16-bit integers.
static int u64_count_trailing_zeros(uint64_t x)
Count the number of trailing zero bits in a 64-bit integer.
static bool u64_mul_overflow(uint64_t a, uint64_t b, uint64_t *result)
Multiply two unsigned 64-bit integers.
static bool u32_add_overflow(uint32_t a, uint32_t b, uint32_t *result)
Add two unsigned 32-bit integers.
static bool u32_mul_overflow(uint32_t a, uint32_t b, uint32_t *result)
Multiply two unsigned 32-bit integers.
static int u32_count_trailing_zeros(uint32_t x)
Count the number of trailing zero bits in a 32-bit integer.
static bool u16_add_overflow(uint16_t a, uint16_t b, uint16_t *result)
Add two unsigned 16-bit integers.
static bool size_mul_overflow(size_t a, size_t b, size_t *result)
Multiply two size_t integers.
static bool size_add_overflow(size_t a, size_t b, size_t *result)
Add two size_t integers.
static int u32_count_leading_zeros(uint32_t x)
Count the number of leading zero bits in a 32-bit integer.
static void i128_multiply_i64_i64(int64_t a, int64_t b, int128_t *result)
Multiply two signed 64-bit integers and store the result in a 128-bit integer.
static int u64_count_leading_zeros(uint64_t x)
Count the number of leading zero bits in a 64-bit integer.
static bool u64_add_overflow(uint64_t a, uint64_t b, uint64_t *result)
Add two unsigned 64-bit integers.
__UINT32_TYPE__ uint32_t
Definition stdint.h:90
__UINT64_TYPE__ uint64_t
Definition stdint.h:91
__UINT16_TYPE__ uint16_t
Definition stdint.h:89
__INT64_TYPE__ int64_t
Definition stdint.h:75
128-bit integer structure.
Definition math_extras.h:189
uint64_t high
High-order 64 bits (includes sign bit).
Definition math_extras.h:193
uint64_t low
Low-order 64 bits.
Definition math_extras.h:191
Macros to abstract toolchain specific capabilities.