]> bbs.cooldavid.org Git - net-next-2.6.git/blob - arch/x86/include/asm/arch_hweight.h
x86: Add optimized popcnt variants
[net-next-2.6.git] / arch / x86 / include / asm / arch_hweight.h
1 #ifndef _ASM_X86_HWEIGHT_H
2 #define _ASM_X86_HWEIGHT_H
3
4 #ifdef CONFIG_64BIT
5 /* popcnt %rdi, %rax */
6 #define POPCNT ".byte 0xf3,0x48,0x0f,0xb8,0xc7"
7 #define REG_IN "D"
8 #define REG_OUT "a"
9 #else
10 /* popcnt %eax, %eax */
11 #define POPCNT ".byte 0xf3,0x0f,0xb8,0xc0"
12 #define REG_IN "a"
13 #define REG_OUT "a"
14 #endif
15
16 /*
17  * __sw_hweightXX are called from within the alternatives below
18  * and callee-clobbered registers need to be taken care of. See
19  * ARCH_HWEIGHT_CFLAGS in <arch/x86/Kconfig> for the respective
20  * compiler switches.
21  */
22 static inline unsigned int __arch_hweight32(unsigned int w)
23 {
24         unsigned int res = 0;
25
26         asm (ALTERNATIVE("call __sw_hweight32", POPCNT, X86_FEATURE_POPCNT)
27                      : "="REG_OUT (res)
28                      : REG_IN (w));
29
30         return res;
31 }
32
33 static inline unsigned int __arch_hweight16(unsigned int w)
34 {
35         return __arch_hweight32(w & 0xffff);
36 }
37
38 static inline unsigned int __arch_hweight8(unsigned int w)
39 {
40         return __arch_hweight32(w & 0xff);
41 }
42
43 static inline unsigned long __arch_hweight64(__u64 w)
44 {
45         unsigned long res = 0;
46
47 #ifdef CONFIG_X86_32
48         return  __arch_hweight32((u32)w) +
49                 __arch_hweight32((u32)(w >> 32));
50 #else
51         asm (ALTERNATIVE("call __sw_hweight64", POPCNT, X86_FEATURE_POPCNT)
52                      : "="REG_OUT (res)
53                      : REG_IN (w));
54 #endif /* CONFIG_X86_32 */
55
56         return res;
57 }
58
59 #endif