Как использовать расширения SSE (и SSE2, SSE3 и т. Д.) При сборке с помощью Visual C ++? - PullRequest
3 голосов
/ 15 августа 2011

Сейчас я работаю над небольшой оптимизацией функции базового точечного произведения, используя инструкции SSE в visual studio.

Вот мой код: (соглашение о вызове функции - cdecl):

float SSEDP4(const vect & vec1, const vect & vec2)
{
    __asm
    {
        // get addresses
        mov ecx, dword ptr[vec1]
        mov edx, dword ptr[vec2]
        // get the first vector
        movups xmm1, xmmword ptr[ecx]
        // get the second vector (must use movups, because data is not assured to be aligned to 16 bytes => TODO align data)
        movups xmm1, xmmword ptr[edx]
        // OP by OP multiply with second vector (by address)
        mulps xmm1, xmm2
        // add everything with horizontal add func (SSE3)
        haddps xmm1, xmm1
        // is one addition enough ?
        // try to extract, we'll see
        pextrd eax, xmm1, 03h
    }
}

vect - это простая структура, которая содержит 4 плавающих одинарной точности, не выровненных по 16 байтам (поэтому я использую movups, а не movaps)

vec1 инициализируетсяс (1.0, 1.2, 1.4, 1.0) и vec2 с (2.0, 1.8, 1.6, 1.0)

Все компилируется хорошо, но при выполнении я получил 0 в обоих регистрах XMM, и поэтому в результате отладки Visual Studio показывает мне 2 регистра (MMX1 иMMX2, или иногда MMX2 и MMX3), которые представляют собой 64-битные регистры, но без XMM и всего до 0.

Кто-нибудь имеет представление о том, что происходит?

Заранее спасибо :))

Ответы [ 2 ]

6 голосов
/ 15 августа 2011

Существует несколько способов получить инструкции SSE для MSVC ++:

  1. Встроенные функции компилятора -> http://msdn.microsoft.com/en-us/library/t467de55.aspx
  2. Внешний файл MASM.

Встроенная сборка (как в вашем примере кода) больше не является разумным вариантом, потому что она не будет компилироваться при сборке для не 32-битных, x86, систем.(Например, сборка 64-битного двоичного файла завершится неудачей)

Более того, блоки сборки блокируют большинство оптимизаций.Это плохо для вас, потому что даже такие простые вещи, как встраивание, для вашей функции не будут.Встроенные функции работают так, чтобы не победить оптимизаторы.

1 голос
/ 16 августа 2011

Вы скомпилировали и запустили правильно, поэтому вы по крайней мере можете использовать SSE.

Чтобы просмотреть регистры SSE в окне регистров, щелкните правой кнопкой мыши окно регистров и выберите SSE. Это должно позволить вам увидеть регистры XMM.

Вы также можете использовать @xmm<register><component> (например, @xmm00 для просмотра xmm0[0]) в окне просмотра для просмотра отдельных компонентов регистров XMM.

Теперь, что касается вашей реальной проблемы, вы перезаписываете xmm1 с помощью [edx] вместо того, чтобы вставить это в xmm2.

Кроме того, скалярные значения с плавающей точкой возвращаются в стеке x87 в st(0). Вместо того чтобы пытаться вспомнить, как это сделать, я просто сохраняю результат в переменной стека и позволяю компилятору сделать это для меня:

float SSEDP4(const vect & vec1, const vect & vec2)
{
    float result;
    __asm
    {
        // get addresses
        mov ecx, dword ptr[vec1]
        mov edx, dword ptr[vec2]
        // get the first vector
        movups xmm1, xmmword ptr[ecx]
        // get the second vector (must use movups, because data is not assured to be aligned to 16 bytes => TODO align data)
        movups xmm2, xmmword ptr[edx] // xmm2, not xmm1
        // OP by OP multiply with second vector (by address)
        mulps xmm1, xmm2
        // add everything with horizontal add func (SSE3)
        haddps xmm1, xmm1
        // is one addition enough ?
        // try to extract, we'll see
        pextrd [result], xmm1, 03h
    }

    return result;
}
...