Skip to content

Commit deab09d

Browse files
committed
sys: util: Power-of-Two utilities
* remove previous `LOG2CEIL()` from `<zephyr/toolchain/common.h>` - `LOG2CEIL()` is not used in-tree by any C or C++ source - only used are in `.ld` files - however, it is built-in to both GNU and LLVM linkers * sys: util: provide LOG2() and LOG2CEIL() macros - calculate `log(x)` and `ceil(log(x))`, respectively - both are compile-time `const` / ok for `constexpr` - also runtime efficient with `__builtin_clz()` - `LOG2()`, `NUMBITS()`, and `IS_POWER_OF_TWO()` macros contributed by @JordanYates - `LOG2CEIL()` contributed by @oyvindronningstad * sys: util: provide Next-Highest Power-of-Two macro `NHPOT()` - calculate `next = pow(2, ceil(log(x)/log(2)))` - leverages `LOG2CEIL()` Signed-off-by: Chris Friedt <cfriedt@meta.com>
1 parent 5cb53ee commit deab09d

File tree

3 files changed

+118
-17
lines changed

3 files changed

+118
-17
lines changed

include/zephyr/sys/util.h

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,90 @@
2626
#include <zephyr/types.h>
2727
#include <stddef.h>
2828

29+
/** @brief Number of bits that make up a type */
30+
#define NUM_BITS(t) (sizeof(t) * 8)
31+
32+
#ifdef __cplusplus
33+
template <typename T> static inline constexpr int __z_log2_impl(T x)
34+
{
35+
if (sizeof(x) < sizeof(unsigned int)) {
36+
return ((x) < 1) * (-1) +
37+
((x) >= 1) * (NUM_BITS(unsigned int) - __builtin_clz(x) - 1);
38+
} else if (sizeof(x) <= sizeof(unsigned long long)) {
39+
return ((x) < 1) * (-1) +
40+
((x) >= 1) * (NUM_BITS(unsigned long long) - __builtin_clzll(x) - 1);
41+
}
42+
43+
/* No declaration of __ASSERT is available here */
44+
static_assert(sizeof(x) <= sizeof(unsigned long long), "unsupported type for LOG2()");
45+
46+
return -1;
47+
}
48+
49+
template <typename T> static inline constexpr int __z_log2ceil_impl(T x)
50+
{
51+
if (sizeof(x) < sizeof(unsigned int)) {
52+
return (x > 1) * (NUM_BITS(unsigned int) - __builtin_clz(x - 1));
53+
} else if (sizeof(x) <= sizeof(unsigned long long)) {
54+
return (x > 1) * (NUM_BITS(unsigned long long) - __builtin_clzll(x - 1));
55+
}
56+
57+
/* No declaration of __ASSERT is available here */
58+
static_assert(sizeof(x) <= sizeof(unsigned long long), "unsupported type for LOG2CEIL()");
59+
60+
return -1;
61+
}
62+
63+
template <typename T> static inline constexpr uint64_t __z_nhpot_impl(T x)
64+
{
65+
int l2c = __z_log2ceil_impl(x);
66+
67+
return (l2c != NUM_BITS(unsigned long long)) * (1ULL << l2c);
68+
}
69+
#else
70+
#define __z_log2_impl(x) \
71+
(((x) < 1) * (-1) + \
72+
((x) >= 1) * _Generic((x), char \
73+
: (NUM_BITS(unsigned int) - __builtin_clz(x) - 1), unsigned char \
74+
: (NUM_BITS(unsigned int) - __builtin_clz(x) - 1), short \
75+
: (NUM_BITS(unsigned int) - __builtin_clz(x) - 1), unsigned short \
76+
: (NUM_BITS(unsigned int) - __builtin_clz(x) - 1), int \
77+
: (NUM_BITS(unsigned int) - __builtin_clz(x) - 1), unsigned int \
78+
: (NUM_BITS(unsigned int) - __builtin_clz(x) - 1), long \
79+
: (NUM_BITS(unsigned long) - __builtin_clzl(x) - 1), unsigned long \
80+
: (NUM_BITS(unsigned long) - __builtin_clzl(x) - 1), long long \
81+
: (NUM_BITS(unsigned long long) - __builtin_clzll(x) - 1), \
82+
unsigned long long \
83+
: (NUM_BITS(unsigned long long) - __builtin_clzll(x) - 1)))
84+
85+
#define __z_log2ceil_impl(x) \
86+
(((x) > 1) * \
87+
_Generic((x), char \
88+
: (NUM_BITS(unsigned int) - __builtin_clz((x)-1)), unsigned char \
89+
: (NUM_BITS(unsigned int) - __builtin_clz((x)-1)), short \
90+
: (NUM_BITS(unsigned int) - __builtin_clz((x)-1)), unsigned short \
91+
: (NUM_BITS(unsigned int) - __builtin_clz((x)-1)), int \
92+
: (NUM_BITS(unsigned int) - __builtin_clz((x)-1)), unsigned int \
93+
: (NUM_BITS(unsigned int) - __builtin_clz((x)-1)), long \
94+
: (NUM_BITS(unsigned long) - __builtin_clzl((x)-1)), unsigned long \
95+
: (NUM_BITS(unsigned long) - __builtin_clzl((x)-1)), long long \
96+
: (NUM_BITS(unsigned long long) - __builtin_clzll((x)-1)), unsigned long long \
97+
: (NUM_BITS(unsigned long long) - __builtin_clzll((x)-1))))
98+
99+
#define __z_nhpot_impl(x) \
100+
_Generic((x), char \
101+
: (1UL << LOG2CEIL(x)), unsigned char \
102+
: (1UL << LOG2CEIL(x)), short \
103+
: (1UL << LOG2CEIL(x)), unsigned short \
104+
: (1ULL << LOG2CEIL(x)), int \
105+
: (1ULL << LOG2CEIL(x)), unsigned int \
106+
: (1ULL << LOG2CEIL(x)), long \
107+
: (1ULL << LOG2CEIL(x)), unsigned long \
108+
: (1ULL << LOG2CEIL(x)), long long \
109+
: (1ULL << LOG2CEIL(x)), unsigned long long \
110+
: (1ULL << LOG2CEIL(x)))
111+
#endif
112+
29113
#ifdef __cplusplus
30114
extern "C" {
31115
#endif
@@ -314,7 +398,7 @@ extern "C" {
314398
*/
315399
static inline bool is_power_of_two(unsigned int x)
316400
{
317-
return (x != 0U) && ((x & (x - 1U)) == 0U);
401+
return IS_POWER_OF_TWO(x);
318402
}
319403

320404
/**
@@ -508,6 +592,35 @@ char *utf8_trunc(char *utf8_str);
508592
*/
509593
char *utf8_lcpy(char *dst, const char *src, size_t n);
510594

595+
/**
596+
* @brief Compute log2(x)
597+
*
598+
* @param x An unsigned integral value
599+
*
600+
* @param x value to compute logarithm of (positive only)
601+
*
602+
* @return log2(x) when 1 <= x <= max(x), -1 when x < 1
603+
*/
604+
#define LOG2(x) __z_log2_impl(x)
605+
606+
/**
607+
* @brief Compute ceil(log2(x))
608+
*
609+
* @param x An unsigned integral value
610+
*
611+
* @return ceil(log2(x)) when 1 <= x <= max(type(x)), 0 when x < 1
612+
*/
613+
#define LOG2CEIL(x) __z_log2ceil_impl(x)
614+
615+
/**
616+
* @brief Compute 2^ceil(log2(x))
617+
*
618+
* @param x An unsigned integral value
619+
*
620+
* @return 2^ceil(log2(x)) or 0 if 2^ceil(log2(x)) would saturate 64-bits
621+
*/
622+
#define NHPOT(x) __z_nhpot_impl(x)
623+
511624
#ifdef __cplusplus
512625
}
513626
#endif
@@ -548,7 +661,7 @@ char *utf8_lcpy(char *dst, const char *src, size_t n);
548661
*/
549662
#define WAIT_FOR(expr, timeout, delay_stmt) \
550663
({ \
551-
uint32_t cycle_count = k_us_to_cyc_ceil32(timeout); \
664+
uint32_t cycle_count = k_us_to_cyc_ceil32(timeout); \
552665
uint32_t start = k_cycle_get_32(); \
553666
while (!(expr) && (cycle_count > (k_cycle_get_32() - start))) { \
554667
delay_stmt; \

include/zephyr/sys/util_macro.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ extern "C" {
7373
*/
7474
#define BIT64_MASK(n) (BIT64(n) - 1ULL)
7575

76+
/** @brief Check if a @p x is a power of two */
77+
#define IS_POWER_OF_TWO(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U))
78+
7679
/**
7780
* @brief Check if bits are set continuously from the specified bit
7881
*

include/zephyr/toolchain/common.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -291,19 +291,4 @@
291291
static const void * const symbol##_ptr __used \
292292
__attribute__((__section__(".symbol_to_keep"))) = (void *)&symbol
293293

294-
#define LOG2CEIL(x) \
295-
((((x) <= 4) ? 2 : (((x) <= 8) ? 3 : (((x) <= 16) ? \
296-
4 : (((x) <= 32) ? 5 : (((x) <= 64) ? 6 : (((x) <= 128) ? \
297-
7 : (((x) <= 256) ? 8 : (((x) <= 512) ? 9 : (((x) <= 1024) ? \
298-
10 : (((x) <= 2048) ? 11 : (((x) <= 4096) ? 12 : (((x) <= 8192) ? \
299-
13 : (((x) <= 16384) ? 14 : (((x) <= 32768) ? 15:(((x) <= 65536) ? \
300-
16 : (((x) <= 131072) ? 17 : (((x) <= 262144) ? 18:(((x) <= 524288) ? \
301-
19 : (((x) <= 1048576) ? 20 : (((x) <= 2097152) ? \
302-
21 : (((x) <= 4194304) ? 22 : (((x) <= 8388608) ? \
303-
23 : (((x) <= 16777216) ? 24 : (((x) <= 33554432) ? \
304-
25 : (((x) <= 67108864) ? 26 : (((x) <= 134217728) ? \
305-
27 : (((x) <= 268435456) ? 28 : (((x) <= 536870912) ? \
306-
29 : (((x) <= 1073741824) ? 30 : (((x) <= 2147483648) ? \
307-
31 : 32)))))))))))))))))))))))))))))))
308-
309294
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_COMMON_H_ */

0 commit comments

Comments
 (0)