4 回答
32 位系统不支持 64 位 POPCOUNT,因为
REX 前缀仅在长模式下可用。(不在 32 位操作系统中)
因此
写 POPCNTQ 会导致“popcnt 的指令后缀无效”。
见这里:http ://www.felixcloutier.com/x86/POPCNT.html (下面引用)
Opcode Instruction Op/En 64-Bit Mode Compat/Leg Mode Description
F3 0F B8 /r POPCNT r16, r/m16 RM Valid Valid POPCNT on r/m16
F3 0F B8 /r POPCNT r32, r/m32 RM Valid Valid POPCNT on r/m32
F3 REX.W 0F B8 /r POPCNT r64,r/m64 RM Valid N.E. POPCNT on r/m64
一种解决方法是将 64/128 位拆分为两个/四个 32 位指令:
; a=uint_64, 64 bit operand, little endian
popcount eax, dword ptr [a]
popcount edx, dword ptr [a+4]
add eax, edx
xor edx, edx ; for first mov below
mov dword ptr [b], edx ; not neccessary, only due to 64 target op (will there ever be 2^64 bits set???)
mov dword ptr [b+4], eax
编辑:MASM32 代码中(二进制)HammingDistance 的 64 位操作数大小版本:
Hamming_64 PROC word1:QWORD , word2: QWORD
mov ecx, dword ptr [word1]
mov edx, dword ptr [word1+4]
xor ecx, dword ptr [word2]
xor edx, dword ptr [word2+4]
popcnt eax, ecx
popcnt ebx, edx
add eax, ebx ; returns distance in EAX
ret
Hamming_64 ENDP
popcnt
是一个整数指令。因此,在 32 位模式下,您不能将其与 64 位操作数一起使用。您需要计算popcnt
两半的 并将它们相加。这就是我测试过的所有 clang 版本为内置函数所做的。但是,我无法获得任何 gcc 版本来使用 popcnt 指令。因此,虽然通常建议使用内置函数,但在这种情况下,内联 asm 可能会更好。
我不知道是否有 32 位 popcnt 指令,但我敢打赌你不能在 32 位代码中使用 64 位 popcnt。尝试将 a 和 b 声明为 uint32_t。BTW uint64_t 是标准C, uint64 不是。
After implementing the 32 bits POPCNT using assembly, it looks like there is no real improvement compared to the SSSE3 shuffle assembly method. As I was suspecting, only the 64 bits POPCNT version can almost double the speed.