Commit 12d9c842 authored by Alexander van Heukelum's avatar Alexander van Heukelum Committed by Ingo Molnar

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: default avatarAlexander van Heukelum <heukelum@fastmail.fm>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 64970b68
...@@ -398,7 +398,7 @@ config X86_TSC ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment