Как сохранить 4 32-битных числа в одном 128-битном регистре xmm? - PullRequest
3 голосов
/ 05 июля 2019

Я хочу сохранить 4 32-битных числа с плавающей запятой в xmm0, где каждое из этих значений с плавающей точкой хранится в одном 128-битном регистре. Например, у меня есть 4 поплавка: хмм1: 10,2 мм2: 5,8 мм3: 9,3 xmm4: 12,7 (каждый использует только 32 бита из 128-битного регистра) и хотите, чтобы они были сохранены в xmm0 следующим образом: 10,2, 5,8, 9,3, 12,7 Так что они хранятся рядом с ними внутри xmm0.

Тогда я также хотел бы извлечь каждый из них по отдельности после того, как я выполнил некоторые математические операции на xmm0 (например, mulps ..)

Я пытался использовать movlps и movhps, но они используют только память для загрузки из, а не 128-битный регистр в качестве источника. Я не хотел бы использовать дополнительную память из-за производительности.

PSLLDQ может помочь, но есть ли лучшее решение для моей проблемы?

1 Ответ

5 голосов
/ 06 июля 2019

Посмотрите на вывод компилятора для _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]

...