【发布时间】: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);
【问题讨论】: