Skip to content

Commit

Permalink
Merge branch 'core-hweight-for-linus' of git://git.kernel.org/pub/scm…
Browse files Browse the repository at this point in the history
…/linux/kernel/git/tip/linux-2.6-tip

* 'core-hweight-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, hweight: Use a 32-bit popcnt for __arch_hweight32()
  arch, hweight: Fix compilation errors
  x86: Add optimized popcnt variants
  bitops: Optimize hweight() by making use of compile-time evaluation
  • Loading branch information
torvalds committed May 18, 2010
2 parents 98f0172 + c59bd56 commit cb41838
Show file tree
Hide file tree
Showing 14 changed files with 188 additions and 62 deletions.
18 changes: 10 additions & 8 deletions arch/alpha/include/asm/bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,29 +405,31 @@ static inline int fls(int x)

#if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67)
/* Whee. EV67 can calculate it directly. */
static inline unsigned long hweight64(unsigned long w)
static inline unsigned long __arch_hweight64(unsigned long w)
{
return __kernel_ctpop(w);
}

static inline unsigned int hweight32(unsigned int w)
static inline unsigned int __arch_weight32(unsigned int w)
{
return hweight64(w);
return __arch_hweight64(w);
}

static inline unsigned int hweight16(unsigned int w)
static inline unsigned int __arch_hweight16(unsigned int w)
{
return hweight64(w & 0xffff);
return __arch_hweight64(w & 0xffff);
}

static inline unsigned int hweight8(unsigned int w)
static inline unsigned int __arch_hweight8(unsigned int w)
{
return hweight64(w & 0xff);
return __arch_hweight64(w & 0xff);
}
#else
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/arch_hweight.h>
#endif

#include <asm-generic/bitops/const_hweight.h>

#endif /* __KERNEL__ */

#include <asm-generic/bitops/find.h>
Expand Down
11 changes: 6 additions & 5 deletions arch/ia64/include/asm/bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,17 +437,18 @@ __fls (unsigned long x)
* hweightN: returns the hamming weight (i.e. the number
* of bits set) of a N-bit word
*/
static __inline__ unsigned long
hweight64 (unsigned long x)
static __inline__ unsigned long __arch_hweight64(unsigned long x)
{
unsigned long result;
result = ia64_popcnt(x);
return result;
}

#define hweight32(x) (unsigned int) hweight64((x) & 0xfffffffful)
#define hweight16(x) (unsigned int) hweight64((x) & 0xfffful)
#define hweight8(x) (unsigned int) hweight64((x) & 0xfful)
#define __arch_hweight32(x) ((unsigned int) __arch_hweight64((x) & 0xfffffffful))
#define __arch_hweight16(x) ((unsigned int) __arch_hweight64((x) & 0xfffful))
#define __arch_hweight8(x) ((unsigned int) __arch_hweight64((x) & 0xfful))

#include <asm-generic/bitops/const_hweight.h>

#endif /* __KERNEL__ */

Expand Down
11 changes: 6 additions & 5 deletions arch/sparc/include/asm/bitops_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,31 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);

#ifdef ULTRA_HAS_POPULATION_COUNT

static inline unsigned int hweight64(unsigned long w)
static inline unsigned int __arch_hweight64(unsigned long w)
{
unsigned int res;

__asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
return res;
}

static inline unsigned int hweight32(unsigned int w)
static inline unsigned int __arch_hweight32(unsigned int w)
{
unsigned int res;

__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
return res;
}

static inline unsigned int hweight16(unsigned int w)
static inline unsigned int __arch_hweight16(unsigned int w)
{
unsigned int res;

__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
return res;
}

static inline unsigned int hweight8(unsigned int w)
static inline unsigned int __arch_hweight8(unsigned int w)
{
unsigned int res;

Expand All @@ -78,9 +78,10 @@ static inline unsigned int hweight8(unsigned int w)

#else

#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/arch_hweight.h>

#endif
#include <asm-generic/bitops/const_hweight.h>
#include <asm-generic/bitops/lock.h>
#endif /* __KERNEL__ */

Expand Down
5 changes: 5 additions & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ config X86_32_LAZY_GS
def_bool y
depends on X86_32 && !CC_STACKPROTECTOR

config ARCH_HWEIGHT_CFLAGS
string
default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64

config KTIME_SCALAR
def_bool X86_32
source "init/Kconfig"
Expand Down
9 changes: 6 additions & 3 deletions arch/x86/include/asm/alternative.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@
#define LOCK_PREFIX ""
#endif

/* This must be included *after* the definition of LOCK_PREFIX */
#include <asm/cpufeature.h>

struct alt_instr {
u8 *instr; /* original instruction */
u8 *replacement;
Expand Down Expand Up @@ -98,6 +95,12 @@ static inline int alternatives_text_reserved(void *start, void *end)
"663:\n\t" newinstr "\n664:\n" /* replacement */ \
".previous"

/*
* This must be included *after* the definition of ALTERNATIVE due to
* <asm/arch_hweight.h>
*/
#include <asm/cpufeature.h>

/*
* Alternative instructions for different CPU types or capabilities.
*
Expand Down
61 changes: 61 additions & 0 deletions arch/x86/include/asm/arch_hweight.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#ifndef _ASM_X86_HWEIGHT_H
#define _ASM_X86_HWEIGHT_H

#ifdef CONFIG_64BIT
/* popcnt %edi, %eax -- redundant REX prefix for alignment */
#define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7"
/* popcnt %rdi, %rax */
#define POPCNT64 ".byte 0xf3,0x48,0x0f,0xb8,0xc7"
#define REG_IN "D"
#define REG_OUT "a"
#else
/* popcnt %eax, %eax */
#define POPCNT32 ".byte 0xf3,0x0f,0xb8,0xc0"
#define REG_IN "a"
#define REG_OUT "a"
#endif

/*
* __sw_hweightXX are called from within the alternatives below
* and callee-clobbered registers need to be taken care of. See
* ARCH_HWEIGHT_CFLAGS in <arch/x86/Kconfig> for the respective
* compiler switches.
*/
static inline unsigned int __arch_hweight32(unsigned int w)
{
unsigned int res = 0;

asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT)
: "="REG_OUT (res)
: REG_IN (w));

return res;
}

static inline unsigned int __arch_hweight16(unsigned int w)
{
return __arch_hweight32(w & 0xffff);
}

static inline unsigned int __arch_hweight8(unsigned int w)
{
return __arch_hweight32(w & 0xff);
}

static inline unsigned long __arch_hweight64(__u64 w)
{
unsigned long res = 0;

#ifdef CONFIG_X86_32
return __arch_hweight32((u32)w) +
__arch_hweight32((u32)(w >> 32));
#else
asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT)
: "="REG_OUT (res)
: REG_IN (w));
#endif /* CONFIG_X86_32 */

return res;
}

#endif
4 changes: 3 additions & 1 deletion arch/x86/include/asm/bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ static inline int fls(int x)

#define ARCH_HAS_FAST_MULTIPLIER 1

#include <asm-generic/bitops/hweight.h>
#include <asm/arch_hweight.h>

#include <asm-generic/bitops/const_hweight.h>

#endif /* __KERNEL__ */

Expand Down
25 changes: 25 additions & 0 deletions include/asm-generic/bitops/arch_hweight.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_
#define _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_

#include <asm/types.h>

static inline unsigned int __arch_hweight32(unsigned int w)
{
return __sw_hweight32(w);
}

static inline unsigned int __arch_hweight16(unsigned int w)
{
return __sw_hweight16(w);
}

static inline unsigned int __arch_hweight8(unsigned int w)
{
return __sw_hweight8(w);
}

static inline unsigned long __arch_hweight64(__u64 w)
{
return __sw_hweight64(w);
}
#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
42 changes: 42 additions & 0 deletions include/asm-generic/bitops/const_hweight.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_
#define _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_

/*
* Compile time versions of __arch_hweightN()
*/
#define __const_hweight8(w) \
( (!!((w) & (1ULL << 0))) + \
(!!((w) & (1ULL << 1))) + \
(!!((w) & (1ULL << 2))) + \
(!!((w) & (1ULL << 3))) + \
(!!((w) & (1ULL << 4))) + \
(!!((w) & (1ULL << 5))) + \
(!!((w) & (1ULL << 6))) + \
(!!((w) & (1ULL << 7))) )

#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8 ))
#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16))
#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32))

/*
* Generic interface.
*/
#define hweight8(w) (__builtin_constant_p(w) ? __const_hweight8(w) : __arch_hweight8(w))
#define hweight16(w) (__builtin_constant_p(w) ? __const_hweight16(w) : __arch_hweight16(w))
#define hweight32(w) (__builtin_constant_p(w) ? __const_hweight32(w) : __arch_hweight32(w))
#define hweight64(w) (__builtin_constant_p(w) ? __const_hweight64(w) : __arch_hweight64(w))

/*
* Interface for known constant arguments
*/
#define HWEIGHT8(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight8(w))
#define HWEIGHT16(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight16(w))
#define HWEIGHT32(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight32(w))
#define HWEIGHT64(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight64(w))

/*
* Type invariant interface to the compile time constant hweight functions.
*/
#define HWEIGHT(w) HWEIGHT64((u64)w)

#endif /* _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ */
8 changes: 2 additions & 6 deletions include/asm-generic/bitops/hweight.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
#define _ASM_GENERIC_BITOPS_HWEIGHT_H_

#include <asm/types.h>

extern unsigned int hweight32(unsigned int w);
extern unsigned int hweight16(unsigned int w);
extern unsigned int hweight8(unsigned int w);
extern unsigned long hweight64(__u64 w);
#include <asm-generic/bitops/arch_hweight.h>
#include <asm-generic/bitops/const_hweight.h>

#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
30 changes: 5 additions & 25 deletions include/linux/bitops.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#endif

extern unsigned int __sw_hweight8(unsigned int w);
extern unsigned int __sw_hweight16(unsigned int w);
extern unsigned int __sw_hweight32(unsigned int w);
extern unsigned long __sw_hweight64(__u64 w);

/*
* Include this here because some architectures need generic_ffs/fls in
* scope
Expand Down Expand Up @@ -44,31 +49,6 @@ static inline unsigned long hweight_long(unsigned long w)
return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
}

/*
* Clearly slow versions of the hweightN() functions, their benefit is
* of course compile time evaluation of constant arguments.
*/
#define HWEIGHT8(w) \
( BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + \
(!!((w) & (1ULL << 0))) + \
(!!((w) & (1ULL << 1))) + \
(!!((w) & (1ULL << 2))) + \
(!!((w) & (1ULL << 3))) + \
(!!((w) & (1ULL << 4))) + \
(!!((w) & (1ULL << 5))) + \
(!!((w) & (1ULL << 6))) + \
(!!((w) & (1ULL << 7))) )

#define HWEIGHT16(w) (HWEIGHT8(w) + HWEIGHT8((w) >> 8))
#define HWEIGHT32(w) (HWEIGHT16(w) + HWEIGHT16((w) >> 16))
#define HWEIGHT64(w) (HWEIGHT32(w) + HWEIGHT32((w) >> 32))

/*
* Type invariant version that simply casts things to the
* largest type.
*/
#define HWEIGHT(w) HWEIGHT64((u64)(w))

/**
* rol32 - rotate a 32-bit value left
* @word: value to rotate
Expand Down
3 changes: 3 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
lib-$(CONFIG_GENERIC_FIND_FIRST_BIT) += find_next_bit.o
lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
obj-$(CONFIG_GENERIC_FIND_LAST_BIT) += find_last_bit.o

CFLAGS_hweight.o = $(subst $(quote),,$(CONFIG_ARCH_HWEIGHT_CFLAGS))
obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o

obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
obj-$(CONFIG_BTREE) += btree.o
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
Expand Down
Loading

0 comments on commit cb41838

Please sign in to comment.