随机播放 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 位整数向量相乘的最快方法

如何检查 256i(16 位)向量以了解它是不是包含任何大于零的元素?

SSE 向量重新对齐?

进行水平 SSE 向量求和(或其他缩减)的最快方法

C - 如何使用 GCC SSE 向量扩展访问向量的元素

随机播放 SSE 寄存器中的偶数和奇数值