Streaming SIMD Extensions
| Definicja intuicyjna |
| SSE to dodatkowe rozkazy rozpoznawane przez mikroprocesory firmy Intel oraz kompatybilnych, które pozwalają znacznie szybciej wykonywać obliczenia matematyczne, szczególnie te wykorzystywane w dziedzinie multimediów, co przekłada się na zwiększenie efektywności działania m.in. gier komputerowych, programów graficznych, muzycznych, kodowania filmów i muzyki. |

SSE (ang. Streaming SIMD Extensions) jest nazwą zestawu instrukcji wprowadzonego w 1999 roku po raz pierwszy w procesorach Pentium III firmy Intel. SSE daje przede wszystkim możliwość wykonywania działań zmiennoprzecinkowych na 4-elementowych wektorach liczb pojedynczej precyzji (48 rozkazów). Ponadto wprowadzono jedenaście nowych rozkazów stałoprzecinkowych w zestawie MMX, a także dano możliwość wskazywania, które dane powinny znaleźć się w pamięci podręcznej.
SSE to również zmiany w architekturze procesora: dodano 8 rejestrów XMM o rozmiarze 128 bitów oraz 32-bitowy rejestr kontrolny MXCSR; w 64-bitowych wersjach procesorów (AMD64, EM64T) dostępne jest jeszcze 8 dodatkowych rejestrów XMM. Rejestry 128-bitowe, na zawartości których wykonywana jest większość rozkazów SSE (nazywane w asemblerze xmm0, xmm1, ..., xmm15), stanowią zupełnie odrębne komórki pamięci – w odróżnieniu od rejestrów MMX nie zostały zamapowane na inne rejestry.
Typy danych
[edytuj | edytuj kod]SSE wprowadza nowy typ danych: 4-elementowy wektor liczb zmiennoprzecinkowych pojedynczej precyzji (ang. 128-bit packed single-precision floating-point); liczba zmiennoprzecinkowa ma rozmiar 32 bitów. Poza tym wykorzystuje typy wektorowe zdefiniowane w MMX.
Rozkazy SSE mogą wykonywać działania arytmetyczne na wektorach liczb zmiennoprzecinkowych na dwa sposoby:
- packed (równoległe) – wykonując równocześnie 4 niezależne działania zmiennoprzecinkowe na odpowiadających sobie elementach wektorów;
- scalar (skalarne) – wykonując działanie tylko na pierwszych elementach wektorów.
Przykład – mnożenie dwóch wektorów (rozkazem MULPS xmm0, xmm1):
+-------+-------+-------+-------+
| x3 | x2 | x1 | x0 | xmm0
+-------+-------+-------+-------+
* * * *
+-------+-------+-------+-------+
| y3 | y2 | y1 | y0 | xmm1
+-------+-------+-------+-------+
= = = =
+-------+-------+-------+-------+
| x3*y3 | x2*y2 | x1*y1 | x0*y0 | xmm0
+-------+-------+-------+-------+
Przykład – mnożenie pierwszych elementów wektorów (rozkazem MULSS xmm0, xmm1):
+-------+-------+-------+-------+
| x3 | x2 | x1 | x0 | xmm0
+-------+-------+-------+-------+
*
+-------+-------+-------+-------+
| y3 | y2 | y1 | y0 | xmm1
+-------+-------+-------+-------+
= = = =
+-------+-------+-------+-------+
| x3 | x2 | x1 | x0*y0 | xmm0
+-------+-------+-------+-------+
Mnemoniki rozkazów
[edytuj | edytuj kod]Mnemoniki instrukcji SSE działających na wektorach liczb całkowitych zostały wybrane zgodnie z konwencję wprowadzoną w MMX – nazwy zaczynają się najczęściej od litery P.
Dla nazw instrukcji działających na liczbach zmiennoprzecinkowych nie wprowadzono żadnego prefiksu; jednak podobnie jak w MMX sufiks nazwy określa typ:
PS(packed single) – działanie na wektorach,SS(scalar single) – działanie na skalarach.
Ponadto jeśli rozkazy działają na połówkach rejestrów XMM (tj. albo odnoszą się do bitów 0..63, albo 64..127), w mnemonikach rozkazu występuje litera – odpowiednio – L albo H, od angielskich słów low („niski”) i high („wysoki”).
Działania zmiennoprzecinkowe
[edytuj | edytuj kod]SSE jest zgodne ze standardem IEEE-754. Możliwe jest jednak włączenie pewnych niestandardowych cech, które w niektórych przypadkach przyspieszają obliczenia.
Działania arytmetyczne
[edytuj | edytuj kod]- dodawanie (
ADDPS,ADDSS) - odejmowanie (
SUBPS,SUBSS) - mnożenie (
MULPS,MULSS) - dzielenie (
DIVPS,DIVSS) - przybliżenie odwrotności (1/x) (
RCPPS,RCPSS) - pierwiastek kwadratowy (
SQRTPS,SQRTSS) - przybliżenie odwrotności pierwiastka kwadratowego (
RSQRTPS,RSQRTSS) - wyznaczenie minimalnej wartości (
MINPS,MINSS) - wyznaczenie maksymalnej wartości (
MAXPS,MAXSS)
Działania logiczne
[edytuj | edytuj kod]Działania logiczne są wykonywane na poziomie bitów, nie na liczbach zmiennoprzecinkowych:
- suma (
ORPS); - iloczyn (
ANDPS); - iloczyn z negacją (
ANDNPS) – jeden z operandów jest negowany przed obliczeniem iloczynu; - różnica symetryczna (
XORPS).
Porównania
[edytuj | edytuj kod]Porównania w SSE są dwojakiego rodzaju:
- Modyfikujące rejestr SSE w sposób analogiczny jak w MMX
- Modyfikujące rejestr flag
Ad. 1. Modyfikujące rejestr SSE w sposób analogiczny jak w MMX: dla tych elementów, dla których wynik porównania jest prawdziwy wszystkie bity w rejestrze docelowym są ustawiane, gdy nieprawdziwy – zerowane. Ten sposób porównania może być zastosowany zarówno dla wektorów (rozkaz CMPPS), jak i skalarów (rozkaz CMPSS).
Przykład testowania, czy liczby są różne (rozkaz CMPNEQPS xmm0, xmm1[1]):
+---------+---------+---------+---------+
| 1.0 | -5.3 | 16.5 | 17.2 | xmm0
+---------+---------+---------+---------+
≠ ≠ ≠ ≠
+---------+---------+---------+---------+
| 7.0 | -5.3 | 16.5 | 17.3 | xmm1
+---------+---------+---------+---------+
= = = =
+---------+---------+---------+---------+
|111..1111|000..0000|000..0000|111..1111| xmm0
+---------+---------+---------+---------+
Można testować 8 różnych relacji:
- równy,
- mniejszy,
- mniejszy lub równy,
- różny,
- większy,
- większy lub równy,
- ang. unordered[2].
- ang. orderded (odwrotność unordered).
Ad. 2. Modyfikujące rejestr flag, dzięki czemu można sterować przepływem sterowania za pomocą rozkazów skoku warunkowego; rozpoznawane są 4 różne relacje liczb: mniejszy, większy, równy oraz unordered. Ten sposób porównania może być stosowany tylko do skalarów, przy czym dostępne są dwa rozkazy: COMISS – sygnalizujący błąd gdy wystąpi nieprawidłowa liczba zmiennoprzecinkowa QNaN lub SNaN oraz UCOMISS – sygnalizująca błąd tylko w przypadku SNaN.
Konwersje pomiędzy liczbami całkowitymi i zmiennoprzecinkowymi
[edytuj | edytuj kod]| # | typ źródłowy | typ docelowy | instrukcja |
|---|---|---|---|
| 1 | liczba całkowita | liczba zmiennoprzecinkowa | CVTSI2SS
|
| 2 | para liczb całkowitych | para liczb zmiennoprzecinkowych | CVTPI2PS
|
| 3 | liczba zmiennoprzecinkowa | liczba całkowita | CVTSS2SI
|
| 4 | CVTTPS2PI
| ||
| 5 | para liczb zmiennoprzecinkowych | para liczb całkowitych | CVTPS2PI
|
| 6 | CVTTPS2PI
|
Uwagi:
- Liczby całkowita, tj. 32-bitowe liczby ze znakiem
- Metoda zaokrąglania w większości rozkazów jest ustawiana w rejestrze kontrolnym
MXCSR, wyjątkiem są rozkazyCVTTPS2PIiCVTTSS2SIdla których zawsze trybem zaokrąglanie jest ucinanie (ang. chop, truncate). - Wyniki zapisywane są do najmłodszego albo dwóch najmłodszych elementów wektora docelowego, zaś pozostałe elementy nie są zmieniane.
Rozmieszczenie elementów w wektorze
[edytuj | edytuj kod]Rozkazy SHUFPS, UNPCKLPS, UNPCKHPS umożliwiają różnorakie rozmieszczenie („wymieszanie”) elementów, np. odwrócenie kolejności elementów w wektorze.
UNPCKLPS, UNPCKHPS
[edytuj | edytuj kod]Rozkazy ustawia na przemian 2 elementy z obu wektorów. UNPCKLPS bierze dwa młodsze elementy (tj. o indeksach 0 i 1), natomiast UNPCKHPS dwa starsze (indeksy 2 i 3). Rozkaz UNPCKLPS xmm1, xmm2 wykonuje:
temp[0] := xmm1[0] temp[1] := xmm2[0] temp[2] := xmm1[1] temp[3] := xmm2[1] xmm1 := temp
zaś UNPCKHPS xmm1, xmm2
temp[0] := xmm1[2] temp[1] := xmm2[2] temp[2] := xmm1[3] temp[3] := xmm2[3] xmm1 := temp
Np.
3 2 1 0
+-----+-----+-----+-----+
xmm1 = | d | c | b | a |
+-----+-----+-----+-----+
+-----+-----+-----+-----+
xmm2 = | h | g | f | e |
+-----+-----+-----+-----+
Wynik UNPCKLPS:
+-----+-----+-----+-----+
xmm1 = | f | b | e | a |
+-----+-----+-----+-----+
Wynik UNPCKHPS:
+-----+-----+-----+-----+
xmm1 = | h | d | g | c |
+-----+-----+-----+-----+
SHUFPS
[edytuj | edytuj kod]Rozkaz bardziej ogólny niż UNPCKxPS, umożliwia wskazanie dowolnych indeksów z wektorów źródłowych za pomocą trzeciego argumentu (stałej natychmiastowej), w którym na każdych kolejnych dwóch bitach zapisane są 4 indeksy. Rozkazowi SHUFPS xmm1, xmm2, imm8 odpowiada:
{ pobranie indeksów }
index1_0 := (imm8 AND 00000011b)
index1_1 := (imm8 AND 00001100b) SHR 2
index2_0 := (imm8 AND 00110000b) SHR 4
index2_1 := (imm8 AND 11000000b) SHR 6
{ rozmieszczenie elementów }
temp[0] := xmm1[index1_0]
temp[1] := xmm1[index1_1]
temp[2] := xmm2[index2_0]
temp[3] := xmm2[index2_1]
xmm1 := temp
MXCSR – rejestr kontrolny/statusu
[edytuj | edytuj kod]Rejestr MXCSR przechowuje:
- Ustawienia operacji zmiennoprzecinkowych:
- sposób zaokrąglanie wyniku:
- do najbliższej liczby całkowitej
- zaokrąglanie w stronę plus nieskończoności
- zaokrąglanie w stronę minus nieskończoności
- ucinanie (zaokrąglanie w stronę zera)
- flaga flush-to-zero – jeśli ustawiona w przypadku niedomiaru zamiast zgłaszania wyjątku, zapisywana jest liczba zero; działanie nie jest zgodne ze standardem, ale powoduje przyspieszenie programów
- sposób zaokrąglanie wyniku:
- Maski włączające zgłaszanie wyjątków przy błędach; wykrywane błędy:
- niewłaściwe argumenty (np. pierwiastkowanie ujemnej liczby),
- dzielenie przez zero,
- nadmiar (wynik jest zbyt duży),
- niedomiar (wynikiem jest liczba nie znormalizowana),
- niedokładny wynik (wynik nie może być dokładnie reprezentowany).
- Flagi wskazujące rodzaj błędu – ustawiane automatycznie przez procesor, niezależnie od tego, czy dany błąd jest zgłaszany, czy nie; muszą zostać wyzerowane programowo (zwykle w procedurze obsługi wyjątków SSE).
Przesłania liczb zmiennoprzecinkowych między rejestrami i pamięcią
[edytuj | edytuj kod]Rozkazy działają na wektorach liczb zmiennoprzecinkowych (4 elementy).
MOVAPS, MOVUPS
[edytuj | edytuj kod]Przesłanie 4 liczb zmiennoprzecinkowych pomiędzy rejestrem XMM a pamięcią lub innym rejestrem XMM:
MOVAPS– wymaga, by adres pamięci był wyrównany do granicy 16 bajtów, tj. jego 4 najmłodsze bity muszą być równe zero – w przeciwnym przypadku zgłaszany jest błąd.MOVUPS– nie nakłada takich ograniczeń, ale odczyt danych niewyrównanych jest zwykle wolniejszy.
MOVSS
[edytuj | edytuj kod]Przesłanie jednej liczby zmiennoprzecinkowej pomiędzy rejestrem XMM a pamięcią lub innym rejestrem XMM. Rozkaz działa na elemencie 0 rejestrów XMM: przy przesłaniach z rejestru do rejestru tylko on jest zmieniany, przy przesłaniu z pamięci do rejestru zerowane są pozostałe elementy.
MOVLPS, MOVHPS
[edytuj | edytuj kod]Przesłanie 2 liczb zmiennoprzecinkowych pomiędzy rejestrem XMM i pamięcią. Rozkaz MOVLPS działa na elementach 0 i 1 rejestru XMM, natomiast MOVHPS na elementach 2 i 3.
MOVLHPS, MOVHLPS
[edytuj | edytuj kod]Przesłanie między rejestrami 64-bitów (2 liczb zmiennoprzecinkowych)
MOVLHPS– zapisanie elementów 0 i 1 rejestru źródłowego na pozycjach 2 i 3 rejestru docelowego;MOVHLPS– zapisanie elementów 2 i 3 rejestru źródłowego na pozycjach 0 i 1 rejestru docelowego.
MOVMSKPS
[edytuj | edytuj kod]Utworzenie 4-bitowej maski z najstarszych bitów każdej z liczb (tj. z bitów znaku) i zapisanie jej do rejestru ogólnego przeznaczenia x86 (EAX, EBX itd.).
Pamięć podręczna
[edytuj | edytuj kod]W SSE dostępne są trzy grupy rozkazów odnoszące się do pamięci podręcznej.
Pobranie danych „bliżej” procesora
[edytuj | edytuj kod]Rozkazy PREFETCH (PREFETCHT0, PREFETCHT1, PREFETCHT2, PREFETCHNTA) są rodzajami podpowiedzi (ang. hint) dla procesora, wskazującymi, że obszar pamięci powinien znaleźć się wyżej w hierarchii pamięci podręcznej: poziom 1 znajduje się najbliżej procesora, poziom 2 dalej itd. Im „bliżej” procesora znajdują się dane, tym mniejszy jest czas oczekiwania na nie; np. jeśli dane są już w pamięci podręcznej pierwszego poziomu, prawie w ogóle nie trzeba czekać, w przeciwnym razie czas oczekiwania może wynieść kilkanaście, a nawet kilkadziesiąt lub kilkaset cykli maszynowych[3].
Programista czy kompilator wie lepiej kiedy i które dane wykorzystuje – za pomocą rozkazów PREFETCH może odpowiednio wcześniej powiadomić procesor o zapotrzebowaniu i uniknąć tym samym oczekiwania, kiedy dane będą już potrzebne.
Należy zauważyć, że procesor może owych „podpowiedzi” w ogóle nie uwzględnić.
Trwały zapis (ang. non-temporal)
[edytuj | edytuj kod]Pamięć podręczna służy m.in. do szybkiego sięgania po ostatnio zapisane informacje. Jednak zauważono, że pewnych przypadkach dane zapisywane z rejestrów do pamięci nie są więcej używane i dlatego nie ma potrzeby, aby zapisywać je w pamięci podręcznej (oraz marnować przy okazji jej ograniczone zasoby).
W SSE wprowadzono trzy rozkazy pozwalające przesłać dane do pamięci z pominięciem pamięci podręcznej:
MOVNTQ– zapis zawartości rejestru MMXMOVNTPS– zapis zawartości rejestru SSEMASKMOVQ– zapis wybranych bajtów z rejestru MMX
W przypadku innych przesłań do pamięci, procesor może zakładać, że wszystkie zapisy do pamięci są tymczasowe (ang. temporal) i w ogóle nie uaktualniać zawartości pamięci głównej. Za pomocą rozkazu SFENCE wymusza się synchronizację – patrz bariera pamięci.
64-bitowe rozkazy całkowitoliczbowe
[edytuj | edytuj kod]Operandami dodatkowych rozkazów całkowitoliczbowych są tylko rejestry MMX; w SSE2 pojawiła się już możliwość wykorzystania również rejestrów SSE.
Rozkazy:
PAVGB,PAVGW– średnia bajtów/słów bez znaku (tutaj: słowo ma 16-bitów)PMAXUB,PMINUB– wybranie bajtów bez znaku o maksymalnej/minimalnej wartościPMAXSW,PMINSW– wybranie słów ze znakiem o maksymalnej/minimalnej wartościPMOVMSKB– utworzenie maski bitowej z najstarszych bitów wszystkich bajtówPMULHUW– starsze słowo z wyniku mnożenia słów bez znakuPSADBW– suma modułów różnicy bajtów (tj. czyli odległość w metryce manhattan)PEXTRW,PINSRW– pobranie/wstawienie dowolnego słowa wektoraPSHUFW– rozmieszczenie słów w wektorze
Rozszerzenia SSE
[edytuj | edytuj kod]Kolejne rozszerzenia do zestawu instrukcji SSE:
- SSE2 – 2000 rok (wprowadzone przez firmę Intel):
- wprowadzenie działań wektorowych i skalarnych na liczbach zmiennoprzecinkowych podwójnej precyzji,
- umożliwienie wykonywania działań całkowitoliczbowych na 128-bitowych rejestrach XMM,
- większa kontrola nad pamięcią podręczną.
- SSE3 – 2004 rok (Intel):
- dodatkowe rozkazy wektorowe działające na liczbach zmiennoprzecinkowych pojedynczej i podwójnej precyzji,
- sprzętowe wspomaganie synchronizacji wątków.
- SSSE3 – 2006 rok (Intel):
- dodatkowe rozkazy wektorowe działające na liczbach całkowitych,
- rozkaz umożliwiający wyznaczenie zadanej permutacji bajtów w rejestrze XMM.
- SSE4 – 2007 rok (Intel):
- dodatkowe rozkazy wektorowe działające zarówno na liczbach całkowitych jak zmiennoprzecinkowych,
- rozkazy wektorowe wspomagające kompresję wideo,
- rozkazy wektorowe wykonujące działania na łańcuchach znaków,
- rozkaz wyznaczający sumę CRC-32.
- SSE5 – 2009 rok (AMD):
- dodatkowe rozkazy wektorowe działające zarówno na liczbach całkowitych jak zmiennoprzecinkowych,
- wprowadzenie rozkazów trój- i czteroargumentowych, w który jeden z argumentów jest docelowy (rozwiązanie z architektury RISC) – dotychczas rozkazy były 2-argumentowe, z czego jeden był równocześnie docelowy i jeśli jego wartość była potrzebna w dalszej części obliczeń, należało go zapamiętać – w rozkazach 3- i 4-argumentowych takiego problemu nie ma,
- rozkazy 4-argumentowe pozwalają akumulować wyniki mnożenia według schematu
- Advanced Vector Extensions – 2010 rok (Intel):
- dodanie nowych, 256-bitowych rejestrów: część istniejących rozkazów SSE, SSE2, SSE3 i SSSE3, głównie zmiennoprzecinkowych może wykonywać działania na tych rejestrach,
- kilka rozkazów wektorowych działających wyłącznie na 256-bitowych rejestrach,
- część istniejących rozkazów może być wykonywana wariantach 3-argumentowych (jak w SSE5),
- rozkazy 4-argumentowe pozwalają akumulować wyniki mnożenia na liczbach zmiennoprzecinkowych według schematu
- zwiększono z 8 do 32 liczbę relacji, które można sprawdzić rozkazami porównania (
CMPPS,CMPPD), - sprzętowe wsparcie szyfrowania AES.
Zobacz też
[edytuj | edytuj kod]Przypisy
[edytuj | edytuj kod]- ↑ Rozkazy
CMPPS/CMPSSsą trójargumentowe: dwa pierwsze argumenty to porównywane wektory, trzeci argument to stała określająca testowaną relację. Jednak Intel proponuje, aby w asemblerze dostępne były dwurgumentowe pseduorozkazy, w których rodzaj relacji zapisany będzie w mnemoniku – np.CMPNEQPS xmm0, xmm1odpowiadaCMPPS xmm0, xmm1, 4(4 – kod dla relacji „różny”, ang. Not EQual). - ↑ Relacja unordered jest prawdziwa, gdy argumentów nie można porównać, ponieważ przynajmniej jeden z nich jest nie-liczbą (NaN) lub nie reprezentuje prawidłowej liczby zmiennoprzecinkowej.
- ↑ Orientacyjne wartości: jeśli dane są w L1 – 2-3 cykle, w L2 – rzędu 10 cykli, w pamięci głównej – rzędu 100–200 cykli.