Aprendendo Assembly
Doar para o autor
  • Introdução
  • Conteúdo
  • Como usar este livro
  • A base
    • Noção geral da arquitetura
    • Modos de operação
    • Sintaxe
    • Registradores de propósito geral
    • Endereçamento
    • Pilha
    • Saltos
    • Procedimentos
    • Seções e símbolos
    • Instruções assembly x86
    • Instruções do NASM
    • Pré-processador do NASM
    • Syscall no Linux
    • Olá mundo no Linux
    • Revisão
  • Aprofundando em Assembly
    • Registradores de segmento
    • CALL e RET
    • Position-independent executable
    • Atributos
    • Prefixos
    • Flags do processador
    • Instruções condicionais
    • Programando no MS-DOS
    • Interrupções de software e exceções
    • Procedimentos do BIOS
    • Usando instruções da FPU
    • Entendendo SSE
      • Instruções de movimentação de dados
      • Instruções aritméticas
      • Instruções lógicas e de comparação
      • Instruções com inteiros 128-bit
      • Instruções de conversão
  • Programando junto com C
    • Sintaxe do GAS
    • Convenção de chamada da System V ABI
    • Convenções de chamada no Windows
    • Variáveis em C
    • Funções em C
    • Ambiente hosted
    • Ambiente freestanding
    • Inline Assembly no GCC
    • Instruções intrínsecas
  • Depuração de código
    • Entendendo os depuradores
    • Depurando com o GDB
    • Depurando com o Dosbox
  • Apêndices
    • Código de máquina
      • Formato das instruções
      • Atributos e prefixos
      • Immediate
      • Displacement
      • ModR/M e SIB
      • Opcode
      • Prefixo REX
      • Codificação dos registradores
  • Metadados
    • TO DO
    • Referências
Powered by GitBook
On this page
  • Registradores XMM
  • Entendendo as instruções SSE

Was this helpful?

Export as PDF
  1. Aprofundando em Assembly

Entendendo SSE

Aprendendo sobre SIMD, SSE e registradores XMM.

PreviousUsando instruções da FPUNextInstruções de movimentação de dados

Last updated 2 years ago

Was this helpful?

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 . 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:

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

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.

de 32 ou 64 bits.

Registrador de propósito geral
prefixo REX
Intel Developer's Manuals | 4.6.2 128-Bit Packed SIMD Data Types