MSVC поддерживает инструкции AVX / AVX2 в течение многих лет и в соответствии с это сообщение в блоге msdn, он может автоматически генерировать сплавлено-умножить-добавить (FMA) инструкции.
Но ни одна из следующих функций не компилируется в инструкцию FMA:
float func1(float x, float y, float z)
{
return x * y + z;
}
float func2(float x, float y, float z)
{
return std::fma(x,y,z);
}
Хуже того, std :: fma не реализована как отдельная инструкция FMA, она работает ужасно, намного медленнее, чем обычная x * y + z
(низкая производительность std :: fma ожидается, если реализация не полагается на инструкцию FMA).
Я собираю с /arch:AVX2 /O2 /Qvec
флаги.
Также попробовал это с /fp:fast
нет успеха.
Итак, вопрос в том, как MSVC может принудительно автоматически выдавать инструкции FMA?
ОБНОВИТЬ
Eсть #pragma fp_contract (on|off)
, который (похоже) ничего не делает.
MSVC 2015 генерирует инструкцию fma для скалярных операций, но не для векторных операций (если вы явно не используете встроенную функцию fma).
Я скомпилировал следующий код
//foo.cpp
float mul_add(float a, float b, float c) {
return a*b + c;
}
//MSVC cannot handle vectors as function parameters so use const references
__m256 mul_addv(__m256 const &a, __m256 const &b, __m256 const &c) {
return _mm256_add_ps(_mm256_mul_ps(a, b), c);
}
с
cl /c /O2 /arch:AVX2 /fp:fast /FA foo.cpp
в MSVC2015 и он произвел следующую сборку
;mul_add
vmovaps xmm3, xmm1
vfmadd213ss xmm3, xmm0, xmm2
vmovaps xmm0, xmm3
а также
;mul_addv
vmovups ymm0, YMMWORD PTR [rcx]
vmulps ymm1, ymm0, YMMWORD PTR [rdx]
vaddps ymm0, ymm1, YMMWORD PTR [r8]
Я решил эту давнюю проблему.
Как оказалось, флаги /fp:fast
, /arch:AVX2
а также /O1
(или выше /O1
) недостаточно для режима Visual Studio 2015 для выдачи инструкций FMA в 32-битном режиме. Вам также нужно «Оптимизация всей программы» включен с флагом /GL
,
Затем Visual Studio 2015 сгенерирует инструкцию FMA vfmadd213ss
за
float func1(float x, float y, float z)
{
return x * y + z;
}
относительно std::fma
Я открыла ошибка в Microsoft Connect. Они подтвердили, что поведение std::fma
не компилируется с инструкциями FMA, потому что компилятор не рассматривает его как встроенный. Согласно их ответу, это будет исправлено в будущем обновлении, чтобы получить наилучший возможный кодоген.