Comparação de Números de Ponto Flutuante em Assembly NASM
As extensões SSE incluem um conjunto de instruções que permitem comparar números de ponto flutuante de forma direta. Essas instruções verificam condições específicas e armazenam o resultado — verdadeiro (todos os bits 1) ou falso (todos os bits 0) — no primeiro operando (registrador XMM).
Principais instruções de comparação
cmpss xmm, xmm/mem32, imm8
cmpsd xmm, xmm/mem64, imm8
cmpeqss xmm, xmm/mem32 ; iguais
cmpltss xmm, xmm/mem32 ; menor que
cmpless xmm, xmm/mem32 ; menor ou igual
cmpunordss xmm, xmm/mem32 ; desordenado (um ou ambos são NaN)
cmpneqss xmm, xmm/mem32 ; diferentes
cmpnltss xmm, xmm/mem32 ; não menor
cmpnless xmm, xmm/mem32 ; não menor ou igual
cmpordss xmm, xmm/mem32 ; ordenado (nenhum é NaN)
cmpeqsd xmm, xmm/mem64 ; iguais
cmpltsd xmm, xmm/mem64 ; menor que
cmplesd xmm, xmm/mem64 ; menor ou igual
cmpunordsd xmm, xmm/mem64 ; desordenado (um ou ambos são NaN)
cmpneqsd xmm, xmm/mem64 ; diferentes
cmpnltsd xmm, xmm/mem64 ; não menor
cmpnlesd xmm, xmm/mem64 ; não menor ou igual
cmpordsd xmm, xmm/mem64 ; ordenadoAs instruções cmpss e cmpsd aceitam um terceiro operando imediato (imm8) que define o tipo de comparação:
| Valor (imm8) | Condição de comparação |
|---|---|
| 0 | Igual (==) |
| 1 | Menor (<) |
| 2 | Menor ou igual (<=) |
| 3 | Desordenado (quando um ou ambos os operandos são NaN) |
| 4 | Diferente (≠) |
| 5 | Não menor (>=) |
| 6 | Maior (>) |
| 7 | Ordenado (nenhum é NaN) |
Funcionamento
Após a comparação, o resultado (verdadeiro ou falso) é gravado em todos os bits do primeiro operando.
Esse valor pode ser movido para um registrador inteiro com as instruções movq ou movd para permitir verificações com instruções condicionais.
Exemplo: comparação de igualdade (Linux)
global _start
section .data
num0 dq 3.4
num1 dq 3.4
section .text
_start:
movsd xmm0, [num0] ; carrega num0 em xmm0
movsd xmm1, [num1] ; carrega num1 em xmm1
cmpeqsd xmm0, xmm1 ; verifica igualdade
movq rdi, xmm0 ; transfere resultado para RDI
mov rax, 60
syscallO resultado será:
- Todos os bits 1 (valor decimal -1) - se os números forem iguais.
- Todos os bits 0 - se forem diferentes.
Exemplo equivalente em Windows
global _start
section .data
num0 dq 3.4
num1 dq 3.4
section .text
_start:
movsd xmm0, [rel num0]
movsd xmm1, [rel num1]
cmpeqsd xmm0, xmm1
movq rax, xmm0
retUso com instruções condicionais
Após copiar o resultado para um registrador geral, é possível utilizar instruções como test e jnz (jump if not zero) para criar estruturas condicionais.
Exemplo completo em Linux
global _start
section .data
num0 dq 3.6
num1 dq 3.5
str_equal db "Equal", 10, 0
str_equal_len equ $ - str_equal
str_notequal db "Not equal", 10, 0
str_notequal_len equ $ - str_notequal
section .text
_start:
movsd xmm0, [num0]
movsd xmm1, [num1]
cmpeqsd xmm0, xmm1
movq rdi, xmm0
test rdi, rdi ; verifica se resultado ≠ 0
jnz equal ; se verdadeiro (==), salta para equal
mov rsi, str_notequal
mov rdx, str_notequal_len
jmp exit
equal:
mov rsi, str_equal
mov rdx, str_equal_len
exit:
mov rax, 1 ; syscall write
mov rdi, 1 ; stdout
syscall
mov rax, 60
syscallO programa imprime “Equal” se os valores forem iguais ou “Not equal” caso contrário.
Exemplo equivalente em Windows
global _start
extern WriteFile
extern GetStdHandle
section .data
num0 dq 3.6
num1 dq 3.5
str_equal db "Equal", 10, 0
str_equal_len equ $ - str_equal
str_notequal db "Not equal", 10, 0
str_notequal_len equ $ - str_notequal
section .text
_start:
sub rsp, 40
movsd xmm0, [rel num0]
movsd xmm1, [rel num1]
cmpeqsd xmm0, xmm1
movq rdi, xmm0
test rdi, rdi
jnz equal
mov rdx, str_notequal
mov r8d, str_notequal_len
jmp exit
equal:
mov rdx, str_equal
mov r8d, str_equal_len
exit:
mov rcx, -11
call GetStdHandle
mov rcx, rax
xor r9, r9
mov qword [rsp + 32], 0
call WriteFile
add rsp, 40
retObservações
- As instruções de comparação (
cmp*ss,cmp*sd) retornam -1 (todos os bits 1) para verdadeiro e 0 para falso. - A combinação de
testejnzé uma forma prática de verificar resultados lógicos em código Assembly. - Comparações envolvendo NaN (Not a Number) podem gerar resultados não ordenados — nesse caso, use
cmpunordssoucmpunordsd. - Instruções
cmpssecmpsdcom o operando imediato (imm8) permitem definir explicitamente o tipo de comparação desejada.
Resumo
- As instruções SSE permitem comparações diretas entre números de ponto flutuante.
cmpeqsd/cmpeqss— igualdade.cmpltsd/cmpltss— menor que.cmplesd/cmpless— menor ou igual.cmpneqsd/cmpneqss— diferentes.cmpordsd/cmpordss— comparação ordenada (sem NaN).- O resultado é retornado em XMM como 0 (falso) ou -1 (verdadeiro).
- Pode-se transferir esse valor para um registrador inteiro e criar fluxos condicionais.