В разделе 2.5.3 "Трансляции" Справочника по программированию наборов инструкций Intel по архитектуре мы узнаем, чем AVX512 (и Knights Corner) имеет
бит-поле для кодирования передачи данных для некоторых команд load-op, то есть инструкций, которые загружать данные из памяти и выполнять некоторые вычислительные или операции перемещения данных.
Например, используя синтаксис сборки Intel, мы можем транслировать скаляр по адресу, хранящемуся в rax
, а затем умножая на 16 поплавков в zmm2
и записываем результат в zmm1
, как этот
vmulps zmm1, zmm2, [rax] {1to16}
Однако нет никаких встроенных функций, которые могут это сделать. Поэтому, с встроенными функциями, компилятор должен иметь возможность сбросить
__m512 bb = _mm512_set1_ps(b);
__m512 ab = _mm512_mul_ps(a,bb);
для одной команды
vmulps zmm1, zmm2, [rax] {1to16}
но я не заметил, что GCC делает это. Я нашел сообщение об ошибке GCC об этом.
Я наблюдал что-то подобное с FMA с GCC. например GCC 4.9 не скроет _mm256_add_ps(_mm256_mul_ps(areg0,breg0)
с одной инструкцией fma с -Ofast
. Однако GCC 5.1 теперь сворачивает его на одну fma. По крайней мере, есть внутренности, чтобы сделать это с помощью FMA, например. _mm256_fmadd_ps
. Но нет, например, _mm512_mulbroad_ps(vector,scalar)
внутренне.
GCC может исправить это в какой-то момент, но до тех пор сборка является единственным решением.
Итак, мой вопрос заключается в том, как это сделать с встроенной сборкой в GCC?
Я думаю, что, возможно, придумал правильный синтаксис (но я не уверен) для встроенной сборки GCC для примера выше.
"vmulps (%%rax)%{1to16}, %%zmm1, %%zmm2\n\t"
Я действительно ищу функцию, подобную этой
static inline __m512 mul_broad(__m512 a, float b) {
return a*b;
}
если if b
находится в точке памяти в rax
, он производит
vmulps (%rax){1to16}, %zmm0, %zmm0
ret
и если b
находится в xmm1
, он производит
vbroadcastss %xmm1, %zmm1
vmulps %zmm1, %zmm0, %zmm0
ret
GCC уже выполнит регистр vbroadcastss
-from-register с intrinsics, но если b
находится в памяти, скомпилирует его с vbroadcastss
из памяти.
__m512 mul_broad(__m512 a, float b) {
__m512 bb = _mm512_set1_ps(b);
__m512 ab = _mm512_mul_ps(a,bb);
return ab;
}
clang будет использовать операнд широковещательной памяти, если b
находится в памяти.