Comment pouvez-vous insérer un NaN dans un registre xmm?

9

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?

Markus
la source
1
Comment déterminez-vous quelle «entrée n'a pas de sens»? Si c'est le résultat d'une comparaison, vous pouvez juste le bit ou votre résultat "normal" avec le masque de résultat de la comparaison.
chtz

Réponses:

13

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,xmm0pour 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 mulsspour la simple précision float. mulpd/ mulpsserait é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 mulsdou 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, xmm0aurait 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 cmpsdou 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/ jnzsur 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.

Peter Cordes
la source