Pour la fonction que j'écris, je voudrais retourner un Nan si l'entrée n'a pas de sens.
Comment puis-je insérer un NaN dans un registre xmm de la manière la plus simple?
Pour la fonction que j'écris, je voudrais retourner un Nan si l'entrée n'a pas de sens.
Comment puis-je insérer un NaN dans un registre xmm de la manière la plus simple?
Réponses:
Tout-en-un est un NaN silencieux (sans signalisation, alias normal), ce que vous voulez. La façon la plus simple d'en produire un est d'utiliser SSE2 pcmpeqd xmm0,xmm0
pour définir chaque bit du registre 1
, c'est- à -dire l'entier complémentaire de 2 -1
. ( Réglez tous les bits du registre CPU à 1 efficacement / Quelles sont les meilleures séquences d'instructions pour générer des constantes vectorielles à la volée? )
C'est en fait un -NaN
- le bit de signe est réglé. Envisagez un décalage à droite entier ( psrld xmm0,1
) ou divisez par zéro / zéro ( xorps xmm0,xmm0
/ divpd xmm0,xmm0
) si cela n'est pas souhaitable.
Les fonctions mathématiques qui veulent renvoyer NaN veulent souvent également s'assurer que le bit d'exception rémanente non valide FP est défini dans MXCSR (ou déclenche réellement une exception si votre appelant a démasqué cette exception). Pour ce faire que , vous pouvez multiplier ou ajouter le NaN avec lui - même. par exemple
...
.error_return_path:
pcmpeqd xmm0, xmm0
mulsd xmm0, xmm0 ; Cause an FP-invalid operation.
ret
Ou mulss
pour la simple précision float
. mulpd
/ mulps
serait également approprié.
Le modèle de bits pour la multiplication ou l'ajout de NaN avec NaN est certainement toujours un NaN, et devrait toujours être la même charge utile, donc toujours tout-en-un.
Le fait que la valeur de retour soit le résultat de mulsd
ou addsd
(ou divsd
) présente également l'avantage que si l'appelant utilise ce registre à plusieurs reprises dans une boucle, il n'aura pas de latence de contournement de domaine. (Sur la famille Sandybridge, cela dure éternellement. Par exemple, tout le monde addsd xmm1, xmm0
aurait un cycle de latence supplémentaire de l'entrée xmm1 à la sortie xmm1 si xmm0 venait depcmpeqd
, même si c'était il y a longtemps et que l'uop entier-SIMD a déjà pris sa retraite.)
Vous pourriez même le faire sans branchement si vous utilisez cmpsd
ou cmppd
: vous pouvezorps
transformer ce masque 0 / -1 en résultat pour le rendre NaN ou inchangé. Si un autre calcul définira (ou aura déjà) défini l'indicateur FP-invalide, ou si vous ne vous souciez pas de cela, vous êtes tous définis.
Méfiez-vous d'allonger le chemin critique avec cmp supplémentaire ou; si vous vous attendez à ce qu'il soit super rare, vous pouvez toujours comparer et créer des branches, par exemple avec movmskpd
/ test eax,eax
/ jnz
sur un résultat cmppd pour voir si l'un ou l'autre bit a été défini => l'un des éléments SIMD a échoué une vérification.