The Daily Newsstand · Free, Always
Friday, September 11, 2026

Пишу алгоритм FFT на Си для процессора Эльбрус: прямая векторизация

Translate

Данная статья является продолжением предыдущей статьи.
Здесь рассматривается вариант прямой векторизации алгоритма FFT.
Перед чтением рекомендуется бегло ознакомиться с предыдущей статьёй.

Промежуточные результаты представлены на графиках в конце каждого раздела реализации.
Итоговые результаты показаны на графиках в разделе Собираем FFT

Исходный код

Исходный код лежит здесь.

Структура кода намеренно сделана как можно проще.
Приоритеты в порядке убывания:
 — Скорость выполнения
 — Единообразие
 — Понятность

Компиляция:
./compile.sh */*.c

Проверка корректности:
./check_all.sh 12 1000 x

Измерение скорости:
taskset 1 ./speed_all_stage.sh 12 10000 x
taskset 1 ./speed_all_fft.sh 12 10000 x

taskset 1 нужен для корректного чтения счётчика тактов (привязка к первому ядру).

Опции компиляции

При компиляции использовались следующие опции lcc:

-Wall -O3 -faligned -ffast-math -march=elbrus-v5

Почему я компилирую для elbrus-v5 написано здесь.

Как измерялось время

Замеры времени делались с помощью функции clock_gettime():

struct timespec t0, t1;
clock_gettime(CLOCK_REALTIME, &t0);
/***  здесь измеряемый код  ***/
clock_gettime(CLOCK_REALTIME, &t1);
int usec = (t1.tv_sec - t0.tv_sec)*1000000 + (t1.tv_nsec - t0.tv_nsec)/1000;


Также использовалось чтение счётчика тактов процессора:

uint64_t get_clock_count()
{
	uint64_t dst;
	#pragma asm_inline
	asm ("rrd %%clkr, %0" : "=r" (dst));
	return dst;
}

...

uint64_t ticks0 = get_clock_count();
/***  здесь измеряемый код  ***/
uint64_t ticks1 = get_clock_count();
uint64_t ticks = ticks1 - ticks0;
Как создавались графики

Графики рисовались в Google Sheets.

Данные для графиков собирались с помощью скрипта data_for_diagram.py, который запускает программу измерения скорости с разными параметрами и парсит её вывод.
Пример запуска скрипта:

taskset 1 ./data_for_diagram.py \
./fft_radix2/fft_radix2_speedtest 4 21 1 1000 -1 > out.txt

taskset 1 нужен для корректного чтения счётчика тактов (привязка к первому ядру).

Содержание:

Пишем векторный Reverse
reverse_radix2_vector2
reverse_radix2_vector4
reverse_radix4_vector2
reverse_radix4_vector4
Пишем векторный Stage
Пишем LastStage
Собираем FFT

Что такое прямая векторизация

Для ряда операций (сложение, умножение и так далее) в процессоре Эльбрус присутствуют векторные инструкции (SIMD). Векторные инструкции выполняют несколько одинаковых операций одновременно.

В предыдущей статье векторные инструкции использовались просто как набор из нескольких инструкций в одной. Например, вместо двух инструкций умножения float чисел, нужных по алгоритму, применялась одна векторная, выполняющая два умножения (SIMD64).
Проблема такого подхода в том, что нет простого способа ускорить алгоритм через замену инструкции SIMD64 на аналогичную SIMD128. Использование SIMD128 приводило к появлению инструкций перетасовки данных (shuf, perm), занимавших исполнительные юниты.

В этой статье векторные инструкции используются по‑другому.
Здесь с их помощью создаются «векторные» версии алгоритмов из исходных.
Векторные алгоритмы выполняют несколько одинаковых задач одновременно аналогично тому, как векторные инструкции выполняют несколько одинаковых операций одновременно.
Такой подход я и называю «прямой векторизацией».

Для выполнения прямой векторизации нужно заменить обычные инструкции на их векторные версии. Чтобы такое было возможно, в исходной программе должны использоваться инструкции, для которых существуют векторные версии. Обрабатываемые данные также требуется привести в векторную форму, то есть такой формат, который ожидается векторными инструкциями.

Прямая векторизация кода на Си

Пусть, например, алгоритм обрабатывает float числа.
Для выполнения прямой векторизации в 2 или 4 раза нужно заменить в Си‑коде исходного алгоритма тип float на __v2sf или __v4sf соответственно. И компилятор сгенерирует векторизованный код с использованием инструкций SIMD64 или SIMD128 соответственно.
При этом операции «+», «-», «*» будут скомпилированы в векторные версии инструкций.

Обрабатываемые данные также требуется предварительно привести в векторную форму:

  • там, где было одно float число, теперь должен быть «вектор» float чисел (расположенные рядом 2 или 4 float числа)

  • там, где был массив float чисел, теперь должен быть массив «векторов» float чисел (фактически исходный массив преобразуется в набор перемежённых массивов)

Прямая векторизация алгоритма Stage

Пусть изначально есть следующий код:

	void stage_radix2_etalon(int data_count, myComplex *data_in, myComplex *data_out, myComplex *coef)
	{
		myComplex *x_in = &data_in[0];
		myComplex *y_in = &data_in[1];
		myComplex *c_in = coef;

		myComplex *out_add = &data_out[0];
		myComplex *out_sub = &data_out[data_count/2];

		#pragma ivdep
		#pragma unroll(1)
		#pragma prefetch
		for(int64_t i = 0; i < data_count/2; ++i)
		{
			myComplex x = x_in[2*i];
			myComplex y = y_in[2*i];
			myComplex c = c_in[i];

			myComplex cy = complex_mul(c, y);

			out_add[i] = complex_add(x, cy);
			out_sub[i] = complex_sub(x, cy);
		}
	}

Избавимся от типа myComplex, оставив просто тип float:

	void stage_radix2_etalon(int data_count, float *data_in, float *data_out, float *coef)
	{
		float *x_real_in = &data_in[0];
		float *x_imag_in = &data_in[1];
		float *y_real_in = &data_in[2];
		float *y_imag_in = &data_in[3];
		float *c_real_in = &coef[0];
		float *c_imag_in = &coef[1];

		float *out_add_real = &data_out[0];
		float *out_add_imag = &data_out[1];
		float *out_sub_real = &data_out[data_count/2 + 0];
		float *out_sub_imag = &data_out[data_count/2 + 1];

		#pragma ivdep
		#pragma unroll(1)
		#pragma prefetch
		for(int64_t i = 0; i < data_count/2; ++i)
		{
			float x_real = x_real_in[4*i];
			float x_imag = x_imag_in[4*i];
			float y_real = y_real_in[4*i];
			float y_imag = y_imag_in[4*i];
			float c_real = c_real_in[2*i];
			float c_imag = c_imag_in[2*i];

			float cy_real = c_real*y_real - c_imag*y_imag;
			float cy_imag = c_real*y_imag + c_imag*y_real;

			out_add_real[2*i] = x_real + cy_real;
			out_add_imag[2*i] = x_imag + cy_imag;
			out_sub_real[2*i] = x_real - cy_real;
			out_sub_imag[2*i] = x_imag - cy_imag;
		}
	}

Получившийся результат будем называть «базовым алгоритмом Stage» для прямой векторизации.
Если в этом коде заменить все float на __v2sf, получим прямую векторизацию в 2 раза.
Если в этом коде заменить все float на __v4sf, получим прямую векторизацию в 4 раза.

К сожалению, я узнал про этот приём уже после того, как написал весь код.
Поэтому сейчас в коде используются интринсики вместе с типами uint64_t и __v2di там, где в базовом алгоритме стоят операции «+», «-», «*».
В будущем я, скорее всего, исправлю код.

Прямая векторизация полного алгоритма FFT

Алгоритм FFT состоит из одного запуска Reverse и нескольких запусков Stage.
Stage был векторизован в предыдущем разделе.
Reverse векторизуется аналогичным образом.
Объединив векторные Reverse и Stage, получим векторный алгоритм FFT.

Этот алгоритм ожидает на входе и выходе набор перемежённых массивов float чисел.
В результате его работы будут вычислены FFT от каждого из перемежённых массивов.

Решение задачи FFT с помощью векторного FFT

Итак, мы умеем вычислять несколько FFT одновременно.
Как использовать это умение, чтобы вычислить FFT от одного набора комплексных чисел?

Для этого нужно вспомнить, как выглядел рекурсивный алгоритм Кули‑Тьюки:

  1. Вычисляются FFT от каждого из перемежённых массивов комплексных чисел.

  2. Вычисляется итоговый FFT с помощью этих перемежённых FFT.

Первый шаг сделаем с помощью векторного алгоритма FFT.
Векторный FFT ожидает на входе и выходе набор перемежённых массивов float чисел, а алгоритм Кули‑Тьюки ожидает набор перемежённых массивов комплексных чисел.
Поэтому добавим перед этим шагом преобразование исходных данных в векторную форму, а после этого шага — преобразование из векторной формы в исходную.

Схемы преобразования данных в векторную форму

Теперь на вход можно подавать массив комплексных чисел.
Алгоритм будет воспринимать его, как набор перемежённых массивов комплексных чисел.
В результате его работы будут вычислены FFT от каждого из перемежённых массивов.


Второй шаг похож на то, что делает адаптированный для Эльбруса алгоритм Stage из прошлой статьи. Если точнее, на этом шаге выполняются те же действия, что делает самый последний Stage в алгоритме FFT (тот Stage, в котором используется полный набор разных коэффициентов). Поэтому далее второй шаг будем называть «LastStage».

В случае выполнения прямой векторизации в 2 раза (когда получаются 2 перемежённых массива) в качестве LastStage можно использовать любой stage_radix2 из прошлой статьи.
В случае выполнения прямой векторизации в 4 раза (когда получаются 4 перемежённых массива) в качестве LastStage можно использовать любой stage_radix4 из прошлой статьи (или сначала stage_radix2_vector2 и затем любой stage_radix2 из прошлой статьи).


Итого, полный порядок действий выглядит так:

  1. Исходные данные преобразуются в векторную форму.

  2. Выполняется векторный Reverse.

  3. Несколько раз выполняется векторный Stage.

  4. Полученные данные преобразуются из векторной формы в исходную.

  5. Выполняется LastStage.


Преобразования данных в векторную форму и обратно — достаточно простые процедуры. Поэтому в итоговой реализации они сразу включены внутрь Reverse и LastStage соответственно.

Пишем векторный Reverse

reverse_radix2_vector2

1. reverse_radix2_vector2_etalon

Эталонный вариант для сравнения на корректность.
Здесь reverseNumber_radix2 вычисляется с помощью цикла.

int reverseNumber_radix2(int number, int bit_count)
{
	int answer = 0;

	for(int i = 0; i < bit_count; ++i)
	{
		answer <<= 1;
		answer |= number & 1;
		number >>= 1;
	}

	return answer;
}


void reverse_radix2_vector2_etalon(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;

	for(int64_t i = 0; i < count_out; ++i)
	{
		int index = reverseNumber_radix2(i, bit_count_out);
		myComplex a = data_in[2*i + 0];
		myComplex b = data_in[2*i + 1];
		data_out[index] = (myComplex2){.real = {a.real, b.real}, .imag = {a.imag, b.imag}};
	}
}

2. reverse_radix2_vector2

В процессоре есть инструкция bitrevd, которая производит операцию reverseNumber_radix2 над 64-битным числом. Заменим reverseNumber_radix2() на __builtin_e2k_bitrevd().

Код на Си
void reverse_radix2_vector2(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in  = (__v2di*)data_in;
	__v2di *out = (__v2di*)data_out;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out; ++i)
	{
		int64_t index = __builtin_e2k_bitrevd(i) >> shift_out;
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		out[index] = __builtin_e2k_qppermb(in[i], in[i], mask);
	}
}
Основной цикл на ассемблере
.L4793:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=5, abs=0, disp=0
        }
.L4668:
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          bitrevd,0,sm  %b[11], %b[13]
          qppermb,1,sm  %b[10], %b[10], %r4, %b[12]
          addd,2,sm     %b[11], 0x1, %b[9]
          shrd,3,sm     %b[17], %r0, %b[19]
          shld,4,sm     %b[21], 0x4, %b[20]
          stqp,5        %r2, %b[22], %b[18]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[0]
        }

Теоретическая скорость: 2 комплексных числа за 1 такт (2/1) = 16 Байт/такт

Замеры скорости

3. reverse_radix2_vector2_x2

Сделаем ручную раскрутку цикла в 2 раза.
Сразу напишем код так, чтобы вместиться в один такт (убираем инструкции shrd и shld).

Код на Си
void reverse_radix2_vector2_x2(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;
	int64_t delta = (1LL << shift_out) / 16;

	__v2di *in    = (__v2di*) data_in;
	__v2di *out_0 = (__v2di*)&data_out[0];
	__v2di *out_1 = (__v2di*)&data_out[count_out/2];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0, shifted_i = 0; i < count_out; i += 2, shifted_i += 2*delta)
	{
		int64_t offset = __builtin_e2k_bitrevd(shifted_i);
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)out_0 + offset) = __builtin_e2k_qppermb(in[i + 0], in[i + 0], mask);
		*(__v2du*)((void*)out_1 + offset) = __builtin_e2k_qppermb(in[i + 1], in[i + 1], mask);
	}
}
Основной цикл на ассемблере
.L5010:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
        }
.L4823:
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          bitrevd,0,sm  %b[22], %b[13]
          qppermb,1,sm  %b[10], %b[10], %r5, %b[19]
          stqp,2        %r4, %b[17], %b[21]
          qppermb,3,sm  %b[11], %b[11], %r5, %b[23]
          addd,4,sm     %b[20], %r0, %b[18]
          stqp,5        %r2, %b[17], %b[25]
          movaqp,0      area=0, ind=16, am=1, be=0, %b[0]
          movaqp,1      area=0, ind=0, am=0, be=0, %b[1]
        }

Теоретическая скорость: 4 комплексных числа за 1 такт (4/1) = 32 Байт/такт

Замеры скорости

Видим ускорение в начале графика.

Здесь происходит два чтения из одного места памяти и запись в два разных места памяти.

4. reverse_radix2_vector2_stream2

Теперь сделаем наоборот: будем читать из двух разных мест, а писать рядом.
Чтение в 2 потока из разных мест памяти, запись в одно место памяти.
Сразу напишем код так, чтобы вместиться в один такт (убираем инструкции shrd и shld).

Код на Си
void reverse_radix2_vector2_stream2(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;
	int64_t delta = (1LL << shift_out) / 16;

	__v2di *in_0 = (__v2di*)&data_in[0];
	__v2di *in_1 = (__v2di*)&data_in[count_in/2];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0, shifted_i = 0; i < count_out/2; ++i, shifted_i += delta)
	{
		int64_t offset = __builtin_e2k_bitrevd(shifted_i);
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_0[i], in_0[i], mask);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_1[i], in_1[i], mask);
	}
}
Основной цикл на ассемблере
.L5212:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=5, abs=0, disp=0
        }
.L5039:
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          bitrevd,0,sm  %b[22], %b[13]
          qppermb,1,sm  %b[11], %b[11], %r5, %b[23]
          stqp,2        %r2, %b[17], %b[25]
          qppermb,3,sm  %b[10], %b[10], %r5, %b[19]
          addd,4,sm     %b[20], %r4, %b[18]
          stqp,5        %r0, %b[17], %b[21]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[1]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[0]
        }

Теоретическая скорость: 4 комплексных числа за 1 такт (4/1) = 32 Байт/такт

Замеры скорости

Видим желаемое ускорение по всей длине графика.

5. reverse_radix2_vector2_stream4

Чтение в 4 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector2_stream4(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_00 = (__v2di*)&data_in[0 * count_in/4];
	__v2di *in_01 = (__v2di*)&data_in[1 * count_in/4];
	__v2di *in_10 = (__v2di*)&data_in[2 * count_in/4];
	__v2di *in_11 = (__v2di*)&data_in[3 * count_in/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/4; ++i)
	{
		int64_t offset = 16 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_00[i], in_00[i], mask);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_10[i], in_10[i], mask);
		*(__v2du*)((void*)data_out + offset + 2*16) = __builtin_e2k_qppermb(in_01[i], in_01[i], mask);
		*(__v2du*)((void*)data_out + offset + 3*16) = __builtin_e2k_qppermb(in_11[i], in_11[i], mask);
	}
}
Основной цикл на ассемблере
.L5516:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=4, abs=0, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=4, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=4, abs=16, disp=0
        }
.L5255:
        {
          loop_mode
          bitrevd,0,sm  %b[4], %b[1]
          qppermb,1,sm  %b[27], %b[27], %r7, %b[9]
          stqp,2        %r2, %b[14], %b[28]
          shld,3,sm     %b[24], 0x4, %b[12]
          qppermb,4,sm  %b[22], %b[22], %r7, %b[5]
          stqp,5        %r4, %b[14], %b[26]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[19], %b[19], %r7, %b[26]
          addd,1,sm     %b[2], 0x1, %b[0]
          stqp,2        %r0, %b[14], %b[11]
          qppermb,3,sm  %b[10], %b[10], %r7, %b[24]
          shrd,4,sm     %b[3], %r6, %b[22]
          stqp,5        %r5, %b[14], %b[7]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[4]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[13]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[16]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[21]
        }

Теоретическая скорость: 8 комплексных чисел за 2 такта (8/2) = 32 Байт/такт

Замеры скорости

Видим замедление в начале и ускорение в конце графика.

6. reverse_radix2_vector2_stream8

Чтение в 8 потоков из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector2_stream8(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_000 = (__v2di*)&data_in[0 * count_in/8];
	__v2di *in_001 = (__v2di*)&data_in[1 * count_in/8];
	__v2di *in_010 = (__v2di*)&data_in[2 * count_in/8];
	__v2di *in_011 = (__v2di*)&data_in[3 * count_in/8];
	__v2di *in_100 = (__v2di*)&data_in[4 * count_in/8];
	__v2di *in_101 = (__v2di*)&data_in[5 * count_in/8];
	__v2di *in_110 = (__v2di*)&data_in[6 * count_in/8];
	__v2di *in_111 = (__v2di*)&data_in[7 * count_in/8];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/8; ++i)
	{
		int64_t offset = 16 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_000[i], in_000[i], mask);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_100[i], in_100[i], mask);
		*(__v2du*)((void*)data_out + offset + 2*16) = __builtin_e2k_qppermb(in_010[i], in_010[i], mask);
		*(__v2du*)((void*)data_out + offset + 3*16) = __builtin_e2k_qppermb(in_110[i], in_110[i], mask);
		*(__v2du*)((void*)data_out + offset + 4*16) = __builtin_e2k_qppermb(in_001[i], in_001[i], mask);
		*(__v2du*)((void*)data_out + offset + 5*16) = __builtin_e2k_qppermb(in_101[i], in_101[i], mask);
		*(__v2du*)((void*)data_out + offset + 6*16) = __builtin_e2k_qppermb(in_011[i], in_011[i], mask);
		*(__v2du*)((void*)data_out + offset + 7*16) = __builtin_e2k_qppermb(in_111[i], in_111[i], mask);
	}
}
Основной цикл на ассемблере
.L6024:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=8, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=7, asz=3, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=6, asz=3, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=5, asz=3, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=3, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=3, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=3, abs=24, disp=0
        }
.L5591:
        {
          loop_mode
          qppermb,1,sm  %b[21], %b[21], %r11, %b[26]
          stqp,2        %r2, %b[18], %b[24]
          qppermb,4,sm  %b[13], %b[13], %r11, %b[25]
          stqp,5        %r4, %b[18], %b[23]
        }
        {
          loop_mode
          qppermb,1,sm  %b[12], %b[12], %r11, %b[24]
          stqp,2        %r0, %b[18], %b[26]
          shrd,3,sm     %b[22], %r12, %b[1]
          qppermb,4,sm  %b[5], %b[5], %r11, %b[23]
          stqp,5        %r5, %b[18], %b[25]
        }
        {
          loop_mode
          qppermb,1,sm  %b[9], %b[9], %r11, %b[27]
          stqp,2        %r6, %b[18], %b[24]
          shld,3,sm     %b[1], 0x4, %b[16]
          qppermb,4,sm  %b[8], %b[8], %r11, %b[25]
          stqp,5        %r9, %b[18], %b[23]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[12]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[13]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[4]
          movaqp,3      area=2, ind=0, am=1, be=0, %b[5]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[15], %b[15], %r11, %b[22]
          addd,1,sm     %b[2], 0x1, %b[0]
          stqp,2        %r7, %b[18], %b[27]
          qppermb,3,sm  %b[14], %b[14], %r11, %b[21]
          bitrevd,4,sm  %b[2], %b[20]
          stqp,5        %r10, %b[18], %b[25]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[1]
          movaqp,1      area=2, ind=0, am=1, be=0, %b[8]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[9]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[17]
        }

Теоретическая скорость: 16 комплексных чисел за 4 такта (16/4) = 32 Байт/такт

Замеры скорости

Видим сильное ускорение.

7. reverse_radix2_vector2_stream16

Чтение в 16 потоков из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector2_stream16(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_0000 = (__v2di*)&data_in[ 0 * count_in/16];
	__v2di *in_0001 = (__v2di*)&data_in[ 1 * count_in/16];
	__v2di *in_0010 = (__v2di*)&data_in[ 2 * count_in/16];
	__v2di *in_0011 = (__v2di*)&data_in[ 3 * count_in/16];
	__v2di *in_0100 = (__v2di*)&data_in[ 4 * count_in/16];
	__v2di *in_0101 = (__v2di*)&data_in[ 5 * count_in/16];
	__v2di *in_0110 = (__v2di*)&data_in[ 6 * count_in/16];
	__v2di *in_0111 = (__v2di*)&data_in[ 7 * count_in/16];
	__v2di *in_1000 = (__v2di*)&data_in[ 8 * count_in/16];
	__v2di *in_1001 = (__v2di*)&data_in[ 9 * count_in/16];
	__v2di *in_1010 = (__v2di*)&data_in[10 * count_in/16];
	__v2di *in_1011 = (__v2di*)&data_in[11 * count_in/16];
	__v2di *in_1100 = (__v2di*)&data_in[12 * count_in/16];
	__v2di *in_1101 = (__v2di*)&data_in[13 * count_in/16];
	__v2di *in_1110 = (__v2di*)&data_in[14 * count_in/16];
	__v2di *in_1111 = (__v2di*)&data_in[15 * count_in/16];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/16; ++i)
	{
		int64_t offset = 16 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_0000[i], in_0000[i], mask);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_1000[i], in_1000[i], mask);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_0100[i], in_0100[i], mask);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_1100[i], in_1100[i], mask);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_0010[i], in_0010[i], mask);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_1010[i], in_1010[i], mask);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_0110[i], in_0110[i], mask);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_1110[i], in_1110[i], mask);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_0001[i], in_0001[i], mask);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_1001[i], in_1001[i], mask);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_0101[i], in_0101[i], mask);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_1101[i], in_1101[i], mask);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_0011[i], in_0011[i], mask);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_1011[i], in_1011[i], mask);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_0111[i], in_0111[i], mask);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_1111[i], in_1111[i], mask);
	}
}
Основной цикл на ассемблере
.L6935:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=1, incr=0, ind=0, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=15, asz=2, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=14, asz=2, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=13, asz=2, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=12, asz=2, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=11, asz=2, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=10, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=9, asz=2, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=8, asz=2, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=7, asz=2, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=6, asz=2, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=5, asz=2, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=2, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=2, abs=24, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=2, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=2, abs=28, disp=0
        }
.L6163:
        {
          loop_mode
          qppermb,1,sm  %b[24], %b[24], %r1, %b[28]
          stqp,2        %r2, %b[13], %b[9]
          qppermb,4,sm  %b[22], %b[22], %r1, %b[27]
          stqp,5        %r5, %b[13], %b[4]
        }
        {
          loop_mode
          qppermb,1,sm  %b[26], %b[26], %r1, %b[30]
          stqp,2        %r0, %b[13], %b[28]
          qppermb,4,sm  %b[25], %b[25], %r1, %b[29]
          stqp,5        %r6, %b[13], %b[27]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[10]
          movaqp,1      area=6, ind=0, am=1, be=0, %b[4]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[7]
          movaqp,3      area=6, ind=0, am=1, be=0, %b[1]
        }
        {
          loop_mode
          qppermb,1,sm  %b[23], %b[23], %r1, %b[27]
          stqp,2        %r7, %b[13], %b[30]
          qppermb,4,sm  %b[16], %b[16], %r1, %b[26]
          stqp,5        %r10, %b[13], %b[29]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[15]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[17]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[9]
          movaqp,3      area=4, ind=0, am=1, be=0, %b[12]
        }
        {
          loop_mode
          qppermb,1,sm  %b[21], %b[21], %r1, %b[29]
          stqp,2        %r9, %b[13], %b[27]
          qppermb,4,sm  %b[14], %b[14], %r1, %b[28]
          stqp,5        %r11, %b[13], %b[26]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[16]
          movaqp,1      area=4, ind=0, am=1, be=0, %b[19]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[20]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[22]
        }
        {
          loop_mode
          addd,0,sm     %b[2], 0x1, %b[0]
          qppermb,1,sm  %b[18], %b[18], %r1, %b[27]
          stqp,2        %r12, %b[13], %b[29]
          bitrevd,3,sm  %b[2], %b[25]
          qppermb,4,sm  %b[11], %b[11], %r1, %b[26]
          stqp,5        %r13, %b[13], %b[28]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[23]
          movaqp,1      area=2, ind=0, am=1, be=0, %b[24]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[14]
          movaqp,3      area=2, ind=0, am=1, be=0, %b[21]
        }
        {
          loop_mode
          qppermb,1,sm  %b[6], %b[6], %r1, %b[29]
          stqp,2        %r14, %b[13], %b[27]
          shrd,3,sm     %b[25], %r20, %b[2]
          qppermb,4,sm  %b[3], %b[3], %r1, %b[28]
          stqp,5        %r15, %b[13], %b[26]
        }
        {
          loop_mode
          qppermb,1,sm  %b[10], %b[10], %r1, %b[6]
          stqp,2        %r16, %b[13], %b[29]
          shld,3,sm     %b[2], 0x4, %b[11]
          qppermb,4,sm  %b[7], %b[7], %r1, %b[3]
          stqp,5        %r17, %b[13], %b[28]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[17], %b[17], %r1, %b[7]
          stqp,2        %r18, %b[13], %b[8]
          qppermb,3,sm  %b[15], %b[15], %r1, %b[2]
          stqp,5        %r19, %b[13], %b[5]
        }

Теоретическая скорость: 32 комплексных числа за 8 тактов (32/8) = 32 Байт/такт

Замеры скорости

Видим сильное ускорение.

8. reverse_radix2_vector2_stream32

Чтение в 32 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector2_stream32(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_00000 = (__v2di*)&data_in[ 0 * count_in/32];
	__v2di *in_00001 = (__v2di*)&data_in[ 1 * count_in/32];
	__v2di *in_00010 = (__v2di*)&data_in[ 2 * count_in/32];
	__v2di *in_00011 = (__v2di*)&data_in[ 3 * count_in/32];
	__v2di *in_00100 = (__v2di*)&data_in[ 4 * count_in/32];
	__v2di *in_00101 = (__v2di*)&data_in[ 5 * count_in/32];
	__v2di *in_00110 = (__v2di*)&data_in[ 6 * count_in/32];
	__v2di *in_00111 = (__v2di*)&data_in[ 7 * count_in/32];
	__v2di *in_01000 = (__v2di*)&data_in[ 8 * count_in/32];
	__v2di *in_01001 = (__v2di*)&data_in[ 9 * count_in/32];
	__v2di *in_01010 = (__v2di*)&data_in[10 * count_in/32];
	__v2di *in_01011 = (__v2di*)&data_in[11 * count_in/32];
	__v2di *in_01100 = (__v2di*)&data_in[12 * count_in/32];
	__v2di *in_01101 = (__v2di*)&data_in[13 * count_in/32];
	__v2di *in_01110 = (__v2di*)&data_in[14 * count_in/32];
	__v2di *in_01111 = (__v2di*)&data_in[15 * count_in/32];
	__v2di *in_10000 = (__v2di*)&data_in[16 * count_in/32];
	__v2di *in_10001 = (__v2di*)&data_in[17 * count_in/32];
	__v2di *in_10010 = (__v2di*)&data_in[18 * count_in/32];
	__v2di *in_10011 = (__v2di*)&data_in[19 * count_in/32];
	__v2di *in_10100 = (__v2di*)&data_in[20 * count_in/32];
	__v2di *in_10101 = (__v2di*)&data_in[21 * count_in/32];
	__v2di *in_10110 = (__v2di*)&data_in[22 * count_in/32];
	__v2di *in_10111 = (__v2di*)&data_in[23 * count_in/32];
	__v2di *in_11000 = (__v2di*)&data_in[24 * count_in/32];
	__v2di *in_11001 = (__v2di*)&data_in[25 * count_in/32];
	__v2di *in_11010 = (__v2di*)&data_in[26 * count_in/32];
	__v2di *in_11011 = (__v2di*)&data_in[27 * count_in/32];
	__v2di *in_11100 = (__v2di*)&data_in[28 * count_in/32];
	__v2di *in_11101 = (__v2di*)&data_in[29 * count_in/32];
	__v2di *in_11110 = (__v2di*)&data_in[30 * count_in/32];
	__v2di *in_11111 = (__v2di*)&data_in[31 * count_in/32];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/32; ++i)
	{
		int64_t offset = 16 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_00000[i], in_00000[i], mask);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_10000[i], in_10000[i], mask);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_01000[i], in_01000[i], mask);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_11000[i], in_11000[i], mask);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_00100[i], in_00100[i], mask);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_10100[i], in_10100[i], mask);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_01100[i], in_01100[i], mask);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_11100[i], in_11100[i], mask);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_00010[i], in_00010[i], mask);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_10010[i], in_10010[i], mask);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_01010[i], in_01010[i], mask);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_11010[i], in_11010[i], mask);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_00110[i], in_00110[i], mask);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_10110[i], in_10110[i], mask);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_01110[i], in_01110[i], mask);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_11110[i], in_11110[i], mask);
		*(__v2du*)((void*)data_out + offset + 16*16) = __builtin_e2k_qppermb(in_00001[i], in_00001[i], mask);
		*(__v2du*)((void*)data_out + offset + 17*16) = __builtin_e2k_qppermb(in_10001[i], in_10001[i], mask);
		*(__v2du*)((void*)data_out + offset + 18*16) = __builtin_e2k_qppermb(in_01001[i], in_01001[i], mask);
		*(__v2du*)((void*)data_out + offset + 19*16) = __builtin_e2k_qppermb(in_11001[i], in_11001[i], mask);
		*(__v2du*)((void*)data_out + offset + 20*16) = __builtin_e2k_qppermb(in_00101[i], in_00101[i], mask);
		*(__v2du*)((void*)data_out + offset + 21*16) = __builtin_e2k_qppermb(in_10101[i], in_10101[i], mask);
		*(__v2du*)((void*)data_out + offset + 22*16) = __builtin_e2k_qppermb(in_01101[i], in_01101[i], mask);
		*(__v2du*)((void*)data_out + offset + 23*16) = __builtin_e2k_qppermb(in_11101[i], in_11101[i], mask);
		*(__v2du*)((void*)data_out + offset + 24*16) = __builtin_e2k_qppermb(in_00011[i], in_00011[i], mask);
		*(__v2du*)((void*)data_out + offset + 25*16) = __builtin_e2k_qppermb(in_10011[i], in_10011[i], mask);
		*(__v2du*)((void*)data_out + offset + 26*16) = __builtin_e2k_qppermb(in_01011[i], in_01011[i], mask);
		*(__v2du*)((void*)data_out + offset + 27*16) = __builtin_e2k_qppermb(in_11011[i], in_11011[i], mask);
		*(__v2du*)((void*)data_out + offset + 28*16) = __builtin_e2k_qppermb(in_00111[i], in_00111[i], mask);
		*(__v2du*)((void*)data_out + offset + 29*16) = __builtin_e2k_qppermb(in_10111[i], in_10111[i], mask);
		*(__v2du*)((void*)data_out + offset + 30*16) = __builtin_e2k_qppermb(in_01111[i], in_01111[i], mask);
		*(__v2du*)((void*)data_out + offset + 31*16) = __builtin_e2k_qppermb(in_11111[i], in_11111[i], mask);
	}
}
Основной цикл на ассемблере
.L8688:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=17, incr=0, ind=0, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=16, incr=0, ind=0, asz=1, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=15, incr=0, ind=0, asz=1, abs=2, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=14, incr=0, ind=0, asz=1, abs=2, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=13, incr=0, ind=0, asz=1, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=12, incr=0, ind=0, asz=1, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=11, incr=0, ind=0, asz=1, abs=6, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=10, incr=0, ind=0, asz=1, abs=6, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=9, incr=0, ind=0, asz=1, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=8, incr=0, ind=0, asz=1, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=7, incr=0, ind=0, asz=1, abs=10, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=6, incr=0, ind=0, asz=1, abs=10, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=5, incr=0, ind=0, asz=1, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=4, incr=0, ind=0, asz=1, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=3, incr=0, ind=0, asz=1, abs=14, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=2, incr=0, ind=0, asz=1, abs=14, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=1, incr=0, ind=0, asz=1, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=15, asz=1, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=14, asz=1, abs=18, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=13, asz=1, abs=18, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=12, asz=1, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=11, asz=1, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=10, asz=1, abs=22, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=9, asz=1, abs=22, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=8, asz=1, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=7, asz=1, abs=24, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=6, asz=1, abs=26, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=5, asz=1, abs=26, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=1, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=1, abs=28, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=1, abs=30, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=1, abs=30, disp=0
        }
.L7202:
        {
          loop_mode
          qppermb,1,sm  %b[37], %b[37], %r0, %b[21]
          stqp,2        %r2, %b[16], %b[20]
          qppermb,4,sm  %b[35], %b[35], %r0, %b[18]
          stqp,5        %r6, %b[16], %b[18]
        }
        {
          loop_mode
          qppermb,1,sm  %b[39], %b[39], %r0, %b[20]
          stqp,2        %r4, %b[16], %b[21]
          qppermb,4,sm  %b[38], %b[38], %r0, %b[18]
          stqp,5        %r7, %b[16], %b[18]
        }
        {
          loop_mode
          qppermb,1,sm  %b[23], %b[23], %r0, %b[19]
          stqp,2        %r9, %b[16], %b[20]
          qppermb,4,sm  %b[19], %b[19], %r0, %b[18]
          stqp,5        %r11, %b[16], %b[18]
        }
        {
          loop_mode
          qppermb,1,sm  %b[26], %b[26], %r0, %b[19]
          stqp,2        %r10, %b[16], %b[19]
          qppermb,4,sm  %b[33], %b[33], %r0, %b[18]
          stqp,5        %r12, %b[16], %b[18]
        }
        {
          loop_mode
          qppermb,1,sm  %b[25], %b[25], %r0, %b[19]
          stqp,2        %r13, %b[16], %b[19]
          qppermb,4,sm  %b[32], %b[32], %r0, %b[18]
          stqp,5        %r14, %b[16], %b[18]
        }
        {
          loop_mode
          qppermb,1,sm  %b[31], %b[31], %r0, %b[24]
          stqp,2        %r15, %b[16], %b[19]
          qppermb,4,sm  %b[30], %b[30], %r0, %b[21]
          stqp,5        %r16, %b[16], %b[18]
          movaqp,0      area=15, ind=0, am=1, be=0, %b[19]
          movaqp,1      area=14, ind=0, am=1, be=0, %b[22]
          movaqp,2      area=15, ind=0, am=1, be=0, %b[18]
          movaqp,3      area=14, ind=0, am=1, be=0, %b[20]
        }
        {
          loop_mode
          qppermb,1,sm  %b[29], %b[29], %r0, %b[26]
          stqp,2        %r17, %b[16], %b[24]
          qppermb,4,sm  %b[17], %b[17], %r0, %b[25]
          stqp,5        %r18, %b[16], %b[21]
          movaqp,0      area=13, ind=0, am=1, be=0, %b[21]
          movaqp,1      area=12, ind=0, am=1, be=0, %b[24]
          movaqp,2      area=13, ind=0, am=1, be=0, %b[17]
          movaqp,3      area=12, ind=0, am=1, be=0, %b[23]
        }
        {
          loop_mode
          qppermb,1,sm  %b[28], %b[28], %r0, %b[26]
          stqp,2        %r19, %b[16], %b[26]
          qppermb,4,sm  %b[27], %b[27], %r0, %b[25]
          stqp,5        %r20, %b[16], %b[25]
          movaqp,0      area=11, ind=0, am=1, be=0, %b[1]
          movaqp,1      area=10, ind=0, am=1, be=0, %b[13]
          movaqp,2      area=11, ind=0, am=1, be=0, %b[0]
          movaqp,3      area=10, ind=0, am=1, be=0, %b[12]
        }
        {
          loop_mode
          qppermb,1,sm  %g17, %g17, %r0, %b[28]
          stqp,2        %r21, %b[16], %b[26]
          qppermb,4,sm  %g16, %g16, %r0, %b[27]
          stqp,5        %r22, %b[16], %b[25]
          movaqp,0      area=9, ind=0, am=1, be=0, %g17
          movaqp,1      area=8, ind=0, am=1, be=0, %b[26]
          movaqp,2      area=9, ind=0, am=1, be=0, %g16
          movaqp,3      area=8, ind=0, am=1, be=0, %b[25]
        }
        {
          loop_mode
          qppermb,1,sm  %b[15], %b[15], %r0, %b[31]
          stqp,2        %r23, %b[16], %b[28]
          qppermb,4,sm  %b[14], %b[14], %r0, %b[30]
          stqp,5        %r24, %b[16], %b[27]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[27]
          movaqp,1      area=6, ind=0, am=1, be=0, %b[29]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[15]
          movaqp,3      area=6, ind=0, am=1, be=0, %b[28]
        }
        {
          loop_mode
          qppermb,1,sm  %b[3], %b[3], %r0, %b[36]
          stqp,2        %r25, %b[16], %b[31]
          qppermb,4,sm  %b[2], %b[2], %r0, %b[33]
          stqp,5        %r26, %b[16], %b[30]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[32]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[34]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[30]
          movaqp,3      area=4, ind=0, am=1, be=0, %b[31]
        }
        {
          loop_mode
          qppermb,1,sm  %b[24], %b[24], %r0, %b[3]
          stqp,2        %r27, %b[16], %b[36]
          qppermb,4,sm  %b[23], %b[23], %r0, %b[2]
          stqp,5        %r28, %b[16], %b[33]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[23]
          movaqp,1      area=4, ind=0, am=1, be=0, %b[24]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[33]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[35]
        }
        {
          loop_mode
          addd,0,sm     %r5, 0x1, %r5
          qppermb,1,sm  %b[21], %b[21], %r0, %b[5]
          stqp,2        %r29, %b[16], %b[5]
          bitrevd,3,sm  %r5, %b[38]
          qppermb,4,sm  %b[17], %b[17], %r0, %b[4]
          stqp,5        %r30, %b[16], %b[4]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[36]
          movaqp,1      area=2, ind=0, am=1, be=0, %b[37]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[17]
          movaqp,3      area=2, ind=0, am=1, be=0, %b[21]
        }
        {
          loop_mode
          qppermb,1,sm  %b[22], %b[22], %r0, %b[7]
          stqp,2        %r31, %b[16], %b[7]
          shrd,3,sm     %b[38], %r1, %b[20]
          qppermb,4,sm  %b[20], %b[20], %r0, %b[6]
          stqp,5        %r32, %b[16], %b[6]
        }
        {
          loop_mode
          qppermb,1,sm  %b[19], %b[19], %r0, %b[9]
          stqp,2        %r33, %b[16], %b[9]
          shld,3,sm     %b[20], 0x4, %b[14]
          qppermb,4,sm  %b[18], %b[18], %r0, %b[8]
          stqp,5        %r34, %b[16], %b[8]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[34], %b[34], %r0, %b[18]
          stqp,2        %r35, %b[16], %b[11]
          qppermb,3,sm  %b[32], %b[32], %r0, %b[16]
          stqp,5        %r36, %b[16], %b[10]
        }

Теоретическая скорость: 64 комплексных числа за 16 тактов (64/16) = 32 Байт/такт

Замеры скорости

Видим замедление по всей длине графика.

При попытке чтения в 64 потока получается резко менее эффективный код.
APB не может читать в 64 потока, поэтому в дополнение к APB компилятор вставляет обычные операции чтения ldqp. В итоге скорость резко проседает.

Итоги по reverse_radix2_vector2

Победителем можно считать reverse_radix2_vector2_stream16.

При реализации Vector-2 Radix-2 FFT будем использовать его.

reverse_radix2_vector4

1. reverse_radix2_vector4_etalon

Эталонный вариант для сравнения на корректность.
Здесь reverseNumber_radix2 вычисляется с помощью цикла.

int reverseNumber_radix2(int number, int bit_count)
{
	int answer = 0;

	for(int i = 0; i < bit_count; ++i)
	{
		answer <<= 1;
		answer |= number & 1;
		number >>= 1;
	}

	return answer;
}


void reverse_radix2_vector4_etalon(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;

	for(int64_t i = 0; i < count_out; ++i)
	{
		int index = reverseNumber_radix2(i, bit_count_out);
		myComplex a = data_in[4*i + 0];
		myComplex b = data_in[4*i + 1];
		myComplex c = data_in[4*i + 2];
		myComplex d = data_in[4*i + 3];
		data_out[index] = (myComplex4){.real = {a.real, b.real, c.real, d.real}, .imag = {a.imag, b.imag, c.imag, d.imag}};
	}
}

2. reverse_radix2_vector4

В процессоре есть инструкция bitrevd, которая производит операцию reverseNumber_radix2 над 64-битным числом. Заменим reverseNumber_radix2() на __builtin_e2k_bitrevd().

Код на Си
void reverse_radix2_vector4(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;
	int64_t delta = (1LL << shift_out) / 32;

	__v2di *in = (__v2di*)data_in;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0, shifted_i = 0; i < count_out; ++i, shifted_i += delta)
	{
		int64_t offset = __builtin_e2k_bitrevd(shifted_i);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in[2*i+1], in[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in[2*i+1], in[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L6535:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
        }
.L6346:
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          bitrevd,0,sm  %b[22], %b[13]
          qppermb,1,sm  %b[11], %b[10], %r5, %b[19]
          stqp,2        %r0, %b[17], %b[21]
          qppermb,3,sm  %b[11], %b[10], %r6, %b[23]
          addd,4,sm     %b[20], %r4, %b[18]
          stqp,5        %r2, %b[17], %b[25]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[0]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[1]
        }

Теоретическая скорость: 4 комплексных числа за 1 такт (4/1) = 32 Байт/такт

Замеры скорости

3. reverse_radix2_vector4_x2

Сделаем ручную раскрутку цикла в 2 раза.

Код на Си
void reverse_radix2_vector4_x2(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in    = (__v2di*) data_in;
	__v2di *out_0 = (__v2di*)&data_out[0];
	__v2di *out_1 = (__v2di*)&data_out[count_out/2];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out; i += 2)
	{
		int64_t offset = 32 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)out_0 + offset + 0*16) = __builtin_e2k_qppermb(in[2*(i+0)+1], in[2*(i+0)+0], mask_real);
		*(__v2du*)((void*)out_0 + offset + 1*16) = __builtin_e2k_qppermb(in[2*(i+0)+1], in[2*(i+0)+0], mask_imag);
		*(__v2du*)((void*)out_1 + offset + 0*16) = __builtin_e2k_qppermb(in[2*(i+1)+1], in[2*(i+1)+0], mask_real);
		*(__v2du*)((void*)out_1 + offset + 1*16) = __builtin_e2k_qppermb(in[2*(i+1)+1], in[2*(i+1)+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L6884:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=32
        }
.L6561:
        {
          loop_mode
          bitrevd,0,sm  %b[4], %b[1]
          qppermb,1,sm  %b[25], %b[20], %r7, %b[28]
          stqp,2        %r0, %b[7], %b[26]
          shld,3,sm     %b[22], 0x5, %b[5]
          qppermb,4,sm  %b[17], %b[12], %r7, %b[27]
          stqp,5        %r4, %b[7], %b[24]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[23], %b[18], %r9, %b[24]
          addd,1,sm     %b[2], 0x2, %b[0]
          stqp,2        %r2, %b[7], %b[28]
          qppermb,3,sm  %b[15], %b[10], %r9, %b[22]
          shrd,4,sm     %b[3], %r6, %b[20]
          stqp,5        %r5, %b[7], %b[27]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[12]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[17]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[4]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[9]
        }

Теоретическая скорость: 8 комплексных чисел за 2 такта (8/2) = 32 Байт/такт

Замеры скорости

Видим ускорение в начале графика.

Здесь происходит два чтения из одного места памяти и запись в два разных места памяти.

4. reverse_radix2_vector4_stream2

Теперь сделаем наоборот: будем читать из двух разных мест, а писать рядом.
Чтение в 2 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector4_stream2(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_0 = (__v2di*)&data_in[0];
	__v2di *in_1 = (__v2di*)&data_in[count_in/2];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/2; ++i)
	{
		int64_t offset = 32 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_0[2*i+1], in_0[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_0[2*i+1], in_0[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 2*16) = __builtin_e2k_qppermb(in_1[2*i+1], in_1[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 3*16) = __builtin_e2k_qppermb(in_1[2*i+1], in_1[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L7199:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
        }
.L6909:
        {
          loop_mode
          bitrevd,0,sm  %b[4], %b[1]
          qppermb,1,sm  %b[25], %b[20], %r9, %b[28]
          stqp,2        %r0, %b[7], %b[26]
          shld,3,sm     %b[22], 0x5, %b[5]
          qppermb,4,sm  %b[17], %b[12], %r9, %b[27]
          stqp,5        %r5, %b[7], %b[24]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[23], %b[18], %r6, %b[24]
          addd,1,sm     %b[2], 0x1, %b[0]
          stqp,2        %r2, %b[7], %b[28]
          qppermb,3,sm  %b[15], %b[10], %r6, %b[22]
          shrd,4,sm     %b[3], %r7, %b[20]
          stqp,5        %r4, %b[7], %b[27]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[12]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[17]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[4]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[9]
        }

Теоретическая скорость: 8 комплексных чисел за 2 такта (8/2) = 32 Байт/такт

Замеры скорости

Видим замедление в начале и ускорение в конце графика.

5. reverse_radix2_vector4_stream4

Чтение в 4 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector4_stream4(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_00 = (__v2di*)&data_in[0 * count_in/4];
	__v2di *in_01 = (__v2di*)&data_in[1 * count_in/4];
	__v2di *in_10 = (__v2di*)&data_in[2 * count_in/4];
	__v2di *in_11 = (__v2di*)&data_in[3 * count_in/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/4; ++i)
	{
		int64_t offset = 32 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_00[2*i+1], in_00[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_00[2*i+1], in_00[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 2*16) = __builtin_e2k_qppermb(in_10[2*i+1], in_10[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 3*16) = __builtin_e2k_qppermb(in_10[2*i+1], in_10[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 4*16) = __builtin_e2k_qppermb(in_01[2*i+1], in_01[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 5*16) = __builtin_e2k_qppermb(in_01[2*i+1], in_01[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 6*16) = __builtin_e2k_qppermb(in_11[2*i+1], in_11[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 7*16) = __builtin_e2k_qppermb(in_11[2*i+1], in_11[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L7728:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=4, abs=0, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=4, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=16, disp=0
        }
.L7242:
        {
          loop_mode
          qppermb,1,sm  %b[20], %b[16], %r13, %b[26]
          stqp,2        %r0, %b[21], %b[25]
          qppermb,4,sm  %b[12], %b[8], %r13, %b[24]
          stqp,5        %r5, %b[21], %b[22]
        }
        {
          loop_mode
          qppermb,1,sm  %b[17], %b[13], %r12, %b[25]
          stqp,2        %r2, %b[21], %b[26]
          shrd,3,sm     %b[19], %r11, %b[1]
          qppermb,4,sm  %b[9], %b[5], %r12, %b[22]
          stqp,5        %r4, %b[21], %b[24]
        }
        {
          loop_mode
          qppermb,1,sm  %b[17], %b[13], %r13, %b[27]
          stqp,2        %r7, %b[21], %b[25]
          shld,3,sm     %b[1], 0x5, %b[19]
          qppermb,4,sm  %b[9], %b[5], %r13, %b[24]
          stqp,5        %r10, %b[21], %b[22]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[12]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[16]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[4]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[8]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[18], %b[14], %r12, %b[23]
          addd,1,sm     %b[2], 0x1, %b[0]
          stqp,2        %r6, %b[21], %b[27]
          qppermb,3,sm  %b[10], %b[6], %r12, %b[20]
          bitrevd,4,sm  %b[2], %b[17]
          stqp,5        %r9, %b[21], %b[24]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[9]
          movaqp,1      area=1, ind=16, am=0, be=0, %b[13]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[1]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[5]
        }

Теоретическая скорость: 16 комплексных чисел за 4 такта (16/4) = 32 Байт/такт

Замеры скорости

Видим сильное ускорение.

6. reverse_radix2_vector4_stream8

Чтение в 8 потоков из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector4_stream8(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_000 = (__v2di*)&data_in[0 * count_in/8];
	__v2di *in_001 = (__v2di*)&data_in[1 * count_in/8];
	__v2di *in_010 = (__v2di*)&data_in[2 * count_in/8];
	__v2di *in_011 = (__v2di*)&data_in[3 * count_in/8];
	__v2di *in_100 = (__v2di*)&data_in[4 * count_in/8];
	__v2di *in_101 = (__v2di*)&data_in[5 * count_in/8];
	__v2di *in_110 = (__v2di*)&data_in[6 * count_in/8];
	__v2di *in_111 = (__v2di*)&data_in[7 * count_in/8];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/8; ++i)
	{
		int64_t offset = 32 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_000[2*i+1], in_000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_000[2*i+1], in_000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_100[2*i+1], in_100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_100[2*i+1], in_100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_010[2*i+1], in_010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_010[2*i+1], in_010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_110[2*i+1], in_110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_110[2*i+1], in_110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_001[2*i+1], in_001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_001[2*i+1], in_001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_101[2*i+1], in_101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_101[2*i+1], in_101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_011[2*i+1], in_011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_011[2*i+1], in_011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_111[2*i+1], in_111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_111[2*i+1], in_111[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L8681:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=8, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=7, asz=3, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=6, asz=3, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=5, asz=3, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=3, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=3, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=24, disp=0
        }
.L7803:
        {
          loop_mode
          qppermb,1,sm  %b[16], %b[15], %r20, %b[28]
          stqp,2        %r0, %b[9], %b[5]
          qppermb,4,sm  %b[14], %b[13], %r20, %b[27]
          stqp,5        %r6, %b[9], %b[4]
        }
        {
          loop_mode
          qppermb,1,sm  %b[26], %b[25], %r21, %b[30]
          stqp,2        %r2, %b[9], %b[28]
          qppermb,4,sm  %b[24], %b[23], %r21, %b[29]
          stqp,5        %r5, %b[9], %b[27]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[5]
          movaqp,1      area=3, ind=16, am=0, be=0, %b[8]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[1]
          movaqp,3      area=3, ind=16, am=0, be=0, %b[4]
        }
        {
          loop_mode
          qppermb,1,sm  %b[26], %b[25], %r20, %b[28]
          stqp,2        %r9, %b[9], %b[30]
          qppermb,4,sm  %b[24], %b[23], %r20, %b[27]
          stqp,5        %r11, %b[9], %b[29]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[13]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[14]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[11]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[12]
        }
        {
          loop_mode
          qppermb,1,sm  %b[22], %b[21], %r20, %b[29]
          stqp,2        %r7, %b[9], %b[28]
          qppermb,4,sm  %b[22], %b[21], %r21, %b[26]
          stqp,5        %r10, %b[9], %b[27]
          movaqp,0      area=2, ind=0, am=1, be=0, %b[19]
          movaqp,1      area=2, ind=16, am=0, be=0, %b[20]
          movaqp,2      area=2, ind=0, am=1, be=0, %b[15]
          movaqp,3      area=2, ind=16, am=0, be=0, %b[16]
        }
        {
          loop_mode
          addd,0,sm     %b[2], 0x1, %b[0]
          qppermb,1,sm  %b[18], %b[17], %r20, %b[28]
          stqp,2        %r12, %b[9], %b[29]
          bitrevd,3,sm  %b[2], %b[25]
          qppermb,4,sm  %b[18], %b[17], %r21, %b[27]
          stqp,5        %r13, %b[9], %b[26]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[23]
          movaqp,1      area=1, ind=16, am=0, be=0, %b[24]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[21]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[22]
        }
        {
          loop_mode
          qppermb,1,sm  %b[10], %b[7], %r20, %b[29]
          stqp,2        %r14, %b[9], %b[28]
          shrd,3,sm     %b[25], %r22, %b[2]
          qppermb,4,sm  %b[10], %b[7], %r21, %b[26]
          stqp,5        %r15, %b[9], %b[27]
        }
        {
          loop_mode
          qppermb,1,sm  %b[6], %b[3], %r20, %b[27]
          stqp,2        %r16, %b[9], %b[29]
          shld,3,sm     %b[2], 0x5, %b[7]
          qppermb,4,sm  %b[6], %b[3], %r21, %b[25]
          stqp,5        %r17, %b[9], %b[26]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[14], %b[13], %r21, %b[3]
          stqp,2        %r18, %b[9], %b[27]
          qppermb,3,sm  %b[12], %b[11], %r21, %b[2]
          stqp,5        %r19, %b[9], %b[25]
        }

Теоретическая скорость: 32 комплексных числа за 8 тактов (32/8) = 32 Байт/такт

Замеры скорости

Видим сильное ускорение.

7. reverse_radix2_vector4_stream16

Чтение в 16 потоков из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector4_stream16(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_0000 = (__v2di*)&data_in[ 0 * count_in/16];
	__v2di *in_0001 = (__v2di*)&data_in[ 1 * count_in/16];
	__v2di *in_0010 = (__v2di*)&data_in[ 2 * count_in/16];
	__v2di *in_0011 = (__v2di*)&data_in[ 3 * count_in/16];
	__v2di *in_0100 = (__v2di*)&data_in[ 4 * count_in/16];
	__v2di *in_0101 = (__v2di*)&data_in[ 5 * count_in/16];
	__v2di *in_0110 = (__v2di*)&data_in[ 6 * count_in/16];
	__v2di *in_0111 = (__v2di*)&data_in[ 7 * count_in/16];
	__v2di *in_1000 = (__v2di*)&data_in[ 8 * count_in/16];
	__v2di *in_1001 = (__v2di*)&data_in[ 9 * count_in/16];
	__v2di *in_1010 = (__v2di*)&data_in[10 * count_in/16];
	__v2di *in_1011 = (__v2di*)&data_in[11 * count_in/16];
	__v2di *in_1100 = (__v2di*)&data_in[12 * count_in/16];
	__v2di *in_1101 = (__v2di*)&data_in[13 * count_in/16];
	__v2di *in_1110 = (__v2di*)&data_in[14 * count_in/16];
	__v2di *in_1111 = (__v2di*)&data_in[15 * count_in/16];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/16; ++i)
	{
		int64_t offset = 32 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_0000[2*i+1], in_0000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_0000[2*i+1], in_0000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_1000[2*i+1], in_1000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_1000[2*i+1], in_1000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_0100[2*i+1], in_0100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_0100[2*i+1], in_0100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_1100[2*i+1], in_1100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_1100[2*i+1], in_1100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_0010[2*i+1], in_0010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_0010[2*i+1], in_0010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_1010[2*i+1], in_1010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_1010[2*i+1], in_1010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_0110[2*i+1], in_0110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_0110[2*i+1], in_0110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_1110[2*i+1], in_1110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_1110[2*i+1], in_1110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 16*16) = __builtin_e2k_qppermb(in_0001[2*i+1], in_0001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 17*16) = __builtin_e2k_qppermb(in_0001[2*i+1], in_0001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 18*16) = __builtin_e2k_qppermb(in_1001[2*i+1], in_1001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 19*16) = __builtin_e2k_qppermb(in_1001[2*i+1], in_1001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 20*16) = __builtin_e2k_qppermb(in_0101[2*i+1], in_0101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 21*16) = __builtin_e2k_qppermb(in_0101[2*i+1], in_0101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 22*16) = __builtin_e2k_qppermb(in_1101[2*i+1], in_1101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 23*16) = __builtin_e2k_qppermb(in_1101[2*i+1], in_1101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 24*16) = __builtin_e2k_qppermb(in_0011[2*i+1], in_0011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 25*16) = __builtin_e2k_qppermb(in_0011[2*i+1], in_0011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 26*16) = __builtin_e2k_qppermb(in_1011[2*i+1], in_1011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 27*16) = __builtin_e2k_qppermb(in_1011[2*i+1], in_1011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 28*16) = __builtin_e2k_qppermb(in_0111[2*i+1], in_0111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 29*16) = __builtin_e2k_qppermb(in_0111[2*i+1], in_0111[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 30*16) = __builtin_e2k_qppermb(in_1111[2*i+1], in_1111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 31*16) = __builtin_e2k_qppermb(in_1111[2*i+1], in_1111[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L10479:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=1, incr=1, ind=0, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=15, asz=2, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=14, asz=2, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=13, asz=2, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=12, asz=2, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=11, asz=2, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=10, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=9, asz=2, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=8, asz=2, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=7, asz=2, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=6, asz=2, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=5, asz=2, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=2, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=2, abs=24, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=2, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=28, disp=0
        }
.L8820:
        {
          loop_mode
          qppermb,1,sm  %b[34], %b[33], %r36, %b[32]
          stqp,2        %r0, %b[4], %b[44]
          qppermb,4,sm  %b[32], %b[31], %r36, %b[31]
          stqp,5        %r6, %b[4], %b[43]
        }
        {
          loop_mode
          qppermb,1,sm  %b[42], %b[41], %r37, %b[32]
          stqp,2        %r2, %b[4], %b[32]
          qppermb,4,sm  %b[40], %b[39], %r37, %b[31]
          stqp,5        %r1, %b[4], %b[31]
        }
        {
          loop_mode
          qppermb,1,sm  %b[42], %b[41], %r36, %b[32]
          stqp,2        %r9, %b[4], %b[32]
          qppermb,4,sm  %b[40], %b[39], %r36, %b[31]
          stqp,5        %r11, %b[4], %b[31]
        }
        {
          loop_mode
          qppermb,1,sm  %b[38], %b[37], %r36, %b[32]
          stqp,2        %r7, %b[4], %b[32]
          qppermb,4,sm  %b[38], %b[37], %r37, %b[31]
          stqp,5        %r10, %b[4], %b[31]
        }
        {
          loop_mode
          qppermb,1,sm  %b[36], %b[35], %r36, %b[32]
          stqp,2        %r12, %b[4], %b[32]
          qppermb,4,sm  %b[36], %b[35], %r37, %b[31]
          stqp,5        %r13, %b[4], %b[31]
        }
        {
          loop_mode
          qppermb,1,sm  %b[30], %b[29], %r36, %b[30]
          stqp,2        %r14, %b[4], %b[32]
          qppermb,4,sm  %b[30], %b[29], %r37, %b[29]
          stqp,5        %r15, %b[4], %b[31]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[5]
          movaqp,1      area=7, ind=16, am=0, be=0, %b[6]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[0]
          movaqp,3      area=7, ind=16, am=0, be=0, %b[1]
        }
        {
          loop_mode
          qppermb,1,sm  %b[26], %b[25], %r36, %b[26]
          stqp,2        %r16, %b[4], %b[30]
          qppermb,4,sm  %b[26], %b[25], %r37, %b[25]
          stqp,5        %r17, %b[4], %b[29]
          movaqp,0      area=6, ind=0, am=1, be=0, %b[13]
          movaqp,1      area=6, ind=16, am=0, be=0, %b[14]
          movaqp,2      area=6, ind=0, am=1, be=0, %b[9]
          movaqp,3      area=6, ind=16, am=0, be=0, %b[10]
        }
        {
          loop_mode
          qppermb,1,sm  %b[28], %b[27], %r36, %b[26]
          stqp,2        %r18, %b[4], %b[26]
          qppermb,4,sm  %b[28], %b[27], %r37, %b[25]
          stqp,5        %r19, %b[4], %b[25]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[21]
          movaqp,1      area=5, ind=16, am=0, be=0, %b[22]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[17]
          movaqp,3      area=5, ind=16, am=0, be=0, %b[18]
        }
        {
          loop_mode
          qppermb,1,sm  %g16, %g17, %r36, %b[28]
          stqp,2        %r20, %b[4], %b[26]
          qppermb,4,sm  %g16, %g17, %r37, %b[27]
          stqp,5        %r21, %b[4], %b[25]
          movaqp,0      area=4, ind=0, am=1, be=0, %b[25]
          movaqp,1      area=4, ind=16, am=0, be=0, %b[26]
          movaqp,2      area=4, ind=0, am=1, be=0, %g17
          movaqp,3      area=4, ind=16, am=0, be=0, %g16
        }
        {
          loop_mode
          qppermb,1,sm  %b[24], %b[23], %r36, %b[30]
          stqp,2        %r22, %b[4], %b[28]
          qppermb,4,sm  %b[24], %b[23], %r37, %b[29]
          stqp,5        %r23, %b[4], %b[27]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[27]
          movaqp,1      area=3, ind=16, am=0, be=0, %b[28]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[23]
          movaqp,3      area=3, ind=16, am=0, be=0, %b[24]
        }
        {
          loop_mode
          qppermb,1,sm  %b[20], %b[19], %r36, %b[34]
          stqp,2        %r24, %b[4], %b[30]
          qppermb,4,sm  %b[20], %b[19], %r37, %b[33]
          stqp,5        %r25, %b[4], %b[29]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[31]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[32]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[29]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[30]
        }
        {
          loop_mode
          qppermb,1,sm  %b[16], %b[15], %r36, %b[38]
          stqp,2        %r26, %b[4], %b[34]
          qppermb,4,sm  %b[16], %b[15], %r37, %b[37]
          stqp,5        %r27, %b[4], %b[33]
          movaqp,0      area=2, ind=0, am=1, be=0, %b[35]
          movaqp,1      area=2, ind=16, am=0, be=0, %b[36]
          movaqp,2      area=2, ind=0, am=1, be=0, %b[33]
          movaqp,3      area=2, ind=16, am=0, be=0, %b[34]
        }
        {
          loop_mode
          addd,0,sm     %r5, 0x1, %r5
          qppermb,1,sm  %b[12], %b[11], %r36, %b[43]
          stqp,2        %r28, %b[4], %b[38]
          bitrevd,3,sm  %r5, %b[41]
          qppermb,4,sm  %b[12], %b[11], %r37, %b[42]
          stqp,5        %r29, %b[4], %b[37]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[39]
          movaqp,1      area=1, ind=16, am=0, be=0, %b[40]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[37]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[38]
        }
        {
          loop_mode
          qppermb,1,sm  %b[8], %b[7], %r36, %b[43]
          stqp,2        %r30, %b[4], %b[43]
          shrd,3,sm     %b[41], %r38, %b[41]
          qppermb,4,sm  %b[8], %b[7], %r37, %b[42]
          stqp,5        %r31, %b[4], %b[42]
        }
        {
          loop_mode
          qppermb,1,sm  %b[3], %b[2], %r36, %b[42]
          stqp,2        %r32, %b[4], %b[43]
          shld,3,sm     %b[41], 0x5, %b[2]
          qppermb,4,sm  %b[3], %b[2], %r37, %b[41]
          stqp,5        %r33, %b[4], %b[42]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[32], %b[31], %r37, %b[42]
          stqp,2        %r34, %b[4], %b[42]
          qppermb,3,sm  %b[30], %b[29], %r37, %b[41]
          stqp,5        %r35, %b[4], %b[41]
        }

Теоретическая скорость: 64 комплексных числа за 16 тактов (64/16) = 32 Байт/такт

Замеры скорости

Видим замедление по всей длине графика.

8. reverse_radix2_vector4_stream32

Чтение в 32 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix2_vector4_stream32(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_00000 = (__v2di*)&data_in[ 0 * count_in/32];
	__v2di *in_00001 = (__v2di*)&data_in[ 1 * count_in/32];
	__v2di *in_00010 = (__v2di*)&data_in[ 2 * count_in/32];
	__v2di *in_00011 = (__v2di*)&data_in[ 3 * count_in/32];
	__v2di *in_00100 = (__v2di*)&data_in[ 4 * count_in/32];
	__v2di *in_00101 = (__v2di*)&data_in[ 5 * count_in/32];
	__v2di *in_00110 = (__v2di*)&data_in[ 6 * count_in/32];
	__v2di *in_00111 = (__v2di*)&data_in[ 7 * count_in/32];
	__v2di *in_01000 = (__v2di*)&data_in[ 8 * count_in/32];
	__v2di *in_01001 = (__v2di*)&data_in[ 9 * count_in/32];
	__v2di *in_01010 = (__v2di*)&data_in[10 * count_in/32];
	__v2di *in_01011 = (__v2di*)&data_in[11 * count_in/32];
	__v2di *in_01100 = (__v2di*)&data_in[12 * count_in/32];
	__v2di *in_01101 = (__v2di*)&data_in[13 * count_in/32];
	__v2di *in_01110 = (__v2di*)&data_in[14 * count_in/32];
	__v2di *in_01111 = (__v2di*)&data_in[15 * count_in/32];
	__v2di *in_10000 = (__v2di*)&data_in[16 * count_in/32];
	__v2di *in_10001 = (__v2di*)&data_in[17 * count_in/32];
	__v2di *in_10010 = (__v2di*)&data_in[18 * count_in/32];
	__v2di *in_10011 = (__v2di*)&data_in[19 * count_in/32];
	__v2di *in_10100 = (__v2di*)&data_in[20 * count_in/32];
	__v2di *in_10101 = (__v2di*)&data_in[21 * count_in/32];
	__v2di *in_10110 = (__v2di*)&data_in[22 * count_in/32];
	__v2di *in_10111 = (__v2di*)&data_in[23 * count_in/32];
	__v2di *in_11000 = (__v2di*)&data_in[24 * count_in/32];
	__v2di *in_11001 = (__v2di*)&data_in[25 * count_in/32];
	__v2di *in_11010 = (__v2di*)&data_in[26 * count_in/32];
	__v2di *in_11011 = (__v2di*)&data_in[27 * count_in/32];
	__v2di *in_11100 = (__v2di*)&data_in[28 * count_in/32];
	__v2di *in_11101 = (__v2di*)&data_in[29 * count_in/32];
	__v2di *in_11110 = (__v2di*)&data_in[30 * count_in/32];
	__v2di *in_11111 = (__v2di*)&data_in[31 * count_in/32];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/32; ++i)
	{
		int64_t offset = 32 * (__builtin_e2k_bitrevd(i) >> shift_out);
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_00000[2*i+1], in_00000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_00000[2*i+1], in_00000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_10000[2*i+1], in_10000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_10000[2*i+1], in_10000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_01000[2*i+1], in_01000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_01000[2*i+1], in_01000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_11000[2*i+1], in_11000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_11000[2*i+1], in_11000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_00100[2*i+1], in_00100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_00100[2*i+1], in_00100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_10100[2*i+1], in_10100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_10100[2*i+1], in_10100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_01100[2*i+1], in_01100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_01100[2*i+1], in_01100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_11100[2*i+1], in_11100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_11100[2*i+1], in_11100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 16*16) = __builtin_e2k_qppermb(in_00010[2*i+1], in_00010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 17*16) = __builtin_e2k_qppermb(in_00010[2*i+1], in_00010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 18*16) = __builtin_e2k_qppermb(in_10010[2*i+1], in_10010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 19*16) = __builtin_e2k_qppermb(in_10010[2*i+1], in_10010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 20*16) = __builtin_e2k_qppermb(in_01010[2*i+1], in_01010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 21*16) = __builtin_e2k_qppermb(in_01010[2*i+1], in_01010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 22*16) = __builtin_e2k_qppermb(in_11010[2*i+1], in_11010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 23*16) = __builtin_e2k_qppermb(in_11010[2*i+1], in_11010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 24*16) = __builtin_e2k_qppermb(in_00110[2*i+1], in_00110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 25*16) = __builtin_e2k_qppermb(in_00110[2*i+1], in_00110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 26*16) = __builtin_e2k_qppermb(in_10110[2*i+1], in_10110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 27*16) = __builtin_e2k_qppermb(in_10110[2*i+1], in_10110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 28*16) = __builtin_e2k_qppermb(in_01110[2*i+1], in_01110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 29*16) = __builtin_e2k_qppermb(in_01110[2*i+1], in_01110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 30*16) = __builtin_e2k_qppermb(in_11110[2*i+1], in_11110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 31*16) = __builtin_e2k_qppermb(in_11110[2*i+1], in_11110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 32*16) = __builtin_e2k_qppermb(in_00001[2*i+1], in_00001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 33*16) = __builtin_e2k_qppermb(in_00001[2*i+1], in_00001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 34*16) = __builtin_e2k_qppermb(in_10001[2*i+1], in_10001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 35*16) = __builtin_e2k_qppermb(in_10001[2*i+1], in_10001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 36*16) = __builtin_e2k_qppermb(in_01001[2*i+1], in_01001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 37*16) = __builtin_e2k_qppermb(in_01001[2*i+1], in_01001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 38*16) = __builtin_e2k_qppermb(in_11001[2*i+1], in_11001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 39*16) = __builtin_e2k_qppermb(in_11001[2*i+1], in_11001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 40*16) = __builtin_e2k_qppermb(in_00101[2*i+1], in_00101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 41*16) = __builtin_e2k_qppermb(in_00101[2*i+1], in_00101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 42*16) = __builtin_e2k_qppermb(in_10101[2*i+1], in_10101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 43*16) = __builtin_e2k_qppermb(in_10101[2*i+1], in_10101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 44*16) = __builtin_e2k_qppermb(in_01101[2*i+1], in_01101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 45*16) = __builtin_e2k_qppermb(in_01101[2*i+1], in_01101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 46*16) = __builtin_e2k_qppermb(in_11101[2*i+1], in_11101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 47*16) = __builtin_e2k_qppermb(in_11101[2*i+1], in_11101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 48*16) = __builtin_e2k_qppermb(in_00011[2*i+1], in_00011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 49*16) = __builtin_e2k_qppermb(in_00011[2*i+1], in_00011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 50*16) = __builtin_e2k_qppermb(in_10011[2*i+1], in_10011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 51*16) = __builtin_e2k_qppermb(in_10011[2*i+1], in_10011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 52*16) = __builtin_e2k_qppermb(in_01011[2*i+1], in_01011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 53*16) = __builtin_e2k_qppermb(in_01011[2*i+1], in_01011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 54*16) = __builtin_e2k_qppermb(in_11011[2*i+1], in_11011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 55*16) = __builtin_e2k_qppermb(in_11011[2*i+1], in_11011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 56*16) = __builtin_e2k_qppermb(in_00111[2*i+1], in_00111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 57*16) = __builtin_e2k_qppermb(in_00111[2*i+1], in_00111[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 58*16) = __builtin_e2k_qppermb(in_10111[2*i+1], in_10111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 59*16) = __builtin_e2k_qppermb(in_10111[2*i+1], in_10111[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 60*16) = __builtin_e2k_qppermb(in_01111[2*i+1], in_01111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 61*16) = __builtin_e2k_qppermb(in_01111[2*i+1], in_01111[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 62*16) = __builtin_e2k_qppermb(in_11111[2*i+1], in_11111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 63*16) = __builtin_e2k_qppermb(in_11111[2*i+1], in_11111[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L13622:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=17, incr=1, ind=0, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=16, incr=1, ind=0, asz=1, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=15, incr=1, ind=0, asz=1, abs=2, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=14, incr=1, ind=0, asz=1, abs=2, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=13, incr=1, ind=0, asz=1, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=12, incr=1, ind=0, asz=1, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=11, incr=1, ind=0, asz=1, abs=6, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=10, incr=1, ind=0, asz=1, abs=6, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=9, incr=1, ind=0, asz=1, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=8, incr=1, ind=0, asz=1, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=7, incr=1, ind=0, asz=1, abs=10, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=6, incr=1, ind=0, asz=1, abs=10, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=5, incr=1, ind=0, asz=1, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=4, incr=1, ind=0, asz=1, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=3, incr=1, ind=0, asz=1, abs=14, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=2, incr=1, ind=0, asz=1, abs=14, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=1, incr=1, ind=0, asz=1, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=15, asz=1, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=14, asz=1, abs=18, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=13, asz=1, abs=18, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=12, asz=1, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=11, asz=1, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=10, asz=1, abs=22, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=9, asz=1, abs=22, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=8, asz=1, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=7, asz=1, abs=24, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=6, asz=1, abs=26, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=5, asz=1, abs=26, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=1, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=1, abs=28, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=1, abs=30, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=30, disp=0
        }
.L13394:
        {
          loop_mode
          disp  %ctpr1, .L13394
          bitrevd,0     %r1, %g20
          addd,1        %r1, 0x1, %r1
          movaqp,0      area=0, ind=16, am=1, be=0, %g17
          movaqp,1      area=0, ind=0, am=0, be=0, %g16
          movaqp,2      area=0, ind=16, am=1, be=0, %g19
          movaqp,3      area=0, ind=0, am=0, be=0, %g18
        }
        {
          loop_mode
          disp  %ctpr3, .L12302
          shrd,0        %g20, %r6, %g20
          movaqp,0      area=1, ind=16, am=1, be=0, %g22
          movaqp,1      area=1, ind=0, am=0, be=0, %g21
          movaqp,2      area=1, ind=16, am=1, be=0, %g24
          movaqp,3      area=1, ind=0, am=0, be=0, %g23
        }
        {
          loop_mode
          shld,0        %g20, 0x5, %g20
          movaqp,0      area=2, ind=16, am=1, be=0, %g26
          movaqp,1      area=2, ind=0, am=0, be=0, %g25
          movaqp,2      area=2, ind=16, am=1, be=0, %g28
          movaqp,3      area=2, ind=0, am=0, be=0, %g27
        }
        {
          loop_mode
          addd,0        %r2, %g20, %r7
          movaqp,0      area=3, ind=16, am=1, be=0, %g30
          movaqp,1      area=3, ind=0, am=0, be=0, %g29
          movaqp,2      area=3, ind=16, am=1, be=0, %r4
          movaqp,3      area=3, ind=0, am=0, be=0, %g31
        }
        {
          loop_mode
          movaqp,0      area=4, ind=16, am=1, be=0, %r10
          movaqp,1      area=4, ind=0, am=0, be=0, %r9
          movaqp,2      area=4, ind=16, am=1, be=0, %r12
          movaqp,3      area=4, ind=0, am=0, be=0, %r11
        }
        {
          loop_mode
          qppermb,0     %g17, %g16, %r0, %r17
          qppermb,1     %g17, %g16, %r5, %g16
          qppermb,3     %g19, %g18, %r0, %g17
          qppermb,4     %g19, %g18, %r5, %g18
          movaqp,0      area=5, ind=16, am=1, be=0, %r14
          movaqp,1      area=5, ind=0, am=0, be=0, %r13
          movaqp,2      area=5, ind=16, am=1, be=0, %r16
          movaqp,3      area=5, ind=0, am=0, be=0, %r15
        }
        {
          loop_mode
          qppermb,0     %g22, %g21, %r0, %r21
          qppermb,1     %g22, %g21, %r5, %g21
          stqp,2        0x10, %r7, %g16
          qppermb,3     %g24, %g23, %r0, %g22
          qppermb,4     %g24, %g23, %r5, %g23
          stqp,5        %r7, _f16s,_lts0lo 0x30, %g18
          movaqp,0      area=6, ind=16, am=1, be=0, %r18
          movaqp,1      area=6, ind=0, am=0, be=0, %g19
          movaqp,2      area=6, ind=16, am=1, be=0, %r20
          movaqp,3      area=6, ind=0, am=0, be=0, %r19
        }
        {
          loop_mode
          qppermb,0     %g26, %g25, %r0, %g17
          qppermb,1     %g26, %g25, %r5, %g20
          stqp,2        %r2, %g20, %r17
          qppermb,3     %g28, %g27, %r0, %g25
          qppermb,4     %g28, %g27, %r5, %g26
          stqp,5        %r7, _f16s,_lts0lo 0x20, %g17
          movaqp,0      area=7, ind=16, am=1, be=0, %g18
          movaqp,1      area=7, ind=0, am=0, be=0, %g16
          movaqp,2      area=7, ind=16, am=1, be=0, %r22
          movaqp,3      area=7, ind=0, am=0, be=0, %g24
        }
        {
          loop_mode
          qppermb,0     %g30, %g29, %r0, %r24
          qppermb,1     %g30, %g29, %r5, %g29
          stqp,2        %r7, _f16s,_lts0lo 0x50, %g21
          qppermb,3     %r4, %g31, %r0, %g21
          qppermb,4     %r4, %g31, %r5, %g23
          stqp,5        %r7, _f16s,_lts0hi 0x70, %g23
          movaqp,0      area=8, ind=16, am=1, be=0, %g28
          movaqp,1      area=8, ind=0, am=0, be=0, %g27
          movaqp,2      area=8, ind=16, am=1, be=0, %r23
          movaqp,3      area=8, ind=0, am=0, be=0, %r17
        }
        {
          loop_mode
          qppermb,0     %r10, %r9, %r0, %g22
          qppermb,1     %r10, %r9, %r5, %r9
          stqp,2        %r7, _f16s,_lts0lo 0x40, %r21
          qppermb,3     %r12, %r11, %r0, %r10
          qppermb,4     %r12, %r11, %r5, %r11
          stqp,5        %r7, _f16s,_lts0hi 0x60, %g22
          movaqp,0      area=9, ind=16, am=1, be=0, %g31
          movaqp,1      area=9, ind=0, am=0, be=0, %g30
          movaqp,2      area=9, ind=16, am=1, be=0, %r25
          movaqp,3      area=9, ind=0, am=0, be=0, %r4
        }
        {
          loop_mode
          qppermb,0     %r14, %r13, %r0, %g17
          qppermb,1     %r14, %r13, %r5, %g20
          stqp,2        %r7, _f16s,_lts0lo 0x80, %g17
          qppermb,3     %r16, %r15, %r0, %r13
          qppermb,4     %r16, %r15, %r5, %r14
          stqp,5        %r7, _f16s,_lts0hi 0x90, %g20
          movaqp,0      area=10, ind=16, am=1, be=0, %r21
          movaqp,1      area=10, ind=0, am=0, be=0, %r12
          movaqp,2      area=10, ind=16, am=1, be=0, %r27
          movaqp,3      area=10, ind=0, am=0, be=0, %r26
        }
        {
          loop_mode
          qppermb,0     %r18, %g19, %r0, %r28
          qppermb,1     %r18, %g19, %r5, %g19
          stqp,2        %r7, _f16s,_lts0lo 0xa0, %g25
          qppermb,3     %r20, %r19, %r0, %r18
          qppermb,4     %r20, %r19, %r5, %r19
          stqp,5        %r7, _f16s,_lts0hi 0xb0, %g26
          movaqp,0      area=11, ind=16, am=1, be=0, %r16
          movaqp,1      area=11, ind=0, am=0, be=0, %r15
          movaqp,2      area=11, ind=16, am=1, be=0, %g26
          movaqp,3      area=11, ind=0, am=0, be=0, %g25
        }
        {
          loop_mode
          qppermb,0     %g18, %g16, %r0, %r30
          qppermb,1     %g18, %g16, %r5, %g16
          stqp,2        %r7, _f16s,_lts0lo 0xc0, %r24
          qppermb,3     %r22, %g24, %r0, %g18
          qppermb,4     %r22, %g24, %r5, %g24
          stqp,5        %r7, _f16s,_lts0hi 0xd0, %g29
          movaqp,0      area=12, ind=16, am=1, be=0, %r20
          movaqp,1      area=12, ind=0, am=0, be=0, %g29
          movaqp,2      area=12, ind=16, am=1, be=0, %r29
          movaqp,3      area=12, ind=0, am=0, be=0, %r24
        }
        {
          loop_mode
          qppermb,0     %g28, %g27, %r0, %r32
          qppermb,1     %g28, %g27, %r5, %g27
          stqp,2        %r7, _f16s,_lts0lo 0xe0, %g21
          qppermb,3     %r23, %r17, %r0, %g28
          qppermb,4     %r23, %r17, %r5, %r17
          stqp,5        %r7, _f16s,_lts0hi 0xf0, %g23
          movaqp,0      area=13, ind=16, am=1, be=0, %g23
          movaqp,1      area=13, ind=0, am=0, be=0, %g21
          movaqp,2      area=13, ind=16, am=1, be=0, %r31
          movaqp,3      area=13, ind=0, am=0, be=0, %r22
        }
        {
          loop_mode
          qppermb,0     %g31, %g30, %r0, %r34
          qppermb,1     %g31, %g30, %r5, %g30
          stqp,2        %r7, _f16s,_lts0lo 0x100, %g22
          qppermb,3     %r25, %r4, %r0, %g31
          qppermb,4     %r25, %r4, %r5, %r4
          stqp,5        %r7, _f16s,_lts0hi 0x110, %r9
          movaqp,0      area=14, ind=16, am=1, be=0, %r9
          movaqp,1      area=14, ind=0, am=0, be=0, %g22
          movaqp,2      area=14, ind=16, am=1, be=0, %r33
          movaqp,3      area=14, ind=0, am=0, be=0, %r23
        }
        {
          loop_mode
          qppermb,0     %r21, %r12, %r0, %r36
          qppermb,1     %r21, %r12, %r5, %r12
          stqp,2        %r7, _f16s,_lts0lo 0x120, %r10
          qppermb,3     %r27, %r26, %r0, %r21
          qppermb,4     %r27, %r26, %r5, %r26
          stqp,5        %r7, _f16s,_lts0hi 0x130, %r11
          movaqp,0      area=15, ind=16, am=1, be=0, %r11
          movaqp,1      area=15, ind=0, am=0, be=0, %r10
          movaqp,2      area=15, ind=16, am=1, be=0, %r35
          movaqp,3      area=15, ind=0, am=0, be=0, %r25
        }
        {
          loop_mode
          qppermb,0     %r16, %r15, %r0, %g17
          qppermb,1     %r16, %r15, %r5, %g20
          stqp,2        %r7, _f16s,_lts0lo 0x140, %g17
          qppermb,3     %g26, %g25, %r0, %r15
          qppermb,4     %g26, %g25, %r5, %g25
          stqp,5        %r7, _f16s,_lts0hi 0x150, %g20
        }
        {
          loop_mode
          qppermb,0     %r20, %g29, %r0, %g26
          qppermb,1     %r20, %g29, %r5, %g29
          stqp,2        %r7, _f16s,_lts0lo 0x160, %r13
          qppermb,3     %r29, %r24, %r0, %r13
          qppermb,4     %r29, %r24, %r5, %r14
          stqp,5        %r7, _f16s,_lts0hi 0x170, %r14
        }
        {
          loop_mode
          qppermb,0     %g23, %g21, %r0, %g19
          qppermb,1     %g23, %g21, %r5, %g21
          stqp,2        %r7, _f16s,_lts0lo 0x180, %r28
          qppermb,3     %r31, %r22, %r0, %g23
          qppermb,4     %r31, %r22, %r5, %r16
          stqp,5        %r7, _f16s,_lts0hi 0x190, %g19
        }
        {
          loop_mode
          qppermb,0     %r9, %g22, %r0, %r18
          qppermb,1     %r9, %g22, %r5, %g22
          stqp,2        %r7, _f16s,_lts0lo 0x1a0, %r18
          qppermb,3     %r33, %r23, %r0, %r9
          qppermb,4     %r33, %r23, %r5, %r19
          stqp,5        %r7, _f16s,_lts0hi 0x1b0, %r19
        }
        {
          loop_mode
          qppermb,0     %r11, %r10, %r0, %g16
          qppermb,1     %r11, %r10, %r5, %r10
          stqp,2        %r7, _f16s,_lts0lo 0x1c0, %r30
          qppermb,3     %r35, %r25, %r0, %r11
          qppermb,4     %r35, %r25, %r5, %r20
          stqp,5        %r7, _f16s,_lts0hi 0x1d0, %g16
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x1e0, %g18
          stqp,5        %r7, _f16s,_lts0hi 0x1f0, %g24
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x200, %r32
          stqp,5        %r7, _f16s,_lts0hi 0x210, %g27
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x220, %g28
          stqp,5        %r7, _f16s,_lts0hi 0x230, %r17
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x240, %r34
          stqp,5        %r7, _f16s,_lts0hi 0x250, %g30
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x260, %g31
          stqp,5        %r7, _f16s,_lts0hi 0x270, %r4
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x280, %r36
          stqp,5        %r7, _f16s,_lts0hi 0x290, %r12
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x2a0, %r21
          stqp,5        %r7, _f16s,_lts0hi 0x2b0, %r26
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x2c0, %g17
          stqp,5        %r7, _f16s,_lts0hi 0x2d0, %g20
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x2e0, %r15
          stqp,5        %r7, _f16s,_lts0hi 0x2f0, %g25
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x300, %g26
          stqp,5        %r7, _f16s,_lts0hi 0x310, %g29
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x320, %r13
          stqp,5        %r7, _f16s,_lts0hi 0x330, %r14
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x340, %g19
          stqp,5        %r7, _f16s,_lts0hi 0x350, %g21
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x360, %g23
          stqp,5        %r7, _f16s,_lts0hi 0x370, %r16
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x380, %r18
          stqp,5        %r7, _f16s,_lts0hi 0x390, %g22
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x3a0, %r9
          stqp,5        %r7, _f16s,_lts0hi 0x3b0, %r19
        }
        {
          loop_mode
          stqp,2        %r7, _f16s,_lts0lo 0x3c0, %g16
          stqp,5        %r7, _f16s,_lts0hi 0x3d0, %r10
        }
        {
          loop_mode
          ct    %ctpr1 ? %NOT_LOOP_END
          alc   alcf=0, alct=1
          stqp,2        %r7, _f16s,_lts0lo 0x3e0, %r11
          stqp,5        %r7, _f16s,_lts0hi 0x3f0, %r20
        }
        {
          loop_mode
          ct    %ctpr3
          alc   alcf=0, alct=1
        }

Теоретическая скорость: 128 комплексных чисел за 39 тактов (128/39) = 26.26 Байт/такт

Замеры скорости

Видим замедление по всей длине графика.

При попытке чтения в 64 потока получается резко менее эффективный код.
APB не может читать в 64 потока, поэтому в дополнение к APB компилятор вставляет обычные операции чтения ldqp. В итоге скорость резко проседает.

Итоги по reverse_radix2_vector4

Победителем можно считать reverse_radix2_vector4_stream8.

При реализации Vector-4 Radix-2 FFT будем использовать его.

reverse_radix4_vector2

1. reverse_radix4_vector2_etalon

Эталонный вариант для сравнения на корректность.
Здесь reverseNumber_radix4 вычисляется с помощью цикла.

int reverseNumber_radix4(int number, int bit_count)
{
	int answer = 0;

	for(int i = 0; i < bit_count/2; ++i)
	{
		answer <<= 2;
		answer |= number & 3;
		number >>= 2;
	}

	return answer;
}


void reverse_radix4_vector2_etalon(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;

	for(int64_t i = 0; i < count_out; ++i)
	{
		int index = reverseNumber_radix4(i, bit_count_out);
		myComplex a = data_in[2*i + 0];
		myComplex b = data_in[2*i + 1];
		data_out[index] = (myComplex2){.real = {a.real, b.real}, .imag = {a.imag, b.imag}};
	}
}

2. reverse_radix4_vector2

В процессоре нет готовых инструкций, производящих операцию reverseNumber_radix4.
Поэтому выполним инструкцию bitrevd и переставим соседние биты местами.

Код на Си
void reverse_radix4_vector2(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in = (__v2di*)data_in;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 16 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset) = __builtin_e2k_qppermb(in[i], in[i], mask);
	}
}
Основной цикл на ассемблере
.L4546:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=5, abs=0, disp=0
        }
.L4397:
        {
          loop_mode
          bitrevd,0,sm  %b[10], %b[1]
          shr_andd,1,sm %b[3], %r5, %r6, %b[9]
          ord,2,sm      %b[11], %b[7], %b[12]
          shld,3,sm     %b[14], 0x4, %b[15]
          qppermb,4,sm  %b[6], %b[6], %r0, %b[13]
          addd,5,sm     %b[10], 0x1, %b[8]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[0]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          shr_andd,1,sm %b[1], %r4, %r7, %b[3]
          stqp,5        %r2, %b[15], %b[13]
        }

Теоретическая скорость: 2 комплексных числа за 2 такта (2/2) = 8 Байт/такт

Замеры скорости

3. reverse_radix4_vector2_x4

Сделаем ручную раскрутку цикла в 4 раза.

Код на Си
void reverse_radix4_vector2_x4(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in    = (__v2di*) data_in;
	__v2di *out_0 = (__v2di*)&data_out[0 * count_out/4];
	__v2di *out_1 = (__v2di*)&data_out[1 * count_out/4];
	__v2di *out_2 = (__v2di*)&data_out[2 * count_out/4];
	__v2di *out_3 = (__v2di*)&data_out[3 * count_out/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out; i += 4)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 16 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)out_0 + offset) = __builtin_e2k_qppermb(in[i + 0], in[i + 0], mask);
		*(__v2du*)((void*)out_1 + offset) = __builtin_e2k_qppermb(in[i + 1], in[i + 1], mask);
		*(__v2du*)((void*)out_2 + offset) = __builtin_e2k_qppermb(in[i + 2], in[i + 2], mask);
		*(__v2du*)((void*)out_3 + offset) = __builtin_e2k_qppermb(in[i + 3], in[i + 3], mask);
	}
}
Основной цикл на ассемблере
.L4888:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=32
        }
.L4593:
        {
          loop_mode
          qppermb,0,sm  %b[11], %b[11], %r7, %b[20]
          shr_andd,1,sm %b[26], %r9, %r11, %b[16]
          qppermb,3,sm  %b[12], %b[12], %r7, %b[23]
          shr_andd,4,sm %b[26], %r6, %r10, %b[19]
          addd,5,sm     %b[17], 0x4, %b[15]
          movaqp,0      area=0, ind=16, am=1, be=0, %b[7]
          movaqp,1      area=0, ind=0, am=0, be=0, %b[8]
          movaqp,2      area=0, ind=16, am=1, be=0, %b[0]
          movaqp,3      area=0, ind=0, am=0, be=0, %b[1]
        }
        {
          loop_mode
          bitrevd,0,sm  %b[17], %b[24]
          qppermb,1,sm  %b[4], %b[4], %r7, %b[11]
          stqp,2        %r5, %b[6], %b[22]
          ord,3,sm      %b[21], %b[18], %b[27]
          qppermb,4,sm  %b[5], %b[5], %r7, %b[12]
          stqp,5        %r2, %b[6], %b[25]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          stqp,2        %r0, %b[6], %b[13]
          shld,4,sm     %b[27], 0x4, %b[4]
          stqp,5        %r4, %b[6], %b[14]
        }

Теоретическая скорость: 8 комплексных чисел за 3 такта (8/3) = 21.33 Байт/такт

Замеры скорости

Видим ускорение в начале графика.

Здесь происходит четыре чтения из одного места памяти и запись в четыре разных места памяти.

4. reverse_radix4_vector2_stream4

Теперь сделаем наоборот: будем читать из четырёх разных мест, а писать рядом.
Чтение в 4 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix4_vector2_stream4(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_0 = (__v2di*)&data_in[0 * count_in/4];
	__v2di *in_1 = (__v2di*)&data_in[1 * count_in/4];
	__v2di *in_2 = (__v2di*)&data_in[2 * count_in/4];
	__v2di *in_3 = (__v2di*)&data_in[3 * count_in/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/4; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 16 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_0[i], in_0[i], mask);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_1[i], in_1[i], mask);
		*(__v2du*)((void*)data_out + offset + 2*16) = __builtin_e2k_qppermb(in_2[i], in_2[i], mask);
		*(__v2du*)((void*)data_out + offset + 3*16) = __builtin_e2k_qppermb(in_3[i], in_3[i], mask);
	}
}
Основной цикл на ассемблере
.L5211:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=4, abs=0, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=4, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=4, abs=16, disp=0
        }
.L4931:
        {
          loop_mode
          qppermb,0,sm  %b[11], %b[11], %r7, %b[20]
          shr_andd,1,sm %b[26], %r9, %r11, %b[16]
          qppermb,3,sm  %b[12], %b[12], %r7, %b[23]
          shr_andd,4,sm %b[26], %r6, %r10, %b[19]
          addd,5,sm     %b[17], 0x1, %b[15]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[1]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[8]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[0]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[7]
        }
        {
          loop_mode
          bitrevd,0,sm  %b[17], %b[24]
          qppermb,1,sm  %b[4], %b[4], %r7, %b[11]
          stqp,2        %r0, %b[6], %b[22]
          ord,3,sm      %b[21], %b[18], %b[27]
          qppermb,4,sm  %b[5], %b[5], %r7, %b[12]
          stqp,5        %r2, %b[6], %b[25]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          stqp,2        %r5, %b[6], %b[13]
          shld,4,sm     %b[27], 0x4, %b[4]
          stqp,5        %r4, %b[6], %b[14]
        }

Теоретическая скорость: 8 комплексных чисел за 3 такта (8/3) = 21.33 Байт/такт

Замеры скорости

Видим желаемое ускорение по всей длине графика.

5. reverse_radix4_vector2_stream16

Чтение в 16 потоков из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix4_vector2_stream16(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_00 = (__v2di*)&data_in[ 0 * count_in/16];
	__v2di *in_01 = (__v2di*)&data_in[ 1 * count_in/16];
	__v2di *in_02 = (__v2di*)&data_in[ 2 * count_in/16];
	__v2di *in_03 = (__v2di*)&data_in[ 3 * count_in/16];
	__v2di *in_10 = (__v2di*)&data_in[ 4 * count_in/16];
	__v2di *in_11 = (__v2di*)&data_in[ 5 * count_in/16];
	__v2di *in_12 = (__v2di*)&data_in[ 6 * count_in/16];
	__v2di *in_13 = (__v2di*)&data_in[ 7 * count_in/16];
	__v2di *in_20 = (__v2di*)&data_in[ 8 * count_in/16];
	__v2di *in_21 = (__v2di*)&data_in[ 9 * count_in/16];
	__v2di *in_22 = (__v2di*)&data_in[10 * count_in/16];
	__v2di *in_23 = (__v2di*)&data_in[11 * count_in/16];
	__v2di *in_30 = (__v2di*)&data_in[12 * count_in/16];
	__v2di *in_31 = (__v2di*)&data_in[13 * count_in/16];
	__v2di *in_32 = (__v2di*)&data_in[14 * count_in/16];
	__v2di *in_33 = (__v2di*)&data_in[15 * count_in/16];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/16; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 16 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_00[i], in_00[i], mask);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_10[i], in_10[i], mask);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_20[i], in_20[i], mask);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_30[i], in_30[i], mask);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_01[i], in_01[i], mask);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_11[i], in_11[i], mask);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_21[i], in_21[i], mask);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_31[i], in_31[i], mask);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_02[i], in_02[i], mask);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_12[i], in_12[i], mask);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_22[i], in_22[i], mask);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_32[i], in_32[i], mask);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_03[i], in_03[i], mask);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_13[i], in_13[i], mask);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_23[i], in_23[i], mask);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_33[i], in_33[i], mask);
	}
}
Основной цикл на ассемблере
.L6141:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=1, incr=0, ind=0, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=15, asz=2, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=14, asz=2, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=13, asz=2, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=12, asz=2, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=11, asz=2, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=10, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=9, asz=2, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=8, asz=2, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=7, asz=2, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=6, asz=2, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=5, asz=2, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=2, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=2, abs=24, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=2, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=2, abs=28, disp=0
        }
.L5350:
        {
          loop_mode
          qppermb,0,sm  %b[12], %b[12], %r20, %b[46]
          shr_andd,1,sm %b[24], %r21, %r24, %b[1]
          stqp,2        %r0, %b[21], %b[4]
          qppermb,3,sm  %b[17], %b[17], %r20, %b[47]
          shr_andd,4,sm %b[24], %r22, %r23, %b[5]
          stqp,5        %r2, %b[21], %b[16]
        }
        {
          loop_mode
          qppermb,1,sm  %b[41], %b[41], %r20, %b[4]
          stqp,2        %r6, %b[21], %b[46]
          qppermb,4,sm  %b[42], %b[42], %r20, %b[9]
          stqp,5        %r5, %b[21], %b[47]
        }
        {
          loop_mode
          qppermb,1,sm  %b[40], %b[40], %r20, %b[24]
          stqp,2        %r10, %b[21], %b[6]
          qppermb,4,sm  %b[39], %b[39], %r20, %b[23]
          stqp,5        %r7, %b[21], %b[11]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[16]
          movaqp,1      area=6, ind=0, am=1, be=0, %b[20]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[12]
          movaqp,3      area=6, ind=0, am=1, be=0, %b[17]
        }
        {
          loop_mode
          qppermb,1,sm  %b[38], %b[38], %r20, %b[30]
          stqp,2        %r9, %b[21], %b[26]
          qppermb,4,sm  %b[37], %b[37], %r20, %b[29]
          stqp,5        %r11, %b[21], %b[25]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[11]
          movaqp,1      area=4, ind=0, am=1, be=0, %b[36]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[6]
          movaqp,3      area=4, ind=0, am=1, be=0, %b[35]
        }
        {
          loop_mode
          qppermb,1,sm  %b[13], %b[13], %r20, %b[26]
          stqp,2        %r12, %b[21], %b[32]
          qppermb,4,sm  %b[8], %b[8], %r20, %b[25]
          stqp,5        %r13, %b[21], %b[31]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[39]
          movaqp,1      area=2, ind=0, am=1, be=0, %b[40]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[37]
          movaqp,3      area=2, ind=0, am=1, be=0, %b[38]
        }
        {
          loop_mode
          addd,0,sm     %b[2], 0x1, %b[0]
          qppermb,1,sm  %b[22], %b[22], %r20, %b[42]
          stqp,2        %r14, %b[21], %b[28]
          ord,3,sm      %b[5], %b[1], %b[45]
          qppermb,4,sm  %b[19], %b[19], %r20, %b[41]
          stqp,5        %r15, %b[21], %b[27]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[13]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[32]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[8]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[31]
        }
        {
          loop_mode
          bitrevd,0,sm  %b[2], %b[22]
          qppermb,1,sm  %b[18], %b[18], %r20, %b[5]
          stqp,2        %r16, %b[21], %b[44]
          shld,3,sm     %b[45], 0x4, %b[19]
          qppermb,4,sm  %b[14], %b[14], %r20, %b[1]
          stqp,5        %r17, %b[21], %b[43]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[33], %b[33], %r20, %b[2]
          stqp,2        %r18, %b[21], %b[7]
          qppermb,3,sm  %b[34], %b[34], %r20, %b[14]
          stqp,5        %r19, %b[21], %b[3]
        }

Теоретическая скорость: 32 комплексных числа за 8 тактов (32/8) = 32 Байт/такт

Замеры скорости

Видим сильное ускорение.

При попытке чтения в 64 потока получается резко менее эффективный код.
APB не может читать в 64 потока, поэтому в дополнение к APB компилятор вставляет обычные операции чтения ldqp. В итоге скорость резко проседает.

Но можно сделать чтение в 32 потока. Для этого напишем чтение в 64 потока и обработаем сначала одну половину строк в одном цикле, а потом вторую половину строк во втором цикле. В каждом цикле будут использованы 32 потока чтения APB.

6. reverse_radix4_vector2_stream32

Чтение в 32 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix4_vector2_stream32(int bit_count_in, myComplex *data_in, myComplex2 *data_out)
{
	int bit_count_out = bit_count_in - 1;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_000 = (__v2di*)&data_in[ 0 * count_in/64];
	__v2di *in_001 = (__v2di*)&data_in[ 1 * count_in/64];
	__v2di *in_002 = (__v2di*)&data_in[ 2 * count_in/64];
	__v2di *in_003 = (__v2di*)&data_in[ 3 * count_in/64];
	__v2di *in_010 = (__v2di*)&data_in[ 4 * count_in/64];
	__v2di *in_011 = (__v2di*)&data_in[ 5 * count_in/64];
	__v2di *in_012 = (__v2di*)&data_in[ 6 * count_in/64];
	__v2di *in_013 = (__v2di*)&data_in[ 7 * count_in/64];
	__v2di *in_020 = (__v2di*)&data_in[ 8 * count_in/64];
	__v2di *in_021 = (__v2di*)&data_in[ 9 * count_in/64];
	__v2di *in_022 = (__v2di*)&data_in[10 * count_in/64];
	__v2di *in_023 = (__v2di*)&data_in[11 * count_in/64];
	__v2di *in_030 = (__v2di*)&data_in[12 * count_in/64];
	__v2di *in_031 = (__v2di*)&data_in[13 * count_in/64];
	__v2di *in_032 = (__v2di*)&data_in[14 * count_in/64];
	__v2di *in_033 = (__v2di*)&data_in[15 * count_in/64];
	__v2di *in_100 = (__v2di*)&data_in[16 * count_in/64];
	__v2di *in_101 = (__v2di*)&data_in[17 * count_in/64];
	__v2di *in_102 = (__v2di*)&data_in[18 * count_in/64];
	__v2di *in_103 = (__v2di*)&data_in[19 * count_in/64];
	__v2di *in_110 = (__v2di*)&data_in[20 * count_in/64];
	__v2di *in_111 = (__v2di*)&data_in[21 * count_in/64];
	__v2di *in_112 = (__v2di*)&data_in[22 * count_in/64];
	__v2di *in_113 = (__v2di*)&data_in[23 * count_in/64];
	__v2di *in_120 = (__v2di*)&data_in[24 * count_in/64];
	__v2di *in_121 = (__v2di*)&data_in[25 * count_in/64];
	__v2di *in_122 = (__v2di*)&data_in[26 * count_in/64];
	__v2di *in_123 = (__v2di*)&data_in[27 * count_in/64];
	__v2di *in_130 = (__v2di*)&data_in[28 * count_in/64];
	__v2di *in_131 = (__v2di*)&data_in[29 * count_in/64];
	__v2di *in_132 = (__v2di*)&data_in[30 * count_in/64];
	__v2di *in_133 = (__v2di*)&data_in[31 * count_in/64];
	__v2di *in_200 = (__v2di*)&data_in[32 * count_in/64];
	__v2di *in_201 = (__v2di*)&data_in[33 * count_in/64];
	__v2di *in_202 = (__v2di*)&data_in[34 * count_in/64];
	__v2di *in_203 = (__v2di*)&data_in[35 * count_in/64];
	__v2di *in_210 = (__v2di*)&data_in[36 * count_in/64];
	__v2di *in_211 = (__v2di*)&data_in[37 * count_in/64];
	__v2di *in_212 = (__v2di*)&data_in[38 * count_in/64];
	__v2di *in_213 = (__v2di*)&data_in[39 * count_in/64];
	__v2di *in_220 = (__v2di*)&data_in[40 * count_in/64];
	__v2di *in_221 = (__v2di*)&data_in[41 * count_in/64];
	__v2di *in_222 = (__v2di*)&data_in[42 * count_in/64];
	__v2di *in_223 = (__v2di*)&data_in[43 * count_in/64];
	__v2di *in_230 = (__v2di*)&data_in[44 * count_in/64];
	__v2di *in_231 = (__v2di*)&data_in[45 * count_in/64];
	__v2di *in_232 = (__v2di*)&data_in[46 * count_in/64];
	__v2di *in_233 = (__v2di*)&data_in[47 * count_in/64];
	__v2di *in_300 = (__v2di*)&data_in[48 * count_in/64];
	__v2di *in_301 = (__v2di*)&data_in[49 * count_in/64];
	__v2di *in_302 = (__v2di*)&data_in[50 * count_in/64];
	__v2di *in_303 = (__v2di*)&data_in[51 * count_in/64];
	__v2di *in_310 = (__v2di*)&data_in[52 * count_in/64];
	__v2di *in_311 = (__v2di*)&data_in[53 * count_in/64];
	__v2di *in_312 = (__v2di*)&data_in[54 * count_in/64];
	__v2di *in_313 = (__v2di*)&data_in[55 * count_in/64];
	__v2di *in_320 = (__v2di*)&data_in[56 * count_in/64];
	__v2di *in_321 = (__v2di*)&data_in[57 * count_in/64];
	__v2di *in_322 = (__v2di*)&data_in[58 * count_in/64];
	__v2di *in_323 = (__v2di*)&data_in[59 * count_in/64];
	__v2di *in_330 = (__v2di*)&data_in[60 * count_in/64];
	__v2di *in_331 = (__v2di*)&data_in[61 * count_in/64];
	__v2di *in_332 = (__v2di*)&data_in[62 * count_in/64];
	__v2di *in_333 = (__v2di*)&data_in[63 * count_in/64];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/32/2; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 16 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_000[i], in_000[i], mask);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_100[i], in_100[i], mask);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_200[i], in_200[i], mask);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_300[i], in_300[i], mask);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_010[i], in_010[i], mask);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_110[i], in_110[i], mask);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_210[i], in_210[i], mask);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_310[i], in_310[i], mask);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_020[i], in_020[i], mask);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_120[i], in_120[i], mask);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_220[i], in_220[i], mask);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_320[i], in_320[i], mask);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_030[i], in_030[i], mask);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_130[i], in_130[i], mask);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_230[i], in_230[i], mask);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_330[i], in_330[i], mask);
		*(__v2du*)((void*)data_out + offset + 16*16) = __builtin_e2k_qppermb(in_001[i], in_001[i], mask);
		*(__v2du*)((void*)data_out + offset + 17*16) = __builtin_e2k_qppermb(in_101[i], in_101[i], mask);
		*(__v2du*)((void*)data_out + offset + 18*16) = __builtin_e2k_qppermb(in_201[i], in_201[i], mask);
		*(__v2du*)((void*)data_out + offset + 19*16) = __builtin_e2k_qppermb(in_301[i], in_301[i], mask);
		*(__v2du*)((void*)data_out + offset + 20*16) = __builtin_e2k_qppermb(in_011[i], in_011[i], mask);
		*(__v2du*)((void*)data_out + offset + 21*16) = __builtin_e2k_qppermb(in_111[i], in_111[i], mask);
		*(__v2du*)((void*)data_out + offset + 22*16) = __builtin_e2k_qppermb(in_211[i], in_211[i], mask);
		*(__v2du*)((void*)data_out + offset + 23*16) = __builtin_e2k_qppermb(in_311[i], in_311[i], mask);
		*(__v2du*)((void*)data_out + offset + 24*16) = __builtin_e2k_qppermb(in_021[i], in_021[i], mask);
		*(__v2du*)((void*)data_out + offset + 25*16) = __builtin_e2k_qppermb(in_121[i], in_121[i], mask);
		*(__v2du*)((void*)data_out + offset + 26*16) = __builtin_e2k_qppermb(in_221[i], in_221[i], mask);
		*(__v2du*)((void*)data_out + offset + 27*16) = __builtin_e2k_qppermb(in_321[i], in_321[i], mask);
		*(__v2du*)((void*)data_out + offset + 28*16) = __builtin_e2k_qppermb(in_031[i], in_031[i], mask);
		*(__v2du*)((void*)data_out + offset + 29*16) = __builtin_e2k_qppermb(in_131[i], in_131[i], mask);
		*(__v2du*)((void*)data_out + offset + 30*16) = __builtin_e2k_qppermb(in_231[i], in_231[i], mask);
		*(__v2du*)((void*)data_out + offset + 31*16) = __builtin_e2k_qppermb(in_331[i], in_331[i], mask);
	}

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/32/2; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 16 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask = {0x0B0A090803020100, 0x0F0E0D0C07060504};
		*(__v2du*)((void*)data_out + offset + 32*16) = __builtin_e2k_qppermb(in_002[i], in_002[i], mask);
		*(__v2du*)((void*)data_out + offset + 33*16) = __builtin_e2k_qppermb(in_102[i], in_102[i], mask);
		*(__v2du*)((void*)data_out + offset + 34*16) = __builtin_e2k_qppermb(in_202[i], in_202[i], mask);
		*(__v2du*)((void*)data_out + offset + 35*16) = __builtin_e2k_qppermb(in_302[i], in_302[i], mask);
		*(__v2du*)((void*)data_out + offset + 36*16) = __builtin_e2k_qppermb(in_012[i], in_012[i], mask);
		*(__v2du*)((void*)data_out + offset + 37*16) = __builtin_e2k_qppermb(in_112[i], in_112[i], mask);
		*(__v2du*)((void*)data_out + offset + 38*16) = __builtin_e2k_qppermb(in_212[i], in_212[i], mask);
		*(__v2du*)((void*)data_out + offset + 39*16) = __builtin_e2k_qppermb(in_312[i], in_312[i], mask);
		*(__v2du*)((void*)data_out + offset + 40*16) = __builtin_e2k_qppermb(in_022[i], in_022[i], mask);
		*(__v2du*)((void*)data_out + offset + 41*16) = __builtin_e2k_qppermb(in_122[i], in_122[i], mask);
		*(__v2du*)((void*)data_out + offset + 42*16) = __builtin_e2k_qppermb(in_222[i], in_222[i], mask);
		*(__v2du*)((void*)data_out + offset + 43*16) = __builtin_e2k_qppermb(in_322[i], in_322[i], mask);
		*(__v2du*)((void*)data_out + offset + 44*16) = __builtin_e2k_qppermb(in_032[i], in_032[i], mask);
		*(__v2du*)((void*)data_out + offset + 45*16) = __builtin_e2k_qppermb(in_132[i], in_132[i], mask);
		*(__v2du*)((void*)data_out + offset + 46*16) = __builtin_e2k_qppermb(in_232[i], in_232[i], mask);
		*(__v2du*)((void*)data_out + offset + 47*16) = __builtin_e2k_qppermb(in_332[i], in_332[i], mask);
		*(__v2du*)((void*)data_out + offset + 48*16) = __builtin_e2k_qppermb(in_003[i], in_003[i], mask);
		*(__v2du*)((void*)data_out + offset + 49*16) = __builtin_e2k_qppermb(in_103[i], in_103[i], mask);
		*(__v2du*)((void*)data_out + offset + 50*16) = __builtin_e2k_qppermb(in_203[i], in_203[i], mask);
		*(__v2du*)((void*)data_out + offset + 51*16) = __builtin_e2k_qppermb(in_303[i], in_303[i], mask);
		*(__v2du*)((void*)data_out + offset + 52*16) = __builtin_e2k_qppermb(in_013[i], in_013[i], mask);
		*(__v2du*)((void*)data_out + offset + 53*16) = __builtin_e2k_qppermb(in_113[i], in_113[i], mask);
		*(__v2du*)((void*)data_out + offset + 54*16) = __builtin_e2k_qppermb(in_213[i], in_213[i], mask);
		*(__v2du*)((void*)data_out + offset + 55*16) = __builtin_e2k_qppermb(in_313[i], in_313[i], mask);
		*(__v2du*)((void*)data_out + offset + 56*16) = __builtin_e2k_qppermb(in_023[i], in_023[i], mask);
		*(__v2du*)((void*)data_out + offset + 57*16) = __builtin_e2k_qppermb(in_123[i], in_123[i], mask);
		*(__v2du*)((void*)data_out + offset + 58*16) = __builtin_e2k_qppermb(in_223[i], in_223[i], mask);
		*(__v2du*)((void*)data_out + offset + 59*16) = __builtin_e2k_qppermb(in_323[i], in_323[i], mask);
		*(__v2du*)((void*)data_out + offset + 60*16) = __builtin_e2k_qppermb(in_033[i], in_033[i], mask);
		*(__v2du*)((void*)data_out + offset + 61*16) = __builtin_e2k_qppermb(in_133[i], in_133[i], mask);
		*(__v2du*)((void*)data_out + offset + 62*16) = __builtin_e2k_qppermb(in_233[i], in_233[i], mask);
		*(__v2du*)((void*)data_out + offset + 63*16) = __builtin_e2k_qppermb(in_333[i], in_333[i], mask);
	}
}
Основной цикл на ассемблере
.L9991:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=17, incr=0, ind=0, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=16, incr=0, ind=0, asz=1, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=15, incr=0, ind=0, asz=1, abs=2, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=14, incr=0, ind=0, asz=1, abs=2, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=13, incr=0, ind=0, asz=1, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=12, incr=0, ind=0, asz=1, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=11, incr=0, ind=0, asz=1, abs=6, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=10, incr=0, ind=0, asz=1, abs=6, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=9, incr=0, ind=0, asz=1, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=8, incr=0, ind=0, asz=1, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=7, incr=0, ind=0, asz=1, abs=10, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=6, incr=0, ind=0, asz=1, abs=10, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=5, incr=0, ind=0, asz=1, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=4, incr=0, ind=0, asz=1, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=3, incr=0, ind=0, asz=1, abs=14, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=2, incr=0, ind=0, asz=1, abs=14, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=1, incr=0, ind=0, asz=1, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=15, asz=1, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=14, asz=1, abs=18, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=13, asz=1, abs=18, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=12, asz=1, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=11, asz=1, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=10, asz=1, abs=22, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=9, asz=1, abs=22, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=8, asz=1, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=7, asz=1, abs=24, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=6, asz=1, abs=26, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=5, asz=1, abs=26, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=1, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=1, abs=28, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=1, abs=30, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=1, abs=30, disp=0
        }
.L6665:
        {
          loop_mode
          qppermb,0,sm  %b[41], %b[41], %r0, %b[58]
          shr_andd,1,sm %b[56], %r1, %r38, %b[54]
          stqp,2        %r5, %b[34], %b[54]
          qppermb,3,sm  %b[46], %b[46], %r0, %b[60]
          shr_andd,4,sm %b[56], %r4, %r37, %b[56]
          stqp,5        %r2, %b[34], %b[58]
        }
        {
          loop_mode
          qppermb,1,sm  %b[76], %b[76], %r0, %b[1]
          stqp,2        %r7, %b[34], %b[58]
          qppermb,4,sm  %b[77], %b[77], %r0, %b[8]
          stqp,5        %r6, %b[34], %b[60]
        }
        {
          loop_mode
          qppermb,1,sm  %b[65], %b[65], %r0, %b[10]
          stqp,2        %r11, %b[34], %b[3]
          qppermb,4,sm  %b[63], %b[63], %r0, %b[3]
          stqp,5        %r9, %b[34], %b[10]
        }
        {
          loop_mode
          qppermb,1,sm  %b[75], %b[75], %r0, %b[12]
          stqp,2        %r10, %b[34], %b[12]
          qppermb,4,sm  %b[74], %b[74], %r0, %b[5]
          stqp,5        %r12, %b[34], %b[5]
        }
        {
          loop_mode
          qppermb,1,sm  %b[73], %b[73], %r0, %b[14]
          stqp,2        %r13, %b[34], %b[14]
          qppermb,4,sm  %b[72], %b[72], %r0, %b[7]
          stqp,5        %r14, %b[34], %b[7]
        }
        {
          loop_mode
          qppermb,1,sm  %b[71], %b[71], %r0, %b[16]
          stqp,2        %r15, %b[34], %b[16]
          qppermb,4,sm  %b[70], %b[70], %r0, %b[9]
          stqp,5        %r16, %b[34], %b[9]
        }
        {
          loop_mode
          qppermb,1,sm  %b[69], %b[69], %r0, %b[18]
          stqp,2        %r17, %b[34], %b[18]
          qppermb,4,sm  %b[67], %b[67], %r0, %b[11]
          stqp,5        %r18, %b[34], %b[11]
          movaqp,0      area=15, ind=0, am=1, be=0, %b[60]
          movaqp,1      area=14, ind=0, am=1, be=0, %b[64]
          movaqp,2      area=15, ind=0, am=1, be=0, %b[58]
          movaqp,3      area=14, ind=0, am=1, be=0, %b[62]
        }
        {
          loop_mode
          qppermb,1,sm  %b[68], %b[68], %r0, %b[36]
          stqp,2        %r19, %b[34], %b[20]
          qppermb,4,sm  %b[61], %b[61], %r0, %b[31]
          stqp,5        %r20, %b[34], %b[13]
          movaqp,0      area=13, ind=0, am=1, be=0, %b[63]
          movaqp,1      area=12, ind=0, am=1, be=0, %b[20]
          movaqp,2      area=13, ind=0, am=1, be=0, %b[61]
          movaqp,3      area=12, ind=0, am=1, be=0, %b[13]
        }
        {
          loop_mode
          qppermb,1,sm  %b[59], %b[59], %r0, %b[53]
          stqp,2        %r21, %b[34], %b[38]
          qppermb,4,sm  %b[57], %b[57], %r0, %b[49]
          stqp,5        %r22, %b[34], %b[33]
          movaqp,0      area=11, ind=0, am=1, be=0, %b[38]
          movaqp,1      area=10, ind=0, am=1, be=0, %b[46]
          movaqp,2      area=11, ind=0, am=1, be=0, %b[33]
          movaqp,3      area=10, ind=0, am=1, be=0, %b[41]
        }
        {
          loop_mode
          qppermb,1,sm  %b[48], %b[48], %r0, %b[48]
          stqp,2        %r23, %b[34], %b[55]
          qppermb,4,sm  %b[43], %b[43], %r0, %b[43]
          stqp,5        %r24, %b[34], %b[51]
          movaqp,0      area=9, ind=0, am=1, be=0, %b[57]
          movaqp,1      area=8, ind=0, am=1, be=0, %b[66]
          movaqp,2      area=9, ind=0, am=1, be=0, %b[55]
          movaqp,3      area=8, ind=0, am=1, be=0, %b[59]
        }
        {
          loop_mode
          qppermb,1,sm  %b[40], %b[40], %r0, %b[40]
          stqp,2        %r25, %b[34], %b[50]
          qppermb,4,sm  %b[35], %b[35], %r0, %b[35]
          stqp,5        %r26, %b[34], %b[45]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[67]
          movaqp,1      area=6, ind=0, am=1, be=0, %b[69]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[65]
          movaqp,3      area=6, ind=0, am=1, be=0, %b[68]
        }
        {
          loop_mode
          qppermb,1,sm  %b[22], %b[22], %r0, %b[22]
          stqp,2        %r27, %b[34], %b[42]
          qppermb,4,sm  %b[15], %b[15], %r0, %b[15]
          stqp,5        %r28, %b[34], %b[37]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[71]
          movaqp,1      area=4, ind=0, am=1, be=0, %b[73]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[70]
          movaqp,3      area=4, ind=0, am=1, be=0, %b[72]
        }
        {
          loop_mode
          qppermb,1,sm  %b[63], %b[63], %r0, %b[24]
          stqp,2        %r29, %b[34], %b[24]
          qppermb,4,sm  %b[61], %b[61], %r0, %b[17]
          stqp,5        %r30, %b[34], %b[17]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[74]
          movaqp,1      area=2, ind=0, am=1, be=0, %b[75]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[61]
          movaqp,3      area=2, ind=0, am=1, be=0, %b[63]
        }
        {
          loop_mode
          addd,0,sm     %b[2], 0x1, %b[0]
          qppermb,1,sm  %b[64], %b[64], %r0, %b[28]
          stqp,2        %r31, %b[34], %b[28]
          ord,3,sm      %b[56], %b[54], %b[54]
          qppermb,4,sm  %b[62], %b[62], %r0, %b[21]
          stqp,5        %r32, %b[34], %b[21]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[42]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[50]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[37]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[45]
        }
        {
          loop_mode
          bitrevd,0,sm  %b[2], %b[54]
          qppermb,1,sm  %b[60], %b[60], %r0, %b[25]
          stqp,2        %r33, %b[34], %b[32]
          shld,3,sm     %b[54], 0x4, %b[32]
          qppermb,4,sm  %b[58], %b[58], %r0, %b[2]
          stqp,5        %r34, %b[34], %b[25]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[47], %b[47], %r0, %b[52]
          stqp,2        %r35, %b[34], %b[29]
          qppermb,3,sm  %b[52], %b[52], %r0, %b[56]
          stqp,5        %r36, %b[34], %b[6]
        }

        ...

.L9337:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=17, incr=0, ind=0, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=16, incr=0, ind=0, asz=1, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=15, incr=0, ind=0, asz=1, abs=2, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=14, incr=0, ind=0, asz=1, abs=2, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=13, incr=0, ind=0, asz=1, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=12, incr=0, ind=0, asz=1, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=11, incr=0, ind=0, asz=1, abs=6, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=10, incr=0, ind=0, asz=1, abs=6, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=9, incr=0, ind=0, asz=1, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=8, incr=0, ind=0, asz=1, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=7, incr=0, ind=0, asz=1, abs=10, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=6, incr=0, ind=0, asz=1, abs=10, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=5, incr=0, ind=0, asz=1, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=4, incr=0, ind=0, asz=1, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=3, incr=0, ind=0, asz=1, abs=14, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=2, incr=0, ind=0, asz=1, abs=14, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=1, incr=0, ind=0, asz=1, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=15, asz=1, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=14, asz=1, abs=18, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=13, asz=1, abs=18, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=12, asz=1, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=11, asz=1, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=10, asz=1, abs=22, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=9, asz=1, abs=22, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=8, asz=1, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=7, asz=1, abs=24, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=6, asz=1, abs=26, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=5, asz=1, abs=26, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=1, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=1, abs=28, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=1, abs=30, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=1, asz=1, abs=30, disp=0
        }
.L7373:
        {
          loop_mode
          qppermb,0,sm  %b[41], %b[41], %r0, %b[58]
          shr_andd,1,sm %b[56], %r1, %r38, %b[54]
          stqp,2        %r5, %b[34], %b[54]
          qppermb,3,sm  %b[46], %b[46], %r0, %b[60]
          shr_andd,4,sm %b[56], %r4, %r37, %b[56]
          stqp,5        %r2, %b[34], %b[58]
        }
        {
          loop_mode
          qppermb,1,sm  %b[76], %b[76], %r0, %b[1]
          stqp,2        %r7, %b[34], %b[58]
          qppermb,4,sm  %b[77], %b[77], %r0, %b[8]
          stqp,5        %r6, %b[34], %b[60]
        }
        {
          loop_mode
          qppermb,1,sm  %b[65], %b[65], %r0, %b[10]
          stqp,2        %r11, %b[34], %b[3]
          qppermb,4,sm  %b[63], %b[63], %r0, %b[3]
          stqp,5        %r9, %b[34], %b[10]
        }
        {
          loop_mode
          qppermb,1,sm  %b[75], %b[75], %r0, %b[12]
          stqp,2        %r10, %b[34], %b[12]
          qppermb,4,sm  %b[74], %b[74], %r0, %b[5]
          stqp,5        %r12, %b[34], %b[5]
        }
        {
          loop_mode
          qppermb,1,sm  %b[73], %b[73], %r0, %b[14]
          stqp,2        %r13, %b[34], %b[14]
          qppermb,4,sm  %b[72], %b[72], %r0, %b[7]
          stqp,5        %r14, %b[34], %b[7]
        }
        {
          loop_mode
          qppermb,1,sm  %b[71], %b[71], %r0, %b[16]
          stqp,2        %r15, %b[34], %b[16]
          qppermb,4,sm  %b[70], %b[70], %r0, %b[9]
          stqp,5        %r16, %b[34], %b[9]
        }
        {
          loop_mode
          qppermb,1,sm  %b[69], %b[69], %r0, %b[18]
          stqp,2        %r17, %b[34], %b[18]
          qppermb,4,sm  %b[67], %b[67], %r0, %b[11]
          stqp,5        %r18, %b[34], %b[11]
          movaqp,0      area=15, ind=0, am=1, be=0, %b[60]
          movaqp,1      area=14, ind=0, am=1, be=0, %b[64]
          movaqp,2      area=15, ind=0, am=1, be=0, %b[58]
          movaqp,3      area=14, ind=0, am=1, be=0, %b[62]
        }
        {
          loop_mode
          qppermb,1,sm  %b[68], %b[68], %r0, %b[36]
          stqp,2        %r19, %b[34], %b[20]
          qppermb,4,sm  %b[61], %b[61], %r0, %b[31]
          stqp,5        %r20, %b[34], %b[13]
          movaqp,0      area=13, ind=0, am=1, be=0, %b[63]
          movaqp,1      area=12, ind=0, am=1, be=0, %b[20]
          movaqp,2      area=13, ind=0, am=1, be=0, %b[61]
          movaqp,3      area=12, ind=0, am=1, be=0, %b[13]
        }
        {
          loop_mode
          qppermb,1,sm  %b[59], %b[59], %r0, %b[53]
          stqp,2        %r21, %b[34], %b[38]
          qppermb,4,sm  %b[57], %b[57], %r0, %b[49]
          stqp,5        %r22, %b[34], %b[33]
          movaqp,0      area=11, ind=0, am=1, be=0, %b[38]
          movaqp,1      area=10, ind=0, am=1, be=0, %b[46]
          movaqp,2      area=11, ind=0, am=1, be=0, %b[33]
          movaqp,3      area=10, ind=0, am=1, be=0, %b[41]
        }
        {
          loop_mode
          qppermb,1,sm  %b[48], %b[48], %r0, %b[48]
          stqp,2        %r23, %b[34], %b[55]
          qppermb,4,sm  %b[43], %b[43], %r0, %b[43]
          stqp,5        %r24, %b[34], %b[51]
          movaqp,0      area=9, ind=0, am=1, be=0, %b[57]
          movaqp,1      area=8, ind=0, am=1, be=0, %b[66]
          movaqp,2      area=9, ind=0, am=1, be=0, %b[55]
          movaqp,3      area=8, ind=0, am=1, be=0, %b[59]
        }
        {
          loop_mode
          qppermb,1,sm  %b[40], %b[40], %r0, %b[40]
          stqp,2        %r25, %b[34], %b[50]
          qppermb,4,sm  %b[35], %b[35], %r0, %b[35]
          stqp,5        %r26, %b[34], %b[45]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[67]
          movaqp,1      area=6, ind=0, am=1, be=0, %b[69]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[65]
          movaqp,3      area=6, ind=0, am=1, be=0, %b[68]
        }
        {
          loop_mode
          qppermb,1,sm  %b[22], %b[22], %r0, %b[22]
          stqp,2        %r27, %b[34], %b[42]
          qppermb,4,sm  %b[15], %b[15], %r0, %b[15]
          stqp,5        %r28, %b[34], %b[37]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[71]
          movaqp,1      area=4, ind=0, am=1, be=0, %b[73]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[70]
          movaqp,3      area=4, ind=0, am=1, be=0, %b[72]
        }
        {
          loop_mode
          qppermb,1,sm  %b[63], %b[63], %r0, %b[24]
          stqp,2        %r29, %b[34], %b[24]
          qppermb,4,sm  %b[61], %b[61], %r0, %b[17]
          stqp,5        %r30, %b[34], %b[17]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[74]
          movaqp,1      area=2, ind=0, am=1, be=0, %b[75]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[61]
          movaqp,3      area=2, ind=0, am=1, be=0, %b[63]
        }
        {
          loop_mode
          addd,0,sm     %b[2], 0x1, %b[0]
          qppermb,1,sm  %b[64], %b[64], %r0, %b[28]
          stqp,2        %r31, %b[34], %b[28]
          ord,3,sm      %b[56], %b[54], %b[54]
          qppermb,4,sm  %b[62], %b[62], %r0, %b[21]
          stqp,5        %r32, %b[34], %b[21]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[42]
          movaqp,1      area=0, ind=0, am=1, be=0, %b[50]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[37]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[45]
        }
        {
          loop_mode
          bitrevd,0,sm  %b[2], %b[54]
          qppermb,1,sm  %b[60], %b[60], %r0, %b[25]
          stqp,2        %r33, %b[34], %b[32]
          shld,3,sm     %b[54], 0x4, %b[32]
          qppermb,4,sm  %b[58], %b[58], %r0, %b[2]
          stqp,5        %r34, %b[34], %b[25]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[47], %b[47], %r0, %b[52]
          stqp,2        %r35, %b[34], %b[29]
          qppermb,3,sm  %b[52], %b[52], %r0, %b[56]
          stqp,5        %r36, %b[34], %b[6]
        }

Теоретическая скорость: 64 комплексных числа за 16 тактов (64/16) = 32 Байт/такт

Замеры скорости

Видим замедление по всей длине графика.

Итоги по reverse_radix4_vector2

Победителем можно считать reverse_radix4_vector2_stream16.

При реализации Vector-2 Radix-4 FFT будем использовать его.

reverse_radix4_vector4

1. reverse_radix4_vector4_etalon

Эталонный вариант для сравнения на корректность.
Здесь reverseNumber_radix4 вычисляется с помощью цикла.

int reverseNumber_radix4(int number, int bit_count)
{
	int answer = 0;

	for(int i = 0; i < bit_count/2; ++i)
	{
		answer <<= 2;
		answer |= number & 3;
		number >>= 2;
	}

	return answer;
}


void reverse_radix4_vector4_etalon(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;

	for(int64_t i = 0; i < count_out; ++i)
	{
		int index = reverseNumber_radix4(i, bit_count_out);
		myComplex a = data_in[4*i + 0];
		myComplex b = data_in[4*i + 1];
		myComplex c = data_in[4*i + 2];
		myComplex d = data_in[4*i + 3];
		data_out[index] = (myComplex4){.real = {a.real, b.real, c.real, d.real}, .imag = {a.imag, b.imag, c.imag, d.imag}};
	}
}

2. reverse_radix4_vector4

В процессоре нет готовых инструкций, производящих операцию reverseNumber_radix4.
Поэтому выполним инструкцию bitrevd и переставим соседние биты местами.

Код на Си
void reverse_radix4_vector4(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in = (__v2di*)data_in;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 32 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in[2*i+1], in[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in[2*i+1], in[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L6561:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
        }
.L6351:
        {
          loop_mode
          qppermb,0,sm  %b[15], %b[12], %r4, %b[19]
          shr_andd,1,sm %b[14], %r6, %r10, %b[0]
          qppermb,3,sm  %b[15], %b[12], %r5, %b[20]
          shr_andd,4,sm %b[16], %r7, %r9, %b[5]
          ord,5,sm      %b[7], %b[4], %b[18]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          bitrevd,0,sm  %b[3], %b[12]
          stqp,2        %r0, %b[17], %b[19]
          addd,3,sm     %b[3], 0x1, %b[1]
          shld,4,sm     %b[18], 0x5, %b[15]
          stqp,5        %r2, %b[17], %b[20]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[4]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[7]
        }

Теоретическая скорость: 4 комплексных числа за 2 такта (4/2) = 16 Байт/такт

Замеры скорости

3. reverse_radix4_vector4_x4

Сделаем ручную раскрутку цикла в 4 раза.

Код на Си
void reverse_radix4_vector4_x4(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

//	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in    = (__v2di*) data_in;
	__v2di *out_0 = (__v2di*)&data_out[0 * count_out/4];
	__v2di *out_1 = (__v2di*)&data_out[1 * count_out/4];
	__v2di *out_2 = (__v2di*)&data_out[2 * count_out/4];
	__v2di *out_3 = (__v2di*)&data_out[3 * count_out/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out; i += 4)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 32 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)out_0 + offset + 0*16) = __builtin_e2k_qppermb(in[2*(i+0)+1], in[2*(i+0)+0], mask_real);
		*(__v2du*)((void*)out_0 + offset + 1*16) = __builtin_e2k_qppermb(in[2*(i+0)+1], in[2*(i+0)+0], mask_imag);
		*(__v2du*)((void*)out_1 + offset + 0*16) = __builtin_e2k_qppermb(in[2*(i+1)+1], in[2*(i+1)+0], mask_real);
		*(__v2du*)((void*)out_1 + offset + 1*16) = __builtin_e2k_qppermb(in[2*(i+1)+1], in[2*(i+1)+0], mask_imag);
		*(__v2du*)((void*)out_2 + offset + 0*16) = __builtin_e2k_qppermb(in[2*(i+2)+1], in[2*(i+2)+0], mask_real);
		*(__v2du*)((void*)out_2 + offset + 1*16) = __builtin_e2k_qppermb(in[2*(i+2)+1], in[2*(i+2)+0], mask_imag);
		*(__v2du*)((void*)out_3 + offset + 0*16) = __builtin_e2k_qppermb(in[2*(i+3)+1], in[2*(i+3)+0], mask_real);
		*(__v2du*)((void*)out_3 + offset + 1*16) = __builtin_e2k_qppermb(in[2*(i+3)+1], in[2*(i+3)+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L7192:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=32
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=16, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=16, disp=96
        }
.L6608:
        {
          loop_mode
          qppermb,0,sm  %b[23], %b[9], %r11, %b[35]
          stqp,2        %r0, %b[33], %b[22]
          qppermb,3,sm  %b[23], %b[9], %r13, %b[36]
          shr_andd,4,sm %b[12], %r14, %r16, %b[1]
          stqp,5        %r2, %b[33], %b[25]
        }
        {
          loop_mode
          ord,0,sm      %b[17], %b[3], %b[23]
          qppermb,1,sm  %b[15], %b[10], %r11, %b[37]
          stqp,2        %r4, %b[33], %b[35]
          qppermb,4,sm  %b[28], %b[20], %r13, %b[38]
          stqp,5        %r10, %b[33], %b[36]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[14]
          movaqp,1      area=1, ind=16, am=0, be=0, %b[22]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[4]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[9]
        }
        {
          loop_mode
          shld,0,sm     %b[23], 0x5, %b[31]
          qppermb,1,sm  %b[28], %b[20], %r11, %b[36]
          stqp,2        %r6, %b[33], %b[37]
          addd,3,sm     %b[2], 0x4, %b[0]
          qppermb,4,sm  %b[15], %b[10], %r13, %b[35]
          stqp,5        %r9, %b[33], %b[38]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[25]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[30]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[3]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[17]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[34], %b[29], %r11, %b[20]
          shr_andd,1,sm %b[12], %r12, %r15, %b[15]
          stqp,2        %r5, %b[33], %b[36]
          qppermb,3,sm  %b[34], %b[29], %r13, %b[23]
          bitrevd,4,sm  %b[2], %b[10]
          stqp,5        %r7, %b[33], %b[35]
        }

Теоретическая скорость: 16 комплексных чисел за 4 такта (16/4) = 32 Байт/такт

Замеры скорости

Видим ускорение в начале и замедление в конце графика.

Здесь происходит четыре чтения из одного места памяти и запись в четыре разных места памяти.

4. reverse_radix4_vector4_stream4

Теперь сделаем наоборот: будем читать из четырёх разных мест, а писать рядом.
Чтение в 4 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix4_vector4_stream4(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_0 = (__v2di*)&data_in[0 * count_in/4];
	__v2di *in_1 = (__v2di*)&data_in[1 * count_in/4];
	__v2di *in_2 = (__v2di*)&data_in[2 * count_in/4];
	__v2di *in_3 = (__v2di*)&data_in[3 * count_in/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/4; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 32 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset + 0*16) = __builtin_e2k_qppermb(in_0[2*i+1], in_0[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 1*16) = __builtin_e2k_qppermb(in_0[2*i+1], in_0[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 2*16) = __builtin_e2k_qppermb(in_1[2*i+1], in_1[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 3*16) = __builtin_e2k_qppermb(in_1[2*i+1], in_1[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 4*16) = __builtin_e2k_qppermb(in_2[2*i+1], in_2[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 5*16) = __builtin_e2k_qppermb(in_2[2*i+1], in_2[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 6*16) = __builtin_e2k_qppermb(in_3[2*i+1], in_3[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 7*16) = __builtin_e2k_qppermb(in_3[2*i+1], in_3[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L7740:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=4, abs=0, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=4, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=16, disp=0
        }
.L7235:
        {
          loop_mode
          qppermb,0,sm  %b[23], %b[9], %r11, %b[35]
          stqp,2        %r0, %b[33], %b[22]
          qppermb,3,sm  %b[23], %b[9], %r13, %b[36]
          shr_andd,4,sm %b[12], %r14, %r16, %b[1]
          stqp,5        %r2, %b[33], %b[25]
        }
        {
          loop_mode
          ord,0,sm      %b[17], %b[3], %b[23]
          qppermb,1,sm  %b[15], %b[10], %r11, %b[37]
          stqp,2        %r5, %b[33], %b[35]
          qppermb,4,sm  %b[28], %b[20], %r13, %b[38]
          stqp,5        %r4, %b[33], %b[36]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[14]
          movaqp,1      area=1, ind=16, am=0, be=0, %b[22]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[4]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[9]
        }
        {
          loop_mode
          shld,0,sm     %b[23], 0x5, %b[31]
          qppermb,1,sm  %b[28], %b[20], %r11, %b[36]
          stqp,2        %r10, %b[33], %b[37]
          addd,3,sm     %b[2], 0x1, %b[0]
          qppermb,4,sm  %b[15], %b[10], %r13, %b[35]
          stqp,5        %r6, %b[33], %b[38]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[25]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[30]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[3]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[17]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[34], %b[29], %r11, %b[20]
          shr_andd,1,sm %b[12], %r12, %r15, %b[15]
          stqp,2        %r7, %b[33], %b[36]
          qppermb,3,sm  %b[34], %b[29], %r13, %b[23]
          bitrevd,4,sm  %b[2], %b[10]
          stqp,5        %r9, %b[33], %b[35]
        }

Теоретическая скорость: 16 комплексных чисел за 4 такта (16/4) = 32 Байт/такт

Замеры скорости

Видим желаемое ускорение по всей длине графика.

5. reverse_radix4_vector4_stream16

Чтение в 16 потоков из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix4_vector4_stream16(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_00 = (__v2di*)&data_in[ 0 * count_in/16];
	__v2di *in_01 = (__v2di*)&data_in[ 1 * count_in/16];
	__v2di *in_02 = (__v2di*)&data_in[ 2 * count_in/16];
	__v2di *in_03 = (__v2di*)&data_in[ 3 * count_in/16];
	__v2di *in_10 = (__v2di*)&data_in[ 4 * count_in/16];
	__v2di *in_11 = (__v2di*)&data_in[ 5 * count_in/16];
	__v2di *in_12 = (__v2di*)&data_in[ 6 * count_in/16];
	__v2di *in_13 = (__v2di*)&data_in[ 7 * count_in/16];
	__v2di *in_20 = (__v2di*)&data_in[ 8 * count_in/16];
	__v2di *in_21 = (__v2di*)&data_in[ 9 * count_in/16];
	__v2di *in_22 = (__v2di*)&data_in[10 * count_in/16];
	__v2di *in_23 = (__v2di*)&data_in[11 * count_in/16];
	__v2di *in_30 = (__v2di*)&data_in[12 * count_in/16];
	__v2di *in_31 = (__v2di*)&data_in[13 * count_in/16];
	__v2di *in_32 = (__v2di*)&data_in[14 * count_in/16];
	__v2di *in_33 = (__v2di*)&data_in[15 * count_in/16];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/16; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 32 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_00[2*i+1], in_00[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_00[2*i+1], in_00[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_10[2*i+1], in_10[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_10[2*i+1], in_10[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_20[2*i+1], in_20[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_20[2*i+1], in_20[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_30[2*i+1], in_30[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_30[2*i+1], in_30[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_01[2*i+1], in_01[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_01[2*i+1], in_01[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_11[2*i+1], in_11[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_11[2*i+1], in_11[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_21[2*i+1], in_21[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_21[2*i+1], in_21[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_31[2*i+1], in_31[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_31[2*i+1], in_31[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 16*16) = __builtin_e2k_qppermb(in_02[2*i+1], in_02[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 17*16) = __builtin_e2k_qppermb(in_02[2*i+1], in_02[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 18*16) = __builtin_e2k_qppermb(in_12[2*i+1], in_12[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 19*16) = __builtin_e2k_qppermb(in_12[2*i+1], in_12[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 20*16) = __builtin_e2k_qppermb(in_22[2*i+1], in_22[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 21*16) = __builtin_e2k_qppermb(in_22[2*i+1], in_22[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 22*16) = __builtin_e2k_qppermb(in_32[2*i+1], in_32[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 23*16) = __builtin_e2k_qppermb(in_32[2*i+1], in_32[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 24*16) = __builtin_e2k_qppermb(in_03[2*i+1], in_03[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 25*16) = __builtin_e2k_qppermb(in_03[2*i+1], in_03[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 26*16) = __builtin_e2k_qppermb(in_13[2*i+1], in_13[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 27*16) = __builtin_e2k_qppermb(in_13[2*i+1], in_13[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 28*16) = __builtin_e2k_qppermb(in_23[2*i+1], in_23[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 29*16) = __builtin_e2k_qppermb(in_23[2*i+1], in_23[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 30*16) = __builtin_e2k_qppermb(in_33[2*i+1], in_33[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 31*16) = __builtin_e2k_qppermb(in_33[2*i+1], in_33[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L9557:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=1, incr=1, ind=0, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=15, asz=2, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=14, asz=2, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=13, asz=2, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=12, asz=2, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=11, asz=2, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=10, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=9, asz=2, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=8, asz=2, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=7, asz=2, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=6, asz=2, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=5, asz=2, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=2, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=2, abs=24, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=2, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=28, disp=0
        }
.L7879:
        {
          loop_mode
          qppermb,0,sm  %b[20], %b[15], %r36, %b[73]
          shr_andd,1,sm %b[69], %r37, %r40, %b[69]
          stqp,2        %r0, %b[4], %b[71]
          qppermb,3,sm  %b[20], %b[15], %r35, %b[72]
          shr_andd,4,sm %b[69], %r38, %r39, %b[71]
          stqp,5        %r2, %b[4], %b[72]
        }
        {
          loop_mode
          qppermb,1,sm  %b[28], %b[23], %r36, %b[72]
          stqp,2        %r5, %b[4], %b[73]
          qppermb,4,sm  %b[67], %b[64], %r35, %b[74]
          stqp,5        %r1, %b[4], %b[72]
        }
        {
          loop_mode
          qppermb,1,sm  %b[67], %b[64], %r36, %b[72]
          stqp,2        %r10, %b[4], %b[72]
          qppermb,4,sm  %b[28], %b[23], %r35, %b[67]
          stqp,5        %r6, %b[4], %b[74]
        }
        {
          loop_mode
          qppermb,1,sm  %b[63], %b[60], %r36, %b[67]
          stqp,2        %r7, %b[4], %b[72]
          qppermb,4,sm  %b[63], %b[60], %r35, %b[72]
          stqp,5        %r9, %b[4], %b[67]
        }
        {
          loop_mode
          qppermb,1,sm  %b[36], %b[31], %r36, %b[67]
          stqp,2        %r12, %b[4], %b[67]
          qppermb,4,sm  %b[36], %b[31], %r35, %b[72]
          stqp,5        %r11, %b[4], %b[72]
        }
        {
          loop_mode
          qppermb,1,sm  %b[59], %b[56], %r36, %b[67]
          stqp,2        %r14, %b[4], %b[67]
          qppermb,4,sm  %b[59], %b[56], %r35, %b[72]
          stqp,5        %r13, %b[4], %b[72]
        }
        {
          loop_mode
          qppermb,1,sm  %b[44], %b[39], %r36, %b[67]
          stqp,2        %r16, %b[4], %b[67]
          qppermb,4,sm  %b[44], %b[39], %r35, %b[72]
          stqp,5        %r15, %b[4], %b[72]
          movaqp,0      area=7, ind=0, am=1, be=0, %b[7]
          movaqp,1      area=7, ind=16, am=0, be=0, %b[12]
          movaqp,2      area=7, ind=0, am=1, be=0, %b[1]
          movaqp,3      area=7, ind=16, am=0, be=0, %b[6]
        }
        {
          loop_mode
          qppermb,1,sm  %b[55], %b[52], %r36, %b[67]
          stqp,2        %r18, %b[4], %b[67]
          qppermb,4,sm  %b[55], %b[52], %r35, %b[72]
          stqp,5        %r17, %b[4], %b[72]
          movaqp,0      area=6, ind=0, am=1, be=0, %b[23]
          movaqp,1      area=6, ind=16, am=0, be=0, %b[28]
          movaqp,2      area=6, ind=0, am=1, be=0, %b[15]
          movaqp,3      area=6, ind=16, am=0, be=0, %b[20]
        }
        {
          loop_mode
          qppermb,1,sm  %b[51], %b[47], %r36, %b[67]
          stqp,2        %r20, %b[4], %b[67]
          qppermb,4,sm  %b[51], %b[47], %r35, %b[72]
          stqp,5        %r19, %b[4], %b[72]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[39]
          movaqp,1      area=5, ind=16, am=0, be=0, %b[44]
          movaqp,2      area=5, ind=0, am=1, be=0, %b[31]
          movaqp,3      area=5, ind=16, am=0, be=0, %b[36]
        }
        {
          loop_mode
          qppermb,1,sm  %b[48], %b[43], %r36, %b[67]
          stqp,2        %r22, %b[4], %b[67]
          qppermb,4,sm  %b[48], %b[43], %r35, %b[72]
          stqp,5        %r21, %b[4], %b[72]
          movaqp,0      area=4, ind=0, am=1, be=0, %b[48]
          movaqp,1      area=4, ind=16, am=0, be=0, %b[51]
          movaqp,2      area=4, ind=0, am=1, be=0, %b[43]
          movaqp,3      area=4, ind=16, am=0, be=0, %b[47]
        }
        {
          loop_mode
          qppermb,1,sm  %b[40], %b[35], %r36, %b[67]
          stqp,2        %r24, %b[4], %b[67]
          qppermb,4,sm  %b[40], %b[35], %r35, %b[72]
          stqp,5        %r23, %b[4], %b[72]
          movaqp,0      area=3, ind=0, am=1, be=0, %b[52]
          movaqp,1      area=3, ind=16, am=0, be=0, %b[55]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[35]
          movaqp,3      area=3, ind=16, am=0, be=0, %b[40]
        }
        {
          loop_mode
          qppermb,1,sm  %b[32], %b[27], %r36, %b[67]
          stqp,2        %r26, %b[4], %b[67]
          qppermb,4,sm  %b[32], %b[27], %r35, %b[72]
          stqp,5        %r25, %b[4], %b[72]
          movaqp,0      area=2, ind=0, am=1, be=0, %b[56]
          movaqp,1      area=2, ind=16, am=0, be=0, %b[59]
          movaqp,2      area=2, ind=0, am=1, be=0, %b[27]
          movaqp,3      area=2, ind=16, am=0, be=0, %b[32]
        }
        {
          loop_mode
          qppermb,1,sm  %b[24], %b[19], %r36, %b[67]
          stqp,2        %r28, %b[4], %b[67]
          qppermb,4,sm  %b[24], %b[19], %r35, %b[72]
          stqp,5        %r27, %b[4], %b[72]
          movaqp,0      area=1, ind=0, am=1, be=0, %b[60]
          movaqp,1      area=1, ind=16, am=0, be=0, %b[63]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[19]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[24]
        }
        {
          loop_mode
          addd,0,sm     %b[2], 0x1, %b[0]
          qppermb,1,sm  %b[16], %b[11], %r36, %b[69]
          stqp,2        %r30, %b[4], %b[67]
          ord,3,sm      %b[71], %b[69], %b[67]
          qppermb,4,sm  %b[16], %b[11], %r35, %b[71]
          stqp,5        %r29, %b[4], %b[72]
          movaqp,0      area=0, ind=0, am=1, be=0, %b[64]
          movaqp,1      area=0, ind=16, am=0, be=0, %b[68]
          movaqp,2      area=0, ind=0, am=1, be=0, %b[11]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[16]
        }
        {
          loop_mode
          bitrevd,0,sm  %b[2], %b[67]
          qppermb,1,sm  %b[10], %b[5], %r36, %b[69]
          stqp,2        %r32, %b[4], %b[69]
          shld,3,sm     %b[67], 0x5, %b[2]
          qppermb,4,sm  %b[10], %b[5], %r35, %b[71]
          stqp,5        %r31, %b[4], %b[71]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qppermb,0,sm  %b[70], %b[66], %r36, %b[69]
          stqp,2        %r34, %b[4], %b[69]
          qppermb,3,sm  %b[70], %b[66], %r35, %b[70]
          stqp,5        %r33, %b[4], %b[71]
        }

Теоретическая скорость: 64 комплексных числа за 16 тактов (64/16) = 32 Байт/такт

Замеры скорости

Видим сильное ускорение.

При попытке чтения в 64 потока получается резко менее эффективный код.
APB не может читать в 64 потока, поэтому в дополнение к APB компилятор вставляет обычные операции чтения ldqp. В итоге скорость резко проседает.

Но можно сделать чтение в 32 потока. Для этого напишем чтение в 64 потока и обработаем сначала одну половину строк в одном цикле, а потом вторую половину строк во втором цикле. В каждом цикле будут использованы 32 потока чтения APB.

6. reverse_radix4_vector4_stream32

Чтение в 32 потока из разных мест памяти, запись в одно место памяти.

Код на Си
void reverse_radix4_vector4_stream32(int bit_count_in, myComplex *data_in, myComplex4 *data_out)
{
	int bit_count_out = bit_count_in - 2;

	int count_in  = 1 << bit_count_in;
	int count_out = 1 << bit_count_out;
	int shift_out = 64 - bit_count_out;

	__v2di *in_000 = (__v2di*)&data_in[ 0 * count_in/64];
	__v2di *in_001 = (__v2di*)&data_in[ 1 * count_in/64];
	__v2di *in_002 = (__v2di*)&data_in[ 2 * count_in/64];
	__v2di *in_003 = (__v2di*)&data_in[ 3 * count_in/64];
	__v2di *in_010 = (__v2di*)&data_in[ 4 * count_in/64];
	__v2di *in_011 = (__v2di*)&data_in[ 5 * count_in/64];
	__v2di *in_012 = (__v2di*)&data_in[ 6 * count_in/64];
	__v2di *in_013 = (__v2di*)&data_in[ 7 * count_in/64];
	__v2di *in_020 = (__v2di*)&data_in[ 8 * count_in/64];
	__v2di *in_021 = (__v2di*)&data_in[ 9 * count_in/64];
	__v2di *in_022 = (__v2di*)&data_in[10 * count_in/64];
	__v2di *in_023 = (__v2di*)&data_in[11 * count_in/64];
	__v2di *in_030 = (__v2di*)&data_in[12 * count_in/64];
	__v2di *in_031 = (__v2di*)&data_in[13 * count_in/64];
	__v2di *in_032 = (__v2di*)&data_in[14 * count_in/64];
	__v2di *in_033 = (__v2di*)&data_in[15 * count_in/64];
	__v2di *in_100 = (__v2di*)&data_in[16 * count_in/64];
	__v2di *in_101 = (__v2di*)&data_in[17 * count_in/64];
	__v2di *in_102 = (__v2di*)&data_in[18 * count_in/64];
	__v2di *in_103 = (__v2di*)&data_in[19 * count_in/64];
	__v2di *in_110 = (__v2di*)&data_in[20 * count_in/64];
	__v2di *in_111 = (__v2di*)&data_in[21 * count_in/64];
	__v2di *in_112 = (__v2di*)&data_in[22 * count_in/64];
	__v2di *in_113 = (__v2di*)&data_in[23 * count_in/64];
	__v2di *in_120 = (__v2di*)&data_in[24 * count_in/64];
	__v2di *in_121 = (__v2di*)&data_in[25 * count_in/64];
	__v2di *in_122 = (__v2di*)&data_in[26 * count_in/64];
	__v2di *in_123 = (__v2di*)&data_in[27 * count_in/64];
	__v2di *in_130 = (__v2di*)&data_in[28 * count_in/64];
	__v2di *in_131 = (__v2di*)&data_in[29 * count_in/64];
	__v2di *in_132 = (__v2di*)&data_in[30 * count_in/64];
	__v2di *in_133 = (__v2di*)&data_in[31 * count_in/64];
	__v2di *in_200 = (__v2di*)&data_in[32 * count_in/64];
	__v2di *in_201 = (__v2di*)&data_in[33 * count_in/64];
	__v2di *in_202 = (__v2di*)&data_in[34 * count_in/64];
	__v2di *in_203 = (__v2di*)&data_in[35 * count_in/64];
	__v2di *in_210 = (__v2di*)&data_in[36 * count_in/64];
	__v2di *in_211 = (__v2di*)&data_in[37 * count_in/64];
	__v2di *in_212 = (__v2di*)&data_in[38 * count_in/64];
	__v2di *in_213 = (__v2di*)&data_in[39 * count_in/64];
	__v2di *in_220 = (__v2di*)&data_in[40 * count_in/64];
	__v2di *in_221 = (__v2di*)&data_in[41 * count_in/64];
	__v2di *in_222 = (__v2di*)&data_in[42 * count_in/64];
	__v2di *in_223 = (__v2di*)&data_in[43 * count_in/64];
	__v2di *in_230 = (__v2di*)&data_in[44 * count_in/64];
	__v2di *in_231 = (__v2di*)&data_in[45 * count_in/64];
	__v2di *in_232 = (__v2di*)&data_in[46 * count_in/64];
	__v2di *in_233 = (__v2di*)&data_in[47 * count_in/64];
	__v2di *in_300 = (__v2di*)&data_in[48 * count_in/64];
	__v2di *in_301 = (__v2di*)&data_in[49 * count_in/64];
	__v2di *in_302 = (__v2di*)&data_in[50 * count_in/64];
	__v2di *in_303 = (__v2di*)&data_in[51 * count_in/64];
	__v2di *in_310 = (__v2di*)&data_in[52 * count_in/64];
	__v2di *in_311 = (__v2di*)&data_in[53 * count_in/64];
	__v2di *in_312 = (__v2di*)&data_in[54 * count_in/64];
	__v2di *in_313 = (__v2di*)&data_in[55 * count_in/64];
	__v2di *in_320 = (__v2di*)&data_in[56 * count_in/64];
	__v2di *in_321 = (__v2di*)&data_in[57 * count_in/64];
	__v2di *in_322 = (__v2di*)&data_in[58 * count_in/64];
	__v2di *in_323 = (__v2di*)&data_in[59 * count_in/64];
	__v2di *in_330 = (__v2di*)&data_in[60 * count_in/64];
	__v2di *in_331 = (__v2di*)&data_in[61 * count_in/64];
	__v2di *in_332 = (__v2di*)&data_in[62 * count_in/64];
	__v2di *in_333 = (__v2di*)&data_in[63 * count_in/64];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/32/2; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 32 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset +  0*16) = __builtin_e2k_qppermb(in_000[2*i+1], in_000[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  1*16) = __builtin_e2k_qppermb(in_000[2*i+1], in_000[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  2*16) = __builtin_e2k_qppermb(in_100[2*i+1], in_100[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  3*16) = __builtin_e2k_qppermb(in_100[2*i+1], in_100[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  4*16) = __builtin_e2k_qppermb(in_200[2*i+1], in_200[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  5*16) = __builtin_e2k_qppermb(in_200[2*i+1], in_200[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  6*16) = __builtin_e2k_qppermb(in_300[2*i+1], in_300[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  7*16) = __builtin_e2k_qppermb(in_300[2*i+1], in_300[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  8*16) = __builtin_e2k_qppermb(in_010[2*i+1], in_010[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  9*16) = __builtin_e2k_qppermb(in_010[2*i+1], in_010[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 10*16) = __builtin_e2k_qppermb(in_110[2*i+1], in_110[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 11*16) = __builtin_e2k_qppermb(in_110[2*i+1], in_110[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 12*16) = __builtin_e2k_qppermb(in_210[2*i+1], in_210[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 13*16) = __builtin_e2k_qppermb(in_210[2*i+1], in_210[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 14*16) = __builtin_e2k_qppermb(in_310[2*i+1], in_310[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 15*16) = __builtin_e2k_qppermb(in_310[2*i+1], in_310[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 16*16) = __builtin_e2k_qppermb(in_020[2*i+1], in_020[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 17*16) = __builtin_e2k_qppermb(in_020[2*i+1], in_020[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 18*16) = __builtin_e2k_qppermb(in_120[2*i+1], in_120[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 19*16) = __builtin_e2k_qppermb(in_120[2*i+1], in_120[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 20*16) = __builtin_e2k_qppermb(in_220[2*i+1], in_220[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 21*16) = __builtin_e2k_qppermb(in_220[2*i+1], in_220[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 22*16) = __builtin_e2k_qppermb(in_320[2*i+1], in_320[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 23*16) = __builtin_e2k_qppermb(in_320[2*i+1], in_320[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 24*16) = __builtin_e2k_qppermb(in_030[2*i+1], in_030[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 25*16) = __builtin_e2k_qppermb(in_030[2*i+1], in_030[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 26*16) = __builtin_e2k_qppermb(in_130[2*i+1], in_130[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 27*16) = __builtin_e2k_qppermb(in_130[2*i+1], in_130[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 28*16) = __builtin_e2k_qppermb(in_230[2*i+1], in_230[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 29*16) = __builtin_e2k_qppermb(in_230[2*i+1], in_230[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 30*16) = __builtin_e2k_qppermb(in_330[2*i+1], in_330[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 31*16) = __builtin_e2k_qppermb(in_330[2*i+1], in_330[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 32*16) = __builtin_e2k_qppermb(in_001[2*i+1], in_001[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 33*16) = __builtin_e2k_qppermb(in_001[2*i+1], in_001[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 34*16) = __builtin_e2k_qppermb(in_101[2*i+1], in_101[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 35*16) = __builtin_e2k_qppermb(in_101[2*i+1], in_101[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 36*16) = __builtin_e2k_qppermb(in_201[2*i+1], in_201[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 37*16) = __builtin_e2k_qppermb(in_201[2*i+1], in_201[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 38*16) = __builtin_e2k_qppermb(in_301[2*i+1], in_301[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 39*16) = __builtin_e2k_qppermb(in_301[2*i+1], in_301[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 40*16) = __builtin_e2k_qppermb(in_011[2*i+1], in_011[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 41*16) = __builtin_e2k_qppermb(in_011[2*i+1], in_011[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 42*16) = __builtin_e2k_qppermb(in_111[2*i+1], in_111[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 43*16) = __builtin_e2k_qppermb(in_111[2*i+1], in_111[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 44*16) = __builtin_e2k_qppermb(in_211[2*i+1], in_211[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 45*16) = __builtin_e2k_qppermb(in_211[2*i+1], in_211[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 46*16) = __builtin_e2k_qppermb(in_311[2*i+1], in_311[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 47*16) = __builtin_e2k_qppermb(in_311[2*i+1], in_311[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 48*16) = __builtin_e2k_qppermb(in_021[2*i+1], in_021[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 49*16) = __builtin_e2k_qppermb(in_021[2*i+1], in_021[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 50*16) = __builtin_e2k_qppermb(in_121[2*i+1], in_121[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 51*16) = __builtin_e2k_qppermb(in_121[2*i+1], in_121[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 52*16) = __builtin_e2k_qppermb(in_221[2*i+1], in_221[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 53*16) = __builtin_e2k_qppermb(in_221[2*i+1], in_221[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 54*16) = __builtin_e2k_qppermb(in_321[2*i+1], in_321[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 55*16) = __builtin_e2k_qppermb(in_321[2*i+1], in_321[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 56*16) = __builtin_e2k_qppermb(in_031[2*i+1], in_031[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 57*16) = __builtin_e2k_qppermb(in_031[2*i+1], in_031[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 58*16) = __builtin_e2k_qppermb(in_131[2*i+1], in_131[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 59*16) = __builtin_e2k_qppermb(in_131[2*i+1], in_131[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 60*16) = __builtin_e2k_qppermb(in_231[2*i+1], in_231[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 61*16) = __builtin_e2k_qppermb(in_231[2*i+1], in_231[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 62*16) = __builtin_e2k_qppermb(in_331[2*i+1], in_331[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 63*16) = __builtin_e2k_qppermb(in_331[2*i+1], in_331[2*i+0], mask_imag);
	}

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < count_out/32/2; ++i)
	{
		uint64_t rev = __builtin_e2k_bitrevd(i);
		int64_t offset = 32 * (((rev>>(shift_out-1)) & 0xAAAAAAAAAAAAAAAA) | ((rev>>(shift_out+1)) & 0x5555555555555555));
		__v2di mask_real = {0x0B0A090803020100, 0x1B1A191813121110};
		__v2di mask_imag = {0x0F0E0D0C07060504, 0x1F1E1D1C17161514};
		*(__v2du*)((void*)data_out + offset +  64*16) = __builtin_e2k_qppermb(in_002[2*i+1], in_002[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  65*16) = __builtin_e2k_qppermb(in_002[2*i+1], in_002[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  66*16) = __builtin_e2k_qppermb(in_102[2*i+1], in_102[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  67*16) = __builtin_e2k_qppermb(in_102[2*i+1], in_102[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  68*16) = __builtin_e2k_qppermb(in_202[2*i+1], in_202[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  69*16) = __builtin_e2k_qppermb(in_202[2*i+1], in_202[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  70*16) = __builtin_e2k_qppermb(in_302[2*i+1], in_302[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  71*16) = __builtin_e2k_qppermb(in_302[2*i+1], in_302[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  72*16) = __builtin_e2k_qppermb(in_012[2*i+1], in_012[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  73*16) = __builtin_e2k_qppermb(in_012[2*i+1], in_012[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  74*16) = __builtin_e2k_qppermb(in_112[2*i+1], in_112[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  75*16) = __builtin_e2k_qppermb(in_112[2*i+1], in_112[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  76*16) = __builtin_e2k_qppermb(in_212[2*i+1], in_212[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  77*16) = __builtin_e2k_qppermb(in_212[2*i+1], in_212[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  78*16) = __builtin_e2k_qppermb(in_312[2*i+1], in_312[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  79*16) = __builtin_e2k_qppermb(in_312[2*i+1], in_312[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  80*16) = __builtin_e2k_qppermb(in_022[2*i+1], in_022[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  81*16) = __builtin_e2k_qppermb(in_022[2*i+1], in_022[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  82*16) = __builtin_e2k_qppermb(in_122[2*i+1], in_122[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  83*16) = __builtin_e2k_qppermb(in_122[2*i+1], in_122[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  84*16) = __builtin_e2k_qppermb(in_222[2*i+1], in_222[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  85*16) = __builtin_e2k_qppermb(in_222[2*i+1], in_222[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  86*16) = __builtin_e2k_qppermb(in_322[2*i+1], in_322[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  87*16) = __builtin_e2k_qppermb(in_322[2*i+1], in_322[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  88*16) = __builtin_e2k_qppermb(in_032[2*i+1], in_032[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  89*16) = __builtin_e2k_qppermb(in_032[2*i+1], in_032[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  90*16) = __builtin_e2k_qppermb(in_132[2*i+1], in_132[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  91*16) = __builtin_e2k_qppermb(in_132[2*i+1], in_132[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  92*16) = __builtin_e2k_qppermb(in_232[2*i+1], in_232[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  93*16) = __builtin_e2k_qppermb(in_232[2*i+1], in_232[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  94*16) = __builtin_e2k_qppermb(in_332[2*i+1], in_332[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  95*16) = __builtin_e2k_qppermb(in_332[2*i+1], in_332[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  96*16) = __builtin_e2k_qppermb(in_003[2*i+1], in_003[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  97*16) = __builtin_e2k_qppermb(in_003[2*i+1], in_003[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset +  98*16) = __builtin_e2k_qppermb(in_103[2*i+1], in_103[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset +  99*16) = __builtin_e2k_qppermb(in_103[2*i+1], in_103[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 100*16) = __builtin_e2k_qppermb(in_203[2*i+1], in_203[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 101*16) = __builtin_e2k_qppermb(in_203[2*i+1], in_203[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 102*16) = __builtin_e2k_qppermb(in_303[2*i+1], in_303[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 103*16) = __builtin_e2k_qppermb(in_303[2*i+1], in_303[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 104*16) = __builtin_e2k_qppermb(in_013[2*i+1], in_013[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 105*16) = __builtin_e2k_qppermb(in_013[2*i+1], in_013[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 106*16) = __builtin_e2k_qppermb(in_113[2*i+1], in_113[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 107*16) = __builtin_e2k_qppermb(in_113[2*i+1], in_113[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 108*16) = __builtin_e2k_qppermb(in_213[2*i+1], in_213[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 109*16) = __builtin_e2k_qppermb(in_213[2*i+1], in_213[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 110*16) = __builtin_e2k_qppermb(in_313[2*i+1], in_313[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 111*16) = __builtin_e2k_qppermb(in_313[2*i+1], in_313[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 112*16) = __builtin_e2k_qppermb(in_023[2*i+1], in_023[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 113*16) = __builtin_e2k_qppermb(in_023[2*i+1], in_023[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 114*16) = __builtin_e2k_qppermb(in_123[2*i+1], in_123[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 115*16) = __builtin_e2k_qppermb(in_123[2*i+1], in_123[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 116*16) = __builtin_e2k_qppermb(in_223[2*i+1], in_223[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 117*16) = __builtin_e2k_qppermb(in_223[2*i+1], in_223[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 118*16) = __builtin_e2k_qppermb(in_323[2*i+1], in_323[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 119*16) = __builtin_e2k_qppermb(in_323[2*i+1], in_323[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 120*16) = __builtin_e2k_qppermb(in_033[2*i+1], in_033[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 121*16) = __builtin_e2k_qppermb(in_033[2*i+1], in_033[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 122*16) = __builtin_e2k_qppermb(in_133[2*i+1], in_133[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 123*16) = __builtin_e2k_qppermb(in_133[2*i+1], in_133[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 124*16) = __builtin_e2k_qppermb(in_233[2*i+1], in_233[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 125*16) = __builtin_e2k_qppermb(in_233[2*i+1], in_233[2*i+0], mask_imag);
		*(__v2du*)((void*)data_out + offset + 126*16) = __builtin_e2k_qppermb(in_333[2*i+1], in_333[2*i+0], mask_real);
		*(__v2du*)((void*)data_out + offset + 127*16) = __builtin_e2k_qppermb(in_333[2*i+1], in_333[2*i+0], mask_imag);
	}
}
Основной цикл на ассемблере
.L15871:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=17, incr=1, ind=0, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=16, incr=1, ind=0, asz=1, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=15, incr=1, ind=0, asz=1, abs=2, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=14, incr=1, ind=0, asz=1, abs=2, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=13, incr=1, ind=0, asz=1, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=12, incr=1, ind=0, asz=1, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=11, incr=1, ind=0, asz=1, abs=6, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=10, incr=1, ind=0, asz=1, abs=6, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=9, incr=1, ind=0, asz=1, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=8, incr=1, ind=0, asz=1, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=7, incr=1, ind=0, asz=1, abs=10, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=6, incr=1, ind=0, asz=1, abs=10, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=5, incr=1, ind=0, asz=1, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=4, incr=1, ind=0, asz=1, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=3, incr=1, ind=0, asz=1, abs=14, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=2, incr=1, ind=0, asz=1, abs=14, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=1, incr=1, ind=0, asz=1, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=15, asz=1, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=14, asz=1, abs=18, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=13, asz=1, abs=18, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=12, asz=1, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=11, asz=1, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=10, asz=1, abs=22, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=9, asz=1, abs=22, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=8, asz=1, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=7, asz=1, abs=24, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=6, asz=1, abs=26, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=5, asz=1, abs=26, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=1, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=1, abs=28, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=1, abs=30, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=30, disp=0
        }
.L15388:
        {
          loop_mode
          disp  %ctpr1, .L15388
          bitrevd,0     %r0, %g16
          addd,1        %r0, 0x1, %r0
          movaqp,0      area=0, ind=16, am=1, be=0, %g18
          movaqp,1      area=0, ind=0, am=0, be=0, %g17
          movaqp,2      area=0, ind=16, am=1, be=0, %g20
          movaqp,3      area=0, ind=0, am=0, be=0, %g19
        }
        {
          loop_mode
          disp  %ctpr3, .L13219
          shrd,0        %g16, %r7, %g25
          shrd,1        %g16, %r6, %g16
          movaqp,0      area=1, ind=16, am=1, be=0, %g22
          movaqp,1      area=1, ind=0, am=0, be=0, %g21
          movaqp,2      area=1, ind=16, am=1, be=0, %g24
          movaqp,3      area=1, ind=0, am=0, be=0, %g23
        }
        {
          loop_mode
          andd,0        %g25, _f64,_lts0 0xaaaaaaaaaaaaaaaa, %g25
          andd,1        %g16, _f64,_lts2 0x5555555555555555, %g16
          movaqp,0      area=2, ind=16, am=1, be=0, %g27
          movaqp,1      area=2, ind=0, am=0, be=0, %g26
          movaqp,2      area=2, ind=16, am=1, be=0, %g29
          movaqp,3      area=2, ind=0, am=0, be=0, %g28
        }
        {
          loop_mode
          ord,0 %g25, %g16, %g16
          movaqp,0      area=3, ind=16, am=1, be=0, %g31
          movaqp,1      area=3, ind=0, am=0, be=0, %g30
          movaqp,2      area=3, ind=16, am=1, be=0, %r9
          movaqp,3      area=3, ind=0, am=0, be=0, %r1
        }
        {
          loop_mode
          shld,0        %g16, 0x5, %g16
          movaqp,0      area=4, ind=16, am=1, be=0, %r10
          movaqp,1      area=4, ind=0, am=0, be=0, %g25
          movaqp,2      area=4, ind=16, am=1, be=0, %r12
          movaqp,3      area=4, ind=0, am=0, be=0, %r11
        }
        {
          loop_mode
          qppermb,0     %g18, %g17, %r4, %r17
          qppermb,1     %g18, %g17, %r5, %g17
          addd,2        %r2, %g16, %g16
          qppermb,3     %g20, %g19, %r4, %g18
          qppermb,4     %g20, %g19, %r5, %g19
          movaqp,0      area=5, ind=16, am=1, be=0, %r14
          movaqp,1      area=5, ind=0, am=0, be=0, %r13
          movaqp,2      area=5, ind=16, am=1, be=0, %r16
          movaqp,3      area=5, ind=0, am=0, be=0, %r15
        }
        {
          loop_mode
          qppermb,0     %g22, %g21, %r4, %r21
          qppermb,1     %g22, %g21, %r5, %g21
          stqp,2        %g16, _f16s,_lts0lo 0x410, %g17
          qppermb,3     %g24, %g23, %r4, %g22
          qppermb,4     %g24, %g23, %r5, %g23
          movaqp,0      area=6, ind=16, am=1, be=0, %r18
          movaqp,1      area=6, ind=0, am=0, be=0, %g20
          movaqp,2      area=6, ind=16, am=1, be=0, %r20
          movaqp,3      area=6, ind=0, am=0, be=0, %r19
        }
        {
          loop_mode
          qppermb,0     %g27, %g26, %r4, %r24
          qppermb,1     %g27, %g26, %r5, %g26
          stqp,2        %g16, _f16s,_lts0lo 0x400, %r17
          qppermb,3     %g29, %g28, %r4, %g27
          qppermb,4     %g29, %g28, %r5, %g28
          stqp,5        %g16, _f16s,_lts0hi 0x430, %g19
          movaqp,0      area=7, ind=16, am=1, be=0, %g24
          movaqp,1      area=7, ind=0, am=0, be=0, %g17
          movaqp,2      area=7, ind=16, am=1, be=0, %r23
          movaqp,3      area=7, ind=0, am=0, be=0, %r22
        }
        {
          loop_mode
          qppermb,0     %g31, %g30, %r4, %r26
          qppermb,1     %g31, %g30, %r5, %g30
          stqp,2        %g16, _f16s,_lts0lo 0x420, %g18
          qppermb,3     %r9, %r1, %r4, %g31
          qppermb,4     %r9, %r1, %r5, %r1
          stqp,5        %g16, _f16s,_lts0hi 0x470, %g23
          movaqp,0      area=8, ind=16, am=1, be=0, %g29
          movaqp,1      area=8, ind=0, am=0, be=0, %g19
          movaqp,2      area=8, ind=16, am=1, be=0, %r25
          movaqp,3      area=8, ind=0, am=0, be=0, %r17
        }
        {
          loop_mode
          qppermb,0     %r10, %g25, %r4, %r28
          qppermb,1     %r10, %g25, %r5, %g25
          stqp,2        %g16, _f16s,_lts0lo 0x440, %r21
          qppermb,3     %r12, %r11, %r4, %r10
          qppermb,4     %r12, %r11, %r5, %r11
          stqp,5        %g16, _f16s,_lts0hi 0x450, %g21
          movaqp,0      area=9, ind=16, am=1, be=0, %g23
          movaqp,1      area=9, ind=0, am=0, be=0, %g18
          movaqp,2      area=9, ind=16, am=1, be=0, %r27
          movaqp,3      area=9, ind=0, am=0, be=0, %r9
        }
        {
          loop_mode
          qppermb,0     %r14, %r13, %r4, %r30
          qppermb,1     %r14, %r13, %r5, %r13
          stqp,2        %g16, _f16s,_lts0lo 0x460, %g22
          qppermb,3     %r16, %r15, %r4, %r14
          qppermb,4     %r16, %r15, %r5, %r15
          stqp,5        %g16, _f16s,_lts0hi 0x490, %g26
          movaqp,0      area=10, ind=16, am=1, be=0, %r12
          movaqp,1      area=10, ind=0, am=0, be=0, %g21
          movaqp,2      area=10, ind=16, am=1, be=0, %r29
          movaqp,3      area=10, ind=0, am=0, be=0, %r21
        }
        {
          loop_mode
          qppermb,0     %r18, %g20, %r4, %r32
          qppermb,1     %r18, %g20, %r5, %g20
          stqp,2        %g16, _f16s,_lts0lo 0x480, %r24
          qppermb,3     %r20, %r19, %r4, %r18
          qppermb,4     %r20, %r19, %r5, %r19
          stqp,5        %g16, _f16s,_lts0hi 0x4b0, %g28
          movaqp,0      area=11, ind=16, am=1, be=0, %g26
          movaqp,1      area=11, ind=0, am=0, be=0, %g22
          movaqp,2      area=11, ind=16, am=1, be=0, %r31
          movaqp,3      area=11, ind=0, am=0, be=0, %r16
        }
        {
          loop_mode
          qppermb,0     %g24, %g17, %r4, %r34
          qppermb,1     %g24, %g17, %r5, %g17
          stqp,2        %g16, _f16s,_lts0lo 0x4a0, %g27
          qppermb,3     %r23, %r22, %r4, %g24
          qppermb,4     %r23, %r22, %r5, %r22
          stqp,5        %g16, _f16s,_lts0hi 0x4d0, %g30
          movaqp,0      area=12, ind=16, am=1, be=0, %r20
          movaqp,1      area=12, ind=0, am=0, be=0, %g28
          movaqp,2      area=12, ind=16, am=1, be=0, %r33
          movaqp,3      area=12, ind=0, am=0, be=0, %r24
        }
        {
          loop_mode
          qppermb,0     %g29, %g19, %r4, %r36
          qppermb,1     %g29, %g19, %r5, %g19
          stqp,2        %g16, _f16s,_lts0lo 0x4c0, %r26
          qppermb,3     %r25, %r17, %r4, %g29
          qppermb,4     %r25, %r17, %r5, %r17
          stqp,5        %g16, _f16s,_lts0hi 0x4f0, %r1
          movaqp,0      area=13, ind=16, am=1, be=0, %g30
          movaqp,1      area=13, ind=0, am=0, be=0, %g27
          movaqp,2      area=13, ind=16, am=1, be=0, %r35
          movaqp,3      area=13, ind=0, am=0, be=0, %r23
        }
        {
          loop_mode
          qppermb,0     %g23, %g18, %r4, %r38
          qppermb,1     %g23, %g18, %r5, %g18
          stqp,2        %g16, _f16s,_lts0lo 0x4e0, %g31
          qppermb,3     %r27, %r9, %r4, %g23
          qppermb,4     %r27, %r9, %r5, %r9
          stqp,5        %g16, _f16s,_lts0hi 0x510, %g25
          movaqp,0      area=14, ind=16, am=1, be=0, %r25
          movaqp,1      area=14, ind=0, am=0, be=0, %r1
          movaqp,2      area=14, ind=16, am=1, be=0, %r37
          movaqp,3      area=14, ind=0, am=0, be=0, %r26
        }
        {
          loop_mode
          qppermb,0     %r12, %g21, %r4, %r40
          qppermb,1     %r12, %g21, %r5, %g21
          stqp,2        %g16, _f16s,_lts0lo 0x500, %r28
          qppermb,3     %r29, %r21, %r4, %r12
          qppermb,4     %r29, %r21, %r5, %r21
          stqp,5        %g16, _f16s,_lts0hi 0x530, %r11
          movaqp,0      area=15, ind=16, am=1, be=0, %g31
          movaqp,1      area=15, ind=0, am=0, be=0, %g25
          movaqp,2      area=15, ind=16, am=1, be=0, %r39
          movaqp,3      area=15, ind=0, am=0, be=0, %r27
        }
        {
          loop_mode
          qppermb,0     %g26, %g22, %r4, %r11
          qppermb,1     %g26, %g22, %r5, %g22
          stqp,2        %g16, _f16s,_lts0lo 0x520, %r10
          qppermb,3     %r31, %r16, %r4, %g26
          qppermb,4     %r31, %r16, %r5, %r16
          stqp,5        %g16, _f16s,_lts0hi 0x550, %r13
        }
        {
          loop_mode
          qppermb,0     %r20, %g28, %r4, %r10
          qppermb,1     %r20, %g28, %r5, %g28
          stqp,2        %g16, _f16s,_lts0lo 0x540, %r30
          qppermb,3     %r33, %r24, %r4, %r13
          qppermb,4     %r33, %r24, %r5, %r20
          stqp,5        %g16, _f16s,_lts0hi 0x570, %r15
        }
        {
          loop_mode
          qppermb,0     %g30, %g27, %r4, %r15
          qppermb,1     %g30, %g27, %r5, %g27
          stqp,2        %g16, _f16s,_lts0lo 0x560, %r14
          qppermb,3     %r35, %r23, %r4, %g30
          qppermb,4     %r35, %r23, %r5, %r23
          stqp,5        %g16, _f16s,_lts0hi 0x590, %g20
        }
        {
          loop_mode
          qppermb,0     %r25, %r1, %r4, %g20
          qppermb,1     %r25, %r1, %r5, %r1
          stqp,2        %g16, _f16s,_lts0lo 0x580, %r32
          qppermb,3     %r37, %r26, %r4, %r14
          qppermb,4     %r37, %r26, %r5, %r24
          stqp,5        %g16, _f16s,_lts0hi 0x5b0, %r19
        }
        {
          loop_mode
          qppermb,0     %g31, %g25, %r4, %r19
          qppermb,1     %g31, %g25, %r5, %g25
          stqp,2        %g16, _f16s,_lts0lo 0x5a0, %r18
          qppermb,3     %r39, %r27, %r4, %g31
          qppermb,4     %r39, %r27, %r5, %r25
          stqp,5        %g16, _f16s,_lts0hi 0x5d0, %g17
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x5c0, %r34
          stqp,5        %g16, _f16s,_lts0hi 0x5f0, %r22
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x5e0, %g24
          stqp,5        %g16, _f16s,_lts0hi 0x610, %g19
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x600, %r36
          stqp,5        %g16, _f16s,_lts0hi 0x630, %r17
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x620, %g29
          stqp,5        %g16, _f16s,_lts0hi 0x650, %g18
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x640, %r38
          stqp,5        %g16, _f16s,_lts0hi 0x670, %r9
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x660, %g23
          stqp,5        %g16, _f16s,_lts0hi 0x690, %g21
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x680, %r40
          stqp,5        %g16, _f16s,_lts0hi 0x6b0, %r21
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x6a0, %r12
          stqp,5        %g16, _f16s,_lts0hi 0x6d0, %g22
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x6c0, %r11
          stqp,5        %g16, _f16s,_lts0hi 0x6f0, %r16
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x6e0, %g26
          stqp,5        %g16, _f16s,_lts0hi 0x710, %g28
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x700, %r10
          stqp,5        %g16, _f16s,_lts0hi 0x730, %r20
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x720, %r13
          stqp,5        %g16, _f16s,_lts0hi 0x750, %g27
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x740, %r15
          stqp,5        %g16, _f16s,_lts0hi 0x770, %r23
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x760, %g30
          stqp,5        %g16, _f16s,_lts0hi 0x790, %r1
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x780, %g20
          stqp,5        %g16, _f16s,_lts0hi 0x7b0, %r24
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x7a0, %r14
          stqp,5        %g16, _f16s,_lts0hi 0x7d0, %g25
        }
        {
          loop_mode
          stqp,2        %g16, _f16s,_lts0lo 0x7c0, %r19
          stqp,5        %g16, _f16s,_lts0hi 0x7f0, %r25
        }
        {
          loop_mode
          ct    %ctpr1 ? %NOT_LOOP_END
          alc   alcf=0, alct=1
          stqp,2        %g16, _f16s,_lts0lo 0x7e0, %g31
        }
        {
          loop_mode
          ct    %ctpr3
          alc   alcf=0, alct=1
        }
.L16599:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=17, incr=1, ind=0, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=16, incr=1, ind=0, asz=1, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=15, incr=1, ind=0, asz=1, abs=2, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=14, incr=1, ind=0, asz=1, abs=2, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=13, incr=1, ind=0, asz=1, abs=4, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=12, incr=1, ind=0, asz=1, abs=4, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=11, incr=1, ind=0, asz=1, abs=6, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=10, incr=1, ind=0, asz=1, abs=6, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=9, incr=1, ind=0, asz=1, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=8, incr=1, ind=0, asz=1, abs=8, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=7, incr=1, ind=0, asz=1, abs=10, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=6, incr=1, ind=0, asz=1, abs=10, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=5, incr=1, ind=0, asz=1, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=4, incr=1, ind=0, asz=1, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=3, incr=1, ind=0, asz=1, abs=14, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=2, incr=1, ind=0, asz=1, abs=14, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=1, incr=1, ind=0, asz=1, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=15, asz=1, abs=16, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=14, asz=1, abs=18, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=13, asz=1, abs=18, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=12, asz=1, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=11, asz=1, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=10, asz=1, abs=22, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=9, asz=1, abs=22, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=8, asz=1, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=7, asz=1, abs=24, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=6, asz=1, abs=26, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=5, asz=1, abs=26, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=4, asz=1, abs=28, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=3, asz=1, abs=28, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=2, asz=1, abs=30, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=30, disp=0
        }
.L15607:
        {
          loop_mode
          disp  %ctpr1, .L15607
          bitrevd,0     %r0, %g16
          addd,1        %r0, 0x1, %r0
          movaqp,0      area=0, ind=16, am=1, be=0, %g18
          movaqp,1      area=0, ind=0, am=0, be=0, %g17
          movaqp,2      area=0, ind=16, am=1, be=0, %g20
          movaqp,3      area=0, ind=0, am=0, be=0, %g19
        }
        {
          loop_mode
          disp  %ctpr3, .L15094
          shrd,0        %g16, %r7, %g25
          shrd,1        %g16, %r6, %g16
          movaqp,0      area=1, ind=16, am=1, be=0, %g22
          movaqp,1      area=1, ind=0, am=0, be=0, %g21
          movaqp,2      area=1, ind=16, am=1, be=0, %g24
          movaqp,3      area=1, ind=0, am=0, be=0, %g23
        }
        {
          loop_mode
          andd,0        %g25, _f64,_lts0 0xaaaaaaaaaaaaaaaa, %g25
          andd,1        %g16, _f64,_lts2 0x5555555555555555, %g16
          movaqp,0      area=2, ind=16, am=1, be=0, %g27
          movaqp,1      area=2, ind=0, am=0, be=0, %g26
          movaqp,2      area=2, ind=16, am=1, be=0, %g29
          movaqp,3      area=2, ind=0, am=0, be=0, %g28
        }
        {
          loop_mode
          ord,0 %g25, %g16, %g16
          movaqp,0      area=3, ind=16, am=1, be=0, %g31
          movaqp,1      area=3, ind=0, am=0, be=0, %g30
          movaqp,2      area=3, ind=16, am=1, be=0, %r14
          movaqp,3      area=3, ind=0, am=0, be=0, %r11
        }
        {
          loop_mode
          shld,0        %g16, 0x5, %g16
          movaqp,0      area=4, ind=16, am=1, be=0, %r18
          movaqp,1      area=4, ind=0, am=0, be=0, %g25
          movaqp,2      area=4, ind=16, am=1, be=0, %r20
          movaqp,3      area=4, ind=0, am=0, be=0, %r19
        }
        {
          loop_mode
          qppermb,0     %g18, %g17, %r4, %r31
          qppermb,1     %g18, %g17, %r5, %g17
          addd,2        %r2, %g16, %g20
          qppermb,3     %g20, %g19, %r4, %g18
          qppermb,4     %g20, %g19, %r5, %g19
          movaqp,0      area=5, ind=16, am=1, be=0, %r25
          movaqp,1      area=5, ind=0, am=0, be=0, %r23
          movaqp,2      area=5, ind=16, am=1, be=0, %r29
          movaqp,3      area=5, ind=0, am=0, be=0, %r28
        }
        {
          loop_mode
          qppermb,0     %g22, %g21, %r4, %r50
          qppermb,1     %g22, %g21, %r5, %g21
          stqp,2        %r2, %g16, %r31
          qppermb,3     %g24, %g23, %r4, %g22
          qppermb,4     %g24, %g23, %r5, %g23
          movaqp,0      area=6, ind=16, am=1, be=0, %r37
          movaqp,1      area=6, ind=0, am=0, be=0, %r34
          movaqp,2      area=6, ind=16, am=1, be=0, %r46
          movaqp,3      area=6, ind=0, am=0, be=0, %r39
        }
        {
          loop_mode
          qppermb,0     %g27, %g26, %r4, %r56
          qppermb,1     %g27, %g26, %r5, %g26
          stqp,2        0x10, %g20, %g17
          qppermb,3     %g29, %g28, %r4, %g27
          qppermb,4     %g29, %g28, %r5, %g28
          stqp,5        %g20, _f16s,_lts0lo 0x30, %g19
          movaqp,0      area=7, ind=16, am=1, be=0, %g24
          movaqp,1      area=7, ind=0, am=0, be=0, %g16
          movaqp,2      area=7, ind=16, am=1, be=0, %r53
          movaqp,3      area=7, ind=0, am=0, be=0, %r31
        }
        {
          loop_mode
          qppermb,0     %g31, %g30, %r4, %r58
          qppermb,1     %g31, %g30, %r5, %g30
          stqp,2        %g20, _f16s,_lts0lo 0x20, %g18
          qppermb,3     %r14, %r11, %r4, %g31
          qppermb,4     %r14, %r11, %r5, %r11
          stqp,5        %g20, _f16s,_lts0hi 0x70, %g23
          movaqp,0      area=8, ind=16, am=1, be=0, %g19
          movaqp,1      area=8, ind=0, am=0, be=0, %g17
          movaqp,2      area=8, ind=16, am=1, be=0, %r57
          movaqp,3      area=8, ind=0, am=0, be=0, %g29
        }
        {
          loop_mode
          qppermb,0     %r18, %g25, %r4, %r61
          qppermb,1     %r18, %g25, %r5, %g25
          stqp,2        %g20, _f16s,_lts0lo 0x40, %r50
          qppermb,3     %r20, %r19, %r4, %r18
          qppermb,4     %r20, %r19, %r5, %r19
          stqp,5        %g20, _f16s,_lts0hi 0x50, %g21
          movaqp,0      area=9, ind=16, am=1, be=0, %g23
          movaqp,1      area=9, ind=0, am=0, be=0, %g18
          movaqp,2      area=9, ind=16, am=1, be=0, %r59
          movaqp,3      area=9, ind=0, am=0, be=0, %r14
        }
        {
          loop_mode
          qppermb,0     %r25, %r23, %r4, %r63
          qppermb,1     %r25, %r23, %r5, %r23
          stqp,2        %g20, _f16s,_lts0lo 0x60, %g22
          qppermb,3     %r29, %r28, %r4, %r25
          qppermb,4     %r29, %r28, %r5, %r28
          stqp,5        %g20, _f16s,_lts0hi 0x90, %g26
          movaqp,0      area=10, ind=16, am=1, be=0, %r20
          movaqp,1      area=10, ind=0, am=0, be=0, %g21
          movaqp,2      area=10, ind=16, am=1, be=0, %r62
          movaqp,3      area=10, ind=0, am=0, be=0, %r50
        }
        {
          loop_mode
          qppermb,0     %r37, %r34, %r4, %b[1]
          qppermb,1     %r37, %r34, %r5, %r34
          stqp,2        %g20, _f16s,_lts0lo 0x80, %r56
          qppermb,3     %r46, %r39, %r4, %r37
          qppermb,4     %r46, %r39, %r5, %r39
          stqp,5        %g20, _f16s,_lts0hi 0xb0, %g28
          movaqp,0      area=11, ind=16, am=1, be=0, %g26
          movaqp,1      area=11, ind=0, am=0, be=0, %g22
          movaqp,2      area=11, ind=16, am=1, be=0, %b[0]
          movaqp,3      area=11, ind=0, am=0, be=0, %r29
        }
        {
          loop_mode
          qppermb,0     %g24, %g16, %r4, %b[3]
          qppermb,1     %g24, %g16, %r5, %g16
          stqp,2        %g20, _f16s,_lts0lo 0xa0, %g27
          qppermb,3     %r53, %r31, %r4, %g24
          qppermb,4     %r53, %r31, %r5, %r31
          stqp,5        %g20, _f16s,_lts0hi 0xd0, %g30
          movaqp,0      area=12, ind=16, am=1, be=0, %r46
          movaqp,1      area=12, ind=0, am=0, be=0, %g28
          movaqp,2      area=12, ind=16, am=1, be=0, %b[2]
          movaqp,3      area=12, ind=0, am=0, be=0, %r56
        }
        {
          loop_mode
          qppermb,0     %g19, %g17, %r4, %b[5]
          qppermb,1     %g19, %g17, %r5, %g17
          stqp,2        %g20, _f16s,_lts0lo 0xc0, %r58
          qppermb,3     %r57, %g29, %r4, %g19
          qppermb,4     %r57, %g29, %r5, %g29
          stqp,5        %g20, _f16s,_lts0hi 0xf0, %r11
          movaqp,0      area=13, ind=16, am=1, be=0, %g30
          movaqp,1      area=13, ind=0, am=0, be=0, %g27
          movaqp,2      area=13, ind=16, am=1, be=0, %b[4]
          movaqp,3      area=13, ind=0, am=0, be=0, %r53
        }
        {
          loop_mode
          qppermb,0     %g23, %g18, %r4, %b[8]
          qppermb,1     %g23, %g18, %r5, %g18
          stqp,2        %g20, _f16s,_lts0lo 0xe0, %g31
          qppermb,3     %r59, %r14, %r4, %g23
          qppermb,4     %r59, %r14, %r5, %r14
          stqp,5        %g20, _f16s,_lts0hi 0x110, %g25
          movaqp,0      area=14, ind=16, am=1, be=0, %r57
          movaqp,1      area=14, ind=0, am=0, be=0, %r11
          movaqp,2      area=14, ind=16, am=1, be=0, %b[6]
          movaqp,3      area=14, ind=0, am=0, be=0, %r58
        }
        {
          loop_mode
          qppermb,0     %r20, %g21, %r4, %b[10]
          qppermb,1     %r20, %g21, %r5, %g21
          stqp,2        %g20, _f16s,_lts0lo 0x100, %r61
          qppermb,3     %r62, %r50, %r4, %r20
          qppermb,4     %r62, %r50, %r5, %r50
          stqp,5        %g20, _f16s,_lts0hi 0x130, %r19
          movaqp,0      area=15, ind=16, am=1, be=0, %g31
          movaqp,1      area=15, ind=0, am=0, be=0, %g25
          movaqp,2      area=15, ind=16, am=1, be=0, %b[9]
          movaqp,3      area=15, ind=0, am=0, be=0, %r59
        }
        {
          loop_mode
          qppermb,0     %g26, %g22, %r4, %r19
          qppermb,1     %g26, %g22, %r5, %g22
          stqp,2        %g20, _f16s,_lts0lo 0x120, %r18
          qppermb,3     %b[0], %r29, %r4, %g26
          qppermb,4     %b[0], %r29, %r5, %r29
          stqp,5        %g20, _f16s,_lts0hi 0x150, %r23
        }
        {
          loop_mode
          qppermb,0     %r46, %g28, %r4, %r18
          qppermb,1     %r46, %g28, %r5, %g28
          stqp,2        %g20, _f16s,_lts0lo 0x140, %r63
          qppermb,3     %b[2], %r56, %r4, %r23
          qppermb,4     %b[2], %r56, %r5, %r46
          stqp,5        %g20, _f16s,_lts0hi 0x170, %r28
        }
        {
          loop_mode
          qppermb,0     %g30, %g27, %r4, %r28
          qppermb,1     %g30, %g27, %r5, %g27
          stqp,2        %g20, _f16s,_lts0lo 0x160, %r25
          qppermb,3     %b[4], %r53, %r4, %g30
          qppermb,4     %b[4], %r53, %r5, %r53
          stqp,5        %g20, _f16s,_lts0hi 0x190, %r34
        }
        {
          loop_mode
          qppermb,0     %r57, %r11, %r4, %r25
          qppermb,1     %r57, %r11, %r5, %r11
          stqp,2        %g20, _f16s,_lts0lo 0x180, %b[1]
          qppermb,3     %b[6], %r58, %r4, %r34
          qppermb,4     %b[6], %r58, %r5, %r56
          stqp,5        %g20, _f16s,_lts0hi 0x1b0, %r39
        }
        {
          loop_mode
          qppermb,0     %g31, %g25, %r4, %r39
          qppermb,1     %g31, %g25, %r5, %g25
          stqp,2        %g20, _f16s,_lts0lo 0x1a0, %r37
          qppermb,3     %b[9], %r59, %r4, %g31
          qppermb,4     %b[9], %r59, %r5, %r57
          stqp,5        %g20, _f16s,_lts0hi 0x1d0, %g16
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x1c0, %b[3]
          stqp,5        %g20, _f16s,_lts0hi 0x1f0, %r31
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x1e0, %g24
          stqp,5        %g20, _f16s,_lts0hi 0x210, %g17
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x200, %b[5]
          stqp,5        %g20, _f16s,_lts0hi 0x230, %g29
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x220, %g19
          stqp,5        %g20, _f16s,_lts0hi 0x250, %g18
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x240, %b[8]
          stqp,5        %g20, _f16s,_lts0hi 0x270, %r14
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x260, %g23
          stqp,5        %g20, _f16s,_lts0hi 0x290, %g21
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x280, %b[10]
          stqp,5        %g20, _f16s,_lts0hi 0x2b0, %r50
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x2a0, %r20
          stqp,5        %g20, _f16s,_lts0hi 0x2d0, %g22
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x2c0, %r19
          stqp,5        %g20, _f16s,_lts0hi 0x2f0, %r29
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x2e0, %g26
          stqp,5        %g20, _f16s,_lts0hi 0x310, %g28
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x300, %r18
          stqp,5        %g20, _f16s,_lts0hi 0x330, %r46
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x320, %r23
          stqp,5        %g20, _f16s,_lts0hi 0x350, %g27
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x340, %r28
          stqp,5        %g20, _f16s,_lts0hi 0x370, %r53
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x360, %g30
          stqp,5        %g20, _f16s,_lts0hi 0x390, %r11
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x380, %r25
          stqp,5        %g20, _f16s,_lts0hi 0x3b0, %r56
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x3a0, %r34
          stqp,5        %g20, _f16s,_lts0hi 0x3d0, %g25
        }
        {
          loop_mode
          stqp,2        %g20, _f16s,_lts0lo 0x3c0, %r39
          stqp,5        %g20, _f16s,_lts0hi 0x3f0, %r57
        }
        {
          loop_mode
          ct    %ctpr1 ? %NOT_LOOP_END
          alc   alcf=0, alct=1
          stqp,2        %g20, _f16s,_lts0lo 0x3e0, %g31
        }
        {
          loop_mode
          ct    %ctpr3
          alc   alcf=0, alct=1
        }

Теоретическая скорость: 128 комплексных чисел за 40 тактов (128/40) = 25.6 Байт/такт

Замеры скорости

Видим замедление по всей длине графика.

Итоги по reverse_radix4_vector4

Победителем можно считать reverse_radix4_vector4_stream16.

При реализации Vector-4 Radix-4 FFT будем использовать его.

Пишем векторный Stage

stage_radix2_vector2

1. stage_radix2_vector2_etalon

Эталонный вариант для сравнения на корректность.

Код на Си
void stage_radix2_vector2_etalon(int data_count, myComplex2 *data_in, myComplex2 *data_out, myComplex2 *coef)
{
	myComplex2 *x_in = &data_in[0];
	myComplex2 *y_in = &data_in[1];
	myComplex2 *c_in = coef;

	myComplex2 *out_add = &data_out[0];
	myComplex2 *out_sub = &data_out[data_count/2];

	#pragma ivdep
	#pragma unroll(1)
//	#pragma prefetch
	for(int64_t i = 0; i < data_count/2; ++i)
	{
		myComplex2 x = x_in[2*i];
		myComplex2 y = y_in[2*i];
		myComplex2 c = c_in[i];

		myComplex2 cy = complex2_mul(c, y);

		out_add[i] = complex2_add(x, cy);
		out_sub[i] = complex2_sub(x, cy);
	}
}
Основной цикл на ассемблере
.L917:
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=5, abs=0, disp=0
        }
.L546:
        {
          loop_mode
          pfmuls,0,sm   %b[67], %b[6], %b[37]
          pfsubs,1,sm   %b[46], %b[24], %b[57]
          staad,2       %b[61], %aad1[ %aasti3 + _f32s,_lts0 0x8 ]
          pfmul_adds,3,sm       %b[55], %b[13], %b[43], %b[14]
          pfadds,4,sm   %b[46], %b[24], %b[58]
          staad,5       %b[62], %aad2[ %aasti4 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=16, am=0, be=0, %b[0]
          movad,1       area=0, ind=24, am=0, be=0, %b[1]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfmuls,0,sm   %b[67], %b[7], %b[62]
          pfsubs,1,sm   %b[35], %b[56], %b[69]
          staad,2       %b[73], %aad1[ %aasti3 ]
          incr,2        %aaincr3
          pfmul_rsubs,3,sm      %b[55], %b[12], %b[68], %b[46]
          pfadds,4,sm   %b[35], %b[56], %b[70]
          staad,5       %b[74], %aad2[ %aasti4 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=0, am=0, be=0, %b[13]
          movad,1       area=0, ind=8, am=1, be=0, %b[24]
          movad,2       area=0, ind=8, am=1, be=0, %b[61]
          movad,3       area=0, ind=0, am=0, be=0, %b[43]
        }

Теоретическая скорость: 4 комплексных числа за 2 такта (4/2) = 16 Байт/такт

Замеры скорости

2. stage_radix2_vector2

Прямая векторизация базового алгоритма в 2 раза с помощью инструкций SIMD64.

Код на Си
void stage_radix2_vector2(int data_count, myComplex2 *data_in, myComplex2 *data_out, myComplex2 *coef)
{
	uint64_t *x_real_in = (uint64_t*)&data_in[0].real;
	uint64_t *x_imag_in = (uint64_t*)&data_in[0].imag;
	uint64_t *y_real_in = (uint64_t*)&data_in[1].real;
	uint64_t *y_imag_in = (uint64_t*)&data_in[1].imag;
	uint64_t *c_real_in = (uint64_t*)&coef[0].real;
	uint64_t *c_imag_in = (uint64_t*)&coef[0].imag;

	uint64_t *out_add_real = (uint64_t*)&data_out[0].real;
	uint64_t *out_add_imag = (uint64_t*)&data_out[0].imag;
	uint64_t *out_sub_real = (uint64_t*)&data_out[data_count/2].real;
	uint64_t *out_sub_imag = (uint64_t*)&data_out[data_count/2].imag;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/2; ++i)
	{
		uint64_t x_real = x_real_in[4*i];
		uint64_t x_imag = x_imag_in[4*i];
		uint64_t y_real = y_real_in[4*i];
		uint64_t y_imag = y_imag_in[4*i];
		uint64_t c_real = c_real_in[2*i];
		uint64_t c_imag = c_imag_in[2*i];

		uint64_t cy_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(c_real, y_real), __builtin_e2k_pfmuls(c_imag, y_imag));
		uint64_t cy_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(c_real, y_imag), __builtin_e2k_pfmuls(c_imag, y_real));

		out_add_real[2*i] = __builtin_e2k_pfadds(x_real, cy_real);
		out_add_imag[2*i] = __builtin_e2k_pfadds(x_imag, cy_imag);
		out_sub_real[2*i] = __builtin_e2k_pfsubs(x_real, cy_real);
		out_sub_imag[2*i] = __builtin_e2k_pfsubs(x_imag, cy_imag);
	}
}
Основной цикл на ассемблере
.L1379:
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=5, abs=0, disp=0
        }
.L1117:
        {
          loop_mode
          pfmuls,0,sm   %b[67], %b[6], %b[37]
          pfsubs,1,sm   %b[46], %b[24], %b[57]
          staad,2       %b[61], %aad1[ %aasti3 + _f32s,_lts0 0x8 ]
          pfmul_adds,3,sm       %b[55], %b[13], %b[43], %b[14]
          pfadds,4,sm   %b[46], %b[24], %b[58]
          staad,5       %b[62], %aad2[ %aasti4 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=16, am=0, be=0, %b[0]
          movad,1       area=0, ind=24, am=0, be=0, %b[1]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfmuls,0,sm   %b[67], %b[7], %b[62]
          pfsubs,1,sm   %b[35], %b[56], %b[69]
          staad,2       %b[73], %aad1[ %aasti3 ]
          incr,2        %aaincr3
          pfmul_rsubs,3,sm      %b[55], %b[12], %b[68], %b[46]
          pfadds,4,sm   %b[35], %b[56], %b[70]
          staad,5       %b[74], %aad2[ %aasti4 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=0, am=0, be=0, %b[13]
          movad,1       area=0, ind=8, am=1, be=0, %b[24]
          movad,2       area=0, ind=8, am=1, be=0, %b[61]
          movad,3       area=0, ind=0, am=0, be=0, %b[43]
        }

Код на ассемблере получился такой же, как в эталонном варианте, то есть компилятор самостоятельно векторизовал эталонный вариант в 2 раза.

Теоретическая скорость: 4 комплексных числа за 2 такта (4/2) = 16 Байт/такт

Замеры скорости

Из консольного вывода от разных размеров массива видно, что эталонный вариант всегда выполняется на 40–50 тактов быстрее.
Я не смог понять, с чем это связано (особенности расположения кода в памяти?).

Итоги по stage_radix2_vector2

stage_radix2_vector4

1. stage_radix2_vector4_etalon

Эталонный вариант для сравнения на корректность.

Код на Си
void stage_radix2_vector4_etalon(int data_count, myComplex4 *data_in, myComplex4 *data_out, myComplex4 *coef)
{
	myComplex4 *x_in = &data_in[0];
	myComplex4 *y_in = &data_in[1];
	myComplex4 *c_in = coef;

	myComplex4 *out_add = &data_out[0];
	myComplex4 *out_sub = &data_out[data_count/2];

	#pragma ivdep
	#pragma unroll(1)
//	#pragma prefetch
	for(int64_t i = 0; i < data_count/2; ++i)
	{
		myComplex4 x = x_in[2*i];
		myComplex4 y = y_in[2*i];
		myComplex4 c = c_in[i];

		myComplex4 cy = complex4_mul(c, y);

		out_add[i] = complex4_add(x, cy);
		out_sub[i] = complex4_sub(x, cy);
	}
}
Основной цикл на ассемблере
.L1531:
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=4, abs=0, disp=16
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=4, abs=16, disp=32
        }
.L926:
        {
          loop_mode
          pfmuls,0,sm   %b[77], %b[39], %b[22]
          pfsubs,1,sm   %b[36], %b[69], %b[52]
          staad,2       %b[54], %aad1[ %aasti3 + _f32s,_lts0 0x8 ]
          pfmul_adds,3,sm       %b[51], %b[43], %b[72], %b[7]
          pfadds,4,sm   %b[36], %b[69], %b[60]
          staad,5       %b[62], %aad2[ %aasti4 + _f32s,_lts0 0x8 ]
          movad,2       area=1, ind=16, am=0, be=0, %b[0]
          movad,3       area=0, ind=0, am=0, be=0, %b[1]
        }
        {
          loop_mode
          pfmuls,0,sm   %b[5], %b[4], %b[62]
          pfsubs,1,sm   %b[23], %b[63], %b[66]
          staad,2       %b[68], %aad1[ %aasti3 ]
          pfmul_adds,3,sm       %b[44], %b[8], %b[78], %b[54]
          pfadds,4,sm   %b[23], %b[63], %b[69]
          staad,5       %b[71], %aad2[ %aasti4 ]
          movad,0       area=1, ind=0, am=0, be=0, %b[36]
          movad,1       area=1, ind=8, am=1, be=0, %b[43]
          movad,3       area=1, ind=8, am=0, be=0, %b[51]
        }
        {
          loop_mode
          pfmuls,0,sm   %b[77], %b[55], %b[68]
          pfsubs,1,sm   %b[35], %b[11], %b[71]
          staad,2       %b[73], %aad1[ %aasti3 + _f32s,_lts0 0x18 ]
          pfmul_rsubs,3,sm      %b[49], %b[57], %b[24], %b[63]
          pfadds,4,sm   %b[35], %b[11], %b[72]
          staad,5       %b[74], %aad2[ %aasti4 + _f32s,_lts0 0x18 ]
          movad,0       area=0, ind=16, am=0, be=0, %b[8]
          movad,1       area=0, ind=24, am=0, be=0, %b[23]
          movad,3       area=1, ind=0, am=0, be=0, %b[44]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfmuls,0,sm   %b[5], %b[48], %b[74]
          pfsubs,1,sm   %b[20], %b[58], %b[77]
          staad,2       %b[79], %aad1[ %aasti3 + _f32s,_lts0 0x10 ]
          incr,2        %aaincr3
          pfmul_rsubs,3,sm      %b[42], %b[50], %b[64], %b[57]
          pfadds,4,sm   %b[20], %b[58], %b[78]
          staad,5       %b[80], %aad2[ %aasti4 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=0, am=0, be=0, %b[11]
          movad,1       area=0, ind=8, am=1, be=0, %b[24]
          movad,2       area=1, ind=24, am=1, be=0, %b[35]
          movad,3       area=0, ind=8, am=1, be=0, %b[73]
        }

Теоретическая скорость: 8 комплексных чисел за 4 такта (8/4) = 16 Байт/такт

Замеры скорости

2. stage_radix2_vector4

Прямая векторизация базового алгоритма в 4 раза с помощью инструкций SIMD128.

Код на Си
void stage_radix2_vector4(int data_count, myComplex4 *data_in, myComplex4 *data_out, myComplex4 *coef)
{
	__v2di *x_real_in = (__v2di*)&data_in[0].real;
	__v2di *x_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *y_real_in = (__v2di*)&data_in[1].real;
	__v2di *y_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *c_real_in = (__v2di*)&coef[0].real;
	__v2di *c_imag_in = (__v2di*)&coef[0].imag;

	__v2di *out_add_real = (__v2di*)&data_out[0].real;
	__v2di *out_add_imag = (__v2di*)&data_out[0].imag;
	__v2di *out_sub_real = (__v2di*)&data_out[data_count/2].real;
	__v2di *out_sub_imag = (__v2di*)&data_out[data_count/2].imag;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/2; ++i)
	{
		__v2di x_real = x_real_in[4*i];
		__v2di x_imag = x_imag_in[4*i];
		__v2di y_real = y_real_in[4*i];
		__v2di y_imag = y_imag_in[4*i];
		__v2di c_real = c_real_in[2*i];
		__v2di c_imag = c_imag_in[2*i];

		__v2di cy_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(c_real, y_real), __builtin_e2k_qpfmuls(c_imag, y_imag));
		__v2di cy_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(c_real, y_imag), __builtin_e2k_qpfmuls(c_imag, y_real));

		out_add_real[2*i] = __builtin_e2k_qpfadds(x_real, cy_real);
		out_add_imag[2*i] = __builtin_e2k_qpfadds(x_imag, cy_imag);
		out_sub_real[2*i] = __builtin_e2k_qpfsubs(x_real, cy_real);
		out_sub_imag[2*i] = __builtin_e2k_qpfsubs(x_imag, cy_imag);
	}
}
Основной цикл на ассемблере
.L1875:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=32
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
        }
.L1577:
        {
          loop_mode
          qpfmuls,0,sm  %b[43], %b[52], %b[45]
          qpfsubs,1,sm  %b[46], %b[24], %b[60]
          staaqp,2      %b[64], %aad1[ %aasti3 + _f32s,_lts0 0x10 ]
          qpfmul_adds,3,sm      %b[12], %b[13], %b[51], %b[14]
          qpfadds,4,sm  %b[46], %b[24], %b[63]
          staaqp,5      %b[67], %aad2[ %aasti4 + _f32s,_lts0 0x10 ]
          movaqp,0      area=1, ind=16, am=1, be=0, %b[37]
          movaqp,1      area=1, ind=0, am=0, be=0, %b[0]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[1]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfmuls,0,sm  %b[43], %b[7], %b[64]
          qpfsubs,1,sm  %b[35], %b[61], %b[67]
          staaqp,2      %b[71], %aad1[ %aasti3 ]
          incr,2        %aaincr3
          qpfmul_rsubs,3,sm     %b[12], %b[58], %b[70], %b[51]
          qpfadds,4,sm  %b[35], %b[61], %b[72]
          staaqp,5      %b[76], %aad2[ %aasti4 ]
          incr,5        %aaincr3
          movaqp,0      area=0, ind=0, am=0, be=0, %b[13]
          movaqp,1      area=0, ind=16, am=1, be=0, %b[24]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[46]
        }

Теоретическая скорость: 8 комплексных чисел за 2 такта (8/2) = 32 Байт/такт

Замеры скорости

Компилятор не сумел векторизовать вариант stage_radix2_vector4_etalon в 4 раза.
До этого он успешно векторизовал вариант stage_radix2_vector2_etalon в 2 раза.

Итоги по stage_radix2_vector4

stage_radix4_vector2

Один проход по stage_radix4_vector2 совершает ту же работу, что 2 прохода по stage_radix2. Поэтому скорость stage_radix4_vector2 будем умножать на 2 для удобства сравнения с stage_radix2 (этот факт подписан на оси графика и в выводе консоли).

1. stage_radix4_vector2_etalon

Эталонный вариант для сравнения на корректность.

Код на Си
void stage_radix4_vector2_etalon(int data_count, myComplex2 *data_in, myComplex2 *data_out, myComplex2 *coefC, myComplex2 *coefD, myComplex2 *coefE)
{
	myComplex2 *x_in = &data_in[0];
	myComplex2 *y_in = &data_in[1];
	myComplex2 *z_in = &data_in[2];
	myComplex2 *w_in = &data_in[3];
	myComplex2 *c_in = coefC;
	myComplex2 *d_in = coefD;
	myComplex2 *e_in = coefE;

	myComplex2 *out_0 = &data_out[0*data_count/4];
	myComplex2 *out_1 = &data_out[1*data_count/4];
	myComplex2 *out_2 = &data_out[2*data_count/4];
	myComplex2 *out_3 = &data_out[3*data_count/4];

	#pragma ivdep
	#pragma unroll(1)
//	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		myComplex2 x = x_in[4*i];
		myComplex2 y = y_in[4*i];
		myComplex2 z = z_in[4*i];
		myComplex2 w = w_in[4*i];
		myComplex2 c = c_in[i];
		myComplex2 d = d_in[i];
		myComplex2 e = e_in[i];

		myComplex2 cy = complex2_mul(c, y);
		myComplex2 dz = complex2_mul(d, z);
		myComplex2 ew = complex2_mul(e, w);

		myComplex2 add02 = complex2_add( x, dz);
		myComplex2 sub02 = complex2_sub( x, dz);
		myComplex2 add13 = complex2_add(cy, ew);
		myComplex2 sub13 = complex2_sub(cy, ew);
		myComplex2 sub13i = complex2_mul_i(sub13);

		out_0[i] = complex2_add(add02, add13);
		out_1[i] = complex2_sub(sub02, sub13i);
		out_2[i] = complex2_sub(add02, add13);
		out_3[i] = complex2_add(sub02, sub13i);
	}
}
Основной цикл на ассемблере
.L2695:
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=4, asz=3, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=3, asz=4, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
        }
.L1896:
        {
          loop_mode
          pfmul_adds,0,sm       %b[48], %b[70], %b[42], %b[0]
          pfsub_rsubs,1,sm      %b[37], %b[73], %b[59], %b[4]
          pfsub_adds,2,sm       %b[37], %b[73], %b[59], %b[1]
          pfmuls,4,sm   %b[63], %b[62], %b[40]
          pfsubs,5,sm   %b[78], %b[74], %b[57]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[48], %b[64], %b[83], %b[70]
          pfadd_adds,1,sm       %b[25], %b[82], %b[90], %b[77]
          pfadd_rsubs,2,sm      %b[25], %b[82], %b[90], %b[73]
          pfmuls,4,sm   %b[63], %b[68], %b[81]
          pfadds,5,sm   %b[78], %b[74], %b[88]
          movad,0       area=2, ind=0, am=0, be=0, %b[42]
          movad,1       area=2, ind=8, am=1, be=0, %b[59]
          movad,2       area=1, ind=0, am=0, be=0, %b[37]
          movad,3       area=0, ind=16, am=0, be=0, %b[58]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[69], %b[13], %b[84], %b[74]
          pfmul_rsubs,1,sm      %b[45], %b[34], %b[85], %b[78]
          staad,2       %b[49], %aad3[ %aasti7 ]
          pfmuls,3,sm   %b[14], %b[53], %b[82]
          pfmuls,4,sm   %b[54], %b[20], %b[83]
          staad,5       %b[26], %aad1[ %aasti5 ]
          movad,0       area=1, ind=0, am=0, be=0, %b[63]
          movad,1       area=0, ind=8, am=0, be=0, %b[25]
          movad,2       area=1, ind=8, am=1, be=0, %b[48]
          movad,3       area=0, ind=24, am=0, be=0, %b[64]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %b[67], %b[53], %b[86], %b[34]
          pfmul_adds,1,sm       %b[45], %b[22], %b[87], %b[69]
          staad,2       %b[10], %aad4[ %aasti8 + _f32s,_lts0 0x8 ]
          pfmuls,3,sm   %b[12], %b[9], %b[84]
          pfmuls,4,sm   %b[54], %b[32], %b[85]
          staad,5       %b[7], %aad2[ %aasti6 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=0, am=0, be=0, %b[13]
          movad,1       area=0, ind=24, am=0, be=0, %b[49]
          movad,2       area=0, ind=0, am=0, be=0, %b[26]
          movad,3       area=0, ind=8, am=1, be=0, %b[14]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[23], %b[80], %b[55], %b[45]
          pfsub_adds,1,sm       %b[23], %b[80], %b[55], %b[22]
          staad,2       %b[6], %aad3[ %aasti7 + _f32s,_lts0 0x8 ]
          incr,2        %aaincr3
          pfsubs,4,sm   %b[2], %b[38], %b[53]
          staad,5       %b[3], %aad1[ %aasti5 + _f32s,_lts0 0x8 ]
          incr,5        %aaincr3
          movad,0       area=1, ind=8, am=1, be=0, %b[10]
          movad,1       area=0, ind=16, am=1, be=0, %b[7]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfadd_adds,0,sm       %b[35], %b[71], %b[56], %b[6]
          pfadd_rsubs,1,sm      %b[35], %b[71], %b[56], %b[3]
          staad,2       %b[79], %aad4[ %aasti8 ]
          incr,2        %aaincr3
          pfadds,4,sm   %b[38], %b[2], %b[54]
          staad,5       %b[75], %aad2[ %aasti6 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 8 комплексных чисел за 6 тактов (8/6) = 10.67 Байт/такт
Двойная теоретическая скорость: 21.33 Байт/такт

Замеры скорости

2. stage_radix4_vector2

Прямая векторизация базового алгоритма в 2 раза с помощью инструкций SIMD64.

Код на Си
void stage_radix4_vector2(int data_count, myComplex2 *data_in, myComplex2 *data_out, myComplex2 *coefC, myComplex2 *coefD, myComplex2 *coefE)
{
	uint64_t *x_real_in = (uint64_t*)&data_in[0].real;
	uint64_t *x_imag_in = (uint64_t*)&data_in[0].imag;
	uint64_t *y_real_in = (uint64_t*)&data_in[1].real;
	uint64_t *y_imag_in = (uint64_t*)&data_in[1].imag;
	uint64_t *z_real_in = (uint64_t*)&data_in[2].real;
	uint64_t *z_imag_in = (uint64_t*)&data_in[2].imag;
	uint64_t *w_real_in = (uint64_t*)&data_in[3].real;
	uint64_t *w_imag_in = (uint64_t*)&data_in[3].imag;
	uint64_t *c_real_in = (uint64_t*)&coefC[0].real;
	uint64_t *c_imag_in = (uint64_t*)&coefC[0].imag;
	uint64_t *d_real_in = (uint64_t*)&coefD[0].real;
	uint64_t *d_imag_in = (uint64_t*)&coefD[0].imag;
	uint64_t *e_real_in = (uint64_t*)&coefE[0].real;
	uint64_t *e_imag_in = (uint64_t*)&coefE[0].imag;

	uint64_t *out_0_real = (uint64_t*)&data_out[0*data_count/4].real;
	uint64_t *out_0_imag = (uint64_t*)&data_out[0*data_count/4].imag;
	uint64_t *out_1_real = (uint64_t*)&data_out[1*data_count/4].real;
	uint64_t *out_1_imag = (uint64_t*)&data_out[1*data_count/4].imag;
	uint64_t *out_2_real = (uint64_t*)&data_out[2*data_count/4].real;
	uint64_t *out_2_imag = (uint64_t*)&data_out[2*data_count/4].imag;
	uint64_t *out_3_real = (uint64_t*)&data_out[3*data_count/4].real;
	uint64_t *out_3_imag = (uint64_t*)&data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		uint64_t x_real = x_real_in[8*i];
		uint64_t x_imag = x_imag_in[8*i];
		uint64_t y_real = y_real_in[8*i];
		uint64_t y_imag = y_imag_in[8*i];
		uint64_t z_real = z_real_in[8*i];
		uint64_t z_imag = z_imag_in[8*i];
		uint64_t w_real = w_real_in[8*i];
		uint64_t w_imag = w_imag_in[8*i];
		uint64_t c_real = c_real_in[2*i];
		uint64_t c_imag = c_imag_in[2*i];
		uint64_t d_real = d_real_in[2*i];
		uint64_t d_imag = d_imag_in[2*i];
		uint64_t e_real = e_real_in[2*i];
		uint64_t e_imag = e_imag_in[2*i];

		uint64_t cy_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(c_real, y_real), __builtin_e2k_pfmuls(c_imag, y_imag));
		uint64_t cy_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(c_real, y_imag), __builtin_e2k_pfmuls(c_imag, y_real));
		uint64_t dz_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(d_real, z_real), __builtin_e2k_pfmuls(d_imag, z_imag));
		uint64_t dz_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(d_real, z_imag), __builtin_e2k_pfmuls(d_imag, z_real));
		uint64_t ew_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(e_real, w_real), __builtin_e2k_pfmuls(e_imag, w_imag));
		uint64_t ew_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(e_real, w_imag), __builtin_e2k_pfmuls(e_imag, w_real));

		uint64_t add02_real = __builtin_e2k_pfadds( x_real, dz_real);
		uint64_t add02_imag = __builtin_e2k_pfadds( x_imag, dz_imag);
		uint64_t sub02_real = __builtin_e2k_pfsubs( x_real, dz_real);
		uint64_t sub02_imag = __builtin_e2k_pfsubs( x_imag, dz_imag);
		uint64_t add13_real = __builtin_e2k_pfadds(cy_real, ew_real);
		uint64_t add13_imag = __builtin_e2k_pfadds(cy_imag, ew_imag);
		uint64_t sub13_real = __builtin_e2k_pfsubs(cy_real, ew_real);
	//	uint64_t sub13_imag = __builtin_e2k_pfsubs(cy_imag, ew_imag);
	//	uint64_t sub13i_real = -sub13_imag;
		uint64_t sub13i_real = __builtin_e2k_pfsubs(ew_imag, cy_imag);
		uint64_t sub13i_imag =  sub13_real;

		out_0_real[2*i] = __builtin_e2k_pfadds(add02_real, add13_real);
		out_0_imag[2*i] = __builtin_e2k_pfadds(add02_imag, add13_imag);
		out_1_real[2*i] = __builtin_e2k_pfsubs(sub02_real, sub13i_real);
		out_1_imag[2*i] = __builtin_e2k_pfsubs(sub02_imag, sub13i_imag);
		out_2_real[2*i] = __builtin_e2k_pfsubs(add02_real, add13_real);
		out_2_imag[2*i] = __builtin_e2k_pfsubs(add02_imag, add13_imag);
		out_3_real[2*i] = __builtin_e2k_pfadds(sub02_real, sub13i_real);
		out_3_imag[2*i] = __builtin_e2k_pfadds(sub02_imag, sub13i_imag);
	}
}
Основной цикл на ассемблере
.L3659:
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=4, asz=3, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=3, asz=4, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
        }
.L3151:
        {
          loop_mode
          pfmul_adds,0,sm       %b[48], %b[70], %b[42], %b[0]
          pfsub_rsubs,1,sm      %b[37], %b[73], %b[59], %b[4]
          pfsub_adds,2,sm       %b[37], %b[73], %b[59], %b[1]
          pfmuls,4,sm   %b[63], %b[62], %b[40]
          pfsubs,5,sm   %b[78], %b[74], %b[57]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[48], %b[64], %b[83], %b[70]
          pfadd_adds,1,sm       %b[25], %b[82], %b[90], %b[77]
          pfadd_rsubs,2,sm      %b[25], %b[82], %b[90], %b[73]
          pfmuls,4,sm   %b[63], %b[68], %b[81]
          pfadds,5,sm   %b[78], %b[74], %b[88]
          movad,0       area=2, ind=0, am=0, be=0, %b[42]
          movad,1       area=2, ind=8, am=1, be=0, %b[59]
          movad,2       area=1, ind=0, am=0, be=0, %b[37]
          movad,3       area=0, ind=16, am=0, be=0, %b[58]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[69], %b[13], %b[84], %b[74]
          pfmul_rsubs,1,sm      %b[45], %b[34], %b[85], %b[78]
          staad,2       %b[49], %aad3[ %aasti7 ]
          pfmuls,3,sm   %b[14], %b[53], %b[82]
          pfmuls,4,sm   %b[54], %b[20], %b[83]
          staad,5       %b[26], %aad1[ %aasti5 ]
          movad,0       area=1, ind=0, am=0, be=0, %b[63]
          movad,1       area=0, ind=8, am=0, be=0, %b[25]
          movad,2       area=1, ind=8, am=1, be=0, %b[48]
          movad,3       area=0, ind=24, am=0, be=0, %b[64]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %b[67], %b[53], %b[86], %b[34]
          pfmul_adds,1,sm       %b[45], %b[22], %b[87], %b[69]
          staad,2       %b[10], %aad4[ %aasti8 + _f32s,_lts0 0x8 ]
          pfmuls,3,sm   %b[12], %b[9], %b[84]
          pfmuls,4,sm   %b[54], %b[32], %b[85]
          staad,5       %b[7], %aad2[ %aasti6 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=0, am=0, be=0, %b[13]
          movad,1       area=0, ind=24, am=0, be=0, %b[49]
          movad,2       area=0, ind=0, am=0, be=0, %b[26]
          movad,3       area=0, ind=8, am=1, be=0, %b[14]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[23], %b[80], %b[55], %b[45]
          pfsub_adds,1,sm       %b[23], %b[80], %b[55], %b[22]
          staad,2       %b[6], %aad3[ %aasti7 + _f32s,_lts0 0x8 ]
          incr,2        %aaincr3
          pfsubs,4,sm   %b[2], %b[38], %b[53]
          staad,5       %b[3], %aad1[ %aasti5 + _f32s,_lts0 0x8 ]
          incr,5        %aaincr3
          movad,0       area=1, ind=8, am=1, be=0, %b[10]
          movad,1       area=0, ind=16, am=1, be=0, %b[7]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfadd_adds,0,sm       %b[35], %b[71], %b[56], %b[6]
          pfadd_rsubs,1,sm      %b[35], %b[71], %b[56], %b[3]
          staad,2       %b[79], %aad4[ %aasti8 ]
          incr,2        %aaincr3
          pfadds,4,sm   %b[38], %b[2], %b[54]
          staad,5       %b[75], %aad2[ %aasti6 ]
          incr,5        %aaincr3
        }

Код на ассемблере получился такой же, как в эталонном варианте, то есть компилятор самостоятельно векторизовал эталонный вариант в 2 раза.

Теоретическая скорость: 8 комплексных чисел за 6 тактов (8/6) = 10.67 Байт/такт
Двойная теоретическая скорость: 21.33 Байт/такт

Замеры скорости

3. stage_radix4_vector2_unroll2

Здесь происходит раскрутка цикла в 2 раза с помощью директивы unroll.

Код на Си
void stage_radix4_vector2_unroll2(int data_count, myComplex2 *data_in, myComplex2 *data_out, myComplex2 *coefC, myComplex2 *coefD, myComplex2 *coefE)
{
	uint64_t *x_real_in = (uint64_t*)&data_in[0].real;
	uint64_t *x_imag_in = (uint64_t*)&data_in[0].imag;
	uint64_t *y_real_in = (uint64_t*)&data_in[1].real;
	uint64_t *y_imag_in = (uint64_t*)&data_in[1].imag;
	uint64_t *z_real_in = (uint64_t*)&data_in[2].real;
	uint64_t *z_imag_in = (uint64_t*)&data_in[2].imag;
	uint64_t *w_real_in = (uint64_t*)&data_in[3].real;
	uint64_t *w_imag_in = (uint64_t*)&data_in[3].imag;
	uint64_t *c_real_in = (uint64_t*)&coefC[0].real;
	uint64_t *c_imag_in = (uint64_t*)&coefC[0].imag;
	uint64_t *d_real_in = (uint64_t*)&coefD[0].real;
	uint64_t *d_imag_in = (uint64_t*)&coefD[0].imag;
	uint64_t *e_real_in = (uint64_t*)&coefE[0].real;
	uint64_t *e_imag_in = (uint64_t*)&coefE[0].imag;

	uint64_t *out_0_real = (uint64_t*)&data_out[0*data_count/4].real;
	uint64_t *out_0_imag = (uint64_t*)&data_out[0*data_count/4].imag;
	uint64_t *out_1_real = (uint64_t*)&data_out[1*data_count/4].real;
	uint64_t *out_1_imag = (uint64_t*)&data_out[1*data_count/4].imag;
	uint64_t *out_2_real = (uint64_t*)&data_out[2*data_count/4].real;
	uint64_t *out_2_imag = (uint64_t*)&data_out[2*data_count/4].imag;
	uint64_t *out_3_real = (uint64_t*)&data_out[3*data_count/4].real;
	uint64_t *out_3_imag = (uint64_t*)&data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(2)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		uint64_t x_real = x_real_in[8*i];
		uint64_t x_imag = x_imag_in[8*i];
		uint64_t y_real = y_real_in[8*i];
		uint64_t y_imag = y_imag_in[8*i];
		uint64_t z_real = z_real_in[8*i];
		uint64_t z_imag = z_imag_in[8*i];
		uint64_t w_real = w_real_in[8*i];
		uint64_t w_imag = w_imag_in[8*i];
		uint64_t c_real = c_real_in[2*i];
		uint64_t c_imag = c_imag_in[2*i];
		uint64_t d_real = d_real_in[2*i];
		uint64_t d_imag = d_imag_in[2*i];
		uint64_t e_real = e_real_in[2*i];
		uint64_t e_imag = e_imag_in[2*i];

		uint64_t cy_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(c_real, y_real), __builtin_e2k_pfmuls(c_imag, y_imag));
		uint64_t cy_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(c_real, y_imag), __builtin_e2k_pfmuls(c_imag, y_real));
		uint64_t dz_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(d_real, z_real), __builtin_e2k_pfmuls(d_imag, z_imag));
		uint64_t dz_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(d_real, z_imag), __builtin_e2k_pfmuls(d_imag, z_real));
		uint64_t ew_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(e_real, w_real), __builtin_e2k_pfmuls(e_imag, w_imag));
		uint64_t ew_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(e_real, w_imag), __builtin_e2k_pfmuls(e_imag, w_real));

		uint64_t add02_real = __builtin_e2k_pfadds( x_real, dz_real);
		uint64_t add02_imag = __builtin_e2k_pfadds( x_imag, dz_imag);
		uint64_t sub02_real = __builtin_e2k_pfsubs( x_real, dz_real);
		uint64_t sub02_imag = __builtin_e2k_pfsubs( x_imag, dz_imag);
		uint64_t add13_real = __builtin_e2k_pfadds(cy_real, ew_real);
		uint64_t add13_imag = __builtin_e2k_pfadds(cy_imag, ew_imag);
		uint64_t sub13_real = __builtin_e2k_pfsubs(cy_real, ew_real);
	//	uint64_t sub13_imag = __builtin_e2k_pfsubs(cy_imag, ew_imag);
	//	uint64_t sub13i_real = -sub13_imag;
		uint64_t sub13i_real = __builtin_e2k_pfsubs(ew_imag, cy_imag);
		uint64_t sub13i_imag =  sub13_real;

		out_0_real[2*i] = __builtin_e2k_pfadds(add02_real, add13_real);
		out_0_imag[2*i] = __builtin_e2k_pfadds(add02_imag, add13_imag);
		out_1_real[2*i] = __builtin_e2k_pfsubs(sub02_real, sub13i_real);
		out_1_imag[2*i] = __builtin_e2k_pfsubs(sub02_imag, sub13i_imag);
		out_2_real[2*i] = __builtin_e2k_pfsubs(add02_real, add13_real);
		out_2_imag[2*i] = __builtin_e2k_pfsubs(add02_imag, add13_imag);
		out_3_real[2*i] = __builtin_e2k_pfadds(sub02_real, sub13i_real);
		out_3_imag[2*i] = __builtin_e2k_pfadds(sub02_imag, sub13i_imag);
	}
}
Основной цикл на ассемблере
.L4871:
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=3, abs=0, disp=16
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=64
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=4, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=16, disp=96
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=3, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=3, asz=3, abs=24, disp=0
        }
.L4115:
        {
          loop_mode
          pfadd_adds,0,sm       %b[56], %b[48], %b[97], %b[91]
          pfadd_rsubs,1,sm      %b[56], %b[48], %b[97], %b[88]
          pfsubs,2,sm   %b[83], %b[73], %b[98]
          pfmul_adds,3,sm       %b[35], %b[49], %b[91], %b[0]
          pfmuls,4,sm   %b[88], %b[4], %b[1]
          pfmuls,5,sm   %b[44], %b[72], %b[95]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[35], %b[29], %g18, %b[11]
          pfmul_adds,1,sm       %b[11], %b[63], %b[96], %b[72]
          pfadds,2,sm   %b[73], %b[83], %b[83]
          pfmul_adds,3,sm       %b[30], %b[72], %b[94], %b[29]
          pfmuls,4,sm   %b[36], %b[47], %g18
          pfadds,5,sm   %g16, %g17, %b[73]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[68], %b[14], %b[24], %g17
          pfmul_rsubs,1,sm      %b[45], %b[34], %b[3], %g16
          pfsubs,2,sm   %g16, %g17, %b[96]
          pfmul_adds,3,sm       %b[18], %b[60], %b[92], %b[3]
          pfmuls,4,sm   %b[10], %b[61], %b[94]
          pfsubs,5,sm   %b[5], %b[31], %b[92]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %b[45], %b[6], %b[71], %b[71]
          pfmul_adds,1,sm       %b[68], %b[41], %b[85], %b[81]
          staad,2       %b[86], %aad3[ %aasti7 + _f32s,_lts0 0x10 ]
          pfmul_rsubs,3,sm      %b[18], %b[67], %b[93], %b[24]
          pfadds,4,sm   %b[31], %b[5], %b[85]
          staad,5       %b[81], %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
          movad,0       area=3, ind=0, am=0, be=0, %b[14]
          movad,1       area=3, ind=8, am=1, be=0, %b[18]
          movad,2       area=3, ind=0, am=0, be=0, %b[5]
          movad,3       area=3, ind=8, am=0, be=0, %b[6]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[19], %b[13], %b[98], %b[84]
          pfsub_adds,1,sm       %b[19], %b[13], %b[98], %b[79]
          staad,2       %b[84], %aad4[ %aasti8 + _f32s,_lts0 0x18 ]
          pfmul_rsubs,3,sm      %b[30], %b[64], %b[95], %b[35]
          pfsubs,4,sm   %b[37], %b[26], %b[93]
          staad,5       %b[79], %aad2[ %aasti6 + _f32s,_lts0 0x18 ]
          movad,0       area=2, ind=24, am=0, be=0, %b[86]
          movad,1       area=1, ind=16, am=0, be=0, %b[30]
          movad,2       area=3, ind=16, am=0, be=0, %b[31]
          movad,3       area=3, ind=24, am=1, be=0, %b[34]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[25], %b[2], %b[83], %b[82]
          pfadd_rsubs,1,sm      %b[25], %b[2], %b[83], %b[77]
          staad,2       %b[82], %aad3[ %aasti7 + _f32s,_lts0 0x18 ]
          pfmuls,3,sm   %g19, %b[12], %b[83]
          pfadds,4,sm   %b[37], %b[26], %b[95]
          staad,5       %b[77], %aad1[ %aasti5 + _f32s,_lts0 0x18 ]
          movad,0       area=2, ind=16, am=0, be=0, %b[41]
          movad,1       area=2, ind=0, am=0, be=0, %b[26]
          movad,2       area=2, ind=24, am=0, be=0, %b[37]
          movad,3       area=0, ind=8, am=0, be=0, %g19
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[25], %b[2], %b[96], %b[80]
          pfsub_adds,1,sm       %b[25], %b[2], %b[96], %b[75]
          staad,2       %b[80], %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          pfmul_rsubs,3,sm      %b[9], %b[40], %b[94], %b[44]
          pfmuls,4,sm   %b[10], %b[40], %b[94]
          staad,5       %b[75], %aad2[ %aasti6 + _f32s,_lts0 0x10 ]
          movad,0       area=2, ind=8, am=1, be=0, %b[40]
          movad,1       area=1, ind=24, am=0, be=0, %b[2]
          movad,2       area=2, ind=0, am=0, be=0, %b[25]
          movad,3       area=2, ind=16, am=0, be=0, %b[10]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[19], %b[13], %b[73], %b[78]
          pfadd_rsubs,1,sm      %b[19], %b[13], %b[73], %b[73]
          staad,2       %b[78], %aad3[ %aasti7 ]
          pfmuls,4,sm   %b[36], %b[27], %b[89]
          staad,5       %b[89], %aad1[ %aasti5 ]
          movad,0       area=1, ind=8, am=1, be=0, %b[19]
          movad,1       area=1, ind=0, am=0, be=0, %b[13]
          movad,2       area=2, ind=8, am=1, be=0, %b[45]
          movad,3       area=1, ind=0, am=0, be=0, %b[36]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[54], %b[46], %b[92], %b[76]
          pfsub_adds,1,sm       %b[54], %b[46], %b[92], %b[87]
          staad,2       %b[76], %aad4[ %aasti8 + _f32s,_lts0 0x8 ]
          pfmuls,4,sm   %b[42], %b[62], %b[92]
          staad,5       %b[87], %aad2[ %aasti6 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=8, am=0, be=0, %b[49]
          movad,1       area=0, ind=0, am=0, be=0, %b[48]
          movad,2       area=1, ind=8, am=0, be=0, %b[57]
          movad,3       area=1, ind=24, am=0, be=0, %b[56]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[55], %b[72], %b[85], %b[74]
          pfadd_rsubs,1,sm      %b[55], %b[72], %b[85], %b[85]
          staad,2       %b[90], %aad3[ %aasti7 + _f32s,_lts0 0x8 ]
          incr,2        %aaincr3
          pfmuls,3,sm   %b[86], %b[30], %b[67]
          pfmuls,4,sm   %b[20], %b[65], %b[90]
          staad,5       %b[74], %aad1[ %aasti5 + _f32s,_lts0 0x8 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=24, am=1, be=0, %b[68]
          movad,1       area=0, ind=16, am=0, be=0, %b[60]
          movad,2       area=1, ind=16, am=1, be=0, %b[63]
          movad,3       area=0, ind=0, am=1, be=0, %b[64]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfsub_rsubs,0,sm      %b[55], %b[72], %b[93], %b[88]
          pfsub_adds,1,sm       %b[55], %b[72], %b[93], %b[72]
          staad,2       %b[91], %aad4[ %aasti8 ]
          incr,2        %aaincr3
          pfmuls,3,sm   %g19, %b[37], %b[20]
          pfmuls,4,sm   %b[20], %b[58], %b[91]
          staad,5       %b[88], %aad2[ %aasti6 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 16 комплексных чисел за 11 тактов (16/11) = 11.64 Байт/такт
Двойная теоретическая скорость: 23.27 Байт/такт

Замеры скорости

4. stage_radix4_vector2_unroll3

Здесь происходит раскрутка цикла в 3 раза с помощью директивы unroll.

Код на Си
void stage_radix4_vector2_unroll3(int data_count, myComplex2 *data_in, myComplex2 *data_out, myComplex2 *coefC, myComplex2 *coefD, myComplex2 *coefE)
{
	uint64_t *x_real_in = (uint64_t*)&data_in[0].real;
	uint64_t *x_imag_in = (uint64_t*)&data_in[0].imag;
	uint64_t *y_real_in = (uint64_t*)&data_in[1].real;
	uint64_t *y_imag_in = (uint64_t*)&data_in[1].imag;
	uint64_t *z_real_in = (uint64_t*)&data_in[2].real;
	uint64_t *z_imag_in = (uint64_t*)&data_in[2].imag;
	uint64_t *w_real_in = (uint64_t*)&data_in[3].real;
	uint64_t *w_imag_in = (uint64_t*)&data_in[3].imag;
	uint64_t *c_real_in = (uint64_t*)&coefC[0].real;
	uint64_t *c_imag_in = (uint64_t*)&coefC[0].imag;
	uint64_t *d_real_in = (uint64_t*)&coefD[0].real;
	uint64_t *d_imag_in = (uint64_t*)&coefD[0].imag;
	uint64_t *e_real_in = (uint64_t*)&coefE[0].real;
	uint64_t *e_imag_in = (uint64_t*)&coefE[0].imag;

	uint64_t *out_0_real = (uint64_t*)&data_out[0*data_count/4].real;
	uint64_t *out_0_imag = (uint64_t*)&data_out[0*data_count/4].imag;
	uint64_t *out_1_real = (uint64_t*)&data_out[1*data_count/4].real;
	uint64_t *out_1_imag = (uint64_t*)&data_out[1*data_count/4].imag;
	uint64_t *out_2_real = (uint64_t*)&data_out[2*data_count/4].real;
	uint64_t *out_2_imag = (uint64_t*)&data_out[2*data_count/4].imag;
	uint64_t *out_3_real = (uint64_t*)&data_out[3*data_count/4].real;
	uint64_t *out_3_imag = (uint64_t*)&data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(3)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		uint64_t x_real = x_real_in[8*i];
		uint64_t x_imag = x_imag_in[8*i];
		uint64_t y_real = y_real_in[8*i];
		uint64_t y_imag = y_imag_in[8*i];
		uint64_t z_real = z_real_in[8*i];
		uint64_t z_imag = z_imag_in[8*i];
		uint64_t w_real = w_real_in[8*i];
		uint64_t w_imag = w_imag_in[8*i];
		uint64_t c_real = c_real_in[2*i];
		uint64_t c_imag = c_imag_in[2*i];
		uint64_t d_real = d_real_in[2*i];
		uint64_t d_imag = d_imag_in[2*i];
		uint64_t e_real = e_real_in[2*i];
		uint64_t e_imag = e_imag_in[2*i];

		uint64_t cy_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(c_real, y_real), __builtin_e2k_pfmuls(c_imag, y_imag));
		uint64_t cy_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(c_real, y_imag), __builtin_e2k_pfmuls(c_imag, y_real));
		uint64_t dz_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(d_real, z_real), __builtin_e2k_pfmuls(d_imag, z_imag));
		uint64_t dz_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(d_real, z_imag), __builtin_e2k_pfmuls(d_imag, z_real));
		uint64_t ew_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(e_real, w_real), __builtin_e2k_pfmuls(e_imag, w_imag));
		uint64_t ew_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(e_real, w_imag), __builtin_e2k_pfmuls(e_imag, w_real));

		uint64_t add02_real = __builtin_e2k_pfadds( x_real, dz_real);
		uint64_t add02_imag = __builtin_e2k_pfadds( x_imag, dz_imag);
		uint64_t sub02_real = __builtin_e2k_pfsubs( x_real, dz_real);
		uint64_t sub02_imag = __builtin_e2k_pfsubs( x_imag, dz_imag);
		uint64_t add13_real = __builtin_e2k_pfadds(cy_real, ew_real);
		uint64_t add13_imag = __builtin_e2k_pfadds(cy_imag, ew_imag);
		uint64_t sub13_real = __builtin_e2k_pfsubs(cy_real, ew_real);
	//	uint64_t sub13_imag = __builtin_e2k_pfsubs(cy_imag, ew_imag);
	//	uint64_t sub13i_real = -sub13_imag;
		uint64_t sub13i_real = __builtin_e2k_pfsubs(ew_imag, cy_imag);
		uint64_t sub13i_imag =  sub13_real;

		out_0_real[2*i] = __builtin_e2k_pfadds(add02_real, add13_real);
		out_0_imag[2*i] = __builtin_e2k_pfadds(add02_imag, add13_imag);
		out_1_real[2*i] = __builtin_e2k_pfsubs(sub02_real, sub13i_real);
		out_1_imag[2*i] = __builtin_e2k_pfsubs(sub02_imag, sub13i_imag);
		out_2_real[2*i] = __builtin_e2k_pfsubs(add02_real, add13_real);
		out_2_imag[2*i] = __builtin_e2k_pfsubs(add02_imag, add13_imag);
		out_3_real[2*i] = __builtin_e2k_pfadds(sub02_real, sub13i_real);
		out_3_imag[2*i] = __builtin_e2k_pfadds(sub02_imag, sub13i_imag);
	}
}
Основной цикл на ассемблере
.L6432:
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=2, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=2, abs=4, disp=64
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=2, abs=4, disp=96
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=128
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=160
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=4, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=3, asz=2, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=2, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=4, asz=3, abs=16, disp=32
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=3, asz=3, abs=24, disp=32
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=3, abs=24, disp=32
        }
.L4979:
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[40], %g19, %g20, %g21
          pfadd_adds,1,sm       %b[77], %g16, %g17, %g18
          pfsubs,2,sm   %g22, %g23, %g24
          pfmuls,3,sm   %b[6], %b[32], %g27
          pfmuls,4,sm   %b[56], %b[65], %g26
          pfmuls,5,sm   %b[72], %b[48], %g25
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[68], %g28, %g29, %g31
          pfadd_rsubs,1,sm      %b[68], %g28, %g29, %g30
          pfadds,2,sm   %g23, %g22, %r0
          pfmuls,3,sm   %b[55], %b[61], %r3
          pfmuls,4,sm   %b[56], %b[102], %r2
          pfmuls,5,sm   %b[52], %b[99], %r1
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[68], %g28, %r4, %r7
          pfsub_adds,1,sm       %b[68], %g28, %r4, %r5
          pfmuls,2,sm   %b[20], %b[78], %r8
          pfmuls,3,sm   %b[18], %b[90], %r11
          pfmuls,4,sm   %b[51], %b[95], %r10
          pfmuls,5,sm   %b[41], %b[83], %r9
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[40], %g19, %r12, %r14
          pfadd_rsubs,1,sm      %b[40], %g19, %r12, %r13
          pfmuls,2,sm   %b[35], %b[112], %r18
          pfmuls,3,sm   %b[55], %b[116], %r20
          pfmuls,4,sm   %b[35], %b[113], %r19
          pfadds,5,sm   %r15, %r16, %r17
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[77], %g16, %g24, %g24
          pfsub_adds,1,sm       %b[77], %g16, %g24, %r22
          staad,2       %b[119], %aad3[ %aasti7 + _f32s,_lts0 0x10 ]
          pfmuls,3,sm   %b[70], %b[104], %b[0]
          pfsubs,4,sm   %r23, %r24, %r25
          staad,5       %r21, %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[14], %b[103], %r0, %b[118]
          pfadd_rsubs,1,sm      %b[14], %b[103], %r0, %r27
          staad,2       %b[118], %aad4[ %aasti8 + _f32s,_lts0 0x18 ]
          pfmul_adds,3,sm       %b[23], %b[107], %r1, %b[20]
          pfadds,4,sm   %r24, %r23, %r0
          staad,5       %r26, %aad2[ %aasti6 + _f32s,_lts0 0x18 ]
          movad,0       area=5, ind=0, am=0, be=0, %b[1]
          movad,1       area=5, ind=8, am=1, be=0, %b[14]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %b[69], %b[106], %g25, %r24
          pfmul_rsubs,1,sm      %b[7], %b[92], %r8, %g16
          staad,2       %r29, %aad3[ %aasti7 + _f32s,_lts0 0x18 ]
          pfmul_adds,3,sm       %b[45], %b[65], %r2, %r23
          pfsubs,4,sm   %r15, %r16, %r1
          staad,5       %r28, %aad1[ %aasti5 + _f32s,_lts0 0x18 ]
          movad,0       area=4, ind=0, am=0, be=0, %b[40]
          movad,1       area=4, ind=16, am=0, be=0, %b[41]
          movad,2       area=5, ind=0, am=0, be=0, %b[7]
          movad,3       area=5, ind=8, am=1, be=0, %b[35]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[45], %b[102], %g26, %r16
          pfmul_rsubs,1,sm      %b[19], %b[113], %r18, %g19
          staad,2       %r31, %aad3[ %aasti7 + _f32s,_lts0 0x28 ]
          pfmul_rsubs,3,sm      %b[23], %b[99], %r34, %b[55]
          pfsubs,4,sm   %r32, %r33, %g25
          staad,5       %r30, %aad1[ %aasti5 + _f32s,_lts0 0x28 ]
          movad,0       area=4, ind=8, am=1, be=0, %b[51]
          movad,1       area=4, ind=24, am=0, be=0, %b[52]
          movad,2       area=4, ind=0, am=0, be=0, %b[23]
          movad,3       area=4, ind=8, am=1, be=0, %b[45]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %b[29], %b[89], %r10, %g23
          pfmul_adds,1,sm       %b[13], %b[86], %r9, %g22
          staad,2       %r36, %aad2[ %aasti6 + _f32s,_lts1 0x10 ]
          pfmul_rsubs,3,sm      %b[11], %b[81], %r37, %r33
          pfadds,4,sm   %r32, %r33, %g17
          staad,5       %r35, %aad2[ %aasti6 + _f32s,_lts0 0x20 ]
          movad,0       area=3, ind=0, am=0, be=0, %b[56]
          movad,1       area=3, ind=16, am=0, be=0, %b[65]
          movad,2       area=3, ind=0, am=0, be=0, %b[13]
          movad,3       area=3, ind=8, am=0, be=0, %b[29]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[69], %b[48], %b[2], %r15
          pfmul_adds,1,sm       %b[19], %b[112], %r19, %g28
          staad,2       %r39, %aad1[ %aasti5 ]
          pfmul_rsubs,3,sm      %b[27], %b[93], %r41, %r32
          pfsubs,4,sm   %r40, %b[80], %g20
          staad,5       %r38, %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          movad,0       area=3, ind=8, am=1, be=0, %b[2]
          movad,1       area=3, ind=24, am=0, be=0, %b[68]
          movad,2       area=3, ind=16, am=0, be=0, %b[19]
          movad,3       area=3, ind=24, am=1, be=0, %b[48]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[28], %b[57], %r25, %b[117]
          pfsub_adds,1,sm       %b[28], %b[57], %r25, %r21
          staad,2       %g21, %aad3[ %aasti7 ]
          pfmul_adds,3,sm       %b[60], %b[117], %g27, %b[78]
          pfmuls,4,sm   %b[6], %b[117], %g18
          staad,5       %g18, %aad4[ %aasti8 + _f32s,_lts0 0x20 ]
          movad,0       area=2, ind=0, am=0, be=0, %b[69]
          movad,1       area=2, ind=8, am=0, be=0, %b[6]
          movad,2       area=2, ind=8, am=0, be=0, %b[72]
          movad,3       area=2, ind=16, am=0, be=0, %b[77]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[98], %b[22], %r0, %b[116]
          pfadd_rsubs,1,sm      %b[98], %b[22], %r0, %r26
          staad,2       %g31, %aad4[ %aasti8 + _f32s,_lts0 0x8 ]
          pfmul_adds,3,sm       %b[44], %b[116], %r3, %r40
          pfadds,4,sm   %b[80], %r40, %g29
          staad,5       %g30, %aad2[ %aasti6 + _f32s,_lts0 0x8 ]
          movad,0       area=2, ind=16, am=0, be=0, %b[89]
          movad,1       area=2, ind=24, am=1, be=0, %b[83]
          movad,2       area=2, ind=0, am=1, be=0, %b[86]
          movad,3       area=2, ind=24, am=0, be=0, %b[80]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[98], %b[22], %r1, %r29
          pfsub_adds,1,sm       %b[98], %b[22], %r1, %r28
          staad,2       %r7, %aad3[ %aasti7 + _f32s,_lts0 0x8 ]
          pfmul_adds,3,sm       %b[5], %b[76], %r11, %b[99]
          pfsubs,4,sm   %r42, %r43, %r4
          staad,5       %r5, %aad1[ %aasti5 + _f32s,_lts0 0x8 ]
          movad,0       area=1, ind=8, am=0, be=0, %b[92]
          movad,1       area=1, ind=0, am=0, be=0, %b[22]
          movad,2       area=1, ind=16, am=0, be=0, %b[98]
          movad,3       area=1, ind=0, am=0, be=0, %b[95]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[12], %b[101], %g25, %r31
          pfsub_adds,1,sm       %b[12], %b[101], %g25, %r30
          staad,2       %r14, %aad4[ %aasti8 ]
          pfmul_rsubs,3,sm      %b[44], %b[61], %r20, %r43
          pfadds,4,sm   %r42, %r43, %r12
          staad,5       %r13, %aad2[ %aasti6 ]
          movad,0       area=1, ind=16, am=0, be=0, %b[44]
          movad,1       area=1, ind=24, am=1, be=0, %b[102]
          movad,2       area=1, ind=24, am=0, be=0, %b[61]
          movad,3       area=1, ind=8, am=1, be=0, %b[103]
        }
        {
          loop_mode
          pfadd_rsubs,0,sm      %b[28], %b[57], %r17, %r36
          pfadd_rsubs,1,sm      %b[75], %g16, %g17, %r35
          staad,2       %g24, %aad3[ %aasti7 + _f32s,_lts0 0x20 ]
          incr,2        %aaincr3
          pfmul_rsubs,3,sm      %b[60], %b[32], %g18, %r42
          pfmuls,4,sm   %b[37], %b[82], %r37
          staad,5       %r22, %aad1[ %aasti5 + _f32s,_lts0 0x20 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=8, am=0, be=0, %b[60]
          movad,1       area=0, ind=0, am=0, be=0, %b[32]
          movad,2       area=0, ind=0, am=0, be=0, %b[107]
          movad,3       area=0, ind=8, am=0, be=0, %b[106]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfsub_adds,0,sm       %b[38], %g19, %g20, %r39
          pfadd_adds,1,sm       %b[28], %b[57], %r17, %r38
          staad,2       %b[118], %aad4[ %aasti8 + _f32s,_lts0 0x28 ]
          incr,2        %aaincr3
          pfmuls,3,sm   %b[47], %b[85], %r41
          pfmuls,4,sm   %b[50], %b[105], %r34
          staad,5       %r27, %aad2[ %aasti6 + _f32s,_lts0 0x28 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=24, am=1, be=0, %b[113]
          movad,1       area=0, ind=16, am=0, be=0, %b[28]
          movad,2       area=0, ind=24, am=1, be=0, %b[112]
          movad,3       area=0, ind=16, am=0, be=0, %b[57]
        }

Теоретическая скорость: 24 комплексных числа за 16 тактов (24/16) = 12 Байт/такт
Двойная теоретическая скорость: 24 Байт/такт

Замеры скорости

Итоги по stage_radix4_vector2

stage_radix4_vector4

Один проход по stage_radix4_vector4 совершает ту же работу, что 2 прохода по stage_radix2. Поэтому скорость stage_radix4_vector4 будем умножать на 2 для удобства сравнения с stage_radix2 (этот факт подписан на оси графика и в выводе консоли).

1. stage_radix4_vector4_etalon

Эталонный вариант для сравнения на корректность.

Код на Си
void stage_radix4_vector4_etalon(int data_count, myComplex4 *data_in, myComplex4 *data_out, myComplex4 *coefC, myComplex4 *coefD, myComplex4 *coefE)
{
	myComplex4 *x_in = &data_in[0];
	myComplex4 *y_in = &data_in[1];
	myComplex4 *z_in = &data_in[2];
	myComplex4 *w_in = &data_in[3];
	myComplex4 *c_in = coefC;
	myComplex4 *d_in = coefD;
	myComplex4 *e_in = coefE;

	myComplex4 *out_0 = &data_out[0*data_count/4];
	myComplex4 *out_1 = &data_out[1*data_count/4];
	myComplex4 *out_2 = &data_out[2*data_count/4];
	myComplex4 *out_3 = &data_out[3*data_count/4];

	#pragma ivdep
	#pragma unroll(1)
//	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		myComplex4 x = x_in[4*i];
		myComplex4 y = y_in[4*i];
		myComplex4 z = z_in[4*i];
		myComplex4 w = w_in[4*i];
		myComplex4 c = c_in[i];
		myComplex4 d = d_in[i];
		myComplex4 e = e_in[i];

		myComplex4 cy = complex4_mul(c, y);
		myComplex4 dz = complex4_mul(d, z);
		myComplex4 ew = complex4_mul(e, w);

		myComplex4 add02 = complex4_add( x, dz);
		myComplex4 sub02 = complex4_sub( x, dz);
		myComplex4 add13 = complex4_add(cy, ew);
		myComplex4 sub13 = complex4_sub(cy, ew);
		myComplex4 sub13i = complex4_mul_i(sub13);

		out_0[i] = complex4_add(add02, add13);
		out_1[i] = complex4_sub(sub02, sub13i);
		out_2[i] = complex4_sub(add02, add13);
		out_3[i] = complex4_add(sub02, sub13i);
	}
}
Основной цикл на ассемблере
.L4263:
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=3, abs=0, disp=16
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=64
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=4, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=3, abs=16, disp=96
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=3, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=0, d=0, incr=2, ind=3, asz=3, abs=24, disp=0
        }
.L3418:
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[68], %b[38], %b[93], %b[98]
          pfsub_adds,1,sm       %b[68], %b[38], %b[93], %b[93]
          pfsubs,2,sm   %b[87], %b[77], %b[102]
          pfmul_adds,3,sm       %b[19], %b[59], %b[98], %b[0]
          pfmuls,4,sm   %b[47], %b[53], %b[1]
          pfmuls,5,sm   %b[26], %b[11], %b[100]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %b[22], %b[32], %b[91], %b[26]
          pfmul_adds,1,sm       %b[18], %b[55], %b[97], %b[32]
          pfadds,2,sm   %b[87], %b[77], %b[91]
          pfmul_adds,3,sm       %b[14], %b[45], %b[99], %b[38]
          pfmuls,4,sm   %b[26], %b[15], %b[87]
          pfadds,5,sm   %g16, %g17, %b[77]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[22], %b[72], %b[6], %g17
          pfmul_rsubs,1,sm      %b[18], %b[76], %b[3], %g16
          pfsubs,2,sm   %g16, %g17, %b[99]
          pfmul_adds,3,sm       %b[10], %b[23], %b[101], %b[23]
          pfadds,4,sm   %b[34], %b[28], %b[76]
          pfsubs,5,sm   %b[25], %b[40], %b[97]
          movad,0       area=3, ind=8, am=1, be=0, %b[6]
          movad,1       area=3, ind=0, am=0, be=0, %b[18]
          movad,2       area=3, ind=0, am=0, be=0, %b[3]
          movad,3       area=3, ind=16, am=0, be=0, %b[22]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[10], %b[71], %b[56], %b[75]
          pfmul_rsubs,1,sm      %b[14], %b[75], %b[31], %b[85]
          staad,2       %b[90], %aad3[ %aasti7 + _f32s,_lts0 0x18 ]
          pfmul_rsubs,3,sm      %b[19], %b[51], %b[95], %b[31]
          pfadds,4,sm   %b[40], %b[25], %b[90]
          staad,5       %b[85], %aad1[ %aasti5 + _f32s,_lts0 0x18 ]
          movad,0       area=2, ind=0, am=0, be=0, %b[14]
          movad,1       area=2, ind=8, am=0, be=0, %b[10]
          movad,2       area=2, ind=24, am=0, be=0, %b[19]
          movad,3       area=0, ind=8, am=0, be=0, %b[25]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[39], %b[2], %b[102], %b[88]
          pfsub_adds,1,sm       %b[39], %b[2], %b[102], %b[83]
          staad,2       %b[89], %aad4[ %aasti8 + _f32s,_lts0 0x8 ]
          pfmul_adds,3,sm       %b[7], %b[15], %b[100], %b[40]
          pfmuls,4,sm   %b[83], %b[70], %b[89]
          staad,5       %b[88], %aad2[ %aasti6 + _f32s,_lts0 0x8 ]
          movad,0       area=2, ind=16, am=0, be=0, %b[45]
          movad,1       area=2, ind=24, am=1, be=0, %b[44]
          movad,2       area=3, ind=8, am=0, be=0, %b[15]
          movad,3       area=1, ind=24, am=0, be=0, %b[41]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[52], %b[33], %b[91], %b[87]
          pfadd_rsubs,1,sm      %b[52], %b[33], %b[91], %b[86]
          staad,2       %b[86], %aad3[ %aasti7 + _f32s,_lts0 0x10 ]
          pfmul_rsubs,3,sm      %b[7], %b[11], %b[87], %b[34]
          pfsubs,4,sm   %b[28], %b[34], %b[91]
          staad,5       %b[81], %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
          movad,0       area=1, ind=16, am=0, be=0, %b[11]
          movad,1       area=1, ind=0, am=0, be=0, %b[7]
          movad,2       area=2, ind=16, am=0, be=0, %b[28]
          movad,3       area=0, ind=0, am=1, be=0, %b[81]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[65], %b[42], %b[99], %b[84]
          pfsub_adds,1,sm       %b[65], %b[42], %b[99], %b[79]
          staad,2       %b[84], %aad4[ %aasti8 ]
          pfmuls,4,sm   %b[47], %b[74], %b[95]
          staad,5       %b[79], %aad2[ %aasti6 ]
          movad,0       area=1, ind=24, am=0, be=0, %b[55]
          movad,1       area=1, ind=8, am=1, be=0, %b[47]
          movad,2       area=3, ind=24, am=1, be=0, %b[56]
          movad,3       area=1, ind=16, am=0, be=0, %b[51]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[66], %b[36], %b[77], %b[82]
          pfadd_rsubs,1,sm      %b[66], %b[36], %b[77], %b[77]
          staad,2       %b[96], %aad3[ %aasti7 + _f32s,_lts0 0x8 ]
          pfmuls,4,sm   %b[58], %b[49], %b[96]
          staad,5       %b[82], %aad1[ %aasti5 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=0, am=0, be=0, %b[60]
          movad,1       area=0, ind=16, am=0, be=0, %b[59]
          movad,2       area=2, ind=8, am=1, be=0, %b[67]
          movad,3       area=2, ind=0, am=0, be=0, %b[68]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[52], %b[33], %b[97], %b[94]
          pfsub_adds,1,sm       %b[52], %b[33], %b[97], %b[80]
          staad,2       %b[94], %aad2[ %aasti6 + _f32s,_lts1 0x10 ]
          pfmuls,3,sm   %b[25], %b[19], %b[52]
          pfmuls,4,sm   %b[46], %b[73], %b[97]
          staad,5       %b[80], %aad2[ %aasti6 + _f32s,_lts0 0x18 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=8, am=1, be=0, %b[46]
          movad,1       area=0, ind=24, am=0, be=0, %b[33]
          movad,2       area=1, ind=8, am=1, be=0, %b[71]
          movad,3       area=1, ind=0, am=0, be=0, %b[72]
        }
        {
          loop_mode
          pfadd_rsubs,0,sm      %b[65], %b[42], %b[76], %b[92]
          pfadd_rsubs,1,sm      %b[39], %b[2], %b[90], %b[78]
          staad,2       %b[92], %aad4[ %aasti8 + _f32s,_lts1 0x10 ]
          pfmuls,3,sm   %b[44], %b[41], %b[27]
          pfmuls,4,sm   %b[27], %b[69], %b[99]
          staad,5       %b[78], %aad4[ %aasti8 + _f32s,_lts0 0x18 ]
          incr,5        %aaincr3
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfadd_adds,0,sm       %b[65], %b[42], %b[76], %b[90]
          pfadd_adds,1,sm       %b[39], %b[2], %b[90], %b[76]
          staad,2       %b[98], %aad3[ %aasti7 ]
          incr,2        %aaincr3
          pfmuls,3,sm   %b[81], %b[28], %b[2]
          pfmuls,4,sm   %b[58], %b[57], %b[93]
          staad,5       %b[93], %aad1[ %aasti5 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 16 комплексных чисел за 11 тактов (16/11) = 11.64 Байт/такт
Двойная теоретическая скорость: 23.27 Байт/такт

Замеры скорости

2. stage_radix4_vector4

Прямая векторизация базового алгоритма в 4 раза с помощью инструкций SIMD128.

Код на Си
void stage_radix4_vector4(int data_count, myComplex4 *data_in, myComplex4 *data_out, myComplex4 *coefC, myComplex4 *coefD, myComplex4 *coefE)
{
	__v2di *x_real_in = (__v2di*)&data_in[0].real;
	__v2di *x_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *y_real_in = (__v2di*)&data_in[1].real;
	__v2di *y_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *z_real_in = (__v2di*)&data_in[2].real;
	__v2di *z_imag_in = (__v2di*)&data_in[2].imag;
	__v2di *w_real_in = (__v2di*)&data_in[3].real;
	__v2di *w_imag_in = (__v2di*)&data_in[3].imag;
	__v2di *c_real_in = (__v2di*)&coefC[0].real;
	__v2di *c_imag_in = (__v2di*)&coefC[0].imag;
	__v2di *d_real_in = (__v2di*)&coefD[0].real;
	__v2di *d_imag_in = (__v2di*)&coefD[0].imag;
	__v2di *e_real_in = (__v2di*)&coefE[0].real;
	__v2di *e_imag_in = (__v2di*)&coefE[0].imag;

	__v2di *out_0_real = (__v2di*)&data_out[0*data_count/4].real;
	__v2di *out_0_imag = (__v2di*)&data_out[0*data_count/4].imag;
	__v2di *out_1_real = (__v2di*)&data_out[1*data_count/4].real;
	__v2di *out_1_imag = (__v2di*)&data_out[1*data_count/4].imag;
	__v2di *out_2_real = (__v2di*)&data_out[2*data_count/4].real;
	__v2di *out_2_imag = (__v2di*)&data_out[2*data_count/4].imag;
	__v2di *out_3_real = (__v2di*)&data_out[3*data_count/4].real;
	__v2di *out_3_imag = (__v2di*)&data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		__v2di x_real = x_real_in[8*i];
		__v2di x_imag = x_imag_in[8*i];
		__v2di y_real = y_real_in[8*i];
		__v2di y_imag = y_imag_in[8*i];
		__v2di z_real = z_real_in[8*i];
		__v2di z_imag = z_imag_in[8*i];
		__v2di w_real = w_real_in[8*i];
		__v2di w_imag = w_imag_in[8*i];
		__v2di c_real = c_real_in[2*i];
		__v2di c_imag = c_imag_in[2*i];
		__v2di d_real = d_real_in[2*i];
		__v2di d_imag = d_imag_in[2*i];
		__v2di e_real = e_real_in[2*i];
		__v2di e_imag = e_imag_in[2*i];

		__v2di cy_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(c_real, y_real), __builtin_e2k_qpfmuls(c_imag, y_imag));
		__v2di cy_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(c_real, y_imag), __builtin_e2k_qpfmuls(c_imag, y_real));
		__v2di dz_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(d_real, z_real), __builtin_e2k_qpfmuls(d_imag, z_imag));
		__v2di dz_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(d_real, z_imag), __builtin_e2k_qpfmuls(d_imag, z_real));
		__v2di ew_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(e_real, w_real), __builtin_e2k_qpfmuls(e_imag, w_imag));
		__v2di ew_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(e_real, w_imag), __builtin_e2k_qpfmuls(e_imag, w_real));

		__v2di add02_real = __builtin_e2k_qpfadds( x_real, dz_real);
		__v2di add02_imag = __builtin_e2k_qpfadds( x_imag, dz_imag);
		__v2di sub02_real = __builtin_e2k_qpfsubs( x_real, dz_real);
		__v2di sub02_imag = __builtin_e2k_qpfsubs( x_imag, dz_imag);
		__v2di add13_real = __builtin_e2k_qpfadds(cy_real, ew_real);
		__v2di add13_imag = __builtin_e2k_qpfadds(cy_imag, ew_imag);
		__v2di sub13_real = __builtin_e2k_qpfsubs(cy_real, ew_real);
	//	__v2di sub13_imag = __builtin_e2k_qpfsubs(cy_imag, ew_imag);
	//	__v2di sub13i_real = -sub13_imag;
		__v2di sub13i_real = __builtin_e2k_qpfsubs(ew_imag, cy_imag);
		__v2di sub13i_imag =  sub13_real;

		out_0_real[2*i] = __builtin_e2k_qpfadds(add02_real, add13_real);
		out_0_imag[2*i] = __builtin_e2k_qpfadds(add02_imag, add13_imag);
		out_1_real[2*i] = __builtin_e2k_qpfsubs(sub02_real, sub13i_real);
		out_1_imag[2*i] = __builtin_e2k_qpfsubs(sub02_imag, sub13i_imag);
		out_2_real[2*i] = __builtin_e2k_qpfsubs(add02_real, add13_real);
		out_2_imag[2*i] = __builtin_e2k_qpfsubs(add02_imag, add13_imag);
		out_3_real[2*i] = __builtin_e2k_qpfadds(sub02_real, sub13i_real);
		out_3_imag[2*i] = __builtin_e2k_qpfadds(sub02_imag, sub13i_imag);
	}
}
Основной цикл на ассемблере
.L5045:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=96
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=4, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=3, abs=24, disp=0
        }
.L4371:
        {
          loop_mode
          qpfmul_adds,0,sm      %b[6], %b[69], %b[57], %b[1]
          qpfsub_rsubs,1,sm     %b[30], %b[74], %b[58], %b[47]
          qpfsub_adds,2,sm      %b[30], %b[74], %b[58], %b[5]
          qpfmuls,4,sm  %b[62], %b[61], %b[55]
          qpfsubs,5,sm  %b[77], %b[73], %b[56]
          movaqp,1      area=3, ind=0, am=0, be=0, %b[0]
        }
        {
          loop_mode
          qpfmul_rsubs,0,sm     %b[6], %b[63], %b[84], %b[69]
          qpfadd_adds,1,sm      %b[29], %b[81], %b[89], %b[78]
          qpfadd_rsubs,2,sm     %b[29], %b[81], %b[89], %b[74]
          qpfmuls,4,sm  %b[62], %b[67], %b[82]
          qpfadds,5,sm  %b[77], %b[73], %b[87]
          movaqp,0      area=3, ind=16, am=1, be=0, %b[58]
          movaqp,1      area=2, ind=0, am=0, be=0, %b[30]
          movaqp,3      area=1, ind=0, am=0, be=0, %b[57]
        }
        {
          loop_mode
          qpfmul_rsubs,0,sm     %b[36], %b[17], %b[83], %b[73]
          qpfmul_rsubs,1,sm     %b[14], %b[70], %b[86], %b[77]
          staaqp,2      %b[46], %aad3[ %aasti7 ]
          qpfmuls,3,sm  %b[18], %b[50], %b[81]
          qpfmuls,4,sm  %b[42], %b[35], %b[84]
          staaqp,5      %b[41], %aad1[ %aasti5 ]
          movaqp,0      area=1, ind=0, am=0, be=0, %b[62]
          movaqp,1      area=1, ind=16, am=1, be=0, %b[29]
          movaqp,2      area=2, ind=0, am=0, be=0, %b[6]
          movaqp,3      area=1, ind=16, am=1, be=0, %b[63]
        }
        {
          loop_mode
          qpfmul_adds,0,sm      %b[34], %b[50], %b[85], %b[41]
          qpfmul_adds,1,sm      %b[14], %b[37], %b[88], %b[70]
          staaqp,2      %b[53], %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          qpfmuls,3,sm  %b[16], %b[13], %b[83]
          qpfmuls,4,sm  %b[42], %b[68], %b[86]
          staaqp,5      %b[11], %aad2[ %aasti6 + _f32s,_lts0 0x10 ]
          movaqp,0      area=0, ind=16, am=1, be=0, %b[18]
          movaqp,1      area=0, ind=0, am=0, be=0, %b[17]
          movaqp,2      area=2, ind=16, am=1, be=0, %b[36]
          movaqp,3      area=0, ind=16, am=0, be=0, %b[46]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[27], %b[79], %b[52], %b[42]
          qpfsub_adds,1,sm      %b[27], %b[79], %b[52], %b[37]
          staaqp,2      %b[49], %aad3[ %aasti7 + _f32s,_lts0 0x10 ]
          incr,2        %aaincr3
          qpfsubs,4,sm  %b[3], %b[45], %b[50]
          staaqp,5      %b[7], %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
          movaqp,1      area=2, ind=16, am=1, be=0, %b[14]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[11]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfadd_adds,0,sm      %b[28], %b[72], %b[54], %b[49]
          qpfadd_rsubs,1,sm     %b[28], %b[72], %b[54], %b[7]
          staaqp,2      %b[80], %aad4[ %aasti8 ]
          incr,2        %aaincr3
          qpfadds,4,sm  %b[45], %b[3], %b[52]
          staaqp,5      %b[76], %aad2[ %aasti6 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 16 комплексных чисел за 6 тактов (16/6) = 21.33 Байт/такт
Двойная теоретическая скорость: 42.67 Байт/такт

Замеры скорости

3. stage_radix4_vector4_unroll2

Здесь происходит раскрутка цикла в 2 раза с помощью директивы unroll.

Код на Си
void stage_radix4_vector4_unroll2(int data_count, myComplex4 *data_in, myComplex4 *data_out, myComplex4 *coefC, myComplex4 *coefD, myComplex4 *coefE)
{
	__v2di *x_real_in = (__v2di*)&data_in[0].real;
	__v2di *x_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *y_real_in = (__v2di*)&data_in[1].real;
	__v2di *y_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *z_real_in = (__v2di*)&data_in[2].real;
	__v2di *z_imag_in = (__v2di*)&data_in[2].imag;
	__v2di *w_real_in = (__v2di*)&data_in[3].real;
	__v2di *w_imag_in = (__v2di*)&data_in[3].imag;
	__v2di *c_real_in = (__v2di*)&coefC[0].real;
	__v2di *c_imag_in = (__v2di*)&coefC[0].imag;
	__v2di *d_real_in = (__v2di*)&coefD[0].real;
	__v2di *d_imag_in = (__v2di*)&coefD[0].imag;
	__v2di *e_real_in = (__v2di*)&coefE[0].real;
	__v2di *e_imag_in = (__v2di*)&coefE[0].imag;

	__v2di *out_0_real = (__v2di*)&data_out[0*data_count/4].real;
	__v2di *out_0_imag = (__v2di*)&data_out[0*data_count/4].imag;
	__v2di *out_1_real = (__v2di*)&data_out[1*data_count/4].real;
	__v2di *out_1_imag = (__v2di*)&data_out[1*data_count/4].imag;
	__v2di *out_2_real = (__v2di*)&data_out[2*data_count/4].real;
	__v2di *out_2_imag = (__v2di*)&data_out[2*data_count/4].imag;
	__v2di *out_3_real = (__v2di*)&data_out[3*data_count/4].real;
	__v2di *out_3_imag = (__v2di*)&data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(2)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		__v2di x_real = x_real_in[8*i];
		__v2di x_imag = x_imag_in[8*i];
		__v2di y_real = y_real_in[8*i];
		__v2di y_imag = y_imag_in[8*i];
		__v2di z_real = z_real_in[8*i];
		__v2di z_imag = z_imag_in[8*i];
		__v2di w_real = w_real_in[8*i];
		__v2di w_imag = w_imag_in[8*i];
		__v2di c_real = c_real_in[2*i];
		__v2di c_imag = c_imag_in[2*i];
		__v2di d_real = d_real_in[2*i];
		__v2di d_imag = d_imag_in[2*i];
		__v2di e_real = e_real_in[2*i];
		__v2di e_imag = e_imag_in[2*i];

		__v2di cy_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(c_real, y_real), __builtin_e2k_qpfmuls(c_imag, y_imag));
		__v2di cy_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(c_real, y_imag), __builtin_e2k_qpfmuls(c_imag, y_real));
		__v2di dz_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(d_real, z_real), __builtin_e2k_qpfmuls(d_imag, z_imag));
		__v2di dz_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(d_real, z_imag), __builtin_e2k_qpfmuls(d_imag, z_real));
		__v2di ew_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(e_real, w_real), __builtin_e2k_qpfmuls(e_imag, w_imag));
		__v2di ew_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(e_real, w_imag), __builtin_e2k_qpfmuls(e_imag, w_real));

		__v2di add02_real = __builtin_e2k_qpfadds( x_real, dz_real);
		__v2di add02_imag = __builtin_e2k_qpfadds( x_imag, dz_imag);
		__v2di sub02_real = __builtin_e2k_qpfsubs( x_real, dz_real);
		__v2di sub02_imag = __builtin_e2k_qpfsubs( x_imag, dz_imag);
		__v2di add13_real = __builtin_e2k_qpfadds(cy_real, ew_real);
		__v2di add13_imag = __builtin_e2k_qpfadds(cy_imag, ew_imag);
		__v2di sub13_real = __builtin_e2k_qpfsubs(cy_real, ew_real);
	//	__v2di sub13_imag = __builtin_e2k_qpfsubs(cy_imag, ew_imag);
	//	__v2di sub13i_real = -sub13_imag;
		__v2di sub13i_real = __builtin_e2k_qpfsubs(ew_imag, cy_imag);
		__v2di sub13i_imag =  sub13_real;

		out_0_real[2*i] = __builtin_e2k_qpfadds(add02_real, add13_real);
		out_0_imag[2*i] = __builtin_e2k_qpfadds(add02_imag, add13_imag);
		out_1_real[2*i] = __builtin_e2k_qpfsubs(sub02_real, sub13i_real);
		out_1_imag[2*i] = __builtin_e2k_qpfsubs(sub02_imag, sub13i_imag);
		out_2_real[2*i] = __builtin_e2k_qpfsubs(add02_real, add13_real);
		out_2_imag[2*i] = __builtin_e2k_qpfsubs(add02_imag, add13_imag);
		out_3_real[2*i] = __builtin_e2k_qpfadds(sub02_real, sub13i_real);
		out_3_imag[2*i] = __builtin_e2k_qpfadds(sub02_imag, sub13i_imag);
	}
}
Основной цикл на ассемблере
.L6226:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=4, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=4, disp=96
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=128
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=160
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=12, disp=192
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=12, disp=224
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=2, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=2, abs=16, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=2, abs=20, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=2, abs=20, disp=32
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=3, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=3, abs=24, disp=32
        }
.L5153:
        {
          loop_mode
          qpfadd_adds,0,sm      %b[32], %b[21], %b[94], %b[65]
          qpfadd_rsubs,1,sm     %b[32], %b[21], %b[94], %b[88]
          qpfsubs,2,sm  %b[61], %b[65], %b[92]
          qpfmuls,3,sm  %b[15], %b[40], %b[0]
          qpfmuls,4,sm  %b[91], %b[48], %b[1]
          qpfmuls,5,sm  %b[17], %b[9], %b[90]
        }
        {
          loop_mode
          qpfmul_rsubs,0,sm     %b[22], %b[60], %g16, %b[21]
          qpfmul_adds,1,sm      %b[8], %b[64], %b[95], %b[22]
          qpfsubs,2,sm  %b[81], %b[70], %b[94]
          qpfmul_adds,3,sm      %b[22], %b[57], %b[83], %b[17]
          qpfmuls,4,sm  %b[35], %b[55], %g16
          qpfsubs,5,sm  %b[16], %b[10], %b[83]
        }
        {
          loop_mode
          qpfmul_rsubs,0,sm     %b[14], %b[51], %b[3], %b[8]
          qpfmul_rsubs,1,sm     %b[46], %b[52], %b[96], %b[14]
          qpfadds,2,sm  %b[81], %b[70], %b[84]
          qpfmul_rsubs,3,sm     %b[8], %b[38], %b[84], %b[3]
          qpfmuls,4,sm  %b[53], %b[50], %b[70]
          qpfmuls,5,sm  %b[91], %b[49], %b[81]
        }
        {
          loop_mode
          qpfmul_rsubs,0,sm     %b[13], %b[9], %b[2], %b[68]
          qpfmul_rsubs,1,sm     %b[56], %b[33], %b[93], %b[79]
          staaqp,2      %b[82], %aad3[ %aasti7 ]
          qpfmul_adds,3,sm      %b[56], %b[68], %b[89], %b[2]
          qpfadds,4,sm  %b[16], %b[10], %b[82]
          staaqp,5      %b[79], %aad1[ %aasti5 ]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[29], %b[5], %b[92], %b[80]
          qpfsub_adds,1,sm      %b[29], %b[5], %b[92], %b[77]
          staaqp,2      %b[80], %aad2[ %aasti6 + _f32s,_lts1 0x10 ]
          qpfmul_adds,3,sm      %b[13], %b[42], %b[90], %b[16]
          qpfsubs,4,sm  %b[18], %b[4], %b[90]
          staaqp,5      %b[77], %aad1[ %aasti5 + _f32s,_lts0 0x30 ]
          movaqp,0      area=6, ind=0, am=0, be=0, %b[10]
          movaqp,1      area=6, ind=16, am=1, be=0, %b[89]
          movaqp,2      area=6, ind=0, am=0, be=0, %b[9]
          movaqp,3      area=6, ind=16, am=1, be=0, %b[13]
        }
        {
          loop_mode
          qpfadd_rsubs,0,sm     %b[47], %b[24], %b[87], %b[78]
          qpfsub_adds,1,sm      %b[30], %b[19], %b[94], %b[75]
          staaqp,2      %b[75], %aad3[ %aasti7 + _f32s,_lts1 0x30 ]
          qpfmuls,3,sm  %g17, %b[66], %b[91]
          qpfadds,4,sm  %b[4], %b[18], %b[92]
          staaqp,5      %b[78], %aad2[ %aasti6 + _f32s,_lts0 0x20 ]
          movaqp,0      area=5, ind=0, am=0, be=0, %b[4]
          movaqp,1      area=5, ind=16, am=1, be=0, %b[32]
          movaqp,2      area=5, ind=0, am=0, be=0, %b[18]
          movaqp,3      area=5, ind=16, am=1, be=0, %b[33]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[30], %b[19], %b[94], %b[73]
          qpfadd_rsubs,1,sm     %b[41], %b[23], %b[84], %b[76]
          staaqp,2      %b[76], %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          qpfmuls,4,sm  %b[34], %b[36], %b[93]
          staaqp,5      %b[73], %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
          movaqp,0      area=4, ind=0, am=0, be=0, %b[42]
          movaqp,1      area=4, ind=16, am=1, be=0, %b[51]
          movaqp,2      area=3, ind=16, am=0, be=0, %b[38]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[46]
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[47], %b[24], %b[87], %b[74]
          qpfsub_adds,1,sm      %b[47], %b[24], %b[83], %b[71]
          staaqp,2      %b[74], %aad3[ %aasti7 + _f32s,_lts1 0x10 ]
          qpfmuls,3,sm  %g17, %b[31], %b[87]
          qpfmuls,4,sm  %b[53], %b[67], %b[94]
          staaqp,5      %b[71], %aad4[ %aasti8 + _f32s,_lts0 0x20 ]
          movaqp,0      area=3, ind=0, am=0, be=0, %b[56]
          movaqp,1      area=3, ind=16, am=1, be=0, %b[53]
          movaqp,2      area=4, ind=0, am=0, be=0, %b[52]
          movaqp,3      area=4, ind=16, am=1, be=0, %g17
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[47], %b[24], %b[83], %b[72]
          qpfadd_adds,1,sm      %b[41], %b[23], %b[84], %b[69]
          staaqp,2      %b[72], %aad4[ %aasti8 ]
          qpfmul_adds,3,sm      %b[12], %b[48], %b[81], %b[57]
          qpfmuls,4,sm  %b[35], %b[58], %b[81]
          staaqp,5      %b[69], %aad2[ %aasti6 ]
          movaqp,0      area=2, ind=0, am=0, be=0, %b[35]
          movaqp,1      area=2, ind=16, am=1, be=0, %b[24]
          movaqp,2      area=1, ind=0, am=1, be=0, %b[47]
          movaqp,3      area=0, ind=0, am=0, be=0, %b[48]
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[29], %b[5], %b[82], %b[70]
          qpfadd_rsubs,1,sm     %b[29], %b[5], %b[82], %b[67]
          staaqp,2      %b[85], %aad3[ %aasti7 + _f32s,_lts0 0x20 ]
          incr,2        %aaincr3
          qpfmul_adds,3,sm      %b[44], %b[67], %b[70], %b[61]
          qpfmuls,4,sm  %b[34], %b[62], %b[82]
          staaqp,5      %b[86], %aad1[ %aasti5 + _f32s,_lts0 0x20 ]
          incr,5        %aaincr3
          movaqp,0      area=1, ind=16, am=1, be=0, %b[60]
          movaqp,1      area=1, ind=0, am=0, be=0, %b[34]
          movaqp,2      area=3, ind=0, am=1, be=0, %b[5]
          movaqp,3      area=2, ind=0, am=0, be=0, %b[29]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfsub_rsubs,0,sm     %b[41], %b[23], %b[90], %b[83]
          qpfsub_adds,1,sm      %b[41], %b[23], %b[90], %b[84]
          staaqp,2      %b[65], %aad4[ %aasti8 + _f32s,_lts0 0x30 ]
          incr,2        %aaincr3
          qpfadds,4,sm  %b[63], %b[59], %b[85]
          staaqp,5      %b[88], %aad2[ %aasti6 + _f32s,_lts0 0x30 ]
          incr,5        %aaincr3
          movaqp,0      area=0, ind=16, am=1, be=0, %b[41]
          movaqp,1      area=0, ind=0, am=0, be=0, %b[23]
          movaqp,2      area=2, ind=16, am=1, be=0, %b[64]
          movaqp,3      area=0, ind=16, am=1, be=0, %b[65]
        }

Теоретическая скорость: 32 комплексных числа за 11 тактов (32/11) = 23.27 Байт/такт
Двойная теоретическая скорость: 46.55 Байт/такт

Замеры скорости

4. stage_radix4_vector4_unroll3

Здесь происходит раскрутка цикла в 3 раза с помощью директивы unroll.

Код на Си
void stage_radix4_vector4_unroll3(int data_count, myComplex4 *data_in, myComplex4 *data_out, myComplex4 *coefC, myComplex4 *coefD, myComplex4 *coefE)
{
	__v2di *x_real_in = (__v2di*)&data_in[0].real;
	__v2di *x_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *y_real_in = (__v2di*)&data_in[1].real;
	__v2di *y_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *z_real_in = (__v2di*)&data_in[2].real;
	__v2di *z_imag_in = (__v2di*)&data_in[2].imag;
	__v2di *w_real_in = (__v2di*)&data_in[3].real;
	__v2di *w_imag_in = (__v2di*)&data_in[3].imag;
	__v2di *c_real_in = (__v2di*)&coefC[0].real;
	__v2di *c_imag_in = (__v2di*)&coefC[0].imag;
	__v2di *d_real_in = (__v2di*)&coefD[0].real;
	__v2di *d_imag_in = (__v2di*)&coefD[0].imag;
	__v2di *e_real_in = (__v2di*)&coefE[0].real;
	__v2di *e_imag_in = (__v2di*)&coefE[0].imag;

	__v2di *out_0_real = (__v2di*)&data_out[0*data_count/4].real;
	__v2di *out_0_imag = (__v2di*)&data_out[0*data_count/4].imag;
	__v2di *out_1_real = (__v2di*)&data_out[1*data_count/4].real;
	__v2di *out_1_imag = (__v2di*)&data_out[1*data_count/4].imag;
	__v2di *out_2_real = (__v2di*)&data_out[2*data_count/4].real;
	__v2di *out_2_imag = (__v2di*)&data_out[2*data_count/4].imag;
	__v2di *out_3_real = (__v2di*)&data_out[3*data_count/4].real;
	__v2di *out_3_imag = (__v2di*)&data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(3)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		__v2di x_real = x_real_in[8*i];
		__v2di x_imag = x_imag_in[8*i];
		__v2di y_real = y_real_in[8*i];
		__v2di y_imag = y_imag_in[8*i];
		__v2di z_real = z_real_in[8*i];
		__v2di z_imag = z_imag_in[8*i];
		__v2di w_real = w_real_in[8*i];
		__v2di w_imag = w_imag_in[8*i];
		__v2di c_real = c_real_in[2*i];
		__v2di c_imag = c_imag_in[2*i];
		__v2di d_real = d_real_in[2*i];
		__v2di d_imag = d_imag_in[2*i];
		__v2di e_real = e_real_in[2*i];
		__v2di e_imag = e_imag_in[2*i];

		__v2di cy_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(c_real, y_real), __builtin_e2k_qpfmuls(c_imag, y_imag));
		__v2di cy_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(c_real, y_imag), __builtin_e2k_qpfmuls(c_imag, y_real));
		__v2di dz_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(d_real, z_real), __builtin_e2k_qpfmuls(d_imag, z_imag));
		__v2di dz_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(d_real, z_imag), __builtin_e2k_qpfmuls(d_imag, z_real));
		__v2di ew_real = __builtin_e2k_qpfsubs(__builtin_e2k_qpfmuls(e_real, w_real), __builtin_e2k_qpfmuls(e_imag, w_imag));
		__v2di ew_imag = __builtin_e2k_qpfadds(__builtin_e2k_qpfmuls(e_real, w_imag), __builtin_e2k_qpfmuls(e_imag, w_real));

		__v2di add02_real = __builtin_e2k_qpfadds( x_real, dz_real);
		__v2di add02_imag = __builtin_e2k_qpfadds( x_imag, dz_imag);
		__v2di sub02_real = __builtin_e2k_qpfsubs( x_real, dz_real);
		__v2di sub02_imag = __builtin_e2k_qpfsubs( x_imag, dz_imag);
		__v2di add13_real = __builtin_e2k_qpfadds(cy_real, ew_real);
		__v2di add13_imag = __builtin_e2k_qpfadds(cy_imag, ew_imag);
		__v2di sub13_real = __builtin_e2k_qpfsubs(cy_real, ew_real);
	//	__v2di sub13_imag = __builtin_e2k_qpfsubs(cy_imag, ew_imag);
	//	__v2di sub13i_real = -sub13_imag;
		__v2di sub13i_real = __builtin_e2k_qpfsubs(ew_imag, cy_imag);
		__v2di sub13i_imag =  sub13_real;

		out_0_real[2*i] = __builtin_e2k_qpfadds(add02_real, add13_real);
		out_0_imag[2*i] = __builtin_e2k_qpfadds(add02_imag, add13_imag);
		out_1_real[2*i] = __builtin_e2k_qpfsubs(sub02_real, sub13i_real);
		out_1_imag[2*i] = __builtin_e2k_qpfsubs(sub02_imag, sub13i_imag);
		out_2_real[2*i] = __builtin_e2k_qpfsubs(add02_real, add13_real);
		out_2_imag[2*i] = __builtin_e2k_qpfsubs(add02_imag, add13_imag);
		out_3_real[2*i] = __builtin_e2k_qpfadds(sub02_real, sub13i_real);
		out_3_imag[2*i] = __builtin_e2k_qpfadds(sub02_imag, sub13i_imag);
	}
}
Основной цикл на ассемблере
.L7982:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=2, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=2, disp=96
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=4, disp=128
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=4, disp=160
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=6, disp=192
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=6, disp=224
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=8, disp=256
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=288
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=1, abs=10, disp=320
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=12, disp=352
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=2, abs=16, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=2, abs=16, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=2, abs=20, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=2, abs=20, disp=32
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=2, abs=24, disp=64
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=2, abs=24, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=2, abs=28, disp=32
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=2, abs=28, disp=64
        }
.L6334:
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[105], %b[23], %g16, %g18
          qpfsub_adds,1,sm      %b[105], %b[23], %g16, %g17
          qpfsubs,2,sm  %g19, %g20, %g21
          qpfmuls,3,sm  %b[38], %b[113], %g24
          qpfmuls,4,sm  %b[46], %b[81], %g23
          qpfmuls,5,sm  %b[38], %b[64], %g22
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[102], %b[49], %g25, %g27
          qpfadd_rsubs,1,sm     %b[102], %b[49], %g25, %g26
          qpfadds,2,sm  %g19, %g20, %g28
          qpfmuls,3,sm  %b[45], %b[109], %g31
          qpfmuls,4,sm  %b[42], %b[31], %g30
          qpfmuls,5,sm  %b[90], %b[94], %g29
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[30], %r0, %r1, %r3
          qpfsub_adds,1,sm      %b[30], %r0, %r1, %r2
          qpfmuls,2,sm  %b[90], %b[97], %r7
          qpfmuls,3,sm  %b[48], %b[104], %b[0]
          qpfmuls,4,sm  %b[82], %b[18], %r5
          qpfmuls,5,sm  %b[19], %b[76], %r4
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[63], %r9, %r10, %r12
          qpfadd_rsubs,1,sm     %b[63], %r9, %r10, %r11
          qpfmuls,2,sm  %b[13], %b[93], %r14
          qpfmuls,3,sm  %b[11], %b[85], %r16
          qpfmuls,4,sm  %b[82], %b[70], %r15
          qpfadds,5,sm  %b[118], %b[119], %r13
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[63], %r9, %g21, %g21
          qpfsub_adds,1,sm      %b[63], %r9, %g21, %r19
          staaqp,2      %r18, %aad3[ %aasti7 ]
          qpfmuls,3,sm  %b[17], %b[73], %b[118]
          qpfsubs,4,sm  %b[119], %b[118], %r20
          staaqp,5      %r17, %aad1[ %aasti5 ]
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[30], %r0, %g28, %g28
          qpfadd_rsubs,1,sm     %b[30], %r0, %g28, %r23
          staaqp,2      %r22, %aad2[ %aasti6 + _f32s,_lts1 0x10 ]
          qpfmul_rsubs,3,sm     %b[86], %b[97], %g29, %b[19]
          qpfsubs,4,sm  %b[116], %r24, %r25
          staaqp,5      %r21, %aad1[ %aasti5 + _f32s,_lts0 0x30 ]
          movaqp,0      area=10, ind=0, am=0, be=0, %b[1]
          movaqp,1      area=10, ind=16, am=1, be=0, %b[13]
        }
        {
          loop_mode
          qpfmul_adds,0,sm      %b[12], %b[113], %g22, %b[49]
          qpfmul_adds,1,sm      %b[86], %b[94], %r7, %b[45]
          staaqp,2      %r27, %aad3[ %aasti7 + _f32s,_lts1 0x30 ]
          qpfmul_rsubs,3,sm     %b[27], %b[35], %g30, %r24
          qpfadds,4,sm  %b[116], %r24, %b[113]
          staaqp,5      %r26, %aad2[ %aasti6 + _f32s,_lts0 0x20 ]
          movaqp,0      area=9, ind=0, am=0, be=0, %b[30]
          movaqp,1      area=9, ind=16, am=1, be=0, %b[46]
          movaqp,2      area=9, ind=0, am=0, be=0, %b[23]
          movaqp,3      area=9, ind=16, am=1, be=0, %b[38]
        }
        {
          loop_mode
          qpfmul_adds,0,sm      %b[34], %b[106], %r30, %b[117]
          qpfmul_adds,1,sm      %b[41], %b[114], %g23, %b[116]
          staaqp,2      %b[117], %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          qpfmul_rsubs,3,sm     %b[22], %b[109], %r31, %b[114]
          qpfsubs,4,sm  %r29, %b[37], %g22
          staaqp,5      %r28, %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
          movaqp,0      area=8, ind=0, am=0, be=0, %b[82]
          movaqp,1      area=8, ind=16, am=1, be=0, %b[86]
          movaqp,2      area=8, ind=0, am=0, be=0, %b[63]
          movaqp,3      area=8, ind=16, am=1, be=0, %b[76]
        }
        {
          loop_mode
          qpfmul_rsubs,0,sm     %b[7], %b[75], %r4, %g20
          qpfmul_rsubs,1,sm     %b[8], %b[87], %r14, %g19
          staaqp,2      %r33, %aad3[ %aasti7 + _f32s,_lts1 0x10 ]
          qpfmul_rsubs,3,sm     %b[34], %b[110], %b[2], %b[35]
          qpfmuls,4,sm  %b[42], %b[35], %g23
          staaqp,5      %r32, %aad4[ %aasti8 + _f32s,_lts0 0x20 ]
          movaqp,0      area=7, ind=0, am=0, be=0, %b[2]
          movaqp,1      area=7, ind=16, am=1, be=0, %b[7]
          movaqp,2      area=7, ind=0, am=0, be=0, %b[8]
          movaqp,3      area=7, ind=16, am=1, be=0, %b[34]
        }
        {
          loop_mode
          qpfmul_adds,0,sm      %b[69], %b[70], %r5, %r9
          qpfmul_rsubs,1,sm     %b[69], %b[18], %r15, %r0
          staaqp,2      %r35, %aad4[ %aasti8 ]
          qpfmul_rsubs,3,sm     %b[41], %b[81], %r36, %r29
          qpfadds,4,sm  %r29, %b[37], %g29
          staaqp,5      %r34, %aad2[ %aasti6 ]
          movaqp,0      area=6, ind=0, am=0, be=0, %b[37]
          movaqp,1      area=6, ind=16, am=1, be=0, %b[42]
          movaqp,2      area=6, ind=0, am=0, be=0, %b[18]
          movaqp,3      area=6, ind=16, am=1, be=0, %b[41]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[54], %b[77], %r20, %r18
          qpfsub_adds,1,sm      %b[54], %b[77], %r20, %r17
          staaqp,2      %g18, %aad3[ %aasti7 + _f32s,_lts0 0x20 ]
          qpfmul_rsubs,3,sm     %b[12], %b[64], %g24, %b[75]
          qpfsubs,4,sm  %r37, %r38, %g16
          staaqp,5      %g17, %aad1[ %aasti5 + _f32s,_lts0 0x20 ]
          movaqp,0      area=5, ind=16, am=1, be=0, %b[64]
          movaqp,1      area=5, ind=0, am=0, be=0, %b[12]
          movaqp,2      area=5, ind=16, am=1, be=0, %b[70]
          movaqp,3      area=5, ind=0, am=0, be=0, %b[69]
        }
        {
          loop_mode
          qpfadd_rsubs,0,sm     %b[60], %b[51], %r13, %r22
          qpfsub_adds,1,sm      %b[100], %b[47], %r25, %r21
          staaqp,2      %g27, %aad4[ %aasti8 + _f32s,_lts0 0x30 ]
          qpfmul_adds,3,sm      %b[22], %b[55], %g31, %r38
          qpfadds,4,sm  %r38, %r37, %g25
          staaqp,5      %g26, %aad2[ %aasti6 + _f32s,_lts0 0x30 ]
          movaqp,0      area=4, ind=16, am=1, be=0, %b[55]
          movaqp,1      area=4, ind=0, am=0, be=0, %b[22]
          movaqp,2      area=4, ind=16, am=1, be=0, %b[87]
          movaqp,3      area=4, ind=0, am=0, be=0, %b[81]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[100], %b[47], %r25, %r27
          qpfadd_rsubs,1,sm     %b[103], %b[21], %b[113], %r26
          staaqp,2      %r3, %aad3[ %aasti7 + _f32s,_lts0 0x40 ]
          qpfmul_adds,3,sm      %b[27], %b[31], %g23, %r37
          qpfsubs,4,sm  %b[115], %r39, %r1
          staaqp,5      %r2, %aad1[ %aasti5 + _f32s,_lts0 0x40 ]
          movaqp,0      area=3, ind=0, am=0, be=0, %b[93]
          movaqp,1      area=3, ind=16, am=1, be=0, %b[90]
          movaqp,2      area=3, ind=0, am=0, be=0, %b[31]
          movaqp,3      area=3, ind=16, am=1, be=0, %b[27]
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[60], %b[51], %r13, %b[115]
          qpfsub_adds,1,sm      %b[60], %b[51], %g22, %r28
          staaqp,2      %r12, %aad4[ %aasti8 + _f32s,_lts0 0x50 ]
          qpfmul_adds,3,sm      %b[6], %b[91], %r16, %r39
          qpfadds,4,sm  %r39, %b[115], %r10
          staaqp,5      %r11, %aad2[ %aasti6 + _f32s,_lts0 0x50 ]
          movaqp,0      area=2, ind=0, am=0, be=0, %b[97]
          movaqp,1      area=2, ind=16, am=1, be=0, %b[94]
          movaqp,2      area=2, ind=0, am=0, be=0, %b[105]
          movaqp,3      area=1, ind=16, am=0, be=0, %b[102]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[60], %b[51], %g22, %r33
          qpfadd_adds,1,sm      %b[103], %b[21], %b[113], %r32
          staaqp,2      %g21, %aad3[ %aasti7 + _f32s,_lts0 0x50 ]
          incr,2        %aaincr3
          qpfmul_adds,3,sm      %b[5], %b[74], %b[118], %b[113]
          qpfmuls,4,sm  %b[43], %b[53], %r31
          staaqp,5      %r19, %aad1[ %aasti5 + _f32s,_lts0 0x50 ]
          incr,5        %aaincr3
          movaqp,0      area=1, ind=16, am=1, be=0, %b[109]
          movaqp,1      area=1, ind=0, am=0, be=0, %b[60]
          movaqp,2      area=2, ind=16, am=1, be=0, %b[51]
          movaqp,3      area=1, ind=0, am=1, be=0, %b[106]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfadd_adds,0,sm      %b[54], %b[77], %g29, %r35
          qpfadd_rsubs,1,sm     %b[54], %b[77], %g29, %r34
          staaqp,2      %g28, %aad4[ %aasti8 + _f32s,_lts0 0x40 ]
          incr,2        %aaincr3
          qpfmuls,3,sm  %b[44], %b[112], %r36
          qpfmuls,4,sm  %b[48], %b[108], %r30
          staaqp,5      %r23, %aad2[ %aasti6 + _f32s,_lts0 0x40 ]
          incr,5        %aaincr3
          movaqp,0      area=0, ind=16, am=1, be=0, %b[54]
          movaqp,1      area=0, ind=0, am=0, be=0, %b[48]
          movaqp,2      area=0, ind=0, am=0, be=0, %b[77]
          movaqp,3      area=0, ind=16, am=1, be=0, %b[110]
        }

Теоретическая скорость: 48 комплексных чисел за 16 тактов (48/16) = 24 Байт/такт
Двойная теоретическая скорость: 48 Байт/такт

Замеры скорости

Компилятор не сумел векторизовать вариант stage_radix4_vector4_etalon в 4 раза.
До этого он успешно векторизовал вариант stage_radix4_vector2_etalon в 2 раза.

Итоги по stage_radix4_vector4

Пишем LastStage

В случае выполнения прямой векторизации в 2 раза нужно использовать lastStage_radix2.
В случае выполнения прямой векторизации в 4 раза нужно использовать lastStage_radix4 (или сначала stage_radix2_vector2 и затем lastStage_radix2).

lastStage_radix2

1. lastStage_radix2_etalon

Эталонный вариант для сравнения на корректность.

Код на Си
void lastStage_radix2_etalon(int data_count, myComplex2 *data_in, myComplex *data_out, myComplex *coef)
{
	float *x_real_in = &data_in[0].real[0];
	float *x_imag_in = &data_in[0].imag[0];
	float *y_real_in = &data_in[0].real[1];
	float *y_imag_in = &data_in[0].imag[1];
	float *c_real_in = &coef[0].real;
	float *c_imag_in = &coef[0].imag;

	float *out_add_real = &data_out[0].real;
	float *out_add_imag = &data_out[0].imag;
	float *out_sub_real = &data_out[data_count/2].real;
	float *out_sub_imag = &data_out[data_count/2].imag;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/2; ++i)
	{
		float x_real = x_real_in[4*i];
		float x_imag = x_imag_in[4*i];
		float y_real = y_real_in[4*i];
		float y_imag = y_imag_in[4*i];
		float c_real = c_real_in[2*i];
		float c_imag = c_imag_in[2*i];

		float cy_real = c_real*y_real - c_imag*y_imag;
		float cy_imag = c_real*y_imag + c_imag*y_real;

		out_add_real[2*i] = x_real + cy_real;
		out_add_imag[2*i] = x_imag + cy_imag;
		out_sub_real[2*i] = x_real - cy_real;
		out_sub_imag[2*i] = x_imag - cy_imag;
	}
}
Основной цикл на ассемблере
.L479:
        {
          fapb  ct=1, dcd=0, fmt=3, mrng=16, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=3, mrng=8, d=0, incr=2, ind=2, asz=5, abs=0, disp=0
        }
.L182:
        {
          loop_mode
          fmuls,0,sm    %b[67], %b[6], %b[37]
          fsubs,1,sm    %b[46], %b[24], %b[58]
          staaw,2       %b[62], %aad1[ %aasti3 + _f32s,_lts0 0x4 ]
          fmul_adds,3,sm        %b[55], %b[13], %b[43], %b[14]
          fadds,4,sm    %b[46], %b[24], %b[57]
          staaw,5       %b[61], %aad2[ %aasti4 + _f32s,_lts0 0x4 ]
          movaw,0       area=0, ind=4, am=0, be=0, %b[0]
          movaw,1       area=0, ind=12, am=0, be=0, %b[1]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          fmuls,0,sm    %b[67], %b[7], %b[62]
          fsubs,1,sm    %b[35], %b[56], %b[70]
          staaw,2       %b[74], %aad1[ %aasti3 ]
          incr,2        %aaincr3
          fmul_rsubs,3,sm       %b[55], %b[12], %b[68], %b[46]
          fadds,4,sm    %b[35], %b[56], %b[69]
          staaw,5       %b[73], %aad2[ %aasti4 ]
          incr,5        %aaincr3
          movaw,0       area=0, ind=0, am=0, be=0, %b[13]
          movaw,1       area=0, ind=8, am=1, be=0, %b[24]
          movaw,2       area=0, ind=4, am=1, be=0, %b[61]
          movaw,3       area=0, ind=0, am=0, be=0, %b[43]
        }

Теоретическая скорость: 2 комплексных числа за 2 такта (2/2) = 8 Байт/такт

Замеры скорости

2. lastStage_radix2_etalon_unroll2

Здесь происходит раскрутка цикла в 2 раза с помощью директивы unroll.

Код на Си
void lastStage_radix2_etalon_unroll2(int data_count, myComplex2 *data_in, myComplex *data_out, myComplex *coef)
{
	float *x_real_in = &data_in[0].real[0];
	float *x_imag_in = &data_in[0].imag[0];
	float *y_real_in = &data_in[0].real[1];
	float *y_imag_in = &data_in[0].imag[1];
	float *c_real_in = &coef[0].real;
	float *c_imag_in = &coef[0].imag;

	float *out_add_real = &data_out[0].real;
	float *out_add_imag = &data_out[0].imag;
	float *out_sub_real = &data_out[data_count/2].real;
	float *out_sub_imag = &data_out[data_count/2].imag;

	#pragma ivdep
	#pragma unroll(2)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/2; ++i)
	{
		float x_real = x_real_in[4*i];
		float x_imag = x_imag_in[4*i];
		float y_real = y_real_in[4*i];
		float y_imag = y_imag_in[4*i];
		float c_real = c_real_in[2*i];
		float c_imag = c_imag_in[2*i];

		float cy_real = c_real*y_real - c_imag*y_imag;
		float cy_imag = c_real*y_imag + c_imag*y_real;

		out_add_real[2*i] = x_real + cy_real;
		out_add_imag[2*i] = x_imag + cy_imag;
		out_sub_real[2*i] = x_real - cy_real;
		out_sub_imag[2*i] = x_imag - cy_imag;
	}
}
Основной цикл на ассемблере
.L1357:
        {
          fapb  ct=0, dcd=0, fmt=3, mrng=12, d=0, incr=1, ind=1, asz=4, abs=0, disp=20
          fapb  dpl=0, dcd=0, fmt=3, mrng=20, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
        }
.L525:
        {
          loop_mode
          pfmuls,0,sm   %b[56], %b[16], %b[26]
          insfd,1,sm    %b[52], %r8, %b[47], %b[1]
          pfmuls,2,sm   %b[56], %b[13], %b[31]
          pshufb,3,sm   %b[19], %b[9], %r0, %b[57]
          insfd,4,sm    %b[55], %r8, %b[37], %b[0]
          pfadds,5,sm   %b[42], %b[43], %b[10]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %b[5], %b[15], %b[28], %b[42]
          insfd,1,sm    %b[27], %r8, %b[22], %b[32]
          pfmul_adds,2,sm       %b[5], %b[18], %b[33], %b[37]
          pshufb,4,sm   %b[12], %b[23], %r0, %b[55]
          staad,5       %b[57], %aad1[ %aasti3 + _f32s,_lts0 0x8 ]
          movad,0       area=1, ind=0, am=1, be=0, %b[43]
          movad,1       area=1, ind=8, am=0, be=0, %b[48]
          movaw,3       area=0, ind=12, am=0, be=0, %b[47]
        }
        {
          loop_mode
          pfsubs,0,sm   %b[8], %b[46], %b[5]
          insfd,1,sm    %b[19], %r8, %b[9], %b[58]
          pfsubs,2,sm   %b[40], %b[41], %b[15]
          insfd,4,sm    %b[12], %r8, %b[23], %b[56]
          staad,5       %b[55], %aad2[ %aasti4 + _f32s,_lts0 0x8 ]
          movaw,0       area=0, ind=8, am=0, be=0, %b[22]
          movaw,1       area=0, ind=0, am=0, be=0, %b[28]
          movaw,2       area=0, ind=8, am=0, be=0, %b[18]
          movaw,3       area=0, ind=4, am=0, be=0, %b[27]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfadds,0,sm   %b[8], %b[46], %b[19]
          insfd,1,sm    %b[30], %r8, %b[29], %b[9]
          staad,2       %b[58], %aad1[ %aasti3 ]
          incr,2        %aaincr3
          pshufb,3,sm   %b[50], %b[45], %r0, %b[52]
          insfd,4,sm    %b[24], %r8, %b[49], %b[12]
          staad,5       %b[56], %aad2[ %aasti4 ]
          incr,5        %aaincr3
          movaw,1       area=0, ind=4, am=1, be=0, %b[23]
          movaw,2       area=0, ind=0, am=1, be=0, %b[33]
          movaw,3       area=0, ind=16, am=0, be=0, %b[51]
        }

Теоретическая скорость: 4 комплексных числа за 4 такта (4/4) = 8 Байт/такт

Замеры скорости

3. lastStage_radix2_simd64

Модифицированный stage_radix2_simd64 для работы с векторными данными.

Код на Си
void lastStage_radix2_simd64(int data_count, myComplex2 *data_in, myComplex *data_out, myComplex *coef)
{
	uint64_t *xy0_real_in = (uint64_t*)&data_in[0].real;
	uint64_t *xy0_imag_in = (uint64_t*)&data_in[0].imag;
	uint64_t *xy1_real_in = (uint64_t*)&data_in[1].real;
	uint64_t *xy1_imag_in = (uint64_t*)&data_in[1].imag;
	uint64_t *c0_in       = (uint64_t*)&coef[0];
	uint64_t *c1_in       = (uint64_t*)&coef[1];

	uint64_t *out_add0 = (uint64_t*)&data_out[0];
	uint64_t *out_add1 = (uint64_t*)&data_out[1];
	uint64_t *out_sub0 = (uint64_t*)&data_out[data_count/2 + 0];
	uint64_t *out_sub1 = (uint64_t*)&data_out[data_count/2 + 1];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		uint64_t xy0_real = xy0_real_in[4*i];
		uint64_t xy0_imag = xy0_imag_in[4*i];
		uint64_t xy1_real = xy1_real_in[4*i];
		uint64_t xy1_imag = xy1_imag_in[4*i];
		uint64_t c0       = c0_in[2*i];
		uint64_t c1       = c1_in[2*i];

		uint64_t x_real = __builtin_e2k_pshufb(xy1_real, xy0_real, 0x0B0A090803020100);
		uint64_t x_imag = __builtin_e2k_pshufb(xy1_imag, xy0_imag, 0x0B0A090803020100);
		uint64_t y_real = __builtin_e2k_pshufb(xy1_real, xy0_real, 0x0F0E0D0C07060504);
		uint64_t y_imag = __builtin_e2k_pshufb(xy1_imag, xy0_imag, 0x0F0E0D0C07060504);
		uint64_t c_real = __builtin_e2k_pshufb(c1, c0, 0x0B0A090803020100);
		uint64_t c_imag = __builtin_e2k_pshufb(c1, c0, 0x0F0E0D0C07060504);

		uint64_t cy_real = __builtin_e2k_pfsubs(__builtin_e2k_pfmuls(c_real, y_real), __builtin_e2k_pfmuls(c_imag, y_imag));
		uint64_t cy_imag = __builtin_e2k_pfadds(__builtin_e2k_pfmuls(c_real, y_imag), __builtin_e2k_pfmuls(c_imag, y_real));

		uint64_t add_real = __builtin_e2k_pfadds(x_real, cy_real);
		uint64_t add_imag = __builtin_e2k_pfadds(x_imag, cy_imag);
		uint64_t sub_real = __builtin_e2k_pfsubs(x_real, cy_real);
		uint64_t sub_imag = __builtin_e2k_pfsubs(x_imag, cy_imag);

		out_add0[2*i] = __builtin_e2k_pshufb(add_imag, add_real, 0x0B0A090803020100);
		out_add1[2*i] = __builtin_e2k_pshufb(add_imag, add_real, 0x0F0E0D0C07060504);
		out_sub0[2*i] = __builtin_e2k_pshufb(sub_imag, sub_real, 0x0B0A090803020100);
		out_sub1[2*i] = __builtin_e2k_pshufb(sub_imag, sub_real, 0x0F0E0D0C07060504);
	}
}
Основной цикл на ассемблере
.L1929:
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=5, abs=0, disp=0
        }
.L1613:
        {
          loop_mode
          pfadds,0,sm   %b[26], %b[50], %b[68]
          pshufb,1,sm   %b[58], %b[61], %r6, %b[1]
          pfadds,2,sm   %b[10], %b[49], %b[9]
          pshufb,3,sm   %b[43], %b[44], %r5, %b[0]
          pshufb,4,sm   %b[71], %b[57], %r6, %b[72]
          pfsubs,5,sm   %b[10], %b[49], %b[69]
        }
        {
          loop_mode
          pshufb,0,sm   %b[53], %b[54], %r5, %b[10]
          pfmul_adds,1,sm       %b[34], %b[66], %b[33], %b[43]
          pfmul_rsubs,2,sm      %b[34], %b[23], %b[67], %b[44]
          pshufb,3,sm   %b[60], %b[63], %r5, %b[26]
          pshufb,4,sm   %b[71], %b[57], %r5, %b[73]
          staad,5       %b[72], %aad1[ %aasti3 + _f32s,_lts0 0x8 ]
          movad,0       area=0, ind=0, am=0, be=0, %b[50]
          movad,1       area=0, ind=16, am=0, be=0, %b[49]
        }
        {
          loop_mode
          pfmuls,0,sm   %b[1], %b[13], %b[23]
          pshufb,1,sm   %b[11], %b[70], %r6, %b[71]
          pfsubs,2,sm   %b[24], %b[48], %b[53]
          pshufb,4,sm   %b[11], %b[70], %r5, %b[72]
          staad,5       %b[73], %aad1[ %aasti3 ]
          incr,5        %aaincr3
          movad,0       area=0, ind=8, am=1, be=0, %b[34]
          movad,1       area=0, ind=24, am=0, be=0, %b[33]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pshufb,0,sm   %b[51], %b[52], %r6, %b[11]
          pfmuls,1,sm   %b[7], %b[62], %b[63]
          staad,2       %b[71], %aad2[ %aasti4 + _f32s,_lts0 0x8 ]
          pshufb,4,sm   %b[41], %b[42], %r6, %b[60]
          staad,5       %b[72], %aad2[ %aasti4 ]
          incr,5        %aaincr3
          movad,2       area=0, ind=0, am=0, be=0, %b[57]
          movad,3       area=0, ind=8, am=1, be=0, %b[54]
        }

Теоретическая скорость: 4 комплексных числа за 4 такта (4/4) = 8 Байт/такт

Замеры скорости

4. lastStage_radix2_simd128_noConj

Модифицированный stage_radix2_simd128_noConj для работы с векторными данными.

Код на Си
void lastStage_radix2_simd128_noConj(int data_count, myComplex2 *data_in, myComplex *data_out, myComplex *coef)
{
	__v2di *xy0_in = (__v2di*)&data_in[0];
	__v2di *xy1_in = (__v2di*)&data_in[1];
	__v2di *c_in   = (__v2di*)coef;

	__v2di *out_add = (__v2di*)&data_out[0];
	__v2di *out_sub = (__v2di*)&data_out[data_count/2];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		__v2di xy0 = xy0_in[2*i];
		__v2di xy1 = xy1_in[2*i];
		__v2di c   = c_in[i];

		__v2di x = __builtin_e2k_qpshufb(xy1, xy0, (__v2di){0x0B0A090803020100, 0x0B0A090803020100});
		__v2di y = __builtin_e2k_qpshufb(xy1, xy0, (__v2di){0x0F0E0D0C07060504, 0x0F0E0D0C07060504});

		__v2di swap_c = __builtin_e2k_qpshufb(c, c, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});

		__v2di cy_real = __builtin_e2k_qpfmuls(     c, y);
		__v2di cy_imag = __builtin_e2k_qpfmuls(swap_c, y);

		__v2di cy_rr = __builtin_e2k_qpfhsubs((__v2di){0}, cy_real);
		__v2di cy_ii = __builtin_e2k_qpfhadds((__v2di){0}, cy_imag);

		__v2di cy = __builtin_e2k_qppermb(cy_ii, cy_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});

		out_add[i] = __builtin_e2k_qpfadds(x, cy);
		out_sub[i] = __builtin_e2k_qpfsubs(x, cy);
	}
}
Основной цикл на ассемблере
.L2215:
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=5, abs=0, disp=0
        }
.L1954:
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[25], %b[28], %r9, %b[16]
          qpfmul_hadds,1,sm     %b[27], %b[28], %r9, %b[1]
          qpfsubs,2,sm  %b[14], %b[42], %b[37]
          qpshufb,3,sm  %b[35], %b[36], %r6, %b[0]
          qppermb,4,sm  %b[11], %b[26], %r7, %b[38]
          staaqp,5      %b[43], %aad1[ %aasti3 ]
          incr,5        %aaincr0
          movaqp,0      area=0, ind=0, am=0, be=0, %b[30]
          movaqp,1      area=0, ind=16, am=1, be=0, %b[29]
          movaqp,3      area=0, ind=0, am=1, be=0, %b[19]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpshufb,0,sm  %b[33], %b[34], %r0, %b[26]
          qpshufb,1,sm  %b[23], %b[23], %r5, %b[25]
          qpfadds,2,sm  %b[14], %b[42], %b[11]
          staaqp,5      %b[17], %aad2[ %aasti4 ]
          incr,5        %aaincr0
        }

Теоретическая скорость: 4 комплексных числа за 2 такта (4/2) = 16 Байт/такт

Замеры скорости

Итоги по lastStage_radix2

При реализации Vector-2 FFT будем использовать lastStage_radix2_simd128_noConj.

lastStage_radix4

Один проход по lastStage_radix4 совершает ту же работу, что 2 прохода по stage_radix2. Поэтому скорость lastStage_radix4 будем умножать на 2 для удобства сравнения с stage_radix2 (этот факт подписан на оси графика и в выводе консоли).

1. lastStage_radix4_etalon

Эталонный вариант для сравнения на корректность.

Код на Си
void lastStage_radix4_etalon(int data_count, myComplex4 *data_in, myComplex *data_out, myComplex *coefC, myComplex *coefD, myComplex *coefE)
{
	float *x_real_in = &data_in[0].real[0];
	float *x_imag_in = &data_in[0].imag[0];
	float *y_real_in = &data_in[0].real[1];
	float *y_imag_in = &data_in[0].imag[1];
	float *z_real_in = &data_in[0].real[2];
	float *z_imag_in = &data_in[0].imag[2];
	float *w_real_in = &data_in[0].real[3];
	float *w_imag_in = &data_in[0].imag[3];
	float *c_real_in = &coefC[0].real;
	float *c_imag_in = &coefC[0].imag;
	float *d_real_in = &coefD[0].real;
	float *d_imag_in = &coefD[0].imag;
	float *e_real_in = &coefE[0].real;
	float *e_imag_in = &coefE[0].imag;

	float *out_0_real = &data_out[0*data_count/4].real;
	float *out_0_imag = &data_out[0*data_count/4].imag;
	float *out_1_real = &data_out[1*data_count/4].real;
	float *out_1_imag = &data_out[1*data_count/4].imag;
	float *out_2_real = &data_out[2*data_count/4].real;
	float *out_2_imag = &data_out[2*data_count/4].imag;
	float *out_3_real = &data_out[3*data_count/4].real;
	float *out_3_imag = &data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		float x_real = x_real_in[8*i];
		float x_imag = x_imag_in[8*i];
		float y_real = y_real_in[8*i];
		float y_imag = y_imag_in[8*i];
		float z_real = z_real_in[8*i];
		float z_imag = z_imag_in[8*i];
		float w_real = w_real_in[8*i];
		float w_imag = w_imag_in[8*i];
		float c_real = c_real_in[2*i];
		float c_imag = c_imag_in[2*i];
		float d_real = d_real_in[2*i];
		float d_imag = d_imag_in[2*i];
		float e_real = e_real_in[2*i];
		float e_imag = e_imag_in[2*i];

		float cy_real = c_real*y_real - c_imag*y_imag;
		float cy_imag = c_real*y_imag + c_imag*y_real;
		float dz_real = d_real*z_real - d_imag*z_imag;
		float dz_imag = d_real*z_imag + d_imag*z_real;
		float ew_real = e_real*w_real - e_imag*w_imag;
		float ew_imag = e_real*w_imag + e_imag*w_real;

		float add02_real =  x_real + dz_real;
		float add02_imag =  x_imag + dz_imag;
		float sub02_real =  x_real - dz_real;
		float sub02_imag =  x_imag - dz_imag;
		float add13_real = cy_real + ew_real;
		float add13_imag = cy_imag + ew_imag;
		float sub13_real = cy_real - ew_real;
		float sub13_imag = cy_imag - ew_imag;
		float sub13i_real = -sub13_imag;
		float sub13i_imag =  sub13_real;

		out_0_real[2*i] = add02_real + add13_real;
		out_0_imag[2*i] = add02_imag + add13_imag;
		out_1_real[2*i] = sub02_real - sub13i_real;
		out_1_imag[2*i] = sub02_imag - sub13i_imag;
		out_2_real[2*i] = add02_real - add13_real;
		out_2_imag[2*i] = add02_imag - add13_imag;
		out_3_real[2*i] = sub02_real + sub13i_real;
		out_3_imag[2*i] = sub02_imag + sub13i_imag;
	}
}
Основной цикл на ассемблере
.L973:
        {
          fapb  ct=0, dcd=0, fmt=3, mrng=8, d=0, incr=2, ind=4, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=3, mrng=0, d=0, incr=1, ind=1, asz=5, abs=0, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=3, mrng=8, d=0, incr=2, ind=3, asz=3, abs=8, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=3, mrng=8, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
        }
.L394:
        {
          loop_mode
          fmul_adds,0,sm        %b[66], %b[72], %b[54], %b[1]
          fsub_rsubs,1,sm       %b[12], %b[71], %b[55], %b[5]
          fsub_adds,2,sm        %b[12], %b[71], %b[55], %b[45]
          fmuls,4,sm    %b[59], %b[58], %b[52]
          fsubs,5,sm    %b[79], %b[75], %b[53]
          movaw,3       area=0, ind=16, am=0, be=0, %b[0]
        }
        {
          loop_mode
          fmul_rsubs,0,sm       %b[66], %b[60], %b[82], %b[71]
          fadd_adds,1,sm        %b[24], %b[83], %b[90], %b[72]
          fadd_rsubs,2,sm       %b[24], %b[83], %b[90], %b[76]
          fmuls,4,sm    %b[59], %b[70], %b[80]
          fadds,5,sm    %b[79], %b[75], %b[88]
          movaw,1       area=2, ind=4, am=0, be=0, %b[55]
          movaw,2       area=0, ind=0, am=0, be=0, %b[12]
          movaw,3       area=0, ind=12, am=0, be=0, %b[54]
        }
        {
          loop_mode
          fmul_rsubs,0,sm       %b[42], %b[17], %b[84], %b[75]
          fmul_rsubs,1,sm       %b[32], %b[67], %b[85], %b[79]
          staaw,2       %b[36], %aad3[ %aasti7 ]
          fmuls,3,sm    %b[29], %b[46], %b[82]
          fmuls,4,sm    %b[35], %b[23], %b[83]
          staaw,5       %b[39], %aad1[ %aasti5 ]
          movaw,0       area=2, ind=0, am=1, be=0, %b[60]
          movaw,1       area=1, ind=0, am=0, be=0, %b[24]
          movaw,2       area=0, ind=8, am=0, be=0, %b[59]
          movaw,3       area=0, ind=28, am=0, be=0, %b[66]
        }
        {
          loop_mode
          fmul_adds,0,sm        %b[40], %b[46], %b[86], %b[39]
          fmul_adds,1,sm        %b[32], %b[25], %b[87], %b[67]
          staaw,2       %b[11], %aad4[ %aasti8 + _f32s,_lts0 0x4 ]
          fmuls,3,sm    %b[27], %b[13], %b[84]
          fmuls,4,sm    %b[35], %b[65], %b[85]
          staaw,5       %b[51], %aad2[ %aasti6 + _f32s,_lts0 0x4 ]
          movaw,0       area=1, ind=4, am=1, be=0, %b[29]
          movaw,1       area=0, ind=0, am=0, be=0, %b[36]
          movaw,2       area=0, ind=24, am=0, be=0, %b[17]
          movaw,3       area=0, ind=20, am=0, be=0, %b[42]
        }
        {
          loop_mode
          fsub_rsubs,0,sm       %b[22], %b[81], %b[48], %b[32]
          fsub_adds,1,sm        %b[22], %b[81], %b[48], %b[35]
          staaw,2       %b[7], %aad3[ %aasti7 + _f32s,_lts0 0x4 ]
          incr,2        %aaincr3
          fsubs,4,sm    %b[3], %b[43], %b[46]
          staaw,5       %b[47], %aad1[ %aasti5 + _f32s,_lts0 0x4 ]
          incr,5        %aaincr3
          movaw,1       area=0, ind=4, am=1, be=0, %b[25]
          movaw,3       area=0, ind=4, am=1, be=0, %b[11]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          fadd_adds,0,sm        %b[10], %b[69], %b[50], %b[7]
          fadd_rsubs,1,sm       %b[10], %b[69], %b[50], %b[47]
          staaw,2       %b[74], %aad4[ %aasti8 ]
          incr,2        %aaincr3
          fadds,4,sm    %b[43], %b[3], %b[48]
          staaw,5       %b[78], %aad2[ %aasti6 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 4 комплексных числа за 6 тактов (4/6) = 5.33 Байт/такт
Двойная теоретическая скорость: 10.67 Байт/такт

Замеры скорости

2. lastStage_radix4_etalon_unroll2

Здесь происходит раскрутка цикла в 2 раза с помощью директивы unroll.

Код на Си
void lastStage_radix4_etalon_unroll2(int data_count, myComplex4 *data_in, myComplex *data_out, myComplex *coefC, myComplex *coefD, myComplex *coefE)
{
	float *x_real_in = &data_in[0].real[0];
	float *x_imag_in = &data_in[0].imag[0];
	float *y_real_in = &data_in[0].real[1];
	float *y_imag_in = &data_in[0].imag[1];
	float *z_real_in = &data_in[0].real[2];
	float *z_imag_in = &data_in[0].imag[2];
	float *w_real_in = &data_in[0].real[3];
	float *w_imag_in = &data_in[0].imag[3];
	float *c_real_in = &coefC[0].real;
	float *c_imag_in = &coefC[0].imag;
	float *d_real_in = &coefD[0].real;
	float *d_imag_in = &coefD[0].imag;
	float *e_real_in = &coefE[0].real;
	float *e_imag_in = &coefE[0].imag;

	float *out_0_real = &data_out[0*data_count/4].real;
	float *out_0_imag = &data_out[0*data_count/4].imag;
	float *out_1_real = &data_out[1*data_count/4].real;
	float *out_1_imag = &data_out[1*data_count/4].imag;
	float *out_2_real = &data_out[2*data_count/4].real;
	float *out_2_imag = &data_out[2*data_count/4].imag;
	float *out_3_real = &data_out[3*data_count/4].real;
	float *out_3_imag = &data_out[3*data_count/4].imag;

	#pragma ivdep
	#pragma unroll(2)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/4; ++i)
	{
		float x_real = x_real_in[8*i];
		float x_imag = x_imag_in[8*i];
		float y_real = y_real_in[8*i];
		float y_imag = y_imag_in[8*i];
		float z_real = z_real_in[8*i];
		float z_imag = z_imag_in[8*i];
		float w_real = w_real_in[8*i];
		float w_imag = w_imag_in[8*i];
		float c_real = c_real_in[2*i];
		float c_imag = c_imag_in[2*i];
		float d_real = d_real_in[2*i];
		float d_imag = d_imag_in[2*i];
		float e_real = e_real_in[2*i];
		float e_imag = e_imag_in[2*i];

		float cy_real = c_real*y_real - c_imag*y_imag;
		float cy_imag = c_real*y_imag + c_imag*y_real;
		float dz_real = d_real*z_real - d_imag*z_imag;
		float dz_imag = d_real*z_imag + d_imag*z_real;
		float ew_real = e_real*w_real - e_imag*w_imag;
		float ew_imag = e_real*w_imag + e_imag*w_real;

		float add02_real =  x_real + dz_real;
		float add02_imag =  x_imag + dz_imag;
		float sub02_real =  x_real - dz_real;
		float sub02_imag =  x_imag - dz_imag;
		float add13_real = cy_real + ew_real;
		float add13_imag = cy_imag + ew_imag;
		float sub13_real = cy_real - ew_real;
		float sub13_imag = cy_imag - ew_imag;
		float sub13i_real = -sub13_imag;
		float sub13i_imag =  sub13_real;

		out_0_real[2*i] = add02_real + add13_real;
		out_0_imag[2*i] = add02_imag + add13_imag;
		out_1_real[2*i] = sub02_real - sub13i_real;
		out_1_imag[2*i] = sub02_imag - sub13i_imag;
		out_2_real[2*i] = add02_real - add13_real;
		out_2_imag[2*i] = add02_imag - add13_imag;
		out_3_real[2*i] = sub02_real + sub13i_real;
		out_3_imag[2*i] = sub02_imag + sub13i_imag;
	}
}
Основной цикл на ассемблере
.L2296:
        {
          fapb  ct=0, dcd=0, fmt=3, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=3, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=4, asz=3, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=3, asz=4, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=4, mrng=16, d=0, incr=2, ind=2, asz=4, abs=16, disp=0
        }
.L1081:
        {
          loop_mode
          pfmul_rsubs,0,sm      %g17, %g18, %g19, %b[62]
          pshufb,1,sm   %b[90], %b[87], %r0, %g16
          pfmul_adds,2,sm       %g17, %b[101], %b[117], %b[73]
          insfd,3,sm    %b[107], %r7, %b[98], %b[27]
          insfd,4,sm    %b[49], %r7, %b[97], %b[49]
          pfmuls,5,sm   %b[91], %b[29], %b[117]
          movad,0       area=1, ind=0, am=0, be=0, %b[1]
          movad,1       area=1, ind=8, am=1, be=0, %b[0]
        }
        {
          loop_mode
          pfsub_adds,0,sm       %b[118], %b[64], %b[108], %b[85]
          pfmuls,1,sm   %b[115], %b[99], %g19
          pfsub_adds,2,sm       %b[119], %b[75], %g20, %b[88]
          insfd,3,sm    %b[32], %r7, %b[37], %b[92]
          insfd,4,sm    %b[78], %r7, %b[68], %b[81]
          pfadds,5,sm   %b[28], %b[33], %b[91]
          movad,0       area=2, ind=0, am=0, be=0, %b[78]
          movad,1       area=2, ind=8, am=1, be=0, %b[68]
          movad,2       area=1, ind=0, am=0, be=0, %b[37]
          movad,3       area=1, ind=8, am=1, be=0, %b[32]
        }
        {
          loop_mode
          pfadd_rsubs,0,sm      %b[118], %b[64], %b[93], %b[98]
          pfsubs,1,sm   %b[55], %b[44], %b[106]
          pfadd_rsubs,2,sm      %b[119], %b[75], %b[113], %b[102]
          insfd,3,sm    %b[50], %r7, %b[61], %b[97]
          insfd,4,sm    %b[15], %r7, %b[14], %g18
          pfmuls,5,sm   %b[114], %b[81], %b[101]
          movaw,0       area=0, ind=0, am=0, be=0, %b[15]
          movaw,1       area=0, ind=16, am=0, be=0, %b[61]
          movaw,2       area=0, ind=0, am=0, be=0, %b[50]
          movaw,3       area=0, ind=16, am=0, be=0, %b[14]
        }
        {
          loop_mode
          pfsub_rsubs,0,sm      %b[118], %b[64], %b[108], %b[107]
          pfadds,1,sm   %b[44], %b[55], %b[111]
          pfsub_rsubs,2,sm      %b[119], %b[75], %g20, %b[108]
          insfd,3,sm    %b[6], %r7, %b[7], %g22
          pshufb,4,sm   %b[104], %b[100], %r0, %g21
          pfmuls,5,sm   %b[115], %g18, %b[115]
          movaw,0       area=0, ind=8, am=0, be=0, %b[6]
          movaw,1       area=0, ind=24, am=0, be=0, %b[55]
          movaw,2       area=0, ind=8, am=0, be=0, %b[7]
          movaw,3       area=0, ind=24, am=0, be=0, %b[44]
        }
        {
          loop_mode
          pfadd_adds,0,sm       %b[118], %b[64], %b[93], %b[75]
          pshufb,1,sm   %b[38], %b[43], %r0, %b[113]
          pfadd_adds,2,sm       %b[119], %b[75], %b[113], %b[84]
          insfd,3,sm    %b[74], %r7, %b[84], %g24
          pshufb,4,sm   %b[110], %b[109], %r0, %g23
          pfsubs,5,sm   %b[28], %b[33], %g20
          movaw,0       area=0, ind=20, am=0, be=0, %b[33]
          movaw,1       area=0, ind=4, am=0, be=0, %b[64]
          movaw,2       area=0, ind=20, am=0, be=0, %b[28]
          movaw,3       area=0, ind=4, am=0, be=0, %b[74]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %g22, %b[94], %b[103], %b[40]
          pshufb,1,sm   %b[2], %b[3], %r0, %b[112]
          staad,2       %g16, %aad1[ %aasti5 + _f32s,_lts0 0x8 ]
          insfd,3,sm    %b[40], %r7, %b[45], %g17
          pshufb,4,sm   %b[86], %b[77], %r0, %g16
          staad,5       %g23, %aad3[ %aasti7 + _f32s,_lts0 0x8 ]
          movaw,0       area=0, ind=12, am=1, be=0, %b[94]
          movaw,1       area=0, ind=28, am=0, be=0, %b[93]
          movaw,2       area=0, ind=12, am=1, be=0, %b[103]
          movaw,3       area=0, ind=28, am=0, be=0, %b[45]
        }
        {
          loop_mode
          pfmul_adds,0,sm       %g24, %b[51], %b[117], %b[51]
          pshufb,1,sm   %b[70], %b[80], %r0, %b[87]
          staad,2       %g21, %aad2[ %aasti6 + _f32s,_lts0 0x8 ]
          insfd,3,sm    %b[90], %r7, %b[87], %b[117]
          insfd,4,sm    %b[110], %r7, %b[109], %g16
          staad,5       %g16, %aad4[ %aasti8 + _f32s,_lts0 0x8 ]
        }
        {
          loop_mode
          pfmul_rsubs,0,sm      %g24, %b[29], %b[116], %b[29]
          pfmuls,1,sm   %b[114], %b[92], %b[77]
          staad,2       %b[117], %aad1[ %aasti5 ]
          incr,2        %aaincr3
          insfd,3,sm    %b[86], %r7, %b[77], %b[114]
          insfd,4,sm    %b[104], %r7, %b[100], %b[116]
          staad,5       %g16, %aad3[ %aasti7 ]
          incr,5        %aaincr3
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          pfmul_rsubs,0,sm      %g22, %b[83], %b[79], %b[24]
          pfmuls,1,sm   %b[89], %b[49], %b[114]
          staad,2       %b[114], %aad4[ %aasti8 ]
          incr,2        %aaincr3
          insfd,3,sm    %b[60], %r7, %b[25], %b[116]
          insfd,4,sm    %b[24], %r7, %b[71], %b[117]
          staad,5       %b[116], %aad2[ %aasti6 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 8 комплексных чисел за 9 тактов (8/9) = 7.11 Байт/такт
Двойная теоретическая скорость: 14.22 Байт/такт

Замеры скорости

3. lastStage_radix4_simd128_noConj

Модифицированный stage_radix4_simd128_noConj для работы с векторными данными.

Код на Си
void lastStage_radix4_simd128_noConj(int data_count, myComplex4 *data_in, myComplex *data_out, myComplex *coefC, myComplex *coefD, myComplex *coefE)
{
	__v2di *xyzw0_real_in = (__v2di*)&data_in[0].real;
	__v2di *xyzw0_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *xyzw1_real_in = (__v2di*)&data_in[1].real;
	__v2di *xyzw1_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *c_in          = (__v2di*)coefC;
	__v2di *d_in          = (__v2di*)coefD;
	__v2di *e_in          = (__v2di*)coefE;

	__v2di *out_0 = (__v2di*)&data_out[0*data_count/4];
	__v2di *out_1 = (__v2di*)&data_out[1*data_count/4];
	__v2di *out_2 = (__v2di*)&data_out[2*data_count/4];
	__v2di *out_3 = (__v2di*)&data_out[3*data_count/4];

	#pragma ivdep
	#pragma unroll(1)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/8; ++i)
	{
		__v2di xyzw0_real = xyzw0_real_in[4*i];
		__v2di xyzw0_imag = xyzw0_imag_in[4*i];
		__v2di xyzw1_real = xyzw1_real_in[4*i];
		__v2di xyzw1_imag = xyzw1_imag_in[4*i];
		__v2di c          = c_in[i];
		__v2di d          = d_in[i];
		__v2di e          = e_in[i];

		__v2di xy_real = __builtin_e2k_qpshufb(xyzw1_real, xyzw0_real, (__v2di){0x0706050403020100, 0x0706050403020100});
		__v2di zw_real = __builtin_e2k_qpshufb(xyzw1_real, xyzw0_real, (__v2di){0x0F0E0D0C0B0A0908, 0x0F0E0D0C0B0A0908});
		__v2di xy_imag = __builtin_e2k_qpshufb(xyzw1_imag, xyzw0_imag, (__v2di){0x0706050403020100, 0x0706050403020100});
		__v2di zw_imag = __builtin_e2k_qpshufb(xyzw1_imag, xyzw0_imag, (__v2di){0x0F0E0D0C0B0A0908, 0x0F0E0D0C0B0A0908});

		__v2di x = __builtin_e2k_qppermb(xy_imag, xy_real, (__v2di){0x1312111003020100, 0x1B1A19180B0A0908});
		__v2di y = __builtin_e2k_qppermb(xy_imag, xy_real, (__v2di){0x1716151407060504, 0x1F1E1D1C0F0E0D0C});
		__v2di z = __builtin_e2k_qppermb(zw_imag, zw_real, (__v2di){0x1312111003020100, 0x1B1A19180B0A0908});
		__v2di w = __builtin_e2k_qppermb(zw_imag, zw_real, (__v2di){0x1716151407060504, 0x1F1E1D1C0F0E0D0C});

		__v2di swap_c = __builtin_e2k_qpshufb(c, c, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_d = __builtin_e2k_qpshufb(d, d, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_e = __builtin_e2k_qpshufb(e, e, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});

		__v2di cy_real = __builtin_e2k_qpfmuls(     c, y);
		__v2di dz_real = __builtin_e2k_qpfmuls(     d, z);
		__v2di ew_real = __builtin_e2k_qpfmuls(     e, w);
		__v2di cy_imag = __builtin_e2k_qpfmuls(swap_c, y);
		__v2di dz_imag = __builtin_e2k_qpfmuls(swap_d, z);
		__v2di ew_imag = __builtin_e2k_qpfmuls(swap_e, w);

		__v2di cy_rr = __builtin_e2k_qpfhsubs((__v2di){0}, cy_real);
		__v2di dz_rr = __builtin_e2k_qpfhsubs((__v2di){0}, dz_real);
		__v2di ew_rr = __builtin_e2k_qpfhsubs((__v2di){0}, ew_real);
		__v2di cy_ii = __builtin_e2k_qpfhadds((__v2di){0}, cy_imag);
		__v2di dz_ii = __builtin_e2k_qpfhadds((__v2di){0}, dz_imag);
		__v2di ew_ii = __builtin_e2k_qpfhadds((__v2di){0}, ew_imag);

		__v2di cy = __builtin_e2k_qppermb(cy_ii, cy_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});
		__v2di dz = __builtin_e2k_qppermb(dz_ii, dz_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});
		__v2di ew = __builtin_e2k_qppermb(ew_ii, ew_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});

		__v2di add02 = __builtin_e2k_qpfadds( x, dz);
		__v2di sub02 = __builtin_e2k_qpfsubs( x, dz);
		__v2di add13 = __builtin_e2k_qpfadds(cy, ew);
		__v2di sub13 = __builtin_e2k_qpfsubs(cy, ew);

		//__v2di conj_sub13 = __builtin_e2k_qpxor(sub13, (__v2di){1LL<<63, 1LL<<63});
		//__v2di sub13i = __builtin_e2k_qpshufb(conj_sub13, conj_sub13, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_sub13 = __builtin_e2k_qpshufb(sub13, sub13, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di sub13i = __builtin_e2k_qpxor(swap_sub13, (__v2di){1LL<<31, 1LL<<31});

		out_0[i] = __builtin_e2k_qpfadds(add02, add13);
		out_1[i] = __builtin_e2k_qpfsubs(sub02, sub13i);
		out_2[i] = __builtin_e2k_qpfsubs(add02, add13);
		out_3[i] = __builtin_e2k_qpfadds(sub02, sub13i);
	}
}
Основной цикл на ассемблере
.L2983:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=4, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=4, asz=3, abs=8, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=3, asz=4, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=0, ind=2, asz=4, abs=16, disp=0
        }
.L2350:
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[21], %b[49], %r14, %b[4]
          qpshufb,1,sm  %b[21], %b[21], %r10, %b[11]
          qpfsub_rsubs,2,sm     %b[42], %b[56], %b[54], %b[1]
          qppermb,4,sm  %b[24], %b[25], %r12, %b[9]
          qpfadds,5,sm  %b[48], %b[45], %b[0]
        }
        {
          loop_mode
          qpfmul_hadds,0,sm     %b[11], %b[49], %r14, %b[21]
          qppermb,1,sm  %b[51], %b[55], %r12, %b[33]
          qpfsub_adds,2,sm      %b[42], %b[56], %b[54], %b[12]
          qpshufb,4,sm  %b[46], %b[46], %r10, %b[32]
          qpfsubs,5,sm  %b[48], %b[45], %b[16]
        }
        {
          loop_mode
          qppermb,1,sm  %b[26], %b[27], %r0, %b[34]
          qpshufb,3,sm  %b[39], %b[39], %r10, %b[48]
          qppermb,4,sm  %b[53], %b[57], %r0, %b[45]
          staaqp,5      %b[37], %aad4[ %aasti8 ]
          incr,5        %aaincr0
          movaqp,1      area=1, ind=0, am=1, be=0, %b[42]
          movaqp,3      area=1, ind=0, am=1, be=0, %b[11]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[41], %b[33], %r14, %b[27]
          qppermb,1,sm  %b[23], %b[6], %r9, %b[54]
          qpfmul_hadds,2,sm     %b[50], %b[33], %r14, %b[26]
          qpshufb,3,sm  %b[52], %b[59], %r11, %b[53]
          qpshufb,4,sm  %b[43], %b[58], %r11, %b[49]
          staaqp,5      %b[22], %aad2[ %aasti6 ]
          incr,5        %aaincr0
          movaqp,1      area=2, ind=0, am=1, be=0, %b[37]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[46], %b[9], %r14, %b[6]
          qpshufb,1,sm  %b[18], %b[18], %r10, %b[60]
          qpfadd_adds,2,sm      %b[40], %b[54], %b[2], %b[33]
          qpshufb,3,sm  %b[52], %b[59], %r13, %b[23]
          qpshufb,4,sm  %b[43], %b[58], %r13, %b[22]
          staaqp,5      %b[3], %aad3[ %aasti7 ]
          incr,5        %aaincr0
          movaqp,0      area=0, ind=0, am=0, be=0, %b[57]
          movaqp,1      area=0, ind=16, am=1, be=0, %b[56]
          movaqp,2      area=0, ind=0, am=0, be=0, %b[50]
          movaqp,3      area=0, ind=16, am=1, be=0, %b[41]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfmul_hadds,0,sm     %b[32], %b[9], %r14, %b[3]
          qpxor,1,sm    %b[60], %r7, %b[52]
          qpfadd_rsubs,2,sm     %b[40], %b[54], %b[2], %b[18]
          qppermb,3,sm  %b[30], %b[31], %r9, %b[43]
          qppermb,4,sm  %b[7], %b[10], %r9, %b[46]
          staaqp,5      %b[14], %aad1[ %aasti5 ]
          incr,5        %aaincr0
        }

Теоретическая скорость: 8 комплексных чисел за 6 тактов (8/6) = 10.67 Байт/такт
Двойная теоретическая скорость: 21.33 Байт/такт

Замеры скорости

4. lastStage_radix4_simd128_noConj_unroll2

Здесь происходит раскрутка цикла в 2 раза с помощью директивы unroll.

Код на Си
void lastStage_radix4_simd128_noConj_unroll2(int data_count, myComplex4 *data_in, myComplex *data_out, myComplex *coefC, myComplex *coefD, myComplex *coefE)
{
	__v2di *xyzw0_real_in = (__v2di*)&data_in[0].real;
	__v2di *xyzw0_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *xyzw1_real_in = (__v2di*)&data_in[1].real;
	__v2di *xyzw1_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *c_in          = (__v2di*)coefC;
	__v2di *d_in          = (__v2di*)coefD;
	__v2di *e_in          = (__v2di*)coefE;

	__v2di *out_0 = (__v2di*)&data_out[0*data_count/4];
	__v2di *out_1 = (__v2di*)&data_out[1*data_count/4];
	__v2di *out_2 = (__v2di*)&data_out[2*data_count/4];
	__v2di *out_3 = (__v2di*)&data_out[3*data_count/4];

	#pragma ivdep
	#pragma unroll(2)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/8; ++i)
	{
		__v2di xyzw0_real = xyzw0_real_in[4*i];
		__v2di xyzw0_imag = xyzw0_imag_in[4*i];
		__v2di xyzw1_real = xyzw1_real_in[4*i];
		__v2di xyzw1_imag = xyzw1_imag_in[4*i];
		__v2di c          = c_in[i];
		__v2di d          = d_in[i];
		__v2di e          = e_in[i];

		__v2di xy_real = __builtin_e2k_qpshufb(xyzw1_real, xyzw0_real, (__v2di){0x0706050403020100, 0x0706050403020100});
		__v2di zw_real = __builtin_e2k_qpshufb(xyzw1_real, xyzw0_real, (__v2di){0x0F0E0D0C0B0A0908, 0x0F0E0D0C0B0A0908});
		__v2di xy_imag = __builtin_e2k_qpshufb(xyzw1_imag, xyzw0_imag, (__v2di){0x0706050403020100, 0x0706050403020100});
		__v2di zw_imag = __builtin_e2k_qpshufb(xyzw1_imag, xyzw0_imag, (__v2di){0x0F0E0D0C0B0A0908, 0x0F0E0D0C0B0A0908});

		__v2di x = __builtin_e2k_qppermb(xy_imag, xy_real, (__v2di){0x1312111003020100, 0x1B1A19180B0A0908});
		__v2di y = __builtin_e2k_qppermb(xy_imag, xy_real, (__v2di){0x1716151407060504, 0x1F1E1D1C0F0E0D0C});
		__v2di z = __builtin_e2k_qppermb(zw_imag, zw_real, (__v2di){0x1312111003020100, 0x1B1A19180B0A0908});
		__v2di w = __builtin_e2k_qppermb(zw_imag, zw_real, (__v2di){0x1716151407060504, 0x1F1E1D1C0F0E0D0C});

		__v2di swap_c = __builtin_e2k_qpshufb(c, c, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_d = __builtin_e2k_qpshufb(d, d, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_e = __builtin_e2k_qpshufb(e, e, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});

		__v2di cy_real = __builtin_e2k_qpfmuls(     c, y);
		__v2di dz_real = __builtin_e2k_qpfmuls(     d, z);
		__v2di ew_real = __builtin_e2k_qpfmuls(     e, w);
		__v2di cy_imag = __builtin_e2k_qpfmuls(swap_c, y);
		__v2di dz_imag = __builtin_e2k_qpfmuls(swap_d, z);
		__v2di ew_imag = __builtin_e2k_qpfmuls(swap_e, w);

		__v2di cy_rr = __builtin_e2k_qpfhsubs((__v2di){0}, cy_real);
		__v2di dz_rr = __builtin_e2k_qpfhsubs((__v2di){0}, dz_real);
		__v2di ew_rr = __builtin_e2k_qpfhsubs((__v2di){0}, ew_real);
		__v2di cy_ii = __builtin_e2k_qpfhadds((__v2di){0}, cy_imag);
		__v2di dz_ii = __builtin_e2k_qpfhadds((__v2di){0}, dz_imag);
		__v2di ew_ii = __builtin_e2k_qpfhadds((__v2di){0}, ew_imag);

		__v2di cy = __builtin_e2k_qppermb(cy_ii, cy_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});
		__v2di dz = __builtin_e2k_qppermb(dz_ii, dz_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});
		__v2di ew = __builtin_e2k_qppermb(ew_ii, ew_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});

		__v2di add02 = __builtin_e2k_qpfadds( x, dz);
		__v2di sub02 = __builtin_e2k_qpfsubs( x, dz);
		__v2di add13 = __builtin_e2k_qpfadds(cy, ew);
		__v2di sub13 = __builtin_e2k_qpfsubs(cy, ew);

		//__v2di conj_sub13 = __builtin_e2k_qpxor(sub13, (__v2di){1LL<<63, 1LL<<63});
		//__v2di sub13i = __builtin_e2k_qpshufb(conj_sub13, conj_sub13, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_sub13 = __builtin_e2k_qpshufb(sub13, sub13, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di sub13i = __builtin_e2k_qpxor(swap_sub13, (__v2di){1LL<<31, 1LL<<31});

		out_0[i] = __builtin_e2k_qpfadds(add02, add13);
		out_1[i] = __builtin_e2k_qpfsubs(sub02, sub13i);
		out_2[i] = __builtin_e2k_qpfsubs(add02, add13);
		out_3[i] = __builtin_e2k_qpfadds(sub02, sub13i);
	}
}
Основной цикл на ассемблере
.L3893:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=3, abs=8, disp=96
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=4, abs=16, disp=0
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=3, abs=24, disp=0
        }
.L3037:
        {
          loop_mode
          qpfsub_adds,0,sm      %b[16], %b[71], %b[66], %b[57]
          qpshufb,1,sm  %b[32], %b[32], %r14, %b[71]
          qpfsub_rsubs,2,sm     %b[16], %b[71], %b[66], %b[64]
          qppermb,3,sm  %b[38], %b[42], %r11, %b[0]
          qppermb,4,sm  %b[73], %b[76], %r11, %b[1]
          qpfadds,5,sm  %b[64], %b[57], %b[66]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[32], %b[83], %r15, %b[74]
          qpshufb,1,sm  %b[10], %b[10], %r14, %b[73]
          qpfmul_hadds,2,sm     %b[71], %b[83], %r15, %b[71]
          qpshufb,4,sm  %b[21], %b[25], %r9, %b[32]
          qpfadds,5,sm  %b[1], %b[0], %b[16]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[31], %b[75], %r15, %b[38]
          qppermb,1,sm  %b[69], %b[34], %r13, %b[31]
          qpfmul_hadds,2,sm     %b[72], %b[75], %r15, %b[34]
          qpshufb,3,sm  %b[19], %b[19], %r14, %b[54]
          qppermb,4,sm  %b[54], %b[55], %r13, %b[42]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[10], %b[65], %r15, %g17
          qpshufb,1,sm  %b[26], %b[26], %r14, %b[65]
          qpfmul_hadds,2,sm     %b[73], %b[65], %r15, %g16
          qppermb,3,sm  %g16, %g17, %r11, %b[55]
          qppermb,4,sm  %b[62], %b[63], %r11, %b[62]
          qpfsubs,5,sm  %b[3], %b[2], %b[63]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[41], %b[82], %r15, %b[61]
          qppermb,1,sm  %b[80], %b[78], %r11, %b[72]
          qpfmul_hadds,2,sm     %b[61], %b[82], %r15, %b[60]
          qpshufb,3,sm  %b[43], %b[46], %r9, %b[67]
          qppermb,4,sm  %b[60], %b[67], %r11, %b[69]
          qpfsubs,5,sm  %b[62], %b[55], %b[2]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[26], %b[35], %r15, %b[65]
          qppermb,1,sm  %b[58], %b[70], %r13, %b[3]
          qpfmul_hadds,2,sm     %b[65], %b[35], %r15, %b[58]
          qpshufb,3,sm  %b[29], %b[29], %r14, %b[70]
          qppermb,4,sm  %b[67], %b[32], %r12, %b[73]
          staaqp,5      %b[77], %aad4[ %aasti8 ]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[19], %b[44], %r15, %b[76]
          qppermb,1,sm  %b[56], %b[68], %r13, %b[10]
          qpfadd_adds,2,sm      %b[7], %b[72], %b[66], %b[75]
          qpshufb,3,sm  %b[49], %b[53], %r0, %b[68]
          qpshufb,4,sm  %b[11], %b[52], %r0, %b[56]
          staaqp,5      %b[79], %aad2[ %aasti6 ]
        }
        {
          loop_mode
          qpfmul_hadds,0,sm     %b[54], %b[44], %r15, %b[78]
          qpshufb,1,sm  %b[4], %b[4], %r14, %b[79]
          qpfadd_rsubs,2,sm     %b[7], %b[72], %b[66], %b[77]
          qpshufb,3,sm  %b[23], %b[27], %r0, %b[66]
          qpshufb,4,sm  %b[45], %b[48], %r0, %b[54]
          staaqp,5      %b[81], %aad2[ %aasti6 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
          movaqp,0      area=3, ind=0, am=0, be=0, %b[4]
          movaqp,1      area=1, ind=0, am=0, be=0, %b[23]
          movaqp,3      area=1, ind=0, am=0, be=0, %b[19]
        }
        {
          loop_mode
          qpfadd_adds,0,sm      %b[14], %b[69], %b[18], %g18
          qpxor,1,sm    %b[79], %r10, %b[82]
          qpfadd_rsubs,2,sm     %b[14], %b[69], %b[18], %b[79]
          qppermb,3,sm  %b[56], %b[68], %r12, %b[80]
          qppermb,4,sm  %b[54], %b[66], %r12, %b[81]
          staaqp,5      %g18, %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
          movaqp,0      area=3, ind=16, am=1, be=0, %b[27]
          movaqp,1      area=2, ind=16, am=0, be=0, %b[26]
          movaqp,3      area=2, ind=16, am=0, be=0, %b[18]
        }
        {
          loop_mode
          qpfsub_adds,0,sm      %b[7], %b[72], %b[82], %g19
          qpshufb,1,sm  %b[63], %b[63], %r14, %b[59]
          staaqp,2      %g19, %aad1[ %aasti5 ]
          qpshufb,3,sm  %b[49], %b[53], %r9, %b[53]
          qpshufb,4,sm  %b[11], %b[52], %r9, %b[52]
          staaqp,5      %b[59], %aad3[ %aasti7 ]
          movaqp,0      area=2, ind=0, am=1, be=0, %b[35]
          movaqp,1      area=1, ind=16, am=1, be=0, %b[44]
          movaqp,2      area=2, ind=0, am=1, be=0, %b[11]
          movaqp,3      area=1, ind=16, am=1, be=0, %b[41]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfsub_rsubs,0,sm     %b[7], %b[72], %b[82], %b[57]
          qpxor,1,sm    %b[59], %r10, %b[64]
          staaqp,2      %b[57], %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
          incr,2        %aaincr3
          qpshufb,3,sm  %b[39], %b[39], %r14, %b[59]
          qppermb,4,sm  %b[52], %b[53], %r12, %b[63]
          staaqp,5      %b[64], %aad3[ %aasti7 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
          movaqp,0      area=0, ind=0, am=0, be=0, %b[49]
          movaqp,1      area=0, ind=16, am=1, be=0, %b[48]
          movaqp,2      area=0, ind=0, am=0, be=0, %b[45]
          movaqp,3      area=0, ind=16, am=1, be=0, %b[7]
        }

Теоретическая скорость: 16 комплексных чисел за 11 тактов (16/11) = 11.64 Байт/такт
Двойная теоретическая скорость: 23.27 Байт/такт

Замеры скорости

5. lastStage_radix4_simd128_noConj_unroll3

Здесь происходит раскрутка цикла в 3 раза с помощью директивы unroll.

Код на Си
void lastStage_radix4_simd128_noConj_unroll3(int data_count, myComplex4 *data_in, myComplex *data_out, myComplex *coefC, myComplex *coefD, myComplex *coefE)
{
	__v2di *xyzw0_real_in = (__v2di*)&data_in[0].real;
	__v2di *xyzw0_imag_in = (__v2di*)&data_in[0].imag;
	__v2di *xyzw1_real_in = (__v2di*)&data_in[1].real;
	__v2di *xyzw1_imag_in = (__v2di*)&data_in[1].imag;
	__v2di *c_in          = (__v2di*)coefC;
	__v2di *d_in          = (__v2di*)coefD;
	__v2di *e_in          = (__v2di*)coefE;

	__v2di *out_0 = (__v2di*)&data_out[0*data_count/4];
	__v2di *out_1 = (__v2di*)&data_out[1*data_count/4];
	__v2di *out_2 = (__v2di*)&data_out[2*data_count/4];
	__v2di *out_3 = (__v2di*)&data_out[3*data_count/4];

	#pragma ivdep
	#pragma unroll(3)
	#pragma prefetch
	for(int64_t i = 0; i < data_count/8; ++i)
	{
		__v2di xyzw0_real = xyzw0_real_in[4*i];
		__v2di xyzw0_imag = xyzw0_imag_in[4*i];
		__v2di xyzw1_real = xyzw1_real_in[4*i];
		__v2di xyzw1_imag = xyzw1_imag_in[4*i];
		__v2di c          = c_in[i];
		__v2di d          = d_in[i];
		__v2di e          = e_in[i];

		__v2di xy_real = __builtin_e2k_qpshufb(xyzw1_real, xyzw0_real, (__v2di){0x0706050403020100, 0x0706050403020100});
		__v2di zw_real = __builtin_e2k_qpshufb(xyzw1_real, xyzw0_real, (__v2di){0x0F0E0D0C0B0A0908, 0x0F0E0D0C0B0A0908});
		__v2di xy_imag = __builtin_e2k_qpshufb(xyzw1_imag, xyzw0_imag, (__v2di){0x0706050403020100, 0x0706050403020100});
		__v2di zw_imag = __builtin_e2k_qpshufb(xyzw1_imag, xyzw0_imag, (__v2di){0x0F0E0D0C0B0A0908, 0x0F0E0D0C0B0A0908});

		__v2di x = __builtin_e2k_qppermb(xy_imag, xy_real, (__v2di){0x1312111003020100, 0x1B1A19180B0A0908});
		__v2di y = __builtin_e2k_qppermb(xy_imag, xy_real, (__v2di){0x1716151407060504, 0x1F1E1D1C0F0E0D0C});
		__v2di z = __builtin_e2k_qppermb(zw_imag, zw_real, (__v2di){0x1312111003020100, 0x1B1A19180B0A0908});
		__v2di w = __builtin_e2k_qppermb(zw_imag, zw_real, (__v2di){0x1716151407060504, 0x1F1E1D1C0F0E0D0C});

		__v2di swap_c = __builtin_e2k_qpshufb(c, c, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_d = __builtin_e2k_qpshufb(d, d, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_e = __builtin_e2k_qpshufb(e, e, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});

		__v2di cy_real = __builtin_e2k_qpfmuls(     c, y);
		__v2di dz_real = __builtin_e2k_qpfmuls(     d, z);
		__v2di ew_real = __builtin_e2k_qpfmuls(     e, w);
		__v2di cy_imag = __builtin_e2k_qpfmuls(swap_c, y);
		__v2di dz_imag = __builtin_e2k_qpfmuls(swap_d, z);
		__v2di ew_imag = __builtin_e2k_qpfmuls(swap_e, w);

		__v2di cy_rr = __builtin_e2k_qpfhsubs((__v2di){0}, cy_real);
		__v2di dz_rr = __builtin_e2k_qpfhsubs((__v2di){0}, dz_real);
		__v2di ew_rr = __builtin_e2k_qpfhsubs((__v2di){0}, ew_real);
		__v2di cy_ii = __builtin_e2k_qpfhadds((__v2di){0}, cy_imag);
		__v2di dz_ii = __builtin_e2k_qpfhadds((__v2di){0}, dz_imag);
		__v2di ew_ii = __builtin_e2k_qpfhadds((__v2di){0}, ew_imag);

		__v2di cy = __builtin_e2k_qppermb(cy_ii, cy_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});
		__v2di dz = __builtin_e2k_qppermb(dz_ii, dz_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});
		__v2di ew = __builtin_e2k_qppermb(ew_ii, ew_rr, (__v2di){0x1B1A19180B0A0908, 0x1F1E1D1C0F0E0D0C});

		__v2di add02 = __builtin_e2k_qpfadds( x, dz);
		__v2di sub02 = __builtin_e2k_qpfsubs( x, dz);
		__v2di add13 = __builtin_e2k_qpfadds(cy, ew);
		__v2di sub13 = __builtin_e2k_qpfsubs(cy, ew);

		//__v2di conj_sub13 = __builtin_e2k_qpxor(sub13, (__v2di){1LL<<63, 1LL<<63});
		//__v2di sub13i = __builtin_e2k_qpshufb(conj_sub13, conj_sub13, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di swap_sub13 = __builtin_e2k_qpshufb(sub13, sub13, (__v2di){0x0302010007060504, 0x0B0A09080F0E0D0C});
		__v2di sub13i = __builtin_e2k_qpxor(swap_sub13, (__v2di){1LL<<31, 1LL<<31});

		out_0[i] = __builtin_e2k_qpfadds(add02, add13);
		out_1[i] = __builtin_e2k_qpfsubs(sub02, sub13i);
		out_2[i] = __builtin_e2k_qpfsubs(add02, add13);
		out_3[i] = __builtin_e2k_qpfadds(sub02, sub13i);
	}
}
Основной цикл на ассемблере
.L5077:
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=0, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=0, disp=32
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=4, disp=64
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=4, disp=96
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=128
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=1, ind=1, asz=2, abs=8, disp=160
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=4, asz=2, abs=12, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=3, asz=2, abs=12, disp=0
        }
        {
          fapb  ct=0, dcd=0, fmt=5, mrng=0, d=0, incr=2, ind=2, asz=3, abs=16, disp=0
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=2, ind=4, asz=3, abs=16, disp=32
        }
        {
          fapb  ct=1, dcd=0, fmt=5, mrng=16, d=0, incr=2, ind=3, asz=3, abs=24, disp=32
          fapb  dpl=0, dcd=0, fmt=5, mrng=16, d=0, incr=2, ind=2, asz=3, abs=24, disp=32
        }
.L3947:
        {
          loop_mode
          qpfmul_hadds,0,sm     %b[93], %b[76], %r15, %b[75]
          qpshufb,1,sm  %b[85], %b[85], %r13, %b[91]
          qpfadd_adds,2,sm      %b[32], %b[87], %b[75], %b[76]
          qppermb,3,sm  %b[18], %b[17], %r10, %b[86]
          qppermb,4,sm  %b[91], %b[86], %r10, %b[85]
          qpfsubs,5,sm  %b[88], %b[89], %b[0]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[52], %b[94], %r15, %b[93]
          qpxor,1,sm    %b[91], %r12, %b[105]
          qpfadd_adds,2,sm      %b[80], %b[77], %b[83], %b[91]
          qppermb,3,sm  %b[44], %b[69], %r11, %b[103]
          qppermb,4,sm  %b[22], %b[27], %r11, %b[104]
          qpfsubs,5,sm  %b[85], %b[86], %b[83]
        }
        {
          loop_mode
          qpfmul_hadds,0,sm     %b[97], %b[94], %r15, %b[85]
          qpxor,1,sm    %b[102], %r12, %b[97]
          qpfsub_adds,2,sm      %b[80], %b[77], %b[105], %b[82]
          qppermb,3,sm  %b[101], %b[100], %r10, %b[94]
          qppermb,4,sm  %b[82], %b[81], %r10, %b[86]
          qpfadds,5,sm  %b[85], %b[86], %b[81]
        }
        {
          loop_mode
          qpfmul_hadds,0,sm     %b[95], %b[72], %r15, %b[100]
          qpshufb,1,sm  %b[2], %b[2], %r13, %b[101]
          qpfsub_adds,2,sm      %b[73], %b[78], %b[97], %b[95]
          qpshufb,3,sm  %b[39], %b[65], %r0, %b[1]
          qpshufb,4,sm  %b[68], %b[60], %r0, %b[2]
          qpfsubs,5,sm  %b[86], %b[94], %b[72]
          movaqp,1      area=4, ind=16, am=0, be=0, %b[8]
          movaqp,3      area=5, ind=0, am=1, be=0, %b[7]
        }
        {
          loop_mode
          qpfsub_rsubs,0,sm     %b[80], %b[77], %b[105], %b[78]
          qpxor,1,sm    %b[101], %r12, %b[88]
          qpfsub_rsubs,2,sm     %b[73], %b[78], %b[97], %b[77]
          qpshufb,3,sm  %b[99], %b[98], %r0, %b[18]
          qppermb,4,sm  %b[2], %b[1], %r11, %b[80]
          qpfadds,5,sm  %b[88], %b[89], %b[73]
          movaqp,0      area=5, ind=0, am=1, be=0, %b[17]
          movaqp,1      area=1, ind=0, am=0, be=0, %b[23]
          movaqp,3      area=1, ind=0, am=0, be=0, %b[26]
        }
        {
          loop_mode
          qpfsub_adds,0,sm      %b[32], %b[87], %b[88], %b[87]
          qpshufb,1,sm  %b[61], %b[61], %r13, %b[89]
          qpfsub_rsubs,2,sm     %b[32], %b[87], %b[88], %b[86]
          qpshufb,3,sm  %b[99], %b[98], %r9, %b[39]
          qpshufb,4,sm  %b[96], %b[92], %r9, %b[45]
          qpfadds,5,sm  %b[86], %b[94], %b[88]
          movaqp,0      area=4, ind=0, am=1, be=0, %b[31]
          movaqp,1      area=1, ind=16, am=1, be=0, %b[32]
          movaqp,2      area=4, ind=0, am=1, be=0, %b[40]
          movaqp,3      area=1, ind=16, am=1, be=0, %b[36]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[61], %b[104], %r15, %b[84]
          qpshufb,1,sm  %b[35], %b[35], %r13, %b[94]
          qpfmul_hadds,2,sm     %b[89], %b[104], %r15, %b[89]
          qpshufb,3,sm  %b[96], %b[92], %r0, %b[60]
          qppermb,4,sm  %b[45], %b[39], %r11, %b[92]
          staaqp,5      %b[84], %aad4[ %aasti8 ]
          movaqp,0      area=3, ind=0, am=0, be=0, %b[52]
          movaqp,1      area=3, ind=16, am=1, be=0, %b[57]
          movaqp,2      area=3, ind=0, am=0, be=0, %b[46]
          movaqp,3      area=3, ind=16, am=1, be=0, %b[51]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[35], %b[103], %r15, %b[98]
          qpshufb,1,sm  %b[56], %b[56], %r13, %b[103]
          qpfmul_hadds,2,sm     %b[94], %b[103], %r15, %b[99]
          qpshufb,3,sm  %b[42], %b[42], %r13, %b[101]
          qppermb,4,sm  %b[60], %b[18], %r11, %b[102]
          staaqp,5      %b[90], %aad2[ %aasti6 ]
          movaqp,0      area=2, ind=16, am=1, be=0, %b[90]
          movaqp,1      area=2, ind=0, am=0, be=0, %b[96]
          movaqp,2      area=2, ind=16, am=1, be=0, %b[94]
          movaqp,3      area=2, ind=0, am=0, be=0, %b[97]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[56], %b[80], %r15, %b[79]
          qppermb,1,sm  %b[11], %b[12], %r11, %b[103]
          qpfmul_hadds,2,sm     %b[103], %b[80], %r15, %b[80]
          qpshufb,3,sm  %b[7], %b[7], %r13, %b[65]
          qpshufb,4,sm  %b[8], %b[8], %r13, %b[68]
          staaqp,5      %b[79], %aad2[ %aasti6 + _f32s,_lts0 0x20 ]
          movaqp,0      area=0, ind=16, am=1, be=0, %b[56]
          movaqp,1      area=0, ind=0, am=0, be=0, %b[61]
          movaqp,2      area=0, ind=16, am=1, be=0, %b[64]
          movaqp,3      area=0, ind=0, am=0, be=0, %b[35]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[10], %b[103], %r15, %b[13]
          qppermb,1,sm  %b[47], %b[41], %r14, %b[70]
          qpfmul_hadds,2,sm     %b[70], %b[103], %r15, %b[14]
          qpshufb,3,sm  %b[26], %b[23], %r9, %b[10]
          qppermb,4,sm  %b[13], %b[14], %r14, %b[74]
          staaqp,5      %b[74], %aad2[ %aasti6 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[9], %b[92], %r15, %b[41]
          qppermb,1,sm  %b[85], %b[93], %r10, %b[76]
          qpfmul_hadds,2,sm     %b[67], %b[92], %r15, %b[47]
          qpshufb,3,sm  %b[36], %b[32], %r9, %b[9]
          qpshufb,4,sm  %b[37], %b[63], %r9, %b[67]
          staaqp,5      %b[76], %aad4[ %aasti8 + _f32s,_lts0 0x20 ]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[42], %b[102], %r15, %b[3]
          qppermb,1,sm  %b[4], %b[3], %r14, %b[71]
          qpfmul_hadds,2,sm     %b[101], %b[102], %r15, %b[4]
          qpshufb,3,sm  %b[66], %b[58], %r9, %b[42]
          qppermb,4,sm  %b[75], %b[71], %r10, %b[75]
          staaqp,5      %b[91], %aad4[ %aasti8 + _f32s,_lts0 0x10 ]
          incr,5        %aaincr3
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[21], %b[70], %r15, %g16
          qppermb,1,sm  %b[100], %g16, %r10, %b[85]
          qpfadd_adds,2,sm      %b[71], %b[76], %b[88], %b[82]
          qpshufb,3,sm  %b[28], %b[25], %r0, %b[25]
          qpshufb,4,sm  %b[55], %b[55], %r13, %b[91]
          staaqp,5      %b[82], %aad1[ %aasti5 + _f32s,_lts0 0x10 ]
        }
        {
          loop_mode
          qpfmul_hsubs,0,sm     %b[55], %b[74], %r15, %b[69]
          qppermb,1,sm  %b[62], %b[20], %r14, %b[28]
          qpfadd_rsubs,2,sm     %b[71], %b[76], %b[88], %b[88]
          qpshufb,3,sm  %b[38], %b[34], %r0, %b[20]
          qppermb,4,sm  %b[44], %b[69], %r14, %b[92]
          staaqp,5      %b[95], %aad1[ %aasti5 ]
        }
        {
          loop_mode
          qpfadd_rsubs,0,sm     %b[30], %b[85], %b[73], %b[77]
          qppermb,1,sm  %b[24], %b[29], %r14, %b[78]
          staaqp,2      %b[78], %aad3[ %aasti7 + _f32s,_lts0 0x10 ]
          qpshufb,3,sm  %b[21], %b[21], %r13, %b[93]
          qpshufb,4,sm  %b[50], %b[50], %r13, %b[95]
          staaqp,5      %b[77], %aad3[ %aasti7 ]
        }
        {
          loop_mode
          alc   alcf=1, alct=1
          abn   abnf=1, abnt=1
          ct    %ctpr1 ? %NOT_LOOP_END
          qpfadd_rsubs,0,sm     %b[78], %b[75], %b[81], %b[72]
          qpshufb,1,sm  %b[72], %b[72], %r13, %b[100]
          staaqp,2      %b[87], %aad1[ %aasti5 + _f32s,_lts0 0x20 ]
          incr,2        %aaincr3
          qppermb,3,sm  %b[49], %b[43], %r10, %b[87]
          qppermb,4,sm  %b[6], %b[5], %r10, %b[86]
          staaqp,5      %b[86], %aad3[ %aasti7 + _f32s,_lts0 0x20 ]
          incr,5        %aaincr3
        }

Теоретическая скорость: 24 комплексных числа за 16 тактов (24/16) = 12 Байт/такт
Двойная теоретическая скорость: 24 Байт/такт

Замеры скорости

Итоги по lastStage_radix4

При реализации Vector-4 FFT будем использовать lastStage_radix4_simd128_noConj_unroll2.

Собираем FFT

fft_radix2_vector2

Собираем fft_radix2_vector2 из reverse_radix2_vector2_stream16, всех вариантов stage_radix2_vector2 и lastStage_radix2_simd128_noConj.

fft_radix2_vector4

Собираем fft_radix2_vector4 из reverse_radix2_vector4_stream8, всех вариантов stage_radix2_vector4 и lastStage_radix4_simd128_noConj_unroll2.

fft_radix4_vector2

Собираем fft_radix4_vector2 из reverse_radix4_vector2_stream16, всех вариантов stage_radix4_vector2 и lastStage_radix2_simd128_noConj.

fft_radix4_vector4

Собираем fft_radix4_vector4 из reverse_radix4_vector4_stream16, всех вариантов stage_radix4_vector4 и lastStage_radix4_simd128_noConj_unroll2.

Дальнейшие улучшения имеющегося кода

Что изменить в текущем коде:

  • Перемежить коэффициенты.
    Сейчас коэффициенты c/d/e размещаются в нескольких массивах.
    Нужно разместить их в одном массиве, перемежив между собой.
    Это повысит эффективность чтения памяти.
    Скорость вне кэша должна вырасти.

  • Заменить типы на векторные для упрощения внешнего вида кода.
    Сейчас везде используются интринсики вместе с типами uint64_t и __v2di.
    Нужно заменить uint64_t и __v2di на __v2sf и __v4sf соответственно.
    Тогда можно будет заменить интринсики на операции «+», «-», «*».
    Код станет выглядеть менее громоздко.

Дальнейшие направления создания кода

Что делать дальше (в дополнение к указанному в предыдущей статье):

  • Рассмотреть все Stage в качестве LastStage.
    Сейчас в качестве LastStage рассмотрены только некоторые Stage из прошлой статьи. Для полноты картины нужно рассмотреть остальные варианты Stage. Небольшое ускорение внутри кэша и замедление вне кэша ожидается от вариантов "_readConjSwap".

  • Оптимизация для малых размеров входных данных (как в EML).
    На графиках скорости FFT можно заметить выделяющийся угол у версии из EML.
    Скорее всего, в EML сделана оптимизация для малых длин массивов (до 64 элементов). Оптимизация может состоять в хранении промежуточных результатов вычислений (между последовательными Stage) прямо в регистрах, а не в памяти. Если размеры входных данных достаточно малы, то такие данные можно целиком разместить в регистрах. В этом случае этап Reverse не нужен. Вместо него нужно просто переименовать регистры в первом Stage.

Заключение

Прямая векторизация проще для написания, понятнее для чтения и работает быстрее, чем тот код, что был написан в прошлой статье. Однако, нельзя сказать, что та работа была сделана напрасно. Ведь LastStage написан на основе кода из прошлой статьи.

Судя по графикам, версия из EML аналогична fft_radix2_vector4 с добавлением перемежения коэффициентов и оптимизации для малых размеров входных данных.

Пока я писал этот код, возникло ощущение, что было бы удобно создать классы myComplex, myComplex2 и myComplex4. Но сейчас думаю, что если заменить myComplex на родной float complex, то классы уже и не нужны.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.