SSE3

Streaming SIMD Extensions 3 (SSE3, oznaczany również przez firmę Intel jako Prescott New Instructions lub PNI) – zestaw instrukcji SIMD wykorzystywany w architekturze IA-32. Wcześniejsze zestawy SIMD stosowane na platformie x86, od najstarszej to: MMX, 3DNow! (używany tylko przez AMD), SSE i SSE2.

SSE3 wprowadza 13 nowych rozkazów w stosunku do swojego poprzednika SSE2, są to:

  • FISTTP – do konwersji liczb zmiennoprzecinkowych do całkowitych
  • ADDSUBPS, ADDSUBPD, MOVSLDUP, MOVSHDUP, MOVDDUP – do arytmetyki zespolonej
  • LDDQU – do kodowania wideo
  • HADDPS, HSUBPS, HADDPD, HSUBPD – do grafiki (SIMD FP/AOS)
  • MONITOR, MWAIT – do synchronizacji wątków

Intel wprowadził SSE3 2 lutego 2004 roku wraz z procesorem Pentium 4 Prescott, natomiast firma AMD w procesorach Athlon 64 od wersji E.

Nowe rozkazy

Nowe rozkazy:

  • rozkazy wektorowe działające albo na wektorach liczb zmiennoprzecinkowych pojedynczej albo podwójnej precyzji (tj. wektory 4 × 32 bity lub 2 × 64 bity):
    • ADDSUBPS
    • ADDSUBPD
    • HADDPS, HSUBPS
    • HADDPD, HSUBPD
    • MOVSLDUP, MOVSHDUP
    • MOVDDUP
  • FISTTP – nowy rozkaz FPU
  • LDDQU
  • MONITOR i MWAIT

Przed wprowadzaniem SSE3 prawie wszystkie rozkazy arytmetyczne występujące w MMX, SSE, SSE2 działały, jak to określa Intel, „pionowo” (ang. vertical), tj. argumentami działań zawsze są elementy z dwóch wektorów. Natomiast w SSE3 pojawiły się rozkazy działające „poziomo” (ang. horizontal) — argumentami operacji arytmetycznych są elementy tego samego wektora; te instrukcje to: HADDPS, HADDPD, HSUBPS, HSUBPD.

FISTTP

Rozkaz koprocesora arytmetycznego zamieniający liczbę zmiennoprzecinkową zapisaną w wierzchołku stosu na liczbę całkowitą ze znakiem; trybem zaokrąglania zawsze jest ucinanie (ang. chop), niezależnie od ustawień zapisanych w rejestrze kontrolnym FPU. Liczba całkowita może być 16-, 32- lub 64-bitowa, zależnie od argumentu.

Zgłaszany jest wyjątek w przypadku, gdy konwersja jest niemożliwa (wartość przekracza zakres liczby całkowitej, albo jest klasy plus/minus nieskończoność lub NaN).

Rozkaz FISTTP to uproszczona wersja istniejącej instrukcji FISTP, w której tryb zaokrąglania sterowany jest poprzez słowo kontrolne koprocesora – jego ewentualna zmiana jest kosztowna (trzeba wykonać kilka lub kilkanaście dodatkowych instrukcji: zachować bieżące ustawienia, włączyć inny tryb zaokrąglania, wykonać FISTP, przywrócić poprzedni tryb).

ADDSUBPS

Rozkaz działa na dwóch wektorach liczb zmiennoprzecinkowych pojedynczej precyzji. Wykonywane jest dodawanie elementów o nieparzystych indeksach, odejmowanie – parzystych. Działania realizowane przez ADDSUBPS xmm1, xmm2:

xmm1[0] := xmm1[0] - xmm2[0]
xmm1[1] := xmm1[1] + xmm2[1]
xmm1[2] := xmm1[2] - xmm2[2]
xmm1[3] := xmm1[3] + xmm2[3]

ADDSUBPD

Rozkaz analogiczny do ADDSUBPS, działa na dwóch wektorach liczb zmiennoprzecinkowych podwójnej precyzji. Działania realizowane przez ADDSUBPD xmm1, xmm2:

xmm1[0] := xmm1[0] - xmm2[0]
xmm1[1] := xmm1[1] + xmm2[1]

HADDPS, HSUBPS

Rozkazy działają na wektorach liczb zmiennoprzecinkowych pojedynczej precyzji. HADDPS dodaje, zaś HSUBPS odejmuje sąsiednie elementy wektorów, tzn. HADDPS xmm1, xmm2 wykonuje:

temp[0] := xmm1[0] + xmm1[1]
temp[1] := xmm1[2] + xmm1[3]
temp[2] := xmm2[0] + xmm2[1]
temp[3] := xmm2[2] + xmm2[3]
xmm1 := temp

natomiast HSUBPS xmm1, xmm2:

temp[0] := xmm1[0] - xmm1[1]
temp[1] := xmm1[2] - xmm1[3]
temp[2] := xmm2[0] - xmm2[1]
temp[3] := xmm2[2] - xmm2[3]
xmm1 := temp

Np.:

           3     2     1     0         3     2     1     0      
        +-----+-----+-----+-----+   +-----+-----+-----+-----+
        |  d  |  c  |  b  |  a  |   |  h  |  g  |  f  |  e  |
        +-----+-----+-----+-----+   +-----+-----+-----+-----+
                   xmm1                        xmm2

Wynik HADDPS:

        +-----+-----+-----+-----+
 xmm1 = | h+g | f+e | c+d | a+b |
        +-----+-----+-----+-----+

Wynik HSUBPS:

        +-----+-----+-----+-----+
 xmm1 = | h-g | f-e | c-d | a-b |
        +-----+-----+-----+-----+

HADDPD, HSUBPD

Rozkazy działają na wektorach liczb zmiennoprzecinkowych podwójnej precyzji. Rozkaz HADDPD dodaje do siebie sąsiednie elementy wektorów, natomiast HSUBPD odejmuje. Instrukcja HADDPD xmm1, xmm2 wykonuje:

temp[0] := xmm1[0] + xmm1[1]
temp[1] := xmm2[0] + xmm2[1]
xmm1 := temp

natomiast HSUBPD xmm1, xmm2:

temp[0] := xmm1[0] - xmm1[1]
temp[1] := xmm2[0] - xmm2[1]
xmm1 := temp

MOVSLDUP, MOVSHDUP

Rozkazy działają na wektorze liczb zmiennoprzecinkowych pojedynczej precyzji; rozkaz MOVSLDUP powiela elementy o parzystych indeksach, MOVHLDUP – o nieparzystych. Instrukcja MOVSLDUP xmm1, xmm2 wykonuje:

xmm1[0] := xmm2[0]
xmm1[1] := xmm2[0]
xmm1[2] := xmm2[2]
xmm1[3] := xmm2[2]

natomiast MOVSHDUP xmm1, xmm2:

xmm1[0] := xmm2[1]
xmm1[1] := xmm2[1]
xmm1[2] := xmm2[3]
xmm1[3] := xmm2[3]

Np.

           3     2     1     0
        +-----+-----+-----+-----+
 xmm2 = |  d  |  c  |  b  |  a  |
        +-----+-----+-----+-----+

Wynik MOVSLDUP:

        +-----+-----+-----+-----+
 xmm1 = |  c  |  c  |  a  |  a  |
        +-----+-----+-----+-----+

Wynik MOVSHDUP:

        +-----+-----+-----+-----+
 xmm1 = |  d  |  d  |  b  |  b  |
        +-----+-----+-----+-----+

MOVDDUP

Argumentem rozkazu jest liczba zmiennoprzecinkowa podwójnej precyzji, która w rejestrze XMM jest powielana, tj. MOVDDUP xmm1, arg wykonuje:

xmm1[0] := arg
xmm1[1] := arg

Argumentem może być albo lokacja pamięci (wówczas czytane są 64 bity), albo rejestr XMM, wówczas brane są jego 64 najmłodsze bity.

LDDQU

Rozkaz ładuje 128 bitów spod adresów niewyrównanych do granicy 16 bajtów (tj. adresy mający niezerowe 4 najmłodsze bity). Rozkaz realizuje działanie analogiczne do istniejącego w SSE MOVDQU, jednak został specjalnie zoptymalizowany do kodu o następującej charakterystyce:

  • występuje spadek wydajności spowodowany częstymi odczytami obszarów znajdujących się na granicy linijek cache,
  • dane są tylko odczytywane i nie mają zostać (po ewentualnej modyfikacji) z powrotem zapisane pod tym samym adresem.

W przeciwnym razie producent poleca, by nadal używać rozkazów SSE MOVDQU lub MOVDQA.

MONITOR i MWAIT

Para rozkazów służy do efektywnego synchronizowania wątków.

Rozkaz MONITOR ustala początkowy adres zakresu pamięci (rozmiar tego obszaru jest stały, zależny od modelu procesora), który następnie jest automatycznie monitorowany przez procesor: w przypadku wystąpienia zapisu gdziekolwiek w obserwowanym zakresie ustawiana jest wewnętrzna flaga, którą odczytuje MWAIT.

Wykonanie rozkazu MWAIT powoduje wejście w zoptymalizowaną sprzętową pętlę, która jest przerywana, dopiero gdy wspomniana flaga zostanie ustawiona, a więc gdy nastąpi zapis pod obserwowany adres.

Producenci procesorów mogą rozszerzać funkcjonalność tych rozkazów, dlatego m.in. możliwe jest przejście w tryb oszczędzanie energii na czas wykonywania MWAIT.

Bibliografia

  • Intel 64 and IA-32 Architectures Software Developer's Manual: Volume 2A: Instruction Set Reference, A-M (253666), maj 2007

Zobacz też