x86: merge the simple bitops and move them to bitops.h
Some of those can be written in such a way that the same inline assembly can be used to generate both 32 bit and 64 bit code. For ffs and fls, x86_64 unconditionally used the cmov instruction and i386 unconditionally used a conditional branch over a mov instruction. In the current patch I chose to select the version based on the availability of the cmov instruction instead. A small detail here is that x86_64 did not previously set CONFIG_X86_CMOV=y. Improved comments for ffs, ffz, fls and variations. Signed-off-by: Alexander van Heukelum <heukelum@fastmail.fm> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
64970b68d2
commit
12d9c8420b
4 changed files with 99 additions and 142 deletions
|
@ -398,7 +398,7 @@ config X86_TSC
|
||||||
# generates cmov.
|
# generates cmov.
|
||||||
config X86_CMOV
|
config X86_CMOV
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7)
|
depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64)
|
||||||
|
|
||||||
config X86_MINIMUM_CPU_FAMILY
|
config X86_MINIMUM_CPU_FAMILY
|
||||||
int
|
int
|
||||||
|
|
|
@ -67,7 +67,6 @@ static inline void __set_bit(int nr, volatile void *addr)
|
||||||
: "Ir" (nr) : "memory");
|
: "Ir" (nr) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clear_bit - Clears a bit in memory
|
* clear_bit - Clears a bit in memory
|
||||||
* @nr: Bit to clear
|
* @nr: Bit to clear
|
||||||
|
@ -304,6 +303,104 @@ static int test_bit(int nr, const volatile unsigned long *addr);
|
||||||
|
|
||||||
#undef BASE_ADDR
|
#undef BASE_ADDR
|
||||||
#undef BIT_ADDR
|
#undef BIT_ADDR
|
||||||
|
/**
|
||||||
|
* __ffs - find first set bit in word
|
||||||
|
* @word: The word to search
|
||||||
|
*
|
||||||
|
* Undefined if no bit exists, so code should check against 0 first.
|
||||||
|
*/
|
||||||
|
static inline unsigned long __ffs(unsigned long word)
|
||||||
|
{
|
||||||
|
__asm__("bsf %1,%0"
|
||||||
|
:"=r" (word)
|
||||||
|
:"rm" (word));
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ffz - find first zero bit in word
|
||||||
|
* @word: The word to search
|
||||||
|
*
|
||||||
|
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||||
|
*/
|
||||||
|
static inline unsigned long ffz(unsigned long word)
|
||||||
|
{
|
||||||
|
__asm__("bsf %1,%0"
|
||||||
|
:"=r" (word)
|
||||||
|
:"r" (~word));
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __fls: find last set bit in word
|
||||||
|
* @word: The word to search
|
||||||
|
*
|
||||||
|
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||||
|
*/
|
||||||
|
static inline unsigned long __fls(unsigned long word)
|
||||||
|
{
|
||||||
|
__asm__("bsr %1,%0"
|
||||||
|
:"=r" (word)
|
||||||
|
:"rm" (word));
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
/**
|
||||||
|
* ffs - find first set bit in word
|
||||||
|
* @x: the word to search
|
||||||
|
*
|
||||||
|
* This is defined the same way as the libc and compiler builtin ffs
|
||||||
|
* routines, therefore differs in spirit from the other bitops.
|
||||||
|
*
|
||||||
|
* ffs(value) returns 0 if value is 0 or the position of the first
|
||||||
|
* set bit if value is nonzero. The first (least significant) bit
|
||||||
|
* is at position 1.
|
||||||
|
*/
|
||||||
|
static inline int ffs(int x)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
#ifdef CONFIG_X86_CMOV
|
||||||
|
__asm__("bsfl %1,%0\n\t"
|
||||||
|
"cmovzl %2,%0"
|
||||||
|
: "=r" (r) : "rm" (x), "r" (-1));
|
||||||
|
#else
|
||||||
|
__asm__("bsfl %1,%0\n\t"
|
||||||
|
"jnz 1f\n\t"
|
||||||
|
"movl $-1,%0\n"
|
||||||
|
"1:" : "=r" (r) : "rm" (x));
|
||||||
|
#endif
|
||||||
|
return r + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fls - find last set bit in word
|
||||||
|
* @x: the word to search
|
||||||
|
*
|
||||||
|
* This is defined in a similar way as the libc and compiler builtin
|
||||||
|
* ffs, but returns the position of the most significant set bit.
|
||||||
|
*
|
||||||
|
* fls(value) returns 0 if value is 0 or the position of the last
|
||||||
|
* set bit if value is nonzero. The last (most significant) bit is
|
||||||
|
* at position 32.
|
||||||
|
*/
|
||||||
|
static inline int fls(int x)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
#ifdef CONFIG_X86_CMOV
|
||||||
|
__asm__("bsrl %1,%0\n\t"
|
||||||
|
"cmovzl %2,%0"
|
||||||
|
: "=&r" (r) : "rm" (x), "rm" (-1));
|
||||||
|
#else
|
||||||
|
__asm__("bsrl %1,%0\n\t"
|
||||||
|
"jnz 1f\n\t"
|
||||||
|
"movl $-1,%0\n"
|
||||||
|
"1:" : "=r" (r) : "rm" (x));
|
||||||
|
#endif
|
||||||
|
return r + 1;
|
||||||
|
}
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
#undef ADDR
|
#undef ADDR
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
|
|
@ -39,20 +39,6 @@ static inline int find_first_zero_bit(const unsigned long *addr, unsigned size)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* __ffs - find first bit in word.
|
|
||||||
* @word: The word to search
|
|
||||||
*
|
|
||||||
* Undefined if no bit exists, so code should check against 0 first.
|
|
||||||
*/
|
|
||||||
static inline unsigned long __ffs(unsigned long word)
|
|
||||||
{
|
|
||||||
__asm__("bsfl %1,%0"
|
|
||||||
:"=r" (word)
|
|
||||||
:"rm" (word));
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find_first_bit - find the first set bit in a memory region
|
* find_first_bit - find the first set bit in a memory region
|
||||||
* @addr: The address to start the search at
|
* @addr: The address to start the search at
|
||||||
|
@ -74,60 +60,10 @@ static inline unsigned find_first_bit(const unsigned long *addr, unsigned size)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ffz - find first zero in word.
|
|
||||||
* @word: The word to search
|
|
||||||
*
|
|
||||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
|
||||||
*/
|
|
||||||
static inline unsigned long ffz(unsigned long word)
|
|
||||||
{
|
|
||||||
__asm__("bsfl %1,%0"
|
|
||||||
:"=r" (word)
|
|
||||||
:"r" (~word));
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
#include <asm-generic/bitops/sched.h>
|
#include <asm-generic/bitops/sched.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* ffs - find first bit set
|
|
||||||
* @x: the word to search
|
|
||||||
*
|
|
||||||
* This is defined the same way as
|
|
||||||
* the libc and compiler builtin ffs routines, therefore
|
|
||||||
* differs in spirit from the above ffz() (man ffs).
|
|
||||||
*/
|
|
||||||
static inline int ffs(int x)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
__asm__("bsfl %1,%0\n\t"
|
|
||||||
"jnz 1f\n\t"
|
|
||||||
"movl $-1,%0\n"
|
|
||||||
"1:" : "=r" (r) : "rm" (x));
|
|
||||||
return r+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fls - find last bit set
|
|
||||||
* @x: the word to search
|
|
||||||
*
|
|
||||||
* This is defined the same way as ffs().
|
|
||||||
*/
|
|
||||||
static inline int fls(int x)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
__asm__("bsrl %1,%0\n\t"
|
|
||||||
"jnz 1f\n\t"
|
|
||||||
"movl $-1,%0\n"
|
|
||||||
"1:" : "=r" (r) : "rm" (x));
|
|
||||||
return r+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <asm-generic/bitops/hweight.h>
|
#include <asm-generic/bitops/hweight.h>
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
|
@ -35,70 +35,10 @@ static inline void set_bit_string(unsigned long *bitmap, unsigned long i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ffz - find first zero in word.
|
|
||||||
* @word: The word to search
|
|
||||||
*
|
|
||||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
|
||||||
*/
|
|
||||||
static inline unsigned long ffz(unsigned long word)
|
|
||||||
{
|
|
||||||
__asm__("bsfq %1,%0"
|
|
||||||
:"=r" (word)
|
|
||||||
:"r" (~word));
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __ffs - find first bit in word.
|
|
||||||
* @word: The word to search
|
|
||||||
*
|
|
||||||
* Undefined if no bit exists, so code should check against 0 first.
|
|
||||||
*/
|
|
||||||
static inline unsigned long __ffs(unsigned long word)
|
|
||||||
{
|
|
||||||
__asm__("bsfq %1,%0"
|
|
||||||
:"=r" (word)
|
|
||||||
:"rm" (word));
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* __fls: find last bit set.
|
|
||||||
* @word: The word to search
|
|
||||||
*
|
|
||||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
|
||||||
*/
|
|
||||||
static inline unsigned long __fls(unsigned long word)
|
|
||||||
{
|
|
||||||
__asm__("bsrq %1,%0"
|
|
||||||
:"=r" (word)
|
|
||||||
:"rm" (word));
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
#include <asm-generic/bitops/sched.h>
|
#include <asm-generic/bitops/sched.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* ffs - find first bit set
|
|
||||||
* @x: the word to search
|
|
||||||
*
|
|
||||||
* This is defined the same way as
|
|
||||||
* the libc and compiler builtin ffs routines, therefore
|
|
||||||
* differs in spirit from the above ffz (man ffs).
|
|
||||||
*/
|
|
||||||
static inline int ffs(int x)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
__asm__("bsfl %1,%0\n\t"
|
|
||||||
"cmovzl %2,%0"
|
|
||||||
: "=r" (r) : "rm" (x), "r" (-1));
|
|
||||||
return r+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fls64 - find last bit set in 64 bit word
|
* fls64 - find last bit set in 64 bit word
|
||||||
* @x: the word to search
|
* @x: the word to search
|
||||||
|
@ -112,22 +52,6 @@ static inline int fls64(__u64 x)
|
||||||
return __fls(x) + 1;
|
return __fls(x) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* fls - find last bit set
|
|
||||||
* @x: the word to search
|
|
||||||
*
|
|
||||||
* This is defined the same way as ffs.
|
|
||||||
*/
|
|
||||||
static inline int fls(int x)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
__asm__("bsrl %1,%0\n\t"
|
|
||||||
"cmovzl %2,%0"
|
|
||||||
: "=&r" (r) : "rm" (x), "rm" (-1));
|
|
||||||
return r+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ARCH_HAS_FAST_MULTIPLIER 1
|
#define ARCH_HAS_FAST_MULTIPLIER 1
|
||||||
|
|
||||||
#include <asm-generic/bitops/hweight.h>
|
#include <asm-generic/bitops/hweight.h>
|
||||||
|
|
Loading…
Reference in a new issue