Этот код
float a = ...;
__m256 b = _mm_broadcast_ss(&a)
всегда быстрее, чем этот код
float a = ...;
_mm_set1_ps(a)
?
Что, если a
определяется как static const float a = ...
, а не float a = ...
?
Этот код
float a = ...;
__m256 b = _mm_broadcast_ss(&a)
всегда быстрее, чем этот код
float a = ...;
_mm_set1_ps(a)
?
Что, если a
определяется как static const float a = ...
, а не float a = ...
?
mm_broadcast_ss, вероятно, будет быстрее, чем mm_set1_ps. Первый преобразуется в одну инструкцию (VBROADCASTSS), а второй эмулируется с использованием нескольких инструкций (вероятно, MOVSS с последующим перемешиванием). Однако для mm_broadcast_ss требуется набор инструкций AVX, а для mm_set1_ps требуется только SSE.
_mm_set1_ps
должна быть одна инструкция shufps
; предполагая, что _mm_broadcast_ss
на самом деле генерирует vbroadcastss
, может потребоваться сохранение, если значение еще не находится в памяти (и для этого требуется загрузка, поэтому его задержка в лучшем случае больше, чем при перемешивании). Даже если бы vbroadcastss
был быстрее, ничто не помешало бы компилятору выдать vbroadcastss
для встроенного _mm_set1_ps
при включенном AVX.
- person Stephen Canon; 05.11.2012
pshufd
, чтобы разбить его, или используйте vbroadcastss
(или один из нескольких других вариантов). Если значение не является константой времени компиляции, то оно должно быть вычислено и, вероятно, уже находится в регистре SSE/AVX, готовом к использованию shufps
.
- person Stephen Canon; 05.11.2012
_mm_broadcast_ss имеет недостатки, вызванные архитектурой, которые в значительной степени скрыты API mm SSE. Самое главное отличие заключается в следующем:
Это означает, что если вы явно используете _mm_broadcast_ss в ситуации, когда источник не находится в памяти, то результат, вероятно, будет менее эффективным, чем результат использования _mm_set1_ps. Такая ситуация обычно возникает при загрузке немедленных значений (констант) или при использовании результата недавнего вычисления. В таких ситуациях результат будет отображен компилятором в регистр. Чтобы использовать значение для широковещательной рассылки, компилятор должен сбросить значение обратно в память. В качестве альтернативы, вместо этого можно использовать pshufd для splat непосредственно из регистра.
_mm_set1_ps определяется реализацией, а не сопоставляется с конкретной основной операцией процессора (инструкцией). Это означает, что он может использовать одну из нескольких инструкций SSE для выполнения знака. Интеллектуальный компилятор с включенной поддержкой AVX обязательно должен использовать vbroadcastss внутри, когда это уместно, но это зависит от состояния реализации AVX оптимизатора компилятора.
Если вы очень уверены, что загружаете из памяти — например, перебираете массив данных — тогда прямое использование широковещательной передачи вполне допустимо. Но если есть какие-то сомнения, я бы рекомендовал придерживаться _mm_set1_ps.
И в конкретном случае с static const float
вы абсолютно не хотите использовать _mm_broadcast_ss().
Если вы ориентируетесь на набор инструкций AVX, gcc будет использовать VBROADCASTSS для реализации встроенного _mm_set1_ps. Однако Clang будет использовать две инструкции (VMOVSS + VPSHUFD).
__m128 b = _mm_broadcast_ss(&a)
. - person user2023370   schedule 21.03.2019