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