高阶位 - 取出它们并将uint64_t转换为uint8_t

fis*_*ion 9 c c++ assembly bit-manipulation

假设您有一个uint64_t,并且只关心uint64_t中每个字节的高位.像这样:

uint32_t:0000 ... 1000 0000 1000 0000 1000 0000 1000 0000 ---> 0000 1111

有没有比以下更快的方式:

   return
   (
     ((x >> 56) & 128)+
     ((x >> 49) &  64)+
     ((x >> 42) &  32)+
     ((x >> 35) &  16)+
     ((x >> 28) &   8)+
     ((x >> 21) &   4)+
     ((x >> 14) &   2)+
     ((x >>  7) &   1)
   )
Run Code Online (Sandbox Code Playgroud)

Aka移位x,屏蔽并为每个字节添加正确的位?这将编译到很多程序集,我正在寻找一个更快的方法...我使用的机器只有SSE2指令,我找不到有用的SIMD操作.

谢谢您的帮助.

har*_*old 11

正如我在评论中提到的,pmovmskb做你想要的.以下是您可以使用它的方法:

MMX + SSE1:

movq mm0, input ; input can be r/m
pmovmskb output, mm0 ; output must be r
Run Code Online (Sandbox Code Playgroud)

SSE2:

movq xmm0, input
pmovmskb output, xmm0
Run Code Online (Sandbox Code Playgroud)

我抬头看着新的方式

BMI2:

mov rax, 0x8080808080808080
pext output, input, rax ; input must be r
Run Code Online (Sandbox Code Playgroud)


小智 10

return ((x & 0x8080808080808080) * 0x2040810204081) >> 56;
Run Code Online (Sandbox Code Playgroud)

作品.&选择要保留的位.将所有位乘以最高有效字节,并将移位移到最低有效字节.由于在大多数现代CPU上乘法很快,因此这不应该比使用汇编慢得多.


Arj*_*kar 5

以下是使用SSE内在函数的方法:

#include <xmmintrin.h>
#include <inttypes.h>
#include <stdio.h>

int main (void)
{
  uint64_t x
  = 0b0000000010000000000000001000000000000000100000000000000010000000;

  printf ("%x\n", _mm_movemask_pi8 ((__m64) x));
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

适用于:

gcc -msse
Run Code Online (Sandbox Code Playgroud)