Aritmética com Números de Ponto Flutuante em Assembly NASM
As extensões SSE fornecem um conjunto de instruções para realizar operações aritméticas sobre números de ponto flutuante. Essas instruções operam sobre valores armazenados nos registradores XMM e podem manipular tanto números de precisão simples (32 bits) quanto de precisão dupla (64 bits).
Principais instruções
| Instrução | Operação |
|---|---|
addss, addsd | Adição |
subss, subsd | Subtração |
mulss, mulsd | Multiplicação |
divss, divsd | Divisão |
minss, minsd | Retorna o menor valor entre dois operandos |
maxss, maxsd | Retorna o maior valor entre dois operandos |
sqrtss, sqrtsd | Calcula a raiz quadrada |
rcpss, rcpsd | Calcula o inverso (1/x) |
rsqrtss, rsqrtsd | Calcula o inverso da raiz quadrada (1/√x) |
Os sufixos indicam o tipo de dado manipulado:
- ss (scalar single) — operações sobre valores de ponto flutuante de 32 bits.
- sd (scalar double) — operações sobre valores de ponto flutuante de 64 bits.
Formato geral das instruções
addss xmm, xmm/mem32
addsd xmm, xmm/mem64
subss xmm, xmm/mem32
subsd xmm, xmm/mem64
mulss xmm, xmm/mem32
mulsd xmm, xmm/mem64
divss xmm, xmm/mem32
divsd xmm, xmm/mem64
minss xmm, xmm/mem32
minsd xmm, xmm/mem64
maxss xmm, xmm/mem32
maxsd xmm, xmm/mem64
sqrtss xmm, xmm/mem32
sqrtsd xmm, xmm/mem64
rcpss xmm, xmm/mem32
rsqrtss xmm, xmm/mem32O primeiro operando (onde o resultado é armazenado) deve ser sempre um registrador XMM. O segundo operando pode ser outro registrador XMM ou um operando de memória.
Exemplo: soma de dois números em Linux
global _start
section .data
num0 dq 3.4
num1 dq 6.6
section .text
_start:
movsd xmm0, [num0] ; carrega num0 em xmm0
movsd xmm1, [num1] ; carrega num1 em xmm1
addsd xmm0, xmm1 ; xmm0 = xmm0 + xmm1
cvtsd2si rdi, xmm0 ; converte resultado para inteiro em RDI
mov rax, 60
syscallNeste exemplo, os números 3.4 e 6.6 são carregados em xmm0 e xmm1.
Após a operação de soma, o resultado (10.0) é convertido para inteiro e armazenado em rdi.
Exemplo equivalente em Windows
global _start
section .data
num0 dq 3.4
num1 dq 6.6
section .text
_start:
movsd xmm0, [rel num0]
movsd xmm1, [rel num1]
addsd xmm0, xmm1
cvtsd2si rax, xmm0
retA lógica é idêntica, com a diferença de endereçamento relativo ([rel var]) utilizado no ambiente Windows.
Outras operações
- Subtração:
subsd xmm0, xmm1- calculaxmm0 = xmm0 - xmm1. - Multiplicação:
mulsd xmm0, xmm1- calculaxmm0 = xmm0 * xmm1. - Divisão:
divsd xmm0, xmm1- calculaxmm0 = xmm0 / xmm1. - Raiz quadrada:
sqrtsd xmm0, xmm1- calculaxmm0 = √xmm1. - Mínimo e máximo:
minsd xmm0, xmm1/maxsd xmm0, xmm1. - Inverso:
rcpss xmm0, xmm1- resultado ≈1 / xmm1. - Inverso da raiz quadrada:
rsqrtss xmm0, xmm1- resultado ≈1 / √xmm1.
Essas instruções também possuem variantes vetoriais (vaddsd, vsubsd, etc.) nas extensões AVX, que funcionam de maneira equivalente, mas com registradores YMM de 256 bits.
Resumo
- As operações aritméticas com ponto flutuante são realizadas diretamente nos registradores XMM.
- O sufixo ss indica operações com precisão simples (32 bits), e sd indica precisão dupla (64 bits).
- O resultado das operações sempre é gravado no primeiro operando.
- As instruções SSE/AVX permitem manipular tanto números escalares quanto vetores.
- Conversões para inteiro podem ser feitas com instruções
cvt*.