xref: /linux/arch/riscv/include/asm/arch_hweight.h (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
155ca8d7aSXiao Wang /* SPDX-License-Identifier: GPL-2.0 */
255ca8d7aSXiao Wang /*
355ca8d7aSXiao Wang  * Based on arch/x86/include/asm/arch_hweight.h
455ca8d7aSXiao Wang  */
555ca8d7aSXiao Wang 
655ca8d7aSXiao Wang #ifndef _ASM_RISCV_HWEIGHT_H
755ca8d7aSXiao Wang #define _ASM_RISCV_HWEIGHT_H
855ca8d7aSXiao Wang 
955ca8d7aSXiao Wang #include <asm/alternative-macros.h>
1055ca8d7aSXiao Wang #include <asm/hwcap.h>
1155ca8d7aSXiao Wang 
1255ca8d7aSXiao Wang #if (BITS_PER_LONG == 64)
1355ca8d7aSXiao Wang #define CPOPW	"cpopw "
1455ca8d7aSXiao Wang #elif (BITS_PER_LONG == 32)
1555ca8d7aSXiao Wang #define CPOPW	"cpop "
1655ca8d7aSXiao Wang #else
1755ca8d7aSXiao Wang #error "Unexpected BITS_PER_LONG"
1855ca8d7aSXiao Wang #endif
1955ca8d7aSXiao Wang 
__arch_hweight32(unsigned int w)2055ca8d7aSXiao Wang static __always_inline unsigned int __arch_hweight32(unsigned int w)
2155ca8d7aSXiao Wang {
2255ca8d7aSXiao Wang #ifdef CONFIG_RISCV_ISA_ZBB
234356e9f8SLinus Torvalds 	asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
2455ca8d7aSXiao Wang 				      RISCV_ISA_EXT_ZBB, 1)
2555ca8d7aSXiao Wang 			  : : : : legacy);
2655ca8d7aSXiao Wang 
2755ca8d7aSXiao Wang 	asm (".option push\n"
2855ca8d7aSXiao Wang 	     ".option arch,+zbb\n"
29*93b63f68SQingfang Deng 	     CPOPW "%0, %1\n"
3055ca8d7aSXiao Wang 	     ".option pop\n"
31*93b63f68SQingfang Deng 	     : "=r" (w) : "r" (w) :);
3255ca8d7aSXiao Wang 
3355ca8d7aSXiao Wang 	return w;
3455ca8d7aSXiao Wang 
3555ca8d7aSXiao Wang legacy:
3655ca8d7aSXiao Wang #endif
3755ca8d7aSXiao Wang 	return __sw_hweight32(w);
3855ca8d7aSXiao Wang }
3955ca8d7aSXiao Wang 
__arch_hweight16(unsigned int w)4055ca8d7aSXiao Wang static inline unsigned int __arch_hweight16(unsigned int w)
4155ca8d7aSXiao Wang {
4255ca8d7aSXiao Wang 	return __arch_hweight32(w & 0xffff);
4355ca8d7aSXiao Wang }
4455ca8d7aSXiao Wang 
__arch_hweight8(unsigned int w)4555ca8d7aSXiao Wang static inline unsigned int __arch_hweight8(unsigned int w)
4655ca8d7aSXiao Wang {
4755ca8d7aSXiao Wang 	return __arch_hweight32(w & 0xff);
4855ca8d7aSXiao Wang }
4955ca8d7aSXiao Wang 
5055ca8d7aSXiao Wang #if BITS_PER_LONG == 64
__arch_hweight64(__u64 w)5155ca8d7aSXiao Wang static __always_inline unsigned long __arch_hweight64(__u64 w)
5255ca8d7aSXiao Wang {
5355ca8d7aSXiao Wang # ifdef CONFIG_RISCV_ISA_ZBB
544356e9f8SLinus Torvalds 	asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
5555ca8d7aSXiao Wang 				      RISCV_ISA_EXT_ZBB, 1)
5655ca8d7aSXiao Wang 			  : : : : legacy);
5755ca8d7aSXiao Wang 
5855ca8d7aSXiao Wang 	asm (".option push\n"
5955ca8d7aSXiao Wang 	     ".option arch,+zbb\n"
60*93b63f68SQingfang Deng 	     "cpop %0, %1\n"
6155ca8d7aSXiao Wang 	     ".option pop\n"
62*93b63f68SQingfang Deng 	     : "=r" (w) : "r" (w) :);
6355ca8d7aSXiao Wang 
6455ca8d7aSXiao Wang 	return w;
6555ca8d7aSXiao Wang 
6655ca8d7aSXiao Wang legacy:
6755ca8d7aSXiao Wang # endif
6855ca8d7aSXiao Wang 	return __sw_hweight64(w);
6955ca8d7aSXiao Wang }
7055ca8d7aSXiao Wang #else /* BITS_PER_LONG == 64 */
__arch_hweight64(__u64 w)7155ca8d7aSXiao Wang static inline unsigned long __arch_hweight64(__u64 w)
7255ca8d7aSXiao Wang {
7355ca8d7aSXiao Wang 	return  __arch_hweight32((u32)w) +
7455ca8d7aSXiao Wang 		__arch_hweight32((u32)(w >> 32));
7555ca8d7aSXiao Wang }
7655ca8d7aSXiao Wang #endif /* !(BITS_PER_LONG == 64) */
7755ca8d7aSXiao Wang 
7855ca8d7aSXiao Wang #endif /* _ASM_RISCV_HWEIGHT_H */
79