exécution de fonctions insortingnsèques avec sse

Je commence actuellement avec SSE. La réponse à ma question précédente concernant SSE ( Vecteur multipliant par constante utilisant SSE ) m’a amené à tester la différence entre utiliser des éléments insortingnsèques tels que _mm_mul_ps() et simplement utiliser des “opérateurs normaux” (ne _mm_mul_ps() pas quel est le meilleur terme), comme * .

J’ai donc écrit deux cas de test qui ne diffèrent que par la manière dont le résultat est calculé:
Méthode 1:

 int main(void){ float4 a, b, c; av = _mm_set_ps(1.0f, 2.0f, 3.0f, 4.0f); bv = _mm_set_ps(-1.0f, -2.0f, -3.0f, -4.0f); printf("method 1\n"); cv = av + bv; // <--- print_vector(a); print_vector(b); printf("1.a) Computed output 1: "); print_vector(c); exit(EXIT_SUCCESS); } 

Méthode 2:

 int main(void){ float4 a, b, c; av = _mm_set_ps(1.0f, 2.0f, 3.0f, 4.0f); bv = _mm_set_ps(-1.0f, -2.0f, -3.0f, -4.0f); printf("\nmethod 2\n"); cv = _mm_add_ps(av, bv); // <--- print_vector(a); print_vector(b); printf("1.b) Computed output 2: "); print_vector(c); exit(EXIT_SUCCESS); } 

les deux cas de test partagent les éléments suivants:

 typedef union float4{ __m128 v; float x,y,z,w; } float4; void print_vector (float4 v){ printf("%f,%f,%f,%f\n", vx, vy, vz, vw); } 

Donc, pour comparer le code généré pour les deux cas, j’ai compilé en utilisant:
gcc -ggdb -msse -c t_vectorExtensions_method1.c

Ce qui a abouti à (montrant seulement la partie où les deux vecteurs sont ajoutés – ce qui diffère):
Méthode 1:

  cv = av + bv; a1: 0f 57 c9 xorps %xmm1,%xmm1 a4: 0f 12 4d d0 movlps -0x30(%rbp),%xmm1 a8: 0f 16 4d d8 movhps -0x28(%rbp),%xmm1 ac: 0f 57 c0 xorps %xmm0,%xmm0 af: 0f 12 45 c0 movlps -0x40(%rbp),%xmm0 b3: 0f 16 45 c8 movhps -0x38(%rbp),%xmm0 b7: 0f 58 c1 addps %xmm1,%xmm0 ba: 0f 13 45 b0 movlps %xmm0,-0x50(%rbp) be: 0f 17 45 b8 movhps %xmm0,-0x48(%rbp) 

Méthode 2:

  cv = _mm_add_ps(av, bv); a1: 0f 57 c0 xorps %xmm0,%xmm0 a4: 0f 12 45 a0 movlps -0x60(%rbp),%xmm0 a8: 0f 16 45 a8 movhps -0x58(%rbp),%xmm0 ac: 0f 57 c9 xorps %xmm1,%xmm1 af: 0f 12 4d b0 movlps -0x50(%rbp),%xmm1 b3: 0f 16 4d b8 movhps -0x48(%rbp),%xmm1 b7: 0f 13 4d f0 movlps %xmm1,-0x10(%rbp) bb: 0f 17 4d f8 movhps %xmm1,-0x8(%rbp) bf: 0f 13 45 e0 movlps %xmm0,-0x20(%rbp) c3: 0f 17 45 e8 movhps %xmm0,-0x18(%rbp) /* Perform the respective operation on the four SPFP values in A and B. */ extern __inline __m128 __atsortingbute__((__gnu_inline__, __always_inline__, __artificial__)) _mm_add_ps (__m128 __A, __m128 __B) { return (__m128) __builtin_ia32_addps ((__v4sf)__A, (__v4sf)__B); c7: 0f 57 c0 xorps %xmm0,%xmm0 ca: 0f 12 45 e0 movlps -0x20(%rbp),%xmm0 ce: 0f 16 45 e8 movhps -0x18(%rbp),%xmm0 d2: 0f 57 c9 xorps %xmm1,%xmm1 d5: 0f 12 4d f0 movlps -0x10(%rbp),%xmm1 d9: 0f 16 4d f8 movhps -0x8(%rbp),%xmm1 dd: 0f 58 c1 addps %xmm1,%xmm0 e0: 0f 13 45 90 movlps %xmm0,-0x70(%rbp) e4: 0f 17 45 98 movhps %xmm0,-0x68(%rbp) 

Il est évident que le code généré lors de l’utilisation de la _mm_add_ps() insortingnsèque est beaucoup plus volumineux. Pourquoi est-ce? Ne devrait-il pas en résulter un meilleur code?

Tout ce qui compte vraiment, c’est les addps . Dans un cas d’utilisation plus réaliste, où vous pourriez append, par exemple, deux grands vecteurs de flottants dans une boucle, le corps de la boucle ne contiendra que des addps , deux charges et un magasin, ainsi que des instructions entières scalaires pour l’arithmétique d’adresse. Sur un processeur superscalaire moderne, plusieurs de ces instructions seront exécutées en parallèle.

Notez également que vous comstackz avec l’optimisation désactivée, vous n’obtiendrez donc pas un code particulièrement efficace. Essayez gcc -O3 -msse3 ...