Operações Aritméticas Vetoriais com Ponto Flutuante em SSE e AVX com Assembly NASM
As extensões SSE e AVX fornecem um conjunto de instruções para realizar operações paralelas com números de ponto flutuante, que são fundamentais em computação gráfica, processamento de sinais e cálculos científicos.
O sufixo da instrução indica o tipo de dado: ps (Packed Single-precision) para float (32 bits) e pd (Packed Double-precision) para double (64 bits).
Instruções Aritméticas Básicas
Adição:
addps/vaddps: Soma vetorial de númerosfloat.addpd/vaddpd: Soma vetorial de númerosdouble.
Subtração:
subps/vsubps: Subtração vetorial defloat.subpd/vsubpd: Subtração vetorial dedouble.
Multiplicação:
mulps/vmulps: Multiplicação vetorial defloat.mulpd/vmulpd: Multiplicação vetorial dedouble.
Divisão:
divps/vdivps: Divisão vetorial defloat.divpd/vdivpd: Divisão vetorial dedouble.
Mínimo e Máximo
maxps/vmaxps: Encontra o valor máximo entre pares defloat.maxpd/vmaxpd: Encontra o valor máximo entre pares dedouble.minps/vminps: Encontra o valor mínimo entre pares defloat.minpd/vminpd: Encontra o valor mínimo entre pares dedouble.
Raiz Quadrada
sqrtps/vsqrtps: Calcula a raiz quadrada de cadafloatno vetor.sqrtpd/vsqrtpd: Calcula a raiz quadrada de cadadoubleno vetor.rsqrtps/vrsqrtps: Calcula uma aproximação do inverso da raiz quadrada (1 / sqrt(x)) para cadafloat, uma operação muito rápida e útil em gráficos 3D para normalização de vetores.
Sintaxe das Instruções
A maioria dessas instruções segue um padrão de sintaxe similar. Exemplificando com (v)addps:
addps xmmdest, xmmsrc/mem128
vaddps xmmdest, xmmsrc1, xmmsrc2/mem128
vaddps ymmdest, ymmsrc1, ymmsrc2/mem256As instruções de raiz quadrada, que são unárias, recebem apenas um operando de origem:
sqrtps xmmdest, xmmsrc/mem128
vsqrtps xmmdest, xmmsrc/mem128
vsqrtps ymmdest, ymmsrc/mem256Exemplo de Adição em Ponto Flutuante
O programa a seguir para Linux demonstra a soma de dois vetores de números float de 32 bits.
global main
extern printf
section .data
nums0 dd 1.1, 2.2, 3.3, 4.4
nums1 dd 1.2, 2.3, 3.4, 4.5
format_str db "%.1f, %.1f, %.1f, %.1f", 10, 0
section .text
main:
sub rsp, 8
movaps xmm0, [nums0]
movaps xmm1, [nums1]
vaddps xmm5, xmm0, xmm1 ; xmm5 = xmm0 + xmm1
; Extrai e exibe cada elemento do resultado
movss xmm0, xmm5 ; Move o primeiro float para o registrador de argumento
cvtss2sd xmm0, xmm0 ; Converte de float para double para printf
psrldq xmm5, 4 ; Desloca para o próximo float
movss xmm1, xmm5
cvtss2sd xmm1, xmm1
psrldq xmm5, 4
movss xmm2, xmm5
cvtss2sd xmm2, xmm2
psrldq xmm5, 4
movss xmm3, xmm5
cvtss2sd xmm3, xmm3
mov rdi, format_str
mov rax, 4 ; Indica a printf que 4 argumentos de ponto flutuante estão nos regs XMM
call printf
add rsp, 8
retNeste código, os vetores nums0 e nums1 são somados com vaddps, e o resultado é armazenado em xmm5. Para exibir o resultado com printf, cada elemento float é extraído de xmm5, convertido para double (pois printf espera double para o formato %f), e passado nos registradores xmm0 a xmm3.
Compilação e execução do programa:
$ nasm -f elf64 hello.asm -o hello.o $ gcc -static hello.o -o hello $ ./hello 2.3, 4.5, 6.7, 8.9
A seguir, a versão análoga do programa para Windows.
global main
extern printf
section .data
nums0 dd 1.1, 2.2, 3.3, 4.4
nums1 dd 1.2, 2.3, 3.4, 4.5
format_str db "%.1f, %.1f, %.1f, %.1f", 10, 0
section .text
main:
sub rsp, 40
movaps xmm0, [rel nums0]
movaps xmm1, [rel nums1]
vaddps xmm5, xmm0, xmm1 ; xmm5 = xmm0 + xmm1
; Extrai e passa os argumentos conforme a convenção do Windows x64
movss xmm1, xmm5
cvtss2sd xmm1, xmm1
movq rdx, xmm1
psrldq xmm5, 4
movss xmm2, xmm5
cvtss2sd xmm2, xmm2
movq r8, xmm2
psrldq xmm5, 4
movss xmm3, xmm5
cvtss2sd xmm3, xmm3
movq r9, xmm3
psrldq xmm5, 4
movss xmm4, xmm5
cvtss2sd xmm4, xmm4
movq qword [rsp+32], xmm4
mov rcx, format_str
call printf
add rsp, 40
retResumo
- As extensões SSE e AVX oferecem um conjunto abrangente de instruções para aritmética paralela com números de ponto flutuante de precisão simples (
ps) e dupla (pd). - As operações incluem adição, subtração, multiplicação, divisão, mínimo/máximo e raiz quadrada.
- O uso dessas instruções pode acelerar significativamente aplicações que dependem de cálculos matemáticos intensivos.