有4位,如何为AVX寄存器生成掩码?

时间:2017-08-30 18:32:04

标签: c++ bit-manipulation vectorization x86-64 avx2

_mm256_blendv_pd()查看位置63,127,191和255中的位。是否有一种有效的方法将uint8_t的4个低位分散到AVX寄存器的这些位置?

或者,是否有一种有效的方式来广播这些位,以便像_mm256_cmp_pd()的结果一样,每个位在AVX寄存器的相应64位组件中重复?

指令集为AVX2(Ryzen CPU,如果需要其他功能)。

3 个答案:

答案 0 :(得分:2)

最有效的方法是使用包含16个256位条目的查找向量,由uint-8索引。

答案 1 :(得分:2)

显而易见的解决方案:将这4位用作查找表的索引。你已经知道了,所以让我们尝试其他的东西。

基于变量移位的方法:将该字节广播到每个qword中,然后将其向左移动{63,62,61,60},在msb中排列正确的位。未经测试,如下所示:

_mm256_sllv_epi64(_mm256_set1_epi64x(mask), _mm256_set_epi64x(63, 62, 61, 60))

作为奖励,因为负载不依赖于面罩,所以它可以从环中抬起。

这对于Ryzen来说不一定是个好主意,内存中的256位加载比单独vpsllvq本身的吞吐量更高(与Ryzen上的大多数256b操作相比,这是2μs),但是这里我们还有vmovq(如果该字节不是来自向量寄存器)和宽vpbroadcastq(再次为2μs)。

根据具体情况,可能值得做或不做。这取决于。

答案 2 :(得分:2)

假设uint8_t存在于通用寄存器中;方法是:

  1. 使用PDEP将四位转换为四位(最高位)
  2. 将四位字节从32位GPR传输到YMM寄存器的低位
  3. 将值放置到位(位63,127,191,255)
  4. 所以我提出了两个版本 - 一个带内存,另一个没有:

    接近记忆:

    .data
      ; Always use the highest bytes of a QWORD as target / 128 means 'set ZERO' 
      ddqValuesDistribution:    .byte  3,128,128,128,128,128,128,128, 2,128,128,128,128,128,128,128, 1,128,128,128,128,128,128,128, 0,128,128,128,128,128,128,128
    .code
      ; Input value in lower 4 bits of EAX
      mov     edx, 0b10000000100000001000000010000000
      pdep    eax, eax, edx
      vmovd   xmm0, eax
      vpshufb ymm0, ymm0, ymmword ptr [ddqValuesDistribution]
    

    这一个在Haswell和Skylake上以5 uOps出现。

    没有记忆变量的方法(由于@Peter Cordes而得到改善):

      mov  edx, 0b10000000100000001000000010000000
      pdep eax, eax, edx
      vmovd xmm0, eax 
      vpmovsxbq ymm0, xmm0
    

    这个在Haswell和Skylake(!)上以4 uOps出现,可以通过将EDX中的蒙版移动到变量来进一步改进。
    输出与第一个版本不同(所有输出与仅最高位设置)。