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