【问题标题】:Shifting SSE/AVX registers 32 bits left and right while shifting in zeros将 SSE/AVX 寄存器左移和右移 32 位,同时移入零
【发布时间】:2013-10-31 05:56:31
【问题描述】:

我想在移入零的同时向左或向右移动 32 位的倍数的 SSE/AVX 寄存器。

让我更准确地说一下我感兴趣的班次。对于 SSE,我想做以下四个 32 位浮点数的班次:

shift1_SSE: [1, 2, 3, 4] -> [0, 1, 2, 3]
shift2_SSE: [1, 2, 3, 4] -> [0, 0, 1, 2]

对于 AVX,我想换档做以下换档:

shift1_AVX: [1, 2, 3, 4, 5, 6, 7, 8] -> [0, 1, 2, 3, 4, 5, 6, 7]
shift2_AVX: [1, 2, 3, 4, 5, 6, 7, 8] -> [0, 0, 1, 2, 3, 4, 5, 6]
shift3_AVX: [1, 2, 3, 4 ,5 ,6, 7, 8] -> [0, 0, 0, 0, 1, 2, 3, 4]

对于 SSE,我想出了以下代码

shift1_SSE = _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(x), 4)); 
shift2_SSE = _mm_shuffle_ps(_mm_setzero_ps(), x, 0x40);
//shift2_SSE = _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(x), 8));

SSE 有没有更好的方法来做到这一点

对于 AVX,我提出了以下需要 AVX2 的代码(并且未经测试)。编辑(正如 Paul R 所解释的,此代码不起作用)。

shift1_AVX2 =_mm256_castsi256_ps(_mm256_slli_si256(_mm256_castps_si256(x), 4)));
shift2_AVX2 =_mm256_castsi256_ps(_mm256_slli_si256(_mm256_castps_si256(x), 8)));
shift3_AVX2 =_mm256_castsi256_ps(_mm256_slli_si256(_mm256_castps_si256(x), 12))); 

如何使用 AVX 而不是 AVX2(例如使用 _mm256_permute 或 _mm256_shuffle`)做到这一点? AVX2 有没有更好的方法来做到这一点?

编辑:

Paul R 告诉我,我的 AVX2 代码不起作用,而且 AVX 代码可能不值得。而对于 AVX2,我应该使用 _mm256_permutevar8x32_ps_mm256_and_ps。我没有带有 AVX2 (Haswell) 的系统,所以这很难测试。

编辑: 根据 Felix Wyss 的回答,我想出了一些 AVX 解决方案,其中 shift1_AVX 和 shift2_AVX 只需要 3 个内部函数,而 shift3_AVX 只需要一个内部函数。这是因为_mm256_permutef128Ps 有一个zeroing feature

shift1_AVX

__m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(2, 1, 0, 3));       
__m256 t1 = _mm256_permute2f128_ps(t0, t0, 41);          
__m256 y = _mm256_blend_ps(t0, t1, 0x11);

shift2_AVX

__m256 t0 = _mm256_permute_ps(x, _MM_SHUFFLE(1, 0, 3, 2));
__m256 t1 = _mm256_permute2f128_ps(t0, t0, 41);
__m256 y = _mm256_blend_ps(t0, t1, 0x33);

shift3_AVX

x = _mm256_permute2f128_ps(x, x, 41);

【问题讨论】:

    标签: x86 sse simd avx avx2


    【解决方案1】:

    您可以使用_mm256_permute_ps_mm256_permute2f128_ps_mm256_blend_ps 进行右移,如下所示:

    __m256 t0 = _mm256_permute_ps(x, 0x39);            // [x4  x7  x6  x5  x0  x3  x2  x1]
    __m256 t1 = _mm256_permute2f128_ps(t0, t0, 0x81);  // [ 0   0   0   0  x4  x7  x6  x5] 
    __m256 y  = _mm256_blend_ps(t0, t1, 0x88);         // [ 0  x7  x6  x5  x4  x3  x2  x1]
    

    结果在y。为了向右旋转,请将置换掩码设置为 0x01 而不是 0x81。通过更改置换和混合控制字节,可以类似地完成向左移位/旋转和更大的移位/旋转。

    【讨论】:

    • 这比我预期的要多。使用 SSE,只需一条指令/内在函数 (_mm_slli_si128) 即可完成。我认为使用 AVX2 我可以使用两个内在函数 _mm256_permute2f128_ps_mm256_and_ps
    • 我刚刚意识到使用 blend 有一个更简单的解决方案。我编辑了答案。
    • 这是一个更好的解决方案。我误解了,虽然这是 AVX2 代码。这是 AVX 代码。我认为shift3_AVX 可以用 AVX 用两条指令完成。
    • 我使用您的解决方案编辑了我的问题。您的解决方案以错误的方式改变了他们,但这个想法是正确的。谢谢!
    • 我想出了一种在一个内在函数中执行 shift3_AVX 的方法。 _mm256_permute2f128_ps 有一个[归零选项](software.intel.com/sites/products/documentation/doclib/iss/2013/…)。所以 shift3_AVX =_mm256_permute2f128_ps(x, x, 41);
    【解决方案2】:

    您的 SSE 实现很好,但我建议您对两个班次都使用 _mm_slli_si128 实现 - 强制转换使它看起来很复杂,但实际上归结为每个班次只有一条指令。

    很遗憾,您的 AVX2 实现不会工作。几乎所有的 AVX 指令实际上只是两个 SSE 指令在两个相邻的 128 位通道上并行运行。因此,对于您的第一个 shift_AVX2 示例,您将得到:

    0, 0, 1, 2, 0, 4, 5, 6
    ----------- ----------
     LS lane     MS lane
    

    然而,一切都没有丢失:确实在 AVX 上跨通道工作的少数指令之一是 _mm256_permutevar8x32_ps。请注意,您需要结合使用 _mm256_and_ps 来将移入的元素归零。另请注意,这是一个 AVX2 解决方案 - AVX 本身对于除基本算术/逻辑运算以外的任何事情都非常有限,所以我认为如果没有 AVX2,您将很难有效地做到这一点。

    【讨论】:

    • 如何在没有内在演员表的情况下使用 mm_slli_si128?当我尝试它时,它会说没有合适的 __m128 到 __m128i 的转换,反之亦然。
    • 强制转换只是为了让编译器满意(我猜是 MSVC?)——它们实际上并不生成任何代码。所以你的代码很好,我只是说对两个班次都使用_mm_slli_si128 实现,而不是第二个班次使用_mm_shuffle_ps 替代方案。
    • 32 位模式下只有 8 个 SSE 寄存器,64 位模式下只有 16 个寄存器。编译器可以在寄存器中保存的临时变量越多,性能可能就越好。如果您的代码需要太多寄存器,则编译器必须将寄存器“​​溢出”到内存中。因此,当您有两种替代解决方案并且一种需要较少的临时寄存器时,如果没有其他需要考虑的因素,那就是一种选择。
    • 我终于对代码进行了基准测试,SSE 和 AVX 代码的速度大约是顺序代码的两倍!我原本没想到。现在,我的 4 核常春藤桥系统的整体提升大约是 7 倍。我在simd-prefix-sum-on-inte 的答案中发布了代码
    • 是的,这将不得不等到我找到一个 Haswell 系统。我在coliru 对代码进行了测试。不知道是什么系统。它没有 AVX,因为我必须删除 AVX 代码才能运行。线程数是 4,但我认为它只有两个内核,因为 OpenMP 的结果并不那么令人印象深刻。无论如何,该系统的增益超过 3 倍,而我的系统则超过 7 倍。不要担心错误。这是由于浮点精度。我正在对计数求和并与确切的公式进行比较。
    猜你喜欢
    • 2020-11-21
    • 2015-03-19
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    相关资源
    最近更新 更多