^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <asm/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <asm/asm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * unsigned int __sw_hweight32(unsigned int w)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * %rdi: w
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) SYM_FUNC_START(__sw_hweight32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #ifdef CONFIG_X86_64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) movl %edi, %eax # w
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) __ASM_SIZE(push,) %__ASM_REG(dx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) movl %eax, %edx # w -> t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) shrl %edx # t >>= 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) andl $0x55555555, %edx # t &= 0x55555555
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) subl %edx, %eax # w -= t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) movl %eax, %edx # w -> t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) shrl $2, %eax # w_tmp >>= 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) andl $0x33333333, %edx # t &= 0x33333333
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) andl $0x33333333, %eax # w_tmp &= 0x33333333
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) addl %edx, %eax # w = w_tmp + t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) movl %eax, %edx # w -> t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) shrl $4, %edx # t >>= 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) addl %edx, %eax # w_tmp += t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) andl $0x0f0f0f0f, %eax # w_tmp &= 0x0f0f0f0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) imull $0x01010101, %eax, %eax # w_tmp *= 0x01010101
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) shrl $24, %eax # w = w_tmp >> 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) __ASM_SIZE(pop,) %__ASM_REG(dx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ret
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) SYM_FUNC_END(__sw_hweight32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) EXPORT_SYMBOL(__sw_hweight32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) SYM_FUNC_START(__sw_hweight64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #ifdef CONFIG_X86_64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) pushq %rdi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) pushq %rdx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) movq %rdi, %rdx # w -> t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) movabsq $0x5555555555555555, %rax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) shrq %rdx # t >>= 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) andq %rdx, %rax # t &= 0x5555555555555555
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) movabsq $0x3333333333333333, %rdx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) subq %rax, %rdi # w -= t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) movq %rdi, %rax # w -> t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) shrq $2, %rdi # w_tmp >>= 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) andq %rdx, %rax # t &= 0x3333333333333333
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) andq %rdi, %rdx # w_tmp &= 0x3333333333333333
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) addq %rdx, %rax # w = w_tmp + t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) movq %rax, %rdx # w -> t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) shrq $4, %rdx # t >>= 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) addq %rdx, %rax # w_tmp += t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) movabsq $0x0f0f0f0f0f0f0f0f, %rdx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) andq %rdx, %rax # w_tmp &= 0x0f0f0f0f0f0f0f0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) movabsq $0x0101010101010101, %rdx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) imulq %rdx, %rax # w_tmp *= 0x0101010101010101
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) shrq $56, %rax # w = w_tmp >> 56
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) popq %rdx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) popq %rdi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ret
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #else /* CONFIG_X86_32 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* We're getting an u64 arg in (%eax,%edx): unsigned long hweight64(__u64 w) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) pushl %ecx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) call __sw_hweight32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) movl %eax, %ecx # stash away result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) movl %edx, %eax # second part of input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) call __sw_hweight32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) addl %ecx, %eax # result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) popl %ecx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ret
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) SYM_FUNC_END(__sw_hweight64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) EXPORT_SYMBOL(__sw_hweight64)