Entendendo SSE
Aprendendo sobre SIMD, SSE e registradores XMM.
Na computação existe um conceito de instrução chamado SIMD (Single Instruction, Multiple Data) que Ă© basicamente uma instrução que processa mĂșltiplos dados de uma Ășnica vez. Todas as instruçÔes que vimos atĂ© agora processavam meramente um dado por vez, porĂ©m instruçÔes SIMD podem processar diversos dados paralelamente. O principal objetivo das instruçÔes SIMD Ă© ganhar performance se aproveitando dos mĂșltiplos nĂșcleos do processador, a maioria das instruçÔes SIMD foram implementadas com o intuito de otimizar cĂĄlculos comuns em ĂĄreas como processamento grĂĄfico, inteligĂȘncia artificial, criptografia, matemĂĄtica etc.
A Intel criou a primeira versão do SSE (streaming SIMD extensions) ainda no IA-32 com o Pentium III, e de lå para cå jå ganhou diversas novas versÔes que estendem a tecnologia adicionando novas instruçÔes. Atualmente nos processadores mais modernos hå as seguintes extensÔes: SSE, SSE2, SSE3, SSSE3 e SSE4.
Processadores da arquitetura x86 tĂȘm diversas tecnologias SIMD, a primeira delas foi o MMX nos processadores Intel antes mesmo do SSE. AlĂ©m de haver diversas outras como AVX, AVX-512, FMA, 3DNow! (da AMD) etc.
Na arquitetura x86 existem literalmente milhares de instruçÔes SIMD. Esteja ciente que esse tĂłpico estĂĄ longe de cobrir todo o assunto e serve meramente como conteĂșdo introdutĂłrio.

Registradores XMM

A tecnologia SSE adiciona novos registradores independentes de 128 bits de tamanho cada. Em todos os modos de operação são adicionados oito novos registradores XMM0 até XMM7, e em 64-bit também hå mais oito registradores XMM8 até XMM15 que podem ser acessados usando o prefixo REX. Isso då um total de 16 registradores em 64-bit e 8 registradores nos outros modos de operação.
Esses registradores podem armazenar vĂĄrios dados diferentes de mesmo tipo/tamanho, conforme demonstra tabela abaixo:
Intel Developer's Manuals | 4.6.2 128-Bit Packed SIMD Data Types
Esses sĂŁo os tipos empacotados (packed), onde em um Ășnico registrador hĂĄ vĂĄrios valores de um mesmo tipo. Existem instruçÔes SIMD especĂ­ficas que executam operaçÔes packed onde elas trabalham com os vĂĄrios dados armazenados no registrador ao mesmo tempo. Em contraste existem tambĂ©m as operaçÔes escalares (scalar) que operam com um Ășnico dado (unpacked) no registrador, onde esse dado estaria armazenado na parte menos significativa do registrador.
Na convenção de chamada para x86-64 da linguagem C os primeiros argumentos float/double passados para uma função vão nos registradores XMM0, XMM1 etc. como valores escalares. E o retorno do tipo float/double fica no registrador XMM0 também como um valor escalar.
Na lista de instruçÔes haverå códigos de exemplo disso.

Entendendo as instruçÔes SSE

As instruçÔes adicionadas pela tecnologia SSE podem ser divididas em quatro grupos:
  • InstruçÔes packed e scalar que lidam com nĂșmeros float.
  • InstruçÔes SIMD com inteiros de 64 bits.
  • InstruçÔes de gerenciamento de estado.
  • InstruçÔes de controle de cache e prefetch.
A tabela abaixo lista a nomenclatura que irei utilizar para descrever as instruçÔes SSE.
Para facilitar o entendimento irei usar o termo float para se referir aos nĂșmeros de ponto flutuante de precisĂŁo Ășnica, ou seja, 32 bits de tamanho e 23 bits de precisĂŁo. JĂĄ o termo double serĂĄ utilizado para se referir aos nĂșmeros de ponto flutuante de dupla precisĂŁo, ou seja, de 64 bits de tamanho e 52 bits de precisĂŁo. Esses sĂŁo os mesmos nomes usados como tipos na linguagem C.
Nomenclatura
Descrição
xmm(n)
Indica qualquer um dos registradores XMM.
float(n)
Indica N nĂșmeros floats em sequĂȘncia na memĂłria RAM. Exemplo: float(4) seriam 4 nĂșmeros float totalizando 128 bits de tamanho.
double(n)
Indica N nĂșmeros double na memĂłria RAM. Exemplo: double(2) que totaliza 128 bits.
ubyte(n)
Indica N bytes nĂŁo-sinalizados na memĂłria RAM. Exemplo: ubyte(16) que totaliza 128 bits.
byte(n)
Indica N bytes sinalizados na memĂłria RAM.
uword(n)
Indica N words (2 bytes) nĂŁo-sinalizados na memĂłria RAM. Exemplo: uword(8) que totaliza 128 bits.
word(n)
Indica N words sinalizadas na memĂłria RAM.
dword(n)
Indica N double words (4 bytes) na memĂłria RAM.
qword(n)
Indica N quadwords (8 bytes) na memĂłria RAM.
reg32/64
​Registrador de propósito geral de 32 ou 64 bits.
imm8
Operando imediato de 8 bits de tamanho.
As instruçÔes SSE terminam com um sufixo de duas letras onde a penĂșltima indica se ela lida com dados packed ou scalar, e a Ășltima letra indica o tipo do dado sendo manipulado. Por exemplo a instrução MOVAPS onde o P indica que a instrução manipula dados packed, enquanto o S indica o tipo do dado como single-precision floating-point, ou seja, float de 32 bits de tamanho.
Jå o D de MOVAPD indica que a instrução lida com valores do tipo double-precision floating-point (64 bits). Eis a lista de sufixos e seus respectivos tipos:
Sufixo
Tipo
S
Single-precision float. Equivalente ao tipo float em C.
D
Double-precision float. Equivalente ao tipo double em C.
Ou inteiro doubleword (4 bytes) que seria um inteiro de 32 bits.
B
Inteiro de um byte (8 bits).
W
Inteiro word (2 bytes | 16 bits).
Q
Inteiro quadword (8 bytes | 64 bits).
Todas as instruçÔes SSE que lidam com valores na memória exigem que o valor esteja em um endereço alinhado em 16 bytes, exceto as instruçÔes que explicitamente dizem lidar com dados desalinhados (unaligned).
Caso uma instrução SSE seja executada com um dado desalinhado uma exceção #GP serå disparada.
Export as PDF
Copy link
On this page
Registradores XMM
Entendendo as instruçÔes SSE