随机播放 16 位向量 SSE
Posted
技术标签:
【中文标题】随机播放 16 位向量 SSE【英文标题】:Shuffle 16 bit vectors SSE 【发布时间】:2016-03-11 09:37:55 【问题描述】:我正在处理SSE
和一个新手。我正在尝试使用shuffle
指令来洗牌如下所示的 16 位向量:
输入:
1 2 3 4 5 6 7 8
输出:
1 5 2 6 3 7 4 8
如何实现预期目标?我对这里使用的常量感到困惑,我没有看到任何 16 位 shuffle
指令。 shuffle
指令仅适用于 8 位和 32 位。
【问题讨论】:
“我没有看到任何 16 位随机播放指令” 有PSHUFHW
/PSHUFLW
,但我不认为他们可以做你正在尝试的事情在这里做。
您始终可以使用较小粒度的随机播放。但是,如果 shuffle 控件不是编译时常量,那么将单词索引向量转换为字节索引向量可能会很麻烦。 AVX512 通过提供具有字节、字、dword 和 qword 粒度的完整跨通道变量混洗来解决此问题。 (vpermb/vpermw/vpermd/vpermq。缺少内在函数指南_mm512_permutexvar_epi16
(nvm,它只是没有标记为“swizzle”))甚至还有 2 源变量控制洗牌,所以你可以有一个 512b向量从其他 2 个 512b 向量中挑选字节/单词/dwords/qwords!
所以基本上编写必须洗牌的代码将会很棒......在可能的 10 年内,我们有时可以放弃为没有 AVX512 的 CPU 进行矢量化。
【参考方案1】:
只要你可以假设 SSSE3 那么你就可以使用pshufb
aka _mm_shuffle_epi8
:
#include <stdio.h>
#include <tmmintrin.h> // SSSE3
int main()
__m128i v_in = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
__m128i v_perm = _mm_setr_epi8(0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15);
__m128i v_out = _mm_shuffle_epi8(v_in, v_perm); // pshufb
printf("v_in = %vhd\n", v_in);
printf("v_out = %vhd\n", v_out);
return 0;
编译运行:
$ gcc -Wall -mssse3 green_goblin.c
$ ./a.out
v_in = 1 2 3 4 5 6 7 8
v_out = 1 5 2 6 3 7 4 8
仅依赖 SSE2 的替代解决方案:
#include <stdio.h>
#include <emmintrin.h> // SSE2
int main()
__m128i v_in = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
__m128i v_out = _mm_shuffle_epi32(v_in, _MM_SHUFFLE(3, 1, 2, 0)); // pshufd
v_out = _mm_shufflelo_epi16(v_out, _MM_SHUFFLE(3, 1, 2, 0)); // pshuflw
v_out = _mm_shufflehi_epi16(v_out, _MM_SHUFFLE(3, 1, 2, 0)); // pshufhw
printf("v_in = %vhd\n", v_in);
printf("v_out = %vhd\n", v_out);
return 0;
编译运行:
$ gcc -Wall -msse2 green_goblin_sse2.c
$ ./a.out
v_in = 1 2 3 4 5 6 7 8
v_out = 1 5 2 6 3 7 4 8
【讨论】:
#!¤52#¤ASDFWERTøøøøååååå!我刚要准确地粘贴你的答案,你又打败了我! @BharatAhuja,短索引很容易使用字节索引 2*i 和 2*i+1。例如。短索引 3 变为字节索引 6 和 7。 @Zboson:你只需要早点起床! ;-) @Zboson thanx 明白了以上是关于随机播放 16 位向量 SSE的主要内容,如果未能解决你的问题,请参考以下文章
用 SSE 在 C++ 中将两个 32 位整数向量相乘的最快方法