将 _mm_shuffle_epi32 转换为 C 表达式以进行排列?
Convert _mm_shuffle_epi32 to C expression for the permutation?
我正在研究 SSE2 到 NEON 的端口。该端口处于早期阶段并且产生了不正确的结果。结果不正确的部分原因是 _mm_shuffle_epi32
和我选择的 NEON 指令。
_mm_shuffle_epi32
的文档比 Microsoft. The Intel 文档更精简,但我不清楚某些伪代码在做什么。
SELECT4(src, control)
{
CASE(control[1:0])
0: tmp[31:0] := src[31:0]
1: tmp[31:0] := src[63:32]
2: tmp[31:0] := src[95:64]
3: tmp[31:0] := src[127:96]
ESAC
RETURN tmp[31:0]
}
dst[31:0] := SELECT4(a[127:0], imm8[1:0])
dst[63:32] := SELECT4(a[127:0], imm8[3:2])
dst[95:64] := SELECT4(a[127:0], imm8[5:4])
dst[127:96] := SELECT4(a[127:0], imm8[7:6])
我需要帮助来设想 _mm_shuffle_epi32
的作用。或者更准确地说,是立即数应用于值的排列。我想我需要将其视为基本的 C 以及 AND 和 OR。
给定 C 语句和宏,如:
v2 = _mm_shuffle_epi32(v1, _MM_SHUFFLE(i1,i2,i3,i4));
将生成的 C 表达式展开为基本 C 语句后会是什么样子?
没有 AND/OR 继续,除非您需要解压缩包含四个 2 位索引的 8 位整数。
为 _MM_SHUFFLE
创建您自己的定义,扩展为四个参数,而不是打包它们。
有点像
// dst = _mm_shuffle_epi32(src, _MM_SHUFFLE(d,c,b,a))
void pshufd(int dst[4], int src[4], int d,int c,int b,int a)
{ // note that the _MM_SHUFFLE args are high-element-first order
dst[0] = src[a];
dst[1] = src[b];
dst[2] = src[c];
dst[3] = src[d];
}
向量从低元素 = 0 开始索引。低元素是存储在内存中最低地址的元素,但是当值在寄存器中时,您应该将它们视为 [ 3 2 1 0 ]
。在这种表示法中,向量右移(如 psrldq
)实际上向右移动。
这就是为什么 _mm_set_epi32(3, 2, 1, 0)
以相反的顺序从 int foo[] = { 0, 1, 2, 3 };
获取其参数。
当不清楚某些内在函数究竟在做什么时,使用简单输入运行一些样本可能也会有所帮助:
int x[] = {0,1,2,3}, y[4];
__m128i s = _mm_shuffle_epi32(_mm_loadu_si128((__m128i*)x), _MM_SHUFFLE(2, 3, 0, 1));
_mm_store_si128((__m128i*)y, s);
printf("{%d,%d,%d,%d} => {%d,%d,%d,%d}\n", x[0], x[1], x[2], x[3], y[0], y[1], y[2], y[3]);
{0,1,2,3} => {1,0,3,2}
我正在研究 SSE2 到 NEON 的端口。该端口处于早期阶段并且产生了不正确的结果。结果不正确的部分原因是 _mm_shuffle_epi32
和我选择的 NEON 指令。
_mm_shuffle_epi32
的文档比 Microsoft. The Intel 文档更精简,但我不清楚某些伪代码在做什么。
SELECT4(src, control)
{
CASE(control[1:0])
0: tmp[31:0] := src[31:0]
1: tmp[31:0] := src[63:32]
2: tmp[31:0] := src[95:64]
3: tmp[31:0] := src[127:96]
ESAC
RETURN tmp[31:0]
}
dst[31:0] := SELECT4(a[127:0], imm8[1:0])
dst[63:32] := SELECT4(a[127:0], imm8[3:2])
dst[95:64] := SELECT4(a[127:0], imm8[5:4])
dst[127:96] := SELECT4(a[127:0], imm8[7:6])
我需要帮助来设想 _mm_shuffle_epi32
的作用。或者更准确地说,是立即数应用于值的排列。我想我需要将其视为基本的 C 以及 AND 和 OR。
给定 C 语句和宏,如:
v2 = _mm_shuffle_epi32(v1, _MM_SHUFFLE(i1,i2,i3,i4));
将生成的 C 表达式展开为基本 C 语句后会是什么样子?
没有 AND/OR 继续,除非您需要解压缩包含四个 2 位索引的 8 位整数。
为 _MM_SHUFFLE
创建您自己的定义,扩展为四个参数,而不是打包它们。
有点像
// dst = _mm_shuffle_epi32(src, _MM_SHUFFLE(d,c,b,a))
void pshufd(int dst[4], int src[4], int d,int c,int b,int a)
{ // note that the _MM_SHUFFLE args are high-element-first order
dst[0] = src[a];
dst[1] = src[b];
dst[2] = src[c];
dst[3] = src[d];
}
向量从低元素 = 0 开始索引。低元素是存储在内存中最低地址的元素,但是当值在寄存器中时,您应该将它们视为 [ 3 2 1 0 ]
。在这种表示法中,向量右移(如 psrldq
)实际上向右移动。
这就是为什么 _mm_set_epi32(3, 2, 1, 0)
以相反的顺序从 int foo[] = { 0, 1, 2, 3 };
获取其参数。
当不清楚某些内在函数究竟在做什么时,使用简单输入运行一些样本可能也会有所帮助:
int x[] = {0,1,2,3}, y[4];
__m128i s = _mm_shuffle_epi32(_mm_loadu_si128((__m128i*)x), _MM_SHUFFLE(2, 3, 0, 1));
_mm_store_si128((__m128i*)y, s);
printf("{%d,%d,%d,%d} => {%d,%d,%d,%d}\n", x[0], x[1], x[2], x[3], y[0], y[1], y[2], y[3]);
{0,1,2,3} => {1,0,3,2}