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



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

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

  • R8 至 R15 的"未知寄存器名称"
  • RAX-RDX 的"错误寄存器名称"
  • 当尝试提供 MM 寄存器或
  • 为我的内联程序集函数提供一些 uint64 或长 uint64 或长 在这样的寄存器中
  • 受到影响时

道路:

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

GCC 告诉"POPCNT 的操作数类型不匹配"

  • 编写 POPCNTQ 会导致"POPCNT 的指令后缀无效"。

如果 POPCNT 支持 128 位 xmm 寄存器,那就太好了......

有什么解决方法可以对程序集中的 64 位数据应用 POPCNT 吗?

PS关于使用随机播放的SSSE3流行计数与SSE4 POPCNT性能的讨论在这里找到了结论 http://danluu.com/assembly-intrinsics/这仅仅是因为使用内部函数并不总是提供有效的汇编代码。使用内联函数快速优化C/C++代码很好,如果这足以满足需求,那很好。但除此之外,与内部函数相比,我在汇编中使用随机排序获得了近 30% 的性能改进。

popcnt是一个

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

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代码中(二进制)汉明距离的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
我不知道

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

使用汇编实现 32 位 POPCNT 后,与 SSSE3 随机汇编方法相比,看起来没有真正的改进。正如我所怀疑的那样,只有64位POPCNT版本才能使速度几乎翻倍。

相关内容

  • 没有找到相关文章

最新更新