dte test coverage


Directory: ./
File: src/util/bit.h
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 21 21 100.0%
Functions: 7 7 100.0%
Branches: 4 4 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 345 static inline unsigned int u64_popcount(uint64_t n)
49 {
50 345 USE_STDBIT(stdc_count_ones, n);
51 345 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 (2→3) taken 82 times.
✓ Branch 1 (2→4) taken 1 times.
83 return x ? 1u << (u32_ffs(x) - 1) : 0;
88 }
89
90 // Count leading zeros
91 9 static inline unsigned int u64_clz(uint64_t x)
92 {
93 9 BUG_ON(x == 0);
94 9 USE_STDBIT(stdc_leading_zeros, x);
95 9 USE_BUILTIN(clz, x);
96 x |= x >> 1;
97 x |= x >> 2;
98 x |= x >> 4;
99 x |= x >> 8;
100 x |= x >> 16;
101 x |= x >> 32;
102 return u64_popcount(~x);
103 }
104
105 // Calculate number of significant bits in `x` (minimum number of
106 // base 2 digits needed to represent it)
107 74 static inline unsigned int umax_bitwidth(uintmax_t x)
108 {
109 74 USE_STDBIT(stdc_bit_width, x);
110
111 #if HAS_BUILTIN(__builtin_stdc_bit_width)
112
2/2
✓ Branch 0 (2→3) taken 70 times.
✓ Branch 1 (2→4) taken 4 times.
74 return __builtin_stdc_bit_width(x);
113 #endif
114
115 if (BITSIZE(x) == 64) {
116 return x ? 64u - u64_clz(x) : 0;
117 }
118
119 unsigned int width = 0;
120 while (x) {
121 x >>= 1;
122 width++;
123 }
124 return width;
125 }
126
127 #endif
128