Могу ли я использовать инструкции разброса AVX2 для ускорения некоторых нагрузок?

Я профилировал имеющуюся у меня функцию AVX2, и узкие места выглядят следующим образом:

std::uint64_t data[8];

// Some computation that fills data

std::uint64_t X[4] = { data[7], data[5], data[3], data[1] };
__m256i vec = _mm256_loadu_si256(reinterpret_cast<__m256i*>(X));

// Compute more with vec
// Later on use data[6], data[4], data[2], and data[0] in a similar fashion

В действительности массивы также выровнены соответствующим образом (так load вместо loadu). Но вопрос в том, есть ли более быстрый способ сделать это с AVX (2)? В частности, я смотрел на инструкции по сбору. Могу ли я использовать их для инициализации vec от data? Или здесь стоит попробовать другие инструкции?

4

Решение

Трудно комментировать, не зная, какой код генерирует ваш компилятор, но вот кое-что, что должен сказать мой компилятор (gcc).

typedef unsigned long long uint64_t;
typedef uint64_t vec2 __attribute__((vector_size(8*sizeof(uint64_t))));
typedef uint64_t vec __attribute__((vector_size(4*sizeof(uint64_t))));
vec f(vec a,vec b){
vec i={7,5,3,1};
return __builtin_shuffle(a,b,i);
}
vec g(vec2 x){
vec r={x[7],x[5],x[3],x[1]};
return r;
}

Я получаю за ф:

vpunpckhqdq %ymm1, %ymm0, %ymm1
vpermq  $39, %ymm1, %ymm0

Я передаю векторы по значению, передавая их через указатели:

vmovdqa (%rdi), %ymm0
vpunpckhqdq (%rsi), %ymm0, %ymm0
vpermq  $39, %ymm0, %ymm0

и для г:

vmovq   32(%rsp), %xmm2
vmovq   64(%rsp), %xmm3
vpinsrq $1, 16(%rsp), %xmm2, %xmm1
vpinsrq $1, 48(%rsp), %xmm3, %xmm0
vinserti128 $0x1, %xmm1, %ymm0, %ymm0
5

Другие решения