В разделе 2.5.3 «Трансляции» Справочник по программированию расширений набора инструкций архитектуры Intel, что мы узнаем, чем у AVX512 (и Knights Corner) есть
битовое поле для кодирования широковещательных данных для некоторых инструкций загрузки, то есть инструкций, которые загружают данные из памяти и выполняют некоторые вычислительные операции или операции перемещения данных.
Например, используя синтаксис сборки 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;
}
где, если b
находится в памяти, указывает на rax
, он производит
vmulps (%rax){1to16}, %zmm0, %zmm0
ret
и если b
находится в xmm1
, он производит
vbroadcastss %xmm1, %zmm1
vmulps %zmm1, %zmm0, %zmm0
ret
GCC уже будет выполнять случай vbroadcastss
из регистра с встроенными функциями, но если 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
находится в памяти.
-m32
(так чтоb
находится в памяти) clang использует широковещательную загрузку. gcc используетvbroadcastss
. (И вроде не работает, потому что делает бесполезныйpush ecx / lea ecx, ... / pop ecx
) Может, пытается временно выровнять стек? В-O1
gcc используетecx
послеlea
. - person Peter Cordes   schedule 22.12.2015b
находится в памяти в 64-битном режиме? - person Z boson   schedule 22.12.2015float *pb
arg. - person Peter Cordes   schedule 22.12.2015static inline
, но это показывает, чего я хочу. - person Z boson   schedule 22.12.2015vmulps (%%rdi)%{1to16%}, %%zmm0, %%zmm0\n\t"
. - person Z boson   schedule 22.12.2015-Ofast
. - person Z boson   schedule 22.12.2015-ffast-math
!. gcc всегда пытается воспользоваться любой аппаратной поддержкой FMA, о которой вы ему рассказываете.clang
объединяет только функции add и mul вместе с-ffast-math
. Я полагаю, что gcc не заботится о сохранении дополнительной точности, сверх того, что требует стандарт C. Я не читалFLT_EVAL_METHOD
или что-то еще в последнее время. - person Peter Cordes   schedule 22.12.2015-ffast-math
). Просто для FMA нужна другая модель с плавающей запятой. Судя по всему, GCC даже не требует другой модели с плавающей запятой для FMA. - person Z boson   schedule 22.12.2015FLT_EVAL_METHOD
с-m32
и эффекта-mfpmath=sse
. (F_E_M = 2 или 0, с x87 / с SSE). - person Peter Cordes   schedule 23.12.2015%q[int_var]
, чтобы испустить%rax
вместо%eax
). Руководство GCC документирует префиксы только для целочисленных регистров. - person Peter Cordes   schedule 23.12.2015vpbroadcastss %[scalar], %%zmm_of_the_same_register
. (Использованиеscalar
в качестве операнда ввода / вывода. Хм, это ухудшит код для встроенной функции, если только параметр не поступает по неконстантной ссылке. О, на самом деле я мог бы просто солгать gcc и сказать ему, что я не напишите входной операнд, содержащий скаляр.Но меня беспокоит поломка при использовании на нижнем элементе нескалярного вектора. - person Peter Cordes   schedule 23.12.2015if
на чем-то вроде__builtin_constant_p(scalar)
, но проверять, нужно ли его загружать или нет. - person Peter Cordes   schedule 25.12.2015