hweight.S 2.4 KB

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