Gcc 在32位Ubuntu上运行时如何使用汇编POPCNT指令

Gcc 在32位Ubuntu上运行时如何使用汇编POPCNT指令,gcc,assembly,optimization,32bit-64bit,hammingweight,Gcc,Assembly,Optimization,32bit 64bit,Hammingweight,对于一个特定的项目,我坚持使用gcc和一个运行在i7内核上的32位12.04 LTS Ubuntu,支持多达AVX SIMD指令 由于32位操作系统,我显然无法使用256位上运行的AVX指令。我可以使用128位访问SSE4.2指令,POPCNT可以在16、32和64位数据上运行,所以看起来很有希望。但我尝试了几种方法向POPCNT提供64位数据,但都没有成功。 GCC 4.6.3退货 r8至r15的“未知寄存器名称” rax rdx的“坏寄存器名” 当试图提供mm寄存器或向我的内联汇编函数提供

对于一个特定的项目,我坚持使用gcc和一个运行在i7内核上的32位12.04 LTS Ubuntu,支持多达AVX SIMD指令

由于32位操作系统,我显然无法使用256位上运行的AVX指令。我可以使用128位访问SSE4.2指令,POPCNT可以在16、32和64位数据上运行,所以看起来很有希望。但我尝试了几种方法向POPCNT提供64位数据,但都没有成功。 GCC 4.6.3退货

  • r8至r15的“未知寄存器名称”
  • rax rdx的“坏寄存器名”
  • 当试图提供mm寄存器或向我的内联汇编函数提供一些uint64或long时,这些寄存器在这种情况下会受到影响
方式:

gcc告诉“popcnt的操作数类型不匹配”

  • 写入POPCNTQ会导致“popcnt的指令后缀无效”
如果POPCNT支持128位xmm寄存器就太好了

在汇编中的64位数据上应用POPCNT有什么解决方法吗

PS:关于使用Sshuffle的SSSE3 popcount与SSE4 POPCNT性能的比较的讨论在这里得出了结论
这仅仅是因为使用内部函数并不总是提供高效的汇编代码。使用intrinsic快速优化C/C++代码是很好的,如果这足以满足需要,那就好了。但除此之外,与intrinsics相比,我在汇编中使用shuffle编码popcount的性能提高了近30%

我不知道是否有32位popcnt指令,但我敢打赌您不能在32位代码中使用64位popcnt。尝试将a和b声明为uint32\t。顺便说一句,uint64是标准C,uint64不是

popcnt
是一条整数指令。因此,在32位模式下,不能将其用于64位操作数。您需要计算两半的
popcnt
,并将它们相加。这就是我测试过的所有叮当版本对内置程序所做的。但是,我无法获得任何gcc版本来使用popcnt指令。因此,虽然通常建议使用内置asm,但在这种情况下,内联asm可能更好。

64位POPCOUNT在32位系统上不受支持,因为

REX前缀仅在长模式下可用。(不在32位操作系统中)

因此

写入POPCNTQ会导致“popcnt的指令后缀无效”

请看这里:(引述如下)

解决方法是将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代码中(二进制)汉明距离的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

在使用assembly实现32位POPCNT之后,与SSSE3 shuffle assembly方法相比,似乎没有什么真正的改进。
正如我所怀疑的,只有64位POPCNT版本的速度几乎可以翻倍。

是的,有。但与当前使用Sshuffle的SSSE3汇编实现相比,我将错过一大部分(全部?)改进。写它只是为了说明我是如何将参数传递给汇编函数寄存器的。好吧,这很尴尬,我可以使用SSEx在32位操作系统上处理多达128位的压缩数据,而汇编POPCNT无法处理64位数据,即使打包:-s@user3581220为什么它在32位模式下工作在64位值上,而那里甚至没有64位寄存器?因为在32位操作系统上有128位xmm寄存器可访问(考虑打包的值并不是什么大问题).@user3581220英特尔决定使XMM寄存器在处理器的所有操作模式下都可访问,但AMD决定只允许在64位长模式下访问整数寄存器的完整64位。@user3581220 XMM寄存器不是用于大128位数字,而是用于同时存储多个值。它们有不同的用法,因为XMM不是通用寄存器。此外,使用64位寄存器需要REX前缀,该前缀采用inc和dec的操作码。这就是为什么不能在64位模式下使用单字节inc/dec。原因是x86中几乎没有前缀和操作码的代码点。我以前在镜像站点上看到过此文档,但我想确定没有人找到使用64位版本的方法。嗯,我目前的组装方法实际上是对两个64字节向量进行异或运算,然后处理汉明距离,因此我尝试用两种不同的方式将洗牌替换为32位POPCNT:a)在处理POPCNT之前将XOR结果从xmm写回对齐数组,b)将XOR结果xmm寄存器移位4个字节,并将其置于32位exx寄存器中,然后在该寄存器上处理POPCNT。将代码中使用的寄存器延迟考虑到指令延迟和吞吐量,我无法改进shuffle方法(实际上我损失了5%到15%)。我仍然不确定您要实现什么或尝试实现什么算法。无论如何,我在文章中添加了一个32位版本,它计算两个64位值(QWord)的汉明距离,而不使用xmm寄存器。很直接,应该很快。我也试过了。使用SSSE3 shuffle与popcount的差异仅为1-2%。不过,这次我测试了在每个内核上运行OpenMP,一个线程用于使用32位GP寄存器的32位XOR和popcount,另一个线程用于使用xmm寄存器的128位XOR和SSSE3 shuffle popcount。一个核心进程在for循环中为线程拆分200.000个向量,首先为[0,100.000]和[100.000,200.000],然后为(i=0;iI)可能是错误的,但在32位模式下RAX和R15的确切含义是什么?它们是GP 64位寄存器的名称,根据定义,在32位模式下没有。宽寄存器是向量“XMM”寄存器。虽然
“r”(a)
似乎是一个无辜的语法,但它确实要求
a
适合GP寄存器。请注意,您正在使用
; 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
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