rculfhash: simplify get_count_order()
[ Edit by Mathieu Desnoyers:
- Updated comments.
- Quick benchmark on Intel(R) Atom(TM) CPU Z520 @ 1.33GHz:
get_count_order_ulong, from 0 to
100000000:
previous: 3.840s
new: 3.187s
- Test comparing bit-exactness for ranges near 0:
/*
* fls: returns the position of the most significant bit.
* Returns 0 if no bit is set, else returns the position of the most
* significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
*/
static inline
unsigned int fls_u32(uint32_t x)
{
int r;
asm("bsrl %1,%0\n\t"
"jnz 1f\n\t"
"movl $-1,%0\n\t"
"1:\n\t"
: "=r" (r) : "rm" (x));
return r + 1;
}
static inline
unsigned int fls_u64(uint64_t x)
{
long r;
asm("bsrq %1,%0\n\t"
"jnz 1f\n\t"
"movq $-1,%0\n\t"
"1:\n\t"
: "=r" (r) : "rm" (x));
return r + 1;
}
static __attribute__((unused))
unsigned int fls_u64(uint64_t x)
{
unsigned int r = 64;
if (!x)
return 0;
if (!(x & 0xFFFFFFFF00000000ULL)) {
x <<= 32;
r -= 32;
}
if (!(x & 0xFFFF000000000000ULL)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xFF00000000000000ULL)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xF000000000000000ULL)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xC000000000000000ULL)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x8000000000000000ULL)) {
x <<= 1;
r -= 1;
}
return r;
}
static __attribute__((unused))
unsigned int fls_u32(uint32_t x)
{
unsigned int r = 32;
if (!x)
return 0;
if (!(x & 0xFFFF0000U)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xFF000000U)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xF0000000U)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xC0000000U)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000U)) {
x <<= 1;
r -= 1;
}
return r;
}
unsigned int fls_ulong(unsigned long x)
{
return fls_u32(x);
return fls_u64(x);
}
int get_count_order_u32(uint32_t x)
{
int order;
order = fls_u32(x) - 1;
if (x & (x - 1))
order++;
return order;
}
int get_count_order_ulong(unsigned long x)
{
int order;
order = fls_ulong(x) - 1;
if (x & (x - 1))
order++;
return order;
}
int test_get_count_order_u32(uint32_t x)
{
if (!x)
return -1;
return fls_u32(x - 1);
}
/* find the minimum order that x <= (1UL << order) */
int test_get_count_order_ulong(unsigned long x)
{
if (!x)
return -1;
return fls_ulong(x - 1);
}
int main(int argc, char **argv)
{
unsigned long i;
for (i = 0UL; i < 10000; i++) {
if (get_count_order_ulong(i) != test_get_count_order_ulong(i))
printf("Error for %lu\n", i);
}
for (i = 4294967293UL; i != 0; i++) {
if (get_count_order_ulong(i) != test_get_count_order_ulong(i))
printf("Error for %lu\n", i);
}
return 0;
}
]
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>