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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user