# Streaming SIMD Extensions

SSE (Streaming SIMD Extensions) è un instruction set SIMD progettato dalla Intel nel 1999 ed utilizzato nel suo processore Pentium III come risposta al 3DNow! prodotto da AMD, che era presente sul mercato da circa un anno. Era originariamente conosciuto con la sigla KNI, da Katmai New Instructions (Katmai era il nome in codice del primo Pentium III). Durante il progetto Katmai Intel cercava di distinguerlo dalla sua precedente linea di prodotti, in particolare il Pentium II. AMD aggiunse successivamente il supporto per le istruzioni SSE nel suo processore Athlon XP.
Il primo tentativo di SIMD da parte della Intel, la tecnologia MMX, fu una delusione. MMX ha principalmente due problemi: riutilizza i registri a virgola mobile rendendo impossibile per la CPU lavorare sui dati in virgola mobile e i dati SIMD contemporaneamente, ma può operare solo sugli interi.
SSE aggiunge otto nuovi registri a 128 bit con nomi che vanno da XMM0 a XMM7. Ogni registro raggruppa quattro numeri a virgola mobile a 32 bit (precisione singola).
Poiché questi registri a 128 bit rappresentano stati aggiuntivi che il sistema operativo deve preservare durante il cambio di contesto dei task, essi sono disabilitati finché il sistema operativo non li abilita esplicitamente. Questo significa che il SO deve essere programmato per utilizzare le istruzioni FXSAVE e FXRSTOR, che sono la coppia di istruzioni introdotte da SSE per salvare in un'unica operazione i registri x86, MMX, 3DNow! e SSE. Il supporto per queste istruzioni fu aggiunto velocemente a tutti i principali sistemi operativi a 32 bit.
Poiché SSE aggiunge il supporto per la virgola mobile, fu molto più utilizzato di MMX dato che tutte le schede video gestiscono internamente i calcoli sui numeri interi. L'intero set era costituito da 70 istruzioni. Con l'introduzione di SSE2 anche gli interi possono essere utilizzati con i nuovi registri XMM, perciò l'instruction set MMX adesso è ridondante.
Sul Pentium III, comunque, SSE è implementato utilizzando gli stessi circuiti della FPU, il che significa che la CPU non può inviare nella pipeline contemporaneamente le istruzioni SSE e quelle riguardanti la virgola mobile. I registri separati permettono di mescolare le operazioni SIMD e a virgola mobile, ma senza le prestazioni raggiunte passando esplicitamente dalla modalità a virgola mobile a quella MMX.
Il Pentium 4 implementa SSE2, un'estensione del set di istruzioni SSE. Le caratteristiche principali di SSE2 sono il supporto per i numeri a virgola mobile a doppia precisione (64 bit) e il supporto per gli interi nel vettore di registri a 128 bit introdotti con SSE, il che permette al programmatore di utilizzare i registri MMX. Lo stesso SSE2 è stato esteso da SSE3 introdotto con in core Prescott delle ultime generazioni di Pentium 4.

## Registri

SSE ha aggiunto otto nuovi registri a 128 bit identificati con i codici da XMM0 a XMM7. Le estensioni AMD64 (poi duplicate da Intel) hanno aggiunto altri otto registri da XMM8 a XMM15. C'è anche un nuovo registro di stato a 32 bit, il MXCSR. I registri da XMM8 a XMM15 sono accessibili solo nella modalità a 64 bit.
Ogni registro può contenere insieme:
* quattro numeri in virgola mobile in singola precisione a 32-bit, oppure
* due numeri in virgola mobile in doppia precisione a 64-bit, oppure
* due interi a 64 bit, oppure
* quattro interi a 32 bit, oppure
* otto interi corti a 16 bit, oppure
* sedici bytes da 8 bit.
Le operazioni sugli interi hanno varianti per numeri con segno e senza segno. Le operazioni intere SIMD possono essere eseguite con gli otto registri MMX a 64 bit.
Visto che questi registri a 128 bit sono degli stati di programma addizionali che devono essere conservati dal sistema operativo durante il cambio di task, sono disabilitati per default fino a che il sistema operativo non li abilita esplicitamente. Questo richiede che il sistema operativo stesso conosca e usi la coppia di istruzioni FXSAVE e FXRSTOR, che salvano tutti i registri di stato x86 e SSE in un colpo solo. Questa capacità è stata rapidamente aggiunta a tutti i sistemi operativi a 32 bit.
Poiché le istruzioni SSE lavorano anche con numeri in virgola mobile, sono molto più utili delle estensioni MMX, e l'aggiunta delle sitruzioni SSE2 ne ha incrementato ancora l'appetibilità. Anche se le istruzioni MMX sono ridondanti, possono però essere eseguite in parallelo con quelle SSE, aumentando le prestazioni in alcune circostanze.

## Istruzioni SSE

SSE introduce sia operazioni su scalari singoli sia su gruppi di numeri in virgola mobile (packed).

### Istruzioni floating point

* Movimenti memoria-registro / registro-memoria / registro-registro
** Scalari – MOVSS
** Packed – MOVAPS, MOVUPS, MOVLPS, MOVHPS, MOVLHPS, MOVHLPS
* Aritmetiche
** Scalari – ADDSS, SUBSS, MULSS, DIVSS, RCPSS, SQRTSS, MAXSS, MINSS, RSQRTSS
** Packed – ADDPS, SUBPS, MULPS, DIVPS, RCPPS, SQRTPS, MAXPS, MINPS, RSQRTPS
* Confronti
** Scalari – CMPSS, COMISS, UCOMISS
** Packed – CMPPS
* Impaccamento/spacchettamento dati
** Packed – SHUFPS, UNPCKHPS, UNPCKLPS
* Conversioni di tipo
** Scalari – CVTSI2SS, CVTSS2SI, CVTTSS2SI
** Packed – CVTPI2PS, CVTPS2PI, CVTTPS2PI
* Operazioni logiche sui bit
** Packed – ANDPS, ORPS, XORPS, ANDNPS

### Istruzioni su interi

* Aritmetiche
** PMULHUW, PSADBW, PAVGB, PAVGW, PMAXUB, PMINUB, PMAXSW, PMINSW
* Movimenti dati
** PEXTRW, PINSRW
* Altre
** PMOVMSKB, PSHUFW

### Altre istruzioni

* Gestione dell'MXCSR
** LDMXCSR, STMXCSR
* Gestione di memoria e cache
** MOVNTQ, MOVNTPS, MASKMOVQ, PREFETCH0, PREFETCH1, PREFETCH2, PREFETCHNTA, SFENCE

## Esempi

Gli esempi che seguono dimostrano il vantaggio di usare le istruzioni SSE. Si consideri un'operazione come la somma di vettori, che si usa molto spesso nella computer grafica; sommare due vettori a precisione singola con 4 componenti ciascuno richiede quattro istruzioni di somma floating point in un normale processore x86:
Queste quattro righe diventano altrettante istruzioni FADD nel codice oggetto compilato. Con le istruzioni SSE invece, come si vede dal codice che segue, basta una sola istruzione 'packed-add' a 128 bit per eseguire il calcolo.

## Differenze fra x87 FPU e SSE

Le istruzioni FPU (x87) di solito memorizzano i risultati con 80 bit di precisione. Quando vecchi algoritmi scritti per le FPU x87 vengono adattati alle nuove estensioni SSE, che supportano solo 64 bit di precisione, alcune combinazioni di operazioni aritmetiche e insiemi di dati possono dare luogo a differenze numeriche significative: questo è molto importante nei calcoli scientifici, se il calcolo deve essere confrontato con risultati ottenuti su altre architetture hardware.
A seconda di quale interprete o compilatore viene usato e di quali ottimizzazioni vengono scelte, può essere necessario salvare temporaneamente certi dati e ricaricarli più tardi; normalmente anche i risultati della FPU x87 vengono arrotondati a 64 o a 32 bit, ma il luogo e il momento esatto in cui questo avviene può causare differenze nell'esito finale dei calcoli. Il seguente esempio di codice in Fortran 95 ne fornisce la prova: il valore corretto del terzo e ultimo numero da stampare è zero.
Compilando con le istruzioni FPU x87 ed eseguendo si ottiene:
Compilando usando le estensioni SSE ed eseguendo si ottiene: