Я хочу написать быстрый simd-код для вычисления мультипликативной редукции сложного массива. В стандарте C это:
#include <complex.h>
complex float f(complex float x[], int n ) {
complex float p = 1.0;
for (int i = 0; i < n; i++)
p *= x[i];
return p;
}
n
будет не более 50.
Gcc не может автоматически векторизовать сложное умножение, но, поскольку я с удовольствием принимаю компилятор gcc, и если бы я знал, что хочу нацелить sse3, я мог бы следовать Как включить autovectorization sse3 в gcc и напишите:
typedef float v4sf __attribute__ ((vector_size (16)));
typedef union {
v4sf v;
float e[4];
} float4
typedef struct {
float4 x;
float4 y;
} complex4;
static complex4 complex4_mul(complex4 a, complex4 b) {
return (complex4){a.x.v*b.x.v -a.y.v*b.y.v, a.y.v*b.x.v + a.x.v*b.y.v};
}
complex4 f4(complex4 x[], int n) {
v4sf one = {1,1,1,1};
complex4 p = {one,one};
for (int i = 0; i < n; i++) p = complex4_mul(p, x[i]);
return p;
}
Это действительно дает быстрый векторный код сборки с использованием gcc. Несмотря на то, что вам по-прежнему нужно вводить свой ввод в несколько раз. Сборка, которую вы получаете, это:
.L3:
vmovaps xmm0, XMMWORD PTR 16[rsi]
add rsi, 32
vmulps xmm1, xmm0, xmm2
vmulps xmm0, xmm0, xmm3
vfmsubps xmm1, xmm3, XMMWORD PTR -32[rsi], xmm1
vmovaps xmm3, xmm1
vfmaddps xmm2, xmm2, XMMWORD PTR -32[rsi], xmm0
cmp rdx, rsi
jne .L3
Однако он предназначен для точного набора команд simd и не является оптимальным для avx2 или avx512, например, для которого вам нужно изменить код.
Как вы можете написать код C или С++, для которого gcc будет создавать оптимальные код при компиляции для любого из sse, avx2 или avx512? То есть, вам всегда приходится писать отдельные функции вручную для каждой разной ширины регистра SIMD?
Есть ли библиотеки с открытым исходным кодом, которые облегчают это?