1d61931d8SBorislav Petkov #ifndef _ASM_X86_HWEIGHT_H
2d61931d8SBorislav Petkov #define _ASM_X86_HWEIGHT_H
3d61931d8SBorislav Petkov 
4cd4d09ecSBorislav Petkov #include <asm/cpufeatures.h>
5cd4d09ecSBorislav Petkov 
6d61931d8SBorislav Petkov #ifdef CONFIG_64BIT
7c59bd568SH. Peter Anvin /* popcnt %edi, %eax -- redundant REX prefix for alignment */
8c59bd568SH. Peter Anvin #define POPCNT32 ".byte 0xf3,0x40,0x0f,0xb8,0xc7"
9d61931d8SBorislav Petkov /* popcnt %rdi, %rax */
10c59bd568SH. Peter Anvin #define POPCNT64 ".byte 0xf3,0x48,0x0f,0xb8,0xc7"
11d61931d8SBorislav Petkov #define REG_IN "D"
12d61931d8SBorislav Petkov #define REG_OUT "a"
13d61931d8SBorislav Petkov #else
14d61931d8SBorislav Petkov /* popcnt %eax, %eax */
15c59bd568SH. Peter Anvin #define POPCNT32 ".byte 0xf3,0x0f,0xb8,0xc0"
16d61931d8SBorislav Petkov #define REG_IN "a"
17d61931d8SBorislav Petkov #define REG_OUT "a"
18d61931d8SBorislav Petkov #endif
19d61931d8SBorislav Petkov 
20d61931d8SBorislav Petkov /*
21d61931d8SBorislav Petkov  * __sw_hweightXX are called from within the alternatives below
22d61931d8SBorislav Petkov  * and callee-clobbered registers need to be taken care of. See
23d61931d8SBorislav Petkov  * ARCH_HWEIGHT_CFLAGS in <arch/x86/Kconfig> for the respective
24d61931d8SBorislav Petkov  * compiler switches.
25d61931d8SBorislav Petkov  */
26d14edb16SDenys Vlasenko static __always_inline unsigned int __arch_hweight32(unsigned int w)
27d61931d8SBorislav Petkov {
28d61931d8SBorislav Petkov 	unsigned int res = 0;
29d61931d8SBorislav Petkov 
30c59bd568SH. Peter Anvin 	asm (ALTERNATIVE("call __sw_hweight32", POPCNT32, X86_FEATURE_POPCNT)
31d61931d8SBorislav Petkov 		     : "="REG_OUT (res)
32d61931d8SBorislav Petkov 		     : REG_IN (w));
33d61931d8SBorislav Petkov 
34d61931d8SBorislav Petkov 	return res;
35d61931d8SBorislav Petkov }
36d61931d8SBorislav Petkov 
37d61931d8SBorislav Petkov static inline unsigned int __arch_hweight16(unsigned int w)
38d61931d8SBorislav Petkov {
39d61931d8SBorislav Petkov 	return __arch_hweight32(w & 0xffff);
40d61931d8SBorislav Petkov }
41d61931d8SBorislav Petkov 
42d61931d8SBorislav Petkov static inline unsigned int __arch_hweight8(unsigned int w)
43d61931d8SBorislav Petkov {
44d61931d8SBorislav Petkov 	return __arch_hweight32(w & 0xff);
45d61931d8SBorislav Petkov }
46d61931d8SBorislav Petkov 
47d14edb16SDenys Vlasenko #ifdef CONFIG_X86_32
48d61931d8SBorislav Petkov static inline unsigned long __arch_hweight64(__u64 w)
49d61931d8SBorislav Petkov {
50d14edb16SDenys Vlasenko 	return  __arch_hweight32((u32)w) +
51d14edb16SDenys Vlasenko 		__arch_hweight32((u32)(w >> 32));
52d14edb16SDenys Vlasenko }
53d14edb16SDenys Vlasenko #else
54d14edb16SDenys Vlasenko static __always_inline unsigned long __arch_hweight64(__u64 w)
55d14edb16SDenys Vlasenko {
56d61931d8SBorislav Petkov 	unsigned long res = 0;
57d61931d8SBorislav Petkov 
58c59bd568SH. Peter Anvin 	asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT)
59d61931d8SBorislav Petkov 		     : "="REG_OUT (res)
60d61931d8SBorislav Petkov 		     : REG_IN (w));
61d61931d8SBorislav Petkov 
62d61931d8SBorislav Petkov 	return res;
63d61931d8SBorislav Petkov }
64d14edb16SDenys Vlasenko #endif /* CONFIG_X86_32 */
65d61931d8SBorislav Petkov 
66d61931d8SBorislav Petkov #endif
67