Streaming SIMD Extensions


Streaming SIMD Extensions w encyklopedii

Z Wikipedii, wolnej encyklopedii Przejdź do nawigacji Przejdź do wyszukiwania Nowe rejestry SSE

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.

Spis treści

Typy danych | 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:

  1. packed (równoległe) – wykonując równocześnie 4 niezależne działania zmiennoprzecinkowe na odpowiadających sobie elementach wektorów;
  2. 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 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 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 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 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 kod

Porównania w SSE są dwojakiego rodzaju:

  1. Modyfikujące rejestr SSE w sposób analogiczny jak w MMX
  2. 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 kod

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ą rozkazy CVTTPS2PI i CVTTSS2SI dla 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 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 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 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 kod

Rejestr MXCSR przechowuje:

  1. 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
  2. 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).
  3. 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 kod

Rozkazy działają na wektorach liczb zmiennoprzecinkowych (4 elementy).

MOVAPS, MOVUPS | 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 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 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 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 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 kod

W SSE dostępne są trzy grupy rozkazów odnoszące się do pamięci podręcznej.

Pobranie danych „bliżej” procesora | 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 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:

  1. MOVNTQ – zapis zawartości rejestru MMX
  2. MOVNTPS – zapis zawartości rejestru SSE
  3. MASKMOVQ – 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 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ści
  • PMAXSW, PMINSW – wybranie słów ze znakiem o maksymalnej/minimalnej wartości
  • PMOVMSKB – utworzenie maski bitowej z najstarszych bitów wszystkich bajtów
  • PMULHUW – starsze słowo z wyniku mnożenia słów bez znaku
  • PSADBW – suma modułów różnicy bajtów (tj. i = 0 7 | a i b i | , {\displaystyle \sum _{i=0}^{7}|a_{i}-b_{i}|,} czyli odległość w metryce manhattan)
  • PEXTRW, PINSRW – pobranie/wstawienie dowolnego słowa wektora
  • PSHUFW – rozmieszczenie słów w wektorze

Rozszerzenia SSE | 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 w = ± z + ( ± x y ) . {\displaystyle w=\pm z+(\pm x\cdot y).}
  • 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 w = ± z + ( ± x y ) , {\displaystyle w=\pm z+(\pm x\cdot y),}
    • 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 kod

Przypisy | edytuj kod

  1. Rozkazy CMPPS/CMPSS są 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, xmm1 odpowiada CMPPS xmm0, xmm1, 4 (4 – kod dla relacji „różny”, ang. Not EQual).
  2. 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.
  3. 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.
Na podstawie artykułu: "Streaming SIMD Extensions" pochodzącego z Wikipedii
OryginałEdytujHistoria i autorzy