xref: /linux/arch/riscv/include/asm/arch_hweight.h (revision 36f353a1ebf88280f58d1ebfe2731251d9159456)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Based on arch/x86/include/asm/arch_hweight.h
4  */
5 
6 #ifndef _ASM_RISCV_HWEIGHT_H
7 #define _ASM_RISCV_HWEIGHT_H
8 
9 #include <asm/alternative-macros.h>
10 #include <asm/hwcap.h>
11 
12 #if (BITS_PER_LONG == 64)
13 #define CPOPW	"cpopw "
14 #elif (BITS_PER_LONG == 32)
15 #define CPOPW	"cpop "
16 #else
17 #error "Unexpected BITS_PER_LONG"
18 #endif
19 
20 static __always_inline unsigned int __arch_hweight32(unsigned int w)
21 {
22 #ifdef CONFIG_RISCV_ISA_ZBB
23 	asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
24 				      RISCV_ISA_EXT_ZBB, 1)
25 			  : : : : legacy);
26 
27 	asm (".option push\n"
28 	     ".option arch,+zbb\n"
29 	     CPOPW "%0, %0\n"
30 	     ".option pop\n"
31 	     : "+r" (w) : :);
32 
33 	return w;
34 
35 legacy:
36 #endif
37 	return __sw_hweight32(w);
38 }
39 
40 static inline unsigned int __arch_hweight16(unsigned int w)
41 {
42 	return __arch_hweight32(w & 0xffff);
43 }
44 
45 static inline unsigned int __arch_hweight8(unsigned int w)
46 {
47 	return __arch_hweight32(w & 0xff);
48 }
49 
50 #if BITS_PER_LONG == 64
51 static __always_inline unsigned long __arch_hweight64(__u64 w)
52 {
53 # ifdef CONFIG_RISCV_ISA_ZBB
54 	asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
55 				      RISCV_ISA_EXT_ZBB, 1)
56 			  : : : : legacy);
57 
58 	asm (".option push\n"
59 	     ".option arch,+zbb\n"
60 	     "cpop %0, %0\n"
61 	     ".option pop\n"
62 	     : "+r" (w) : :);
63 
64 	return w;
65 
66 legacy:
67 # endif
68 	return __sw_hweight64(w);
69 }
70 #else /* BITS_PER_LONG == 64 */
71 static inline unsigned long __arch_hweight64(__u64 w)
72 {
73 	return  __arch_hweight32((u32)w) +
74 		__arch_hweight32((u32)(w >> 32));
75 }
76 #endif /* !(BITS_PER_LONG == 64) */
77 
78 #endif /* _ASM_RISCV_HWEIGHT_H */
79