Является ли _mm_broadcast_ss быстрее, чем _mm_set1_ps?

Этот код

float a = ...;
__m256 b = _mm_broadcast_ss(&a)

всегда быстрее, чем этот код

float a = ...;
_mm_set1_ps(a)

?

Что, если a определяется как static const float a = ..., а не float a = ...?


person Yoav    schedule 04.11.2012    source источник
comment
Я думаю, что это должно быть __m128 b = _mm_broadcast_ss(&a).   -  person user2023370    schedule 21.03.2019


Ответы (3)


mm_broadcast_ss, вероятно, будет быстрее, чем mm_set1_ps. Первый преобразуется в одну инструкцию (VBROADCASTSS), а второй эмулируется с использованием нескольких инструкций (вероятно, MOVSS с последующим перемешиванием). Однако для mm_broadcast_ss требуется набор инструкций AVX, а для mm_set1_ps требуется только SSE.

person Jason R    schedule 04.11.2012
comment
Хм? _mm_set1_ps должна быть одна инструкция shufps; предполагая, что _mm_broadcast_ss на самом деле генерирует vbroadcastss, может потребоваться сохранение, если значение еще не находится в памяти (и для этого требуется загрузка, поэтому его задержка в лучшем случае больше, чем при перемешивании). Даже если бы vbroadcastss был быстрее, ничто не помешало бы компилятору выдать vbroadcastss для встроенного _mm_set1_ps при включенном AVX. - person Stephen Canon; 05.11.2012
comment
Как бы вы реализовали это, используя всего одну перетасовку? Вам нужно получить одиночное значение с плавающей запятой в один из регистров SIMD, прежде чем вы сможете выполнить перетасовку, которая потребует что-то вроде MOVSS, который я описал. Если сравнивать яблоки с яблоками, вам нужно будет включить эти накладные расходы. Ваша точка зрения о том, что компилятор может свободно выдавать VBROADCASTSS для _mm_set1_ps, верна, если включен AVX. Однако я не знаю, действительно ли это делают какие-либо известные компиляторы. - person Jason R; 05.11.2012
comment
Разбиваемое значение вычисляется либо во время компиляции, либо во время выполнения; если он вычисляется во время компиляции, то компилятор может либо сохранить его в разбросанном виде (и использовать простую векторную загрузку или форму загрузочного операнда инструкции, которая его потребляет), либо может поместить его с известным выравниванием и использовать форму загрузочного операнда pshufd, чтобы разбить его, или используйте vbroadcastss (или один из нескольких других вариантов). Если значение не является константой времени компиляции, то оно должно быть вычислено и, вероятно, уже находится в регистре SSE/AVX, готовом к использованию shufps. - person Stephen Canon; 05.11.2012

_mm_broadcast_ss имеет недостатки, вызванные архитектурой, которые в значительной степени скрыты API mm SSE. Самое главное отличие заключается в следующем:

  • _mm_broadcast_ss ограничивается загрузкой значений только из памяти.

Это означает, что если вы явно используете _mm_broadcast_ss в ситуации, когда источник не находится в памяти, то результат, вероятно, будет менее эффективным, чем результат использования _mm_set1_ps. Такая ситуация обычно возникает при загрузке немедленных значений (констант) или при использовании результата недавнего вычисления. В таких ситуациях результат будет отображен компилятором в регистр. Чтобы использовать значение для широковещательной рассылки, компилятор должен сбросить значение обратно в память. В качестве альтернативы, вместо этого можно использовать pshufd для splat непосредственно из регистра.

_mm_set1_ps определяется реализацией, а не сопоставляется с конкретной основной операцией процессора (инструкцией). Это означает, что он может использовать одну из нескольких инструкций SSE для выполнения знака. Интеллектуальный компилятор с включенной поддержкой AVX обязательно должен использовать vbroadcastss внутри, когда это уместно, но это зависит от состояния реализации AVX оптимизатора компилятора.

Если вы очень уверены, что загружаете из памяти — например, перебираете массив данных — тогда прямое использование широковещательной передачи вполне допустимо. Но если есть какие-то сомнения, я бы рекомендовал придерживаться _mm_set1_ps.

И в конкретном случае с static const float вы абсолютно не хотите использовать _mm_broadcast_ss().

person jstine    schedule 27.10.2014

Если вы ориентируетесь на набор инструкций AVX, gcc будет использовать VBROADCASTSS для реализации встроенного _mm_set1_ps. Однако Clang будет использовать две инструкции (VMOVSS + VPSHUFD).

person Marat Dukhan    schedule 04.11.2012
comment
Спасибо. Я использую Кланг. Есть ли веская причина, по которой Clang не использует VBROADCASTSS? - person Yoav; 05.11.2012
comment
Нет, это просто ошибка компилятора. - person Marat Dukhan; 05.11.2012