Como você pode inserir um NaN em um registro xmm?

9

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?

Markus
fonte
11
Como você determina qual "entrada não faz sentido"? Se este é o resultado de uma comparação, você pode apenas bit a bit - ou seu resultado "normal" com a máscara de resultado da comparação.
chtz 21/01

Respostas:

13

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,xmm0para 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 mulsspara precisão única float. mulpd/ mulpstambé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 mulsdou 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, xmm0teriam 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 cmpsdou cmppd: pode orpsmascarar 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/ jnzem um resultado cmppd para ver se um dos bits foi definido => um dos elementos SIMD falhou em alguma verificação.

Peter Cordes
fonte