Запутать насчет растрового изображения регистра XMM - PullRequest
1 голос
/ 27 ноября 2011

Извините, у меня нет хорошего заголовка ...

Я читал эту тему: Умножение векторной матрицы в SSE

Оригинальный постер содержал следующеекод

// xmm0 = (v0,v1,v2,v3)
movups xmm0, [eax]

// xmm0 = (v0,v0,v0,v0)
// xmm1 = (v1,v1,v1,v1)
// xmm2 = (v2,v2,v2,v2)
// xmm3 = (v3,v3,v3,v3)
shufps xmm3, xmm0, 255
shufps xmm2, xmm0, 170
shufps xmm1, xmm0, 85
shufps xmm0, xmm0, 0

Кто-то сказал следующее:

Но что на самом деле происходит в соответствии с руководством: (a, b, c, d) означает, что a являются битами от 0 до 31,b - это биты с 32 по 63 и т. д.

// xmm0 = (v0,v1,v2,v3)
movups xmm0, [eax]

// xmm0 = (v0, v0, v0, v0)
shufps xmm0, xmm0, 0

Это имеет смысл для меня, поскольку в модели линейного массива [elt0, elt1, elt2, ....] elt0 равно Array [0].

Что меня смущает, так это то, что согласно руководству битовый массив регистра xmm имеет вид [127 ... 0] (см. Рисунок ниже).

Я был похож на оригинальный постер, глядя на растровое изображение, и думал, что самый левый из [elt0, elt2, elt3, elt4] был битом «11».

Итак, если я хочу, чтобы xmm0 содержал только v0

shufps xmm0, xmm0, 0xFF  // 11 11 11 11  === 0xFF

Какое объяснение верно?

enter image description here

1 Ответ

7 голосов
/ 27 ноября 2011

Может быть некоторая путаница, потому что биты в регистрах 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]
...