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