7
votes

Comment lancer Simd Int vecteurs pour flotter dans GCC?

J'utilise l'extension de vecteur Simd GCC pour un projet, tout fonctionne assez bien mais jette simplement, ils réinitialisent simplement tous les composants d'un vecteur.

the manuel états:

Il est possible de lancer d'un type de vecteur à un autre, à condition qu'ils soient de la même taille (en fait, vous pouvez également lancer des vecteurs vers et à partir d'autres types de données de la même taille).

Voici un exemple simple: xxx

compilation avec GCC Cast.c -O3 -O coule et exécuté sur ma machine Je reçois: xxx

Je ne suis pas ce garu assembleur mais je viens de voir quelques mouvements d'octets ici: xxx

i Suspectez l'équivalent de vecteur du scalaire: xxx

Comment pouvez-vous expliquer ce comportement?


7 commentaires

Oui, c'est ce à quoi on dirait se produit - une conversion bitwise. (ou plutôt, pas de conversion du tout) afin que vous obteniez 4 flotteurs dénormalisés au lieu d'une conversion de valeur réelle.


C'est ce que les couts de vecteur sont définis à faire (tout ce qui serait complètement bonkers et ferait des idiomes de programmation vectorielle standard très douloureux à écrire). Si vous voulez réellement obtenir une conversion, vous voudrez probablement utiliser un intrinsèque d'une sorte, comme _mm_cvtepi32_ps (ceci brise la belle indépendance architecturale de votre code de vecteur, bien sûr, qui est également ennuyeux. ; une approche commune consiste à utiliser un en-tête de traduction qui définit un ensemble portable de "intrinsics").


Je peux voir votre point, mais la question devient: quand cela casser serait utile?


@Cyrus le croit ou non, j'utilise réellement cela (bitwise) coulé plus souvent qu'une valeur de la valeur.


@Stephencanon Si vous voulez transformer ce commentaire dans une réponse, je serai heureux de l'accepter.


@Stephencanon j'ai essayé _mm_cvtepi32_ps, mais il n'est pas autorisé à moins que les conversions vectorielles, mais cette option ne doit pas être utilisée pour le nouveau code. Que faire à la place?


@ user877329 Vous avez besoin d'une distribution et de l'intrinsèque sur la machine GCC plus récente (il s'agit de Bonehed of the GCC Devs, mais c'est ce qu'il est): _mm_cvtepi32_ps ((__ m128i) x)


3 Réponses :


9
votes

C'est ce que les moulages de vecteur sont définis à faire (tout ce qui serait complètement bonkers et ferait des idiomes de programmation vectorielle standard très douloureux à écrire). Si vous voulez réellement obtenir une conversion, vous voudrez probablement utiliser un intrinsèque d'une sorte, comme _MM_CVTEPI32_PS (cela enfreint la belle indépendance architecturale de votre code de vecteur, ce qui est également ennuyeux; une approche commune est d'utiliser une en-tête de traduction qui définit un ensemble portable de "intrinsics").

Pourquoi est-ce utile? Une variété de raisons, mais voici le plus grand:

Dans le code de vecteur, vous ne voulez presque jamais brancher. Au lieu de cela, si vous avez besoin de faire quelque chose de conditionnellement, vous évaluez les deux côtés de la condition et utilisez un masque pour sélectionner la voie de résultat appropriée de la voie. Ces vecteurs de masque "naturellement" ont un type d'entier, alors que vos vecteurs de données sont souvent des points flottants; Vous voulez combiner les deux opérations logiques. Cet idiome extrêmement courant est le plus naturel si les lancers de vecteur réintroduisent simplement les bits.

accordé, il est possible de contourner ce cas, ou n'importe lequel d'un sac d'autres idiomes de vecteur commun, mais le vecteur est un sac de bits "est extrêmement courant et reflète la façon dont la plupart des programmeurs vectoriels pensent.


0 commentaires

2
votes

En fait, aucune instruction vectorielle unique n'est même générée dans votre cas et qu'aucun document n'est même pas effectué au moment de l'exécution. Tout cela s'est fait lors de la compilation en raison du commutateur -O3 code>. Les quatre MOVSD code> sont en train de charger les arguments préconvertis sur printf code>. En effet, selon le SYSV AMD64 ABI, des arguments à virgule flottante sont transmis dans les registres XMM. La section que vous avez désassemblée est (code d'assemblage obtenu en compilant avec -s code>): xxx pré>

.LC5 code> étiquette la chaîne de format: p> xxx pré>

Le pointeur sur la chaîne de format est de classe integer code> et est donc transmis dans le registre rdi code> registre (être quelque part Dans la première 4 gibières de l'espace VA, certains octets de code sont enregistrés en émettant un déplacement 32 bits à la partie inférieure de RDI code>). Registre RAX code> ( EAX code> utilisé pour enregistrer les octets de code) est chargé avec le nombre d'arguments transmis dans les registres XMM (à nouveau en fonction de l'ABI SYSV AMD64 pour les appels aux fonctions avec des fonctions avec nombre variable d'arguments). Tous les quatre MOVSD CODE> (déplacez la double précision scalaire) Déplacez les arguments correspondants dans les registres XMM. .LC9 code> par exemple étiquettes Deux Motswords: P>

    movss   -20(%rbp), %xmm0
    unpcklps        %xmm0, %xmm0
    cvtps2pd        %xmm0, %xmm3


1 commentaires

Merci pour la clarification!



2
votes

Vous pouvez lancer de INT pour flotter en bouchent sur les éléments directement xxx

gcc, clang et icc générant une instruction cvtdq2ps xmm0, xmm0 pour cela .

https://godbolt.org/g/ku1apg


0 commentaires