dte test coverage


Directory: ./
File: src/util/bit.h
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 14 14 100.0%
Functions: 5 5 100.0%
Branches: 2 2 100.0%

Line Branch Exec Source
1 #ifndef UTIL_BIT_H
2 #define UTIL_BIT_H
3
4 #include <stdint.h>
5 #include "debug.h"
6 #include "macros.h"
7
8 /*
9 * The default C compiler on FreeBSD 14.1 (Clang 18.1.5) accepts the
10 * -std=gnu23 command-line option and then defines __STDC_VERSION__ as
11 * 202311L, while not actually providing a C23 conforming libc (the
12 * <stdbit.h> header is missing). This guard condition originally used
13 * `||` instead of `&&`, but it was changed so as to work around this
14 * disregard for standards. Fortunately this doesn't really have any
15 * downsides for other platforms, since __has_include() is also part
16 * of C23.
17 */
18 #if __STDC_VERSION__ >= 202311L && HAS_INCLUDE(<stdbit.h>)
19 #include <stdbit.h>
20 #define USE_STDBIT(fn, arg) return fn(arg)
21 #else
22 #define USE_STDBIT(fn, arg)
23 #endif
24
25 #define U64(x) (UINT64_C(x))
26 #define U32(x) (UINT32_C(x))
27
28 #ifdef HAS_BUILTIN_TYPES_COMPATIBLE_P
29 #define HAS_COMPATIBLE_BUILTIN(arg, type, fn) \
30 (GNUC_AT_LEAST(3, 4) || HAS_BUILTIN(__builtin_ ## fn)) \
31 && __builtin_types_compatible_p(__typeof__(arg), type)
32
33 // If there's an appropriate built-in function for `arg`, emit
34 // a call to it (and eliminate everything below it as dead code)
35 #define USE_BUILTIN(fn, arg) \
36 if (HAS_COMPATIBLE_BUILTIN(arg, unsigned long long, fn ## ll)) { \
37 return __builtin_ ## fn ## ll(arg); \
38 } else if (HAS_COMPATIBLE_BUILTIN(arg, unsigned long, fn ## l)) { \
39 return __builtin_ ## fn ## l(arg); \
40 } else if (HAS_COMPATIBLE_BUILTIN(arg, unsigned int, fn)) { \
41 return __builtin_ ## fn(arg); \
42 }
43 #else
44 #define USE_BUILTIN(fn, arg)
45 #endif
46
47 // Population count (cardinality) of set bits
48 344 static inline unsigned int u64_popcount(uint64_t n)
49 {
50 344 USE_STDBIT(stdc_count_ones, n);
51 344 USE_BUILTIN(popcount, n);
52 n -= ((n >> 1) & U64(0x5555555555555555));
53 n = (n & U64(0x3333333333333333)) + ((n >> 2) & U64(0x3333333333333333));
54 n = (n + (n >> 4)) & U64(0x0F0F0F0F0F0F0F0F);
55 return (n * U64(0x0101010101010101)) >> 56;
56 }
57
58 104 static inline unsigned int u32_popcount(uint32_t n)
59 {
60 104 USE_STDBIT(stdc_count_ones, n);
61 104 USE_BUILTIN(popcount, n);
62 n -= ((n >> 1) & U32(0x55555555));
63 n = (n & U32(0x33333333)) + ((n >> 2) & U32(0x33333333));
64 n = (n + (n >> 4)) & U32(0x0F0F0F0F);
65 return (n * U32(0x01010101)) >> 24;
66 }
67
68 // Count trailing zeros
69 168 static inline unsigned int u32_ctz(uint32_t n)
70 {
71 168 BUG_ON(n == 0);
72 168 USE_STDBIT(stdc_trailing_zeros, n);
73 168 USE_BUILTIN(ctz, n);
74 return u32_popcount(~n & (n - 1));
75 }
76
77 // Find position of first (least significant) set bit (starting at 1)
78 94 static inline unsigned int u32_ffs(uint32_t n)
79 {
80 94 USE_BUILTIN(ffs, n);
81 return n ? u32_ctz(n) + 1 : 0;
82 }
83
84 // Extract (isolate) least significant set bit
85 83 static inline uint32_t u32_lsbit(uint32_t x)
86 {
87
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 1 times.
83 return x ? 1u << (u32_ffs(x) - 1) : 0;
88 }
89
90 #endif
91