Посмотрите на вывод компилятора для _mm_set_ps(f3,f2,f1,f0)
или для _mm_setr_ps(f0,f1,f2,f3)
с вашим выбором мелодии и -march
опций.
Или посмотрите Руководство по оптимизации Агнера Фога : у него есть глава по SSE / AVX с удобной таблицей инструкций перемещения данных по типам. Отлично подходит для изучения вашего пути, в котором доступны перемешивания в сильно неортогональных расширениях SSE / AVX.
Как отмечали люди, стандартным способом является 2x unpcklps
для объединения пар в векторы [00ba]
[00dc]
, где 0
- это значение безразличия или фактически 0.0
, если верхние элементы из ваших скалярных поплавков оказалось ноль. (Моя нотация соответствует соглашению Intel на диаграммах, в которых верхний элемент находится в влево , поэтому сдвиги влево перемещают данные влево в нотации, и просмотр ваших данных с различной шириной элемента не меняет того, как ты пишешь это.)
Затем movlhps
, чтобы скопировать младшее слово одного регистра xmm в старшее слово другого (слияние с существующим значением).
Если это не было очевидно и хорошо вам известно, вы должны писать на C с внутренними признаками и смотреть на оптимизированный вывод компилятора, чтобы изучить основные способы. У clang есть очень хороший оптимизатор перемешивания, который может найти лучшие способы для воплощения логики ваших внутренних функций в asm.
Там может быть лучший способ:
Все эти 3 инструкции являются случайными, а на процессорах семейства Intel Sandybridge ограничена 1 пропускная способность на тактовую частоту (для порта 5).
Если у нас есть SSE4.1 для blendps
(с немедленным смешиванием), мы могли бы использовать его в качестве последнего шага вместо перемешивания. Может работать на любом порту.
Я думаю, мы можем использовать shufps
для создания векторов [0c0a]
и [d0b0]
. 2 младших элемента вывода shufps
поступают из первого операнда source = dst, другая половина - из другого источника.
Если ваши входные векторы на самом деле были расширены нулями, без особого мусора, вы можете использовать SSE1 orps
вместо смеси, чтобы получить [dcba]