C AVX2中的8位移位操作,零移位

C AVX2中的8位移位操作,零移位,c,sse,simd,avx,avx2,C,Sse,Simd,Avx,Avx2,有没有办法在AVX2中重建\u mm\u slli\u si128指令,将\u mm256i寄存器移位x字节 \u mm256\u slli\u si256似乎只是在[127:0]和[255:128]上执行两个\u mm\u slli\u si128 在\uuuu m256i上,左换档应该可以工作,如下所示: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ..., 32] -> [2, 3, 4, 5, 6, 7, 8, 9, ..., 0] 我发现可以

有没有办法在AVX2中重建
\u mm\u slli\u si128
指令,将
\u mm256i
寄存器移位x字节

\u mm256\u slli\u si256
似乎只是在[127:0]和[255:128]上执行两个
\u mm\u slli\u si128

\uuuu m256i
上,左换档应该可以工作,如下所示:

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

我发现可以使用32位的
\u mm256\u permutevar8x32\u ps
创建移位。但是我需要一个更通用的解决方案来移动x字节。有人已经找到了这个问题的解决方案吗?

好的,我实现了一个函数,可以左移到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);
}

如果您发现自己需要经常这样做,您可能需要考虑另一种方法。AVX及更高版本将矢量分解为128位的“通道”。交叉车道的运营费用非常昂贵。查看Agner Fog的文档,跨车道操作似乎比未对齐内存访问更昂贵。非常感谢您的回答。我会检查他的文件。但我不必使用命令。但如果我能使用SIMD命令就好了。移位量是编译时常量吗?是的,它是编译时常量time@Mysticial:这是延迟惩罚,而不是吞吐量<代码>VPERMD y,y,y,
VPERMQ y,y,i
,和
VPERM2I128 y,y,y,i
都是1OP,lat=3c,吞吐量=1/周期。(所有这些都只在Haswell的5号端口上运行。)我同意,如果你能在不穿越车道的情况下组织工作,那就最好了。但是如果你的算法本身就有好处,而且额外的延迟不是致命的,那么这可能是一个胜利。你可以通过使用
\u mm256\u aligner\u epi8
而不是同时使用移位和“or”来优化它。有人知道为什么VPALIGNRB(\u mm256\u aligner\u epi8)不在Agner Fog的指令表中吗?我想知道延迟和吞吐量。@Zboson:我不知道为什么Agner Fog跳过了它。但是报告的延迟和吞吐量正好是一个时钟。旧的注释,所以可能在1.5年前丢失了,但Agner Fog的insn表中列出了Haswell的
PALIGNR v,v,i/v,v,v,i
。如果没有非AVX版本,他只列出带有V前缀的INSN。否则,非V助记符就在那里,你必须查看参数,看看是否有不同的条目,如果在
xmm
ymm
args上使用它有区别的话。@BeeOnRope:heh,是的。我忽略了延迟和吞吐量。哦,在Haswell上,几乎所有的通道内洗牌都有相同的延迟和吞吐量。
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");
}
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);
}