按 1 个位置打乱 AVX 256 向量元素 left/right - C 内在函数
Shuffle AVX 256 Vector elements by 1 position left/right - C intrinsics
我正在尝试找到一种更有效的方法来 "rotate" 或将 avx _m256 向量中的 32 位浮点值向右或向左移动一个位置。
这样:
a7、a6、a5、a4、a3、a2、a1、a0
变成
0, a7, a6, a5, a4, a3, a2, a1
(我不介意在更换电池时数据是否丢失。)
我已经看过这个帖子了:Emulating shifts on 32 bytes with AVX
但我真的不明白发生了什么,也没有解释 _MM_SHUFFLE(0, 0, 3, 0) 作为输入参数的作用。
我正在尝试优化这段代码:
_mm256_store_ps(temp, array[POS(ii, jj)]);
_mm256_store_ps(left, array[POS(ii, jj-1)]);
tmp_array[POS(ii, jj)] = _mm256_set_ps(left[0], temp[7], temp[6], temp[5], temp[4], temp[3], temp[2], temp[1]);
我知道一旦轮班到位,我就可以使用插入来替换剩余的单元格。我觉得这会比解包成一个 float[8] 数组并重建更有效率。
-- 我也希望能够左右移动,因为我需要在其他地方执行类似的操作。
非常感谢任何帮助!谢谢!
对于 AVX2:
使用VPERMPS在一次交叉洗牌指令中完成。
rotated_right = _mm256_permutevar8x32_ps(src, _mm256_set_epi32(0,7,6,5,4,3,2,1));
对于 AVX(没有 AVX2)
既然你说数据已经来自内存,那么这可能很好:
- 使用未对齐的负载将 7 个元素放到正确的位置,解决所有的车道交叉问题。
- 然后将环绕的元素混合到其他 7 个向量中。
- 要获得为混合就地包装的元素,可以使用广播加载将其放到高位置。 AVX 可以在一个 VBROADCASTPS instruction (so
set1()
is cheap), although it does need the shuffle port on Intel SnB and IvB (the only two Intel microarchitectures with AVX but not AVX2). (See perf links in the x86 标签 wiki 中广播加载。
INSERTPS 仅适用于 XMM 目的地,无法到达上车道。
您可以使用 VINSERTF128 执行另一个未对齐的加载,最终将您想要的元素作为高元素放在上层通道中(在低层通道中有一些无关向量)。
这可以编译,但未经测试。
__m256 load_rotr(float *src)
{
#ifdef __AVX2__
__m256 orig = _mm256_loadu_ps(src);
__m256 rotated_right = _mm256_permutevar8x32_ps(orig, _mm256_set_epi32(0,7,6,5,4,3,2,1));
return rotated_right;
#else
__m256 shifted = _mm256_loadu_ps(src + 1);
__m256 bcast = _mm256_set1_ps(*src);
return _mm256_blend_ps(shifted, bcast, 0b10000000);
#endif
}
我正在尝试找到一种更有效的方法来 "rotate" 或将 avx _m256 向量中的 32 位浮点值向右或向左移动一个位置。
这样:
a7、a6、a5、a4、a3、a2、a1、a0
变成
0, a7, a6, a5, a4, a3, a2, a1
(我不介意在更换电池时数据是否丢失。)
我已经看过这个帖子了:Emulating shifts on 32 bytes with AVX 但我真的不明白发生了什么,也没有解释 _MM_SHUFFLE(0, 0, 3, 0) 作为输入参数的作用。
我正在尝试优化这段代码:
_mm256_store_ps(temp, array[POS(ii, jj)]);
_mm256_store_ps(left, array[POS(ii, jj-1)]);
tmp_array[POS(ii, jj)] = _mm256_set_ps(left[0], temp[7], temp[6], temp[5], temp[4], temp[3], temp[2], temp[1]);
我知道一旦轮班到位,我就可以使用插入来替换剩余的单元格。我觉得这会比解包成一个 float[8] 数组并重建更有效率。
-- 我也希望能够左右移动,因为我需要在其他地方执行类似的操作。
非常感谢任何帮助!谢谢!
对于 AVX2:
使用VPERMPS在一次交叉洗牌指令中完成。
rotated_right = _mm256_permutevar8x32_ps(src, _mm256_set_epi32(0,7,6,5,4,3,2,1));
对于 AVX(没有 AVX2)
既然你说数据已经来自内存,那么这可能很好:
- 使用未对齐的负载将 7 个元素放到正确的位置,解决所有的车道交叉问题。
- 然后将环绕的元素混合到其他 7 个向量中。
- 要获得为混合就地包装的元素,可以使用广播加载将其放到高位置。 AVX 可以在一个 VBROADCASTPS instruction (so
set1()
is cheap), although it does need the shuffle port on Intel SnB and IvB (the only two Intel microarchitectures with AVX but not AVX2). (See perf links in the x86 标签 wiki 中广播加载。
INSERTPS 仅适用于 XMM 目的地,无法到达上车道。
您可以使用 VINSERTF128 执行另一个未对齐的加载,最终将您想要的元素作为高元素放在上层通道中(在低层通道中有一些无关向量)。
这可以编译,但未经测试。
__m256 load_rotr(float *src)
{
#ifdef __AVX2__
__m256 orig = _mm256_loadu_ps(src);
__m256 rotated_right = _mm256_permutevar8x32_ps(orig, _mm256_set_epi32(0,7,6,5,4,3,2,1));
return rotated_right;
#else
__m256 shifted = _mm256_loadu_ps(src + 1);
__m256 bcast = _mm256_set1_ps(*src);
return _mm256_blend_ps(shifted, bcast, 0b10000000);
#endif
}