问题 AVX2中的8位移位操作,零位移


有没有办法重建 _mm_slli_si128 AVX2中的指令移位 __mm256i 按x字节注册?

_mm256_slli_si256 似乎只是执行两个 _mm_slli_si128 在[127:0]和[255:128]上。

左移应该适用于 __m256i 喜欢这个:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ..., 32] -> [2, 3, 4, 5, 6, 7, 8, 9, ..., 0]

我看到了 线 可以创建一个班次 _mm256_permutevar8x32_ps 为32位。但我需要一个更通用的解决方案来换班x字节。有人已经解决了这个问题吗?


3906
2017-12-25 17:00


起源

如果您发现自己需要做很多事情,那么您可能想要考虑另一种方法。 AVX及其他版本将向量分解为128位的“通道”。跨车道运营非常昂贵。看看Agner Fog的文档,看起来跨站操作比未对齐的内存访问更昂贵。 - Mysticial
非常感谢你的回答。我会结账他的文件。但是我没有必要使用扩展命令。但是如果我可以使用SIMD命令那就好了。 - martin s
移位量是编译时常量吗? - Iwillnotexist Idonotexist
是的,它是编译时间 - martin s
@Mysticial:这是一个延迟惩罚,而不是吞吐量。 VPERMD y,y,y, VPERMQ y,y,i,和 VPERM2I128 y,y,y,i 都是1uop,lat = 3c,吞吐量= 1 /周期。 (并且所有这些都只在Haswell中运行在port5上。)我同意,如果你能够在没有跨越车道的情况下构建工作,那就是最好的。但是如果你的算法本身就会受益,并且额外的延迟不是杀手,那么它可能是一场胜利。 - Peter Cordes


答案:


好吧,我实现了一个可以向左移动到16字节的功能。

template  <unsigned int N> __m256i _mm256_shift_left(__m256i a)
{
  __m256i mask =  _mm256_srli_si256(
          _mm256_permute2x128_si256(a, a, _MM_SHUFFLE(0,0,3,0))
          , 16-N);
  return _mm256_or_si256(_mm256_slli_si256(a,N),mask);
}

例:

int main(int argc, char* argv[]) {
   __m256i reg =  _mm256_set_epi8(32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,
                                  14,13,12,11,10,9,8,7,6,5,4,3,2,1);

   __m256i result = _mm256_shift_left<1>(reg);
   for(int i = 0; i < 32; i++)
     printf("%2d ",((unsigned char *)&result)[i]);
   printf("\n");
}

输出是
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

编辑: 带有新对齐指令的新版本。 感谢@Evgney Kluev的提示

template  <unsigned int N> __m256i _mm256_shift_left(__m256i a)
{
  __m256i mask = _mm256_permute2x128_si256(a, a, _MM_SHUFFLE(0,0,3,0) );
  return _mm256_alignr_epi8(a,mask,16-N);
}

9
2017-12-29 16:35



你可以通过使用来优化它 _mm256_alignr_epi8 而不是两个班次和“或”。 - Evgeny Kluev
有谁知道为什么VPALIGNRB(_mm256_alignr_epi8)不在Agner Fog的指令表中?我想知道延迟和吞吐量。 - Z boson
@Zboson:我不知道为什么Agner Fog会跳过它。但 这个资源 报告延迟和吞吐量恰好是一个时钟。 - Evgeny Kluev
老评论,所以也许它在1.5年前失踪了,但是 PALIGNR v,v,i / v,v,v,i 在Agner Fog的insn表中列出Haswell。如果没有非AVX版本,他只列出带有V前缀的insn。否则非V助记符就在那里,如果在使用它之间有区别,你必须查看args以查看是否有不同的条目 xmm 和 ymm ARGS。 - Peter Cordes
@BeeOnRope:嘿,呀。我忽略了包括延迟和吞吐量。哦,几乎所有的通道内洗牌都具有与Haswell相同的延迟和吞吐量。 - Peter Cordes