Conversão entre Números de Ponto Flutuante e Inteiros em Assembly NASM
As extensões SSE, AVX e AVX2 incluem diversas instruções para conversão entre números de ponto flutuante e inteiros. Essas instruções permitem converter tanto valores escalares (únicos) quanto vetores de valores (conjuntos).
Conversão de valores escalares
As instruções a seguir realizam a conversão de um valor entre diferentes tipos numéricos:
cvtsd2si— converte um número de ponto flutuante de 64 bits em um inteiro de 32 ou 64 bits. O arredondamento segue o modo definido no registrador MXCSR. O resultado é armazenado em um registrador geral de 32 ou 64 bits.cvtsd2si reg32/64, xmmn/mem64
cvtsd2ss— converte um número de ponto flutuante de 64 bits (em um registrador XMM ou variável) em um número de ponto flutuante de 32 bits, armazenando o resultado no registrador XMM de destino.cvtsd2ss xmmn, xmmn/mem64
cvtsi2sd— converte um inteiro de 32 ou 64 bits (de um registrador ou memória) em um número de ponto flutuante de 64 bits, armazenado no registrador XMM.cvtsi2sd xmmn, reg32/reg64/mem32/mem64
cvtsi2ss— converte um inteiro de 32 ou 64 bits em um número de ponto flutuante de 32 bits, armazenando o resultado em um registrador XMM.cvtsi2ss xmmn, reg32/reg64/mem32/mem64
cvtss2sd— converte um número de ponto flutuante de 32 bits (em XMM ou memória) em um número de 64 bits, armazenando o resultado no registrador XMM.cvtss2sd xmmn, xmmn/mem32
cvtss2si— converte um número de ponto flutuante de 32 bits em um inteiro de 32 ou 64 bits, com arredondamento conforme o modo do MXCSR.cvtss2si reg32/reg64, xmmn/mem32
cvttsd2si— converte um número de ponto flutuante de 64 bits em inteiro de 32 ou 64 bits, usando truncamento (sem arredondamento). O resultado é armazenado em um registrador geral.cvttsd2si reg32/64, xmmn/mem64
cvttss2si— converte um número de ponto flutuante de 32 bits em inteiro de 32 ou 64 bits, também com truncamento (sem usar o controle de arredondamento).cvttss2si reg32/reg64, xmmn/mem32
O padrão de nomenclatura das instruções segue uma lógica regular.
Por exemplo, cvtsi2sd significa:
cvt (convert) + si (signed integer) + 2 (para) + sd (scalar double).
Exemplo de conversão em Linux
global _start
section .data
number dq 3.4
section .text
_start:
movsd xmm0, [number] ; carrega número em xmm0
cvtsd2si rdi, xmm0 ; converte para inteiro, resultado em RDI
mov rax, 60
syscallO valor 3.4 armazenado em xmm0 é convertido em um inteiro — o resultado em rdi será 3.
Exemplo equivalente em Windows
global _start
section .data
number dq 3.4
section .text
_start:
movsd xmm0, [rel number]
cvtsd2si rax, xmm0
retControle de arredondamento com MXCSR
O modo de arredondamento é definido pelos bits 13 e 14 do registrador MXCSR:
| Bits | Modo de arredondamento |
|---|---|
| 00 | Para o mais próximo (padrão) |
| 01 | Para -∞ |
| 10 | Para +∞ |
| 11 | Truncamento (para zero) |
Por padrão, o arredondamento é para o mais próximo. Assim, 3.4 → 3 e 3.5 → 4. Esses bits podem ser alterados para modificar o comportamento do arredondamento.
Exemplo em Linux
global _start
section .data
number dq 5.6
state dd 0
section .text
_start:
stmxcsr [state] ; salva estado atual
or dword [state], 0b110000000000000 ; define bits 13 e 14
ldmxcsr [state] ; recarrega no registrador
movsd xmm0, [number]
cvtsd2si rdi, xmm0 ; converte com truncamento
mov rax, 60
syscallO programa configura o MXCSR para truncar a parte fracionária, resultando em 5 ao converter 5.6.
Exemplo em Windows
global _start
section .data
number dq 5.6
state dd 0
section .text
_start:
stmxcsr [rel state]
or dword [rel state], 0b110000000000000
ldmxcsr [rel state]
movsd xmm0, [rel number]
cvtsd2si rax, xmm0
retConversão de vetores
Além de valores individuais, há instruções específicas para conversão de vetores de números.
cvtdq2pd— converte dois inteiros de 32 bits com sinal em dois números de ponto flutuante de 64 bits.cvtdq2pd xmmdest, xmmsrc/mem64 vcvtdq2pd xmmdest, xmmsrc/mem64 vcvtdq2pd ymmdest, xmmsrc/mem128
cvtdq2ps— converte quatro inteiros de 32 bits com sinal em quatro números de ponto flutuante de 32 bits.cvtdq2ps xmmdest, xmmsrc/mem128 vcvtdq2ps xmmdest, xmmsrc/mem128 vcvtdq2ps ymmdest, ymmsrc/mem256
cvtpd2dq— converte dois números de ponto flutuante de 64 bits em dois inteiros de 32 bits com sinal.cvtpd2dq xmmdest, xmmsrc/mem128 vcvtpd2dq xmmdest, xmmsrc/mem128 vcvtpd2dq xmmdest, ymmsrc/mem256
cvtpd2ps— converte dois números de 64 bits em dois números de 32 bits.cvtpd2ps xmmdest, xmmsrc/mem128 vcvtpd2ps xmmdest, xmmsrc/mem128 vcvtpd2ps ymmdest, ymmsrc/mem256
cvtps2dq— converte quatro números de ponto flutuante de 32 bits em quatro inteiros de 32 bits com sinal.cvtps2dq xmmdest, xmmsrc/mem128 vcvtps2dq xmmdest, xmmsrc/mem128 vcvtps2dq ymmdest, ymmsrc/mem256
cvtps2pd— converte dois números de 32 bits em dois números de 64 bits.cvtps2pd xmmdest, xmmsrc/mem64 vcvtps2pd xmmdest, xmmsrc/mem64 vcvtps2pd ymmdest, xmmsrc/mem128
cvttpd2dq— converte números de 64 bits para inteiros de 32 bits com truncamento.cvttpd2dq xmmdest, xmmsrc/mem128 vcvttpd2dq xmmdest, xmmsrc/mem128 vcvttpd2dq xmmdest, ymmsrc/mem256
cvttps2dq— converte números de 32 bits para inteiros de 32 bits com truncamento.cvttps2dq xmmdest, xmmsrc/mem128 vcvttps2dq xmmdest, xmmsrc/mem128 vcvttps2dq ymmdest, ymmsrc/mem256
Essas instruções são úteis quando há necessidade de converter vetores inteiros de valores.
Exemplo em Linux
global _start
section .data
floatNums dd 4.2, 5.3, 6.4, 7.5
section .bss
intNums resd 4
section .text
_start:
cvttps2dq xmm0, [floatNums]
movaps [intNums], xmm0
mov edi, [intNums] ; EDI = 4
mov rax, 60
syscallO vetor de quatro números de ponto flutuante é convertido em quatro inteiros de 32 bits, armazenados em intNums.
Exemplo equivalente em Windows
global _start
section .data
floatNums dd 4.2, 5.3, 6.4, 7.5
section .bss
intNums resd 4
section .text
_start:
cvttps2dq xmm0, [rel floatNums]
movaps [rel intNums], xmm0
mov eax, [rel intNums]
retResumo
- As instruções
cvt*realizam conversões entre inteiros e números de ponto flutuante. - O controle de arredondamento é definido no registrador MXCSR.
- Existem versões escalares (para valores únicos) e vetoriais (para blocos de dados).
- As versões com tt aplicam truncamento em vez de arredondamento.
- As versões com v pertencem às extensões AVX e trabalham com registradores YMM.