Преобразовать _mm_shuffle_epi32 в выражение C для перестановки?
Я работаю над портом SSE2 для NEON. Порт находится на ранней стадии и дает неверные результаты. Частично причина неправильных результатов _mm_shuffle_epi32
и неоновые инструкции, которые я выбрал.
Документация для _mm_shuffle_epi32
находится на скудной стороне от Microsoft. Документация 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?
2 ответа
И / ИЛИ не происходит, если только вам не нужно распаковать 8-битное целое число, содержащее четыре 2-битных индекса.
Сделайте свое собственное определение для _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}