2016-10-25 1 views
0

J'essaie de faire des calculs avec des nombres complexes à virgule flottante, en utilisant les unités vectorielles __m128. Avec __m128 je peux stocker deux complex float, car chaque nombre complexe se compose de deux nombres à virgule flottante, une partie réelle et une partie imaginaire.Charger et stocker des flottants complexes avec Intel intrinsics dans C

Jusqu'ici, tout va bien.

Mon problème se pose quand je dois «recueillir» mes réponses en uncomplex float. Dites que j'ai deux vecteurs __m128, et quatre nombres complexes stockés dans ces deux vecteurs. Par exemple, je peux ajouter deux vecteurs (deux et deux flottants) ensemble en utilisant le _mm_add_ps intrinsèque, mais comment puis-je "réduire" les deux nombres complexes dans le vecteur de résultat à un nombre complexe (deux float s) et le stocker dans un tableau? De même, si je veux saisir un nombre complexe de mon tableau et le stocker deux fois dans un vecteur (la partie réelle dans le 1er et 3ème bloc, et la partie imaginaire dans le 2ème et le 4ème bloc), comment pouvez-vous J'accomplis cela?

Répondre

0

Ne stockez pas vos numéros complexes au format entrelacé/compressé en premier lieu, si vous souhaitez utiliser SIMD sur eux. Stockez les pièces réelles et les pièces imaginaires dans des tableaux séparés, de sorte que vous pouvez faire quatre multiplications complexes en parallèle sans aucun brassage (ou des opérations horizontales lentes comme HSUBPS).

Pour répondre directement à la question: est-ce the first stage of a horizontal sum: amener le 64 haut vers le bas à la faible 64 d'un autre vecteur (avec _mm_movehl_ps), puis _mm_add_ps, comme indiqué dans ma réponse à cette question.

Ensuite, vous pouvez MOVLPS pour stocker les 2 bas flotteurs: void _mm_storel_pi (__m64 *p, __m128 a). Il semblerait que vous ayez besoin d'un casting ennuyeux pour l'utiliser:/MOVSD fonctionnerait aussi, mais prend un octet de plus à encoder.


Et de même, si je veux saisir un nombre complexe de mon tableau et stocker deux fois dans un vecteur

Utilisez MOVDDUP pour diffuser 64 bits de mémoire ou d'un autre registre. Vous aurez besoin d'un casting d'utiliser les valeurs intrinsèques, mais c'est très bien (ils ne seront pas à compiler toutes les instructions, et en utilisant des instructions double comme MOVDDUP sur des données float n'a pas pénalité à la CPU existante):

__m128d _mm_loaddup_pd(double const * dp); 
__m128d _mm_movedup_pd(__m128d a); 

A moins il a une charge intrinsèque, contrairement à PMOVZX (this design flaw is one of my major pet peeves with intrinsics).