kernel/util: Add fls to BitUtils.

Implemented using __builtin_clz where available, otherwise using
an algorithm derived from "Bit Twiddling Hacks" which is similar
to the one ramfs uses. GCC and Clang seem to unroll the loop on
x86 at least (but it doesn't matter there as the builtin exists,
implemented using the "bsr" instruction.)
This commit is contained in:
Augustin Cavalier
2024-09-02 14:16:05 -04:00
parent 31b7065940
commit b973a1b377
2 changed files with 25 additions and 56 deletions
+25
View File
@@ -40,6 +40,31 @@ count_set_bits(uint32 v)
}
static inline uint32
fls(uint32 value)
{
if (value == 0)
return 0;
#if __has_builtin(__builtin_clz)
return ((sizeof(value) * 8) - __builtin_clz(value));
#else
// https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
static const uint32 masks[] = {
0xaaaaaaaa,
0xcccccccc,
0xf0f0f0f0,
0xff00ff00,
0xffff0000
};
uint32 result = (value & masks[0]) != 0;
for (int i = 4; i > 0; i--)
result |= ((value & masks[i]) != 0) << i;
return result + 1;
#endif
}
static inline uint32
log2(uint32 v)
{
@@ -17,62 +17,6 @@ static inline C min(const C &a, const C &b) { return (a < b ? a : b); }
template<typename C>
static inline C max(const C &a, const C &b) { return (a > b ? a : b); }
// find last (most significant) set bit
static inline
int
fls(uint32 value)
{
if (!value)
return -1;
int index = 0;
#define HAND_OPTIMIZED_FLS 1
#if !HAND_OPTIMIZED_FLS
// This is the algorithm in its pure form.
const uint32 masks[] = {
0xffff0000,
0xff00ff00,
0xf0f0f0f0,
0xcccccccc,
0xaaaaaaaa,
};
int range = 16;
for (int i = 0; i < 5; i++) {
if (value & masks[i]) {
index += range;
value &= masks[i];
}
range /= 2;
}
#else // HAND_OPTIMIZED_FLS
// This is how the compiler should optimize it for us: Unroll the loop and
// inline the masks.
// 0: 0xffff0000
if (value & 0xffff0000) {
index += 16;
value &= 0xffff0000;
}
// 1: 0xff00ff00
if (value & 0xff00ff00) {
index += 8;
value &= 0xff00ff00;
}
// 2: 0xf0f0f0f0
if (value & 0xf0f0f0f0) {
index += 4;
value &= 0xf0f0f0f0;
}
// 3: 0xcccccccc
if (value & 0xcccccccc) {
index += 2;
value &= 0xcccccccc;
}
// 4: 0xaaaaaaaa
if (value & 0xaaaaaaaa)
index++;
#endif // HAND_OPTIMIZED_FLS
return index;
}
// node_child_hash
static inline
uint32