xref: /linux/arch/riscv/include/asm/arch_hweight.h (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
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 	if (!(IS_ENABLED(CONFIG_RISCV_ISA_ZBB) &&
23 	      IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB) &&
24 	      riscv_has_extension_likely(RISCV_ISA_EXT_ZBB)))
25 		return __sw_hweight32(w);
26 
27 	asm (".option push\n"
28 	     ".option arch,+zbb\n"
29 	     CPOPW "%0, %1\n"
30 	     ".option pop\n"
31 	     : "=r" (w) : "r" (w) :);
32 
33 	return w;
34 }
35 
36 static inline unsigned int __arch_hweight16(unsigned int w)
37 {
38 	return __arch_hweight32(w & 0xffff);
39 }
40 
41 static inline unsigned int __arch_hweight8(unsigned int w)
42 {
43 	return __arch_hweight32(w & 0xff);
44 }
45 
46 #if BITS_PER_LONG == 64
47 static __always_inline unsigned long __arch_hweight64(__u64 w)
48 {
49 	if (!(IS_ENABLED(CONFIG_RISCV_ISA_ZBB) &&
50 	      IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB) &&
51 	      riscv_has_extension_likely(RISCV_ISA_EXT_ZBB)))
52 		return __sw_hweight64(w);
53 
54 	asm (".option push\n"
55 	     ".option arch,+zbb\n"
56 	     "cpop %0, %1\n"
57 	     ".option pop\n"
58 	     : "=r" (w) : "r" (w) :);
59 
60 	return w;
61 }
62 #else /* BITS_PER_LONG == 64 */
63 static inline unsigned long __arch_hweight64(__u64 w)
64 {
65 	return  __arch_hweight32((u32)w) +
66 		__arch_hweight32((u32)(w >> 32));
67 }
68 #endif /* !(BITS_PER_LONG == 64) */
69 
70 #endif /* _ASM_RISCV_HWEIGHT_H */
71