Может быть некоторая путаница, потому что биты в регистрах xmm (и всех других регистрах BTW) нумеруются справа налево, то есть младший бит справа, а старший бит слева:
xmm0 = [bit 127, bit 126, ..., bit 1, bit 0]
Если вы рассматриваете содержимое регистра xmm как 32-битные слова, они также располагаются справа налево:
xmm0 = [dword 3, dword 2, dword 1, dword 0]
Источник этой путаницы состоит в том, что если у вас есть массивв памяти
float A[4] = { 0.0f, 1.0f, 2.0f, 3.0f };
и вы загружаете этот массив в регистр xmm, элементы появляются в регистре xmm в обратном порядке:
; xmm0 = (A3 = 3.0f, A2 = 2.0f, A1 = 1.0f, A0 = 0.0f) after the load
movups xmm0, [A]
Следовательно, правильный способ скопировать первыйdword для всех dwords в регистре xmm:
shufps xmm0, xmm0, 0
Кроме того, если вы хотите выполнять загрузку и трансляцию одного плавающего во все элементы регистра xmm, из соображений производительности лучше использовать
; MOVSS can be much faster than MOVUPS, and is never slower
; Load A[0] into low dword of xmm0
movss xmm0, [A]
; Copy low dword of xmm0 to all dwords of xmm0
shufps xmm0, xmm0, 0
Набор инструкций AVX (поддерживается в последних процессорах Intel Sandy Bridge и AMD Bulldozer) содержит специальную инструкцию vbroadcasts, которая выполняет загрузку и трансляцию:
; xmm0 = (A[0], A[0], A[0], A[0]) after execution of vbroadcastss
vbroadcastss xmm0, [A]
SSE3 insВ набор Truction входит аналогичная инструкция MOVDDUP, которая, однако, работает только для двойников
const double B = 2.718281828459045;
; xmm0 = ( 2.718281828459045, 2.718281828459045 ) after execution of movddup
movddup xmm0, [B]