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

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

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

Ответ 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)
    
  • Пусть компилятор лучше всего выбирает с помощью _mm_set1_ps и _mm_cvtss_f32:

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

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

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

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

Ответ 2

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

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

MOVAPS XMM0, XMM2
SHUFPS XMM0, XMM0, 0x00

Ответ 3

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

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

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

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