8

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

让我更准确地了解我感兴趣的班次。对于 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_permuteor _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这是由于具有归零功能的事实。

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);
4

2 回答 2

7

您可以使用、 和进行右移_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. 通过更改置换和混合控制字节,可以类似地完成向左移位/旋转和更大的移位/旋转。

于 2013-10-23T03:46:23.173 回答
5

您的 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。请注意,您需要结合使用 an 来将移入的元素归零。另请注意,这是一个 AVX2 解决方案 - AVX 本身对于基本算术/逻辑运算以外的任何事情都非常有限,所以我认为如果没有 AVX2,您将很难有效地做到这一点。_mm256_and_ps

于 2013-10-22T12:21:47.967 回答