对于特定项目,我在i7 Core上运行gcc和 32位 12.04 LTS Ubuntu,支持AVX SIMD指令。
由于32位操作系统,我显然无法使用256位运行的AVX指令。我可以使用128位访问SSE4.2指令,POPCNT可以运行16位,32位和64位数据,因此看起来很有前途。但我尝试了几种方法向POPCNT提供64位数据但没有成功。 GCC 4.6.3返回
的方法:
uint64 a, b;
__asm__ volatile (“POPCNT %1, %0;”
:”=r”(b)
:”r”(a)
:
)
gcc告诉“popcnt的操作数类型不匹配”,
如果POPCNT支持128位xmm寄存器,那本来会很好......
在汇编中对64位数据应用POPCNT的任何解决方法?
PS :使用shuffle进行SSSE3 popcount的讨论与SSE4相比,POPCNT性能在此处得出结论http://danluu.com/assembly-intrinsics/ 并且仅仅因为使用内在函数并不总是提供有效的汇编代码。使用内在函数快速优化C / C ++代码并且如果它足以满足需求,那很好。但是,与内在函数相比,我在汇编时使用shuffle获得了近30%的性能提升编码popcount。
答案 0 :(得分:1)
popcnt
是一个整数指令。因此,在32位模式下,您无法将其与64位操作数一起使用。您需要计算两半的popcnt
并将它们加在一起。这就是我测试过的所有clang版本对内置版本的影响。但是,我无法获得任何gcc版本来使用popcnt指令。因此,虽然通常建议使用内置,但在这种情况下,内联asm可能会更好。
答案 1 :(得分:0)
我不知道是否有32位popcnt指令,但我敢打赌你不能在32位代码中使用64位popcnt。尝试将a和b声明为uint32_t。 BTW uint64_t是标准C,uint64不是。
答案 2 :(得分:0)
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
答案 3 :(得分:0)
使用汇编实现32位POPCNT后,与SSSE3 shuffle汇编方法相比,看起来没有真正的改进。 正如我怀疑的那样,只有64位POPCNT版本几乎可以加倍速度。