Para a função que estou escrevendo, gostaria de retornar um Nan se a entrada não fizer sentido.
Como inserir um NaN em um registro xmm da maneira mais fácil?
Para a função que estou escrevendo, gostaria de retornar um Nan se a entrada não fizer sentido.
Como inserir um NaN em um registro xmm da maneira mais fácil?
Respostas:
All-ones é um NaN silencioso (sem sinalização, também conhecido como normal), que é o que você deseja. A maneira mais fácil de produzir uma é com o SSE2 pcmpeqd xmm0,xmm0
para definir cada bit no registrador como 1
, ou seja, o número inteiro do complemento de 2 -1
. ( Defina todos os bits no registro da CPU como 1 de forma eficiente / Quais são as melhores seqüências de instruções para gerar constantes de vetores em tempo real? )
Na verdade, é um -NaN
- o bit do sinal está definido. Considere shift inteiro à direita ( psrld xmm0,1
) ou divida por zero / zero ( xorps xmm0,xmm0
/ divpd xmm0,xmm0
), se isso for indesejável.
As funções matemáticas que desejam retornar o NaN geralmente também desejam garantir que o bit de exceção autônomo FP-inválido seja definido no MXCSR (ou, na verdade, crie uma exceção se o chamador desmascarou essa exceção). Para fazer isso , você pode multiplicar ou adicionar o NaN com ele mesmo. por exemplo
...
.error_return_path:
pcmpeqd xmm0, xmm0
mulsd xmm0, xmm0 ; Cause an FP-invalid operation.
ret
Ou mulss
para precisão única float
. mulpd
/ mulps
também seria apropriado.
O padrão de bits para multiplicar ou adicionar NaN com NaN ainda é definitivamente um NaN e ainda deve ser a mesma carga útil, portanto ainda é tudo.
Ter o valor de retorno como resultado de mulsd
ou addsd
(ou divsd
) também tem a vantagem de que, se o chamador usar esse registro repetidamente em um loop, ele não terá latência de desvio de cruzamento de domínio. (Na família Sandybridge, isso dura para sempre. Por exemplo, todos addsd xmm1, xmm0
teriam um ciclo extra de latência da entrada xmm1 para a saída xmm1 se xmm0 viesse pcmpeqd
, mesmo que isso tenha sido há muito tempo e o uop SIMD inteiro já tenha se aposentado.)
Você pode até fazê-lo sem ramificações se usar cmpsd
ou cmppd
: pode orps
mascarar 0 / -1 em um resultado para torná-lo NaN ou inalterado. Se algum outro cálculo (ou já tiver) definido o sinalizador de FP inválido, ou se você não se importa com isso, está tudo pronto.
Cuidado ao prolongar o caminho crítico com extra cmp / ou; se você acha que é super raro, você ainda pode comparar e ramificar, por exemplo, com movmskpd
/ test eax,eax
/ jnz
em um resultado cmppd para ver se um dos bits foi definido => um dos elementos SIMD falhou em alguma verificação.