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łkowitychADDSUBPS
, ADDSUBPD
, MOVSLDUP
, MOVSHDUP
, MOVDDUP
– do arytmetyki zespolonejLDDQU
– do kodowania wideoHADDPS
, HSUBPS
, HADDPD
, HSUBPD
– do grafiki (SIMD FP/AOS)MONITOR
, MWAIT
– do synchronizacji wątkówIntel wprowadził SSE3 2 lutego 2004 roku wraz z procesorem Pentium 4 Prescott, natomiast firma AMD w procesorach Athlon 64 od wersji E.
Nowe rozkazy:
ADDSUBPS
ADDSUBPD
HADDPS
, HSUBPS
HADDPD
, HSUBPD
MOVSLDUP
, MOVSHDUP
MOVDDUP
FISTTP
– nowy rozkaz FPULDDQU
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
.
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).
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]
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]
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 | +-----+-----+-----+-----+
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
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 | +-----+-----+-----+-----+
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.
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:
W przeciwnym razie producent poleca, by nadal używać rozkazów SSE MOVDQU
lub MOVDQA
.
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
.