12

我正在将使用 SSE2 内在函数编写的矢量化代码迁移到 AVX2 内在函数。

令我失望的是,我发现移位指令_mm256_slli_si256_mm256_srli_si256仅分别在 AVX 寄存器的两半上运行,并且在它们之间引入了零。(这与处理整个 SSE 寄存器的_mm_slli_si128_mm_srli_si128形成对比。)

你能给我推荐一个短的替代品吗?

更新:

_mm256_slli_si256有效地实现了

_mm256_alignr_epi8(A, _mm256_permute2x128_si256(A, A, _MM_SHUFFLE(0, 0, 3, 0)), N)

或者

_mm256_slli_si256(_mm256_permute2x128_si256(A, A, _MM_SHUFFLE(0, 0, 3, 0)), N)

对于大于 16 字节的移位。

但问题仍然存在_mm256_srli_si256

4

3 回答 3

9

从不同的输入中,我收集了这些解决方案。跨越车道间障碍的关键是对齐指令,_mm256_alignr_epi8.

_mm256_slli_si256(A, N)

0 < N < 16

_mm256_alignr_epi8(A, _mm256_permute2x128_si256(A, A, _MM_SHUFFLE(0, 0, 2, 0)), 16 - N)

N = 16

_mm256_permute2x128_si256(A, A, _MM_SHUFFLE(0, 0, 2, 0))

16 < N < 32

_mm256_slli_si256(_mm256_permute2x128_si256(A, A, _MM_SHUFFLE(0, 0, 2, 0)), N - 16)

_mm256_srli_si256(A, N)

0 < N < 16

_mm256_alignr_epi8(_mm256_permute2x128_si256(A, A, _MM_SHUFFLE(2, 0, 0, 1)), A, N)

N = 16

_mm256_permute2x128_si256(A, A, _MM_SHUFFLE(2, 0, 0, 1))

16 < N < 32

_mm256_srli_si256(_mm256_permute2x128_si256(A, A, _MM_SHUFFLE(2, 0, 0, 1)), N - 16)
于 2014-08-12T12:54:33.227 回答
5

这是一个使用 avx2 将 ymm 寄存器左移的函数。我用它左移一位,虽然它看起来最多可用于 63 位移位。

//----------------------------------------------------------------------------
// bit shift left a 256-bit value using ymm registers
//          __m256i *data - data to shift
//          int count     - number of bits to shift
// return:  __m256i       - carry out bit(s)

static __m256i bitShiftLeft256ymm (__m256i *data, int count)
   {
   __m256i innerCarry, carryOut, rotate;

   innerCarry = _mm256_srli_epi64 (*data, 64 - count);                        // carry outs in bit 0 of each qword
   rotate     = _mm256_permute4x64_epi64 (innerCarry, 0x93);                  // rotate ymm left 64 bits
   innerCarry = _mm256_blend_epi32 (_mm256_setzero_si256 (), rotate, 0xFC);   // clear lower qword
   *data      = _mm256_slli_epi64 (*data, count);                             // shift all qwords left
   *data      = _mm256_or_si256 (*data, innerCarry);                          // propagate carrys from low qwords
   carryOut   = _mm256_xor_si256 (innerCarry, rotate);                        // clear all except lower qword
   return carryOut;
   }

//----------------------------------------------------------------------------
于 2014-08-11T19:29:31.160 回答
1

如果移位计数是 4 个字节的倍数,带有正确随机播放掩码的vpermd( ) 将使用一条指令来解决问题(或者更多,如果您实际上需要将移入的字节归零而不是在它们上复制不同的元素)。_mm256_permutevar8x32_epi32

为了支持可变(4B 的倍数)移位计数,您可以将控制掩码从窗口加载到数组0 0 0 0 0 0 0 1 2 3 4 5 6 7 0 0 0 0 0 0 0或其他内容中,除了这0只是底部元素,并且不会将内容归零。有关从滑动窗口生成蒙版的更多信息,请参阅我对另一个问题的回答

这个答案非常小,因为vpermd不能直接解决问题。我指出它是一种替代方案,在您正在寻找完整矢量移位的某些情况下可能会起作用。

于 2016-03-31T13:19:52.460 回答