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ł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ó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
[edytuj | edytuj kod]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 FPULDDQU
MONITOR
iMWAIT
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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]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
[edytuj | edytuj kod]- Intel 64 and IA-32 Architectures Software Developer's Manual: Volume 2A: Instruction Set Reference, A-M (253666), maj 2007