Как заполнить регистр XMM x86 4 идентичными числами с плавающей запятой из другой записи регистра XMM?

Я пытаюсь реализовать встроенный ассемблер (в коде C / C ++), чтобы воспользоваться преимуществами SSE. Я хотел бы копировать и дублировать значения (из регистра XMM или из памяти) в другой регистр XMM. Например, предположим, что у меня есть некоторые значения {1, 2, 3, 4} в памяти. Я хотел бы скопировать эти значения так, чтобы xmm1 был заполнен {1, 1, 1, 1}, xmm2 - {2, 2, 2, 2} и так далее и так далее.

Просматривая справочные руководства Intel, я не нашел инструкции для этого. Мне просто нужно использовать комбинацию повторяющихся MOVSS и поворотов (через PSHUFD?)?


person jbl    schedule 06.01.2010    source источник


Ответы (3)


Есть два пути:

  1. Используйте shufps исключительно:

    __m128 first = ...;
    __m128 xxxx = _mm_shuffle_ps(first, first, 0x00); // _MM_SHUFFLE(0, 0, 0, 0)
    __m128 yyyy = _mm_shuffle_ps(first, first, 0x55); // _MM_SHUFFLE(1, 1, 1, 1)
    __m128 zzzz = _mm_shuffle_ps(first, first, 0xAA); // _MM_SHUFFLE(2, 2, 2, 2)
    __m128 wwww = _mm_shuffle_ps(first, first, 0xFF); // _MM_SHUFFLE(3, 3, 3, 3)
    
  2. Пусть компилятор выберет лучший способ, используя _mm_set1_ps и _mm_cvtss_f32:

    __m128 first = ...;
    __m128 xxxx = _mm_set1_ps(_mm_cvtss_f32(first));
    

Обратите внимание, что второй метод приведет к созданию ужасного кода на MSVC, , как описано здесь, и в результате будет выдано только «xxxx», в отличие от первого варианта.

Я пытаюсь реализовать встроенный ассемблер (в коде C / C ++), чтобы воспользоваться преимуществами SSE

Это крайне непереносимо. Используйте встроенные функции.

person LiraNuna    schedule 06.01.2010
comment
Это очень хороший момент в отношении портативности. На самом деле я об этом не думал, потому что для меня это в основном обучающее упражнение. Ваша статья тоже на первый взгляд выглядит очень интересной. Я с нетерпением жду возможности провести с ним еще немного времени. - person jbl; 07.01.2010
comment
Внутренний метод, показанный в этом ответе, лучше, чем встроенный asm, потому что встроенные функции позволяют компилятору выполнять гораздо больше оптимизаций, которые не выполняются на встроенном asm: назначение регистров, развертывание цикла, чередование инструкций, подъем инвариантов из циклов и т. Д. Мой ответ был ASM, потому что это то, о чем спрашивал исходный вопрос, но если бы я собирался использовать код сам, я бы написал его с помощью встроенных функций для ПРОИЗВОДИТЕЛЬНОСТИ И ПОРТАТИВНОСТИ. - person Adisak; 07.01.2010
comment
Адисак: то, что вы сказали, верно для всего, кроме MSVC - он очень плохо обрабатывает встроенные функции (см. Мою статью). в MSVC рукописная сборка лучше, если производительность важнее переносимости и ремонтопригодности (редко). Я бы просто предложил переключить компиляторы :). - person LiraNuna; 07.01.2010
comment
Что ж, по крайней мере, у Intrinsics есть потенциал для оптимизации. Печально слышать, что MSVC плохо их реализует. Надеюсь, что в ближайшем будущем это будет рассмотрено для VS2010. - person Adisak; 07.01.2010
comment
Что ж, это не так. Те же результаты, что и у VC2008 (по крайней мере, пока). - person LiraNuna; 08.01.2010
comment
Было бы уместно использовать _mm_shuffle_epi32 из SSE2? Если я правильно понимаю основные инструкции ассемблера, _mm_shuffle_epi32 сохранит одну операцию перемещения (регистр назначения заполняется, не касаясь исходного регистра, поэтому вам не нужно делать предварительную копию). msdn.microsoft.com/en-us/ library / 56f67xbk% 28v = vs.90% 29.aspx - person Antonio; 21.10.2013

Переместите источник в регистр назначения. Используйте 'shufps' и просто дважды используйте новый регистр назначения, а затем выберите соответствующую маску.

В следующем примере значения XMM2.x передаются в XMM0.xyzw.

MOVAPS XMM0, XMM2
SHUFPS XMM0, XMM0, 0x00
person Adisak    schedule 06.01.2010

Если ваши значения выровнены по памяти на 16 байт:

movdqa    (mem),    %xmm1
pshufd    $0xff,    %xmm1,    %xmm4
pshufd    $0xaa,    %xmm1,    %xmm3
pshufd    $0x55,    %xmm1,    %xmm2
pshufd    $0x00,    %xmm1,    %xmm1

Если нет, вы можете выполнить невыровненную нагрузку или четыре скалярных нагрузки. На более новых платформах невыровненная загрузка должна быть быстрее; на старых платформах скалярные нагрузки могут выиграть.

Как отмечали другие, вы также можете использовать shufps.

person Stephen Canon    schedule 06.01.2010
comment
Примечание: pshufd - инструкция SSE2. - person LiraNuna; 03.03.2010
comment
@LiraNuna: Я понял, что использование SSE опрашивающим означает некоторое неуказанное подмножество SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 и т. Д. Поскольку практически все оборудование x86 имеет поддержку SSE2 уже довольно много лет. , казалось довольно безопасным предположить, что спрашивающий не собирался запрещать это. - person Stephen Canon; 03.03.2010
comment
Это общее замечание - оно никоим образом не направлено против вашего ответа. - person LiraNuna; 03.03.2010