如何在32位Ubuntu上运行时使用程序集POPCNT指令

时间:2015-01-23 13:07:56

标签: gcc assembly optimization 32bit-64bit hammingweight

对于特定项目,我在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返回

  • r8到r15的“未知注册名称”
  • rax-rdx的“错误注册名称”
  • 当试图提供mm寄存器或给我的内联汇编函数时,某些uint64或long long会对这样的寄存器产生影响

的方法:

uint64 a, b;
__asm__ volatile (“POPCNT %1, %0;”
            :”=r”(b)
            :”r”(a)
            :
        )

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

  • 并且编写POPCNTQ会导致“popcnt的无效指令后缀”

如果POPCNT支持128位xmm寄存器,那本来会很好......

在汇编中对64位数据应用POPCNT的任何解决方法?

PS 使用shuffle进行SSSE3 popcount的讨论与SSE4相比,POPCNT性能在此处得出结论http://danluu.com/assembly-intrinsics/ 并且仅仅因为使用内在函数并不总是提供有效的汇编代码。使用内在函数快速优化C / C ++代码并且如果它足以满足需求,那很好。但是,与内在函数相比,我在汇编时使用shuffle获得了近30%的性能提升编码popcount。

4 个答案:

答案 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版本几乎可以加倍速度。