12
votes

G ++ SSE Memory Alignement sur la pile

Je tente de ré-écrire un Raytracer à l'aide d'extensions Streaming SIMD. Mon Raytracer d'origine a utilisé l'assemblage intégré et les instructions forts> Mouvements forts> pour charger les données dans les registres XMM. J'ai lu que le compilateur intrinsique n'est pas significativement plus lent que l'assemblage en ligne (je suppose que je peux même gagner de la vitesse en évitant les accès à la mémoire non alignée), et beaucoup plus portable, je tente donc de migrer mon code SSE pour utiliser la intrinsèque de XMMintrin.h . La classe principale affectée est vectorielle, qui ressemble à ceci comme ceci:

#include "xmmintrin.h"
union vector {
    __m128 simd;
    float raw[4];
    //some constructors
    //a bunch of functions and operators
} __attribute__ ((aligned (16)));


5 commentaires

Si vous avez une version récente de g ++ qui prend en charge std :: aligned_storage , vous pouvez obtenir un stockage aligné de manière portable et fonctionnera également sur d'autres compilateurs aussi.


Et si vous contournez le syndicat et utilisez simplement le DIRECT __M128? Est-ce que cela change quelque chose?


Contourner entièrement l'Union en fait beaucoup plus douloureux d'accéder aux membres individuels. J'ai également une classe de vecteur Vectorpacket qui obtient plus d'avantages de la SSE que des vecteurs standard, mais comme exemple, mon analyse comparative indique qu'il est plus rapide que je puisse ajouter les membres d'un seul produit de points en série au lieu de mélanger à plusieurs reprises le registre à Ajouter tout en restant dans mon bloc SSE. Je ne connais pas std :: aligné_storage ; Cela dit, ma machine a g ++ 4.4.3, mais il y a une deuxième machine que j'espérais pouvoir pouvoir l'exécuter sur ce qui est verrouillé à 3.4.6.


logiciel.intel.com/en-us/forums/showThread. PHP? T = 63876 Notez-vous qu'elles couchent des types de M128. Vous pouvez également lancer M128 au tableau.


@Tanycorn: Non, (flotteur *) my_m128 est pas sûr. La propriété May-alias-quoi que ce soit des types de vecteur Intel ne va à une seule manière, juste comment vous pouvez accéder à n'importe quoi avec Char * , mais il n'est pas garanti d'accès à un Char [] avec un int * . (C'est sûr dans MSVC, qui est comme GCC -Fno-strict-aliasing , mais dans d'autres compilateurs, vous devez utiliser des syndicats ou la diffusion intrinsèque pour accéder aux éléments de vecteurs.) Voir Print une variable __m128i pour un exemple.


5 Réponses :


0
votes

Si vous avez besoin d'un tableau de N de ces objets, allocation Vecteur RAW [N + 1] et utilisez Vector * Constry Array = Reterpret_cast (REINTPRET_CAST (RAW + 1) & ~ 15) comme adresse de base de votre tableau. Cela sera toujours aligné.


2 commentaires

Mon problème principal est de déclarer des instances locales de ces objets - je n'ai pas réellement besoin d'un tableau d'entre eux.


@Octavianus: Cela peut certainement être utilisé pour N = 1, vous avez juste une plus grande quantité de frais généraux.



6
votes

Le moyen le plus simple est std :: aligné_storage , qui prend un alignement en tant que second paramètre.

Si vous ne l'avez pas encore, vous voudrez peut-être vérifier La version de Boost .

alors vous pouvez construire Votre syndicat: xxx

Enfin, si cela ne fonctionne pas, vous pouvez toujours créer votre propre petite classe: xxx

Il allouera un peu plus de stockage que nécessaire, mais de cette manière l'alignement est garanti. xxx

avec chance, le compilateur peut être capable d'optimiser le truc d'alignement du pointeur s'il détecte L'alignement est nécessaire correctement.


2 commentaires

Cela semble attrayant, mais où puis-je trouver std :: aligné_storage? Google a été violemment inutile; Il suggère des types_Traits mais y compris cela ne me permet pas de compiler avec elle. Est aligné_storage si nouveau que g ++ 4.4.3 ne le supporte pas?


@Octavianus: possible, je n'ai pas g ++ 4.4.3 à portée de main. Peut-être devriez-vous essayer d'utiliser std :: tr1 :: aligned_storage à la place (dans )



1
votes

J'utilise ce truc de l'Union tout le temps avec __ m128 et fonctionnait avec GCC sur Mac et Visual C ++ sous Windows, il faut donc être un bogue dans le compilateur que vous utilisez.

Les autres réponses contiennent de bonnes soluarardages cependant.


4 commentaires

Ce n'est pas un bug de compilateur. De nombreuses machines sont par défaut à 16 octets d'alignement sur la pile, mais certaines machines plus anciennes ne garantissent rien au-dessus de 8 octets.


__M128 garantit un alignement de 16 octets


Oui. Mais si vous le collez dans une structure, il semble de garantir l'alignement de 16 octets par rapport au début de la structure.


@Octavianus: Alors c'est un bug de compilateur. Alignof (Union) doit être> = Alignof () Son membre le plus aligné.



2
votes

Normalement, tout ce dont vous avez besoin est:

union vector {
    __m128 simd;
    float raw[4];
};


0 commentaires

3
votes

Il y a quelques semaines, j'avais réécrit une mission de traçage de la vieille rayon de mes journées universitaires, à la mettre à jour pour l'exécuter sur 64 bits Linux et à utiliser les instructions SIMD. (L'ancienne version a été incidemment dirigée sous DOS sur un 486, pour vous donner une idée de quand je l'ai fait quand je l'ai fait).

Il y a très bien peut-être de meilleures façons de le faire, mais voici ce que j'ai fait ... P>

typedef float    v4f_t __attribute__((vector_size (16)));

class Vector {
    ...
    union {
        v4f_t     simd;
        float     f[4];
    } __attribute__ ((aligned (16)));

    ...
};


2 commentaires

Le __M128 TypeDEF est identique à votre typlef pour v4f_t, c'est donc ce que j'ai peur.


@OCTAVIANUS: le __ M128 TLEDEF comprend également l'attribut May_alias , ce qui permet de créer des points sûrs pour créer __ m128 * des pointeurs sur n'importe quel objet arbitraire, même non - float . (c'est-à-dire que c'est comme char * peut alias sur n'importe quoi). Mais ouais, __ attribut __ ((aligné (16))) sur l'Union est redondant; Il a déjà cela à partir du v4f_t ou du membre __ m128 . De plus, la syntaxe de vecteur native GNU C permet d'indexer dans un __ m128 v comme V [3] , de sorte que l'Union est redondante. (Sauf pour y accéder avec un float * ; la chose stricte d'aliasing ne va pas dans les deux sens. Ou pour MSVC Compat.)