SSE (SIMD): multiplier le vecteur par scalaire

Une opération courante que je fais dans mon programme est la mise à l’échelle de vecteurs par un scalaire (V * s, par exemple [1,2,3,4] * 2 == [2,4,6,8]). Existe-t-il une instruction SSE (ou AVX) pour cela, autre que de charger d’abord le scalaire à chaque position d’un vecteur (par exemple, _mm_set_ps (2,2,2,2)), puis de le multiplier?

C’est ce que je fais maintenant:

__m128 _scalar = _mm_set_ps(s,s,s,s); __m128 _result = _mm_mul_ps(_vector, _scalar); 

Je cherche quelque chose comme …

 __m128 _result = _mm_scale_ps(_vector, s); 

Selon votre compilateur, vous pourrez peut-être améliorer un peu la génération de code en utilisant _mm_set1_ps :

 const __m128 scalar = _mm_set1_ps(s); __m128 result = _mm_mul_ps(vector, scalar); 

Cependant, des constantes scalaires comme celle-ci ne doivent être initialisées qu’une seule fois, en dehors de toute boucle, de sorte que le coût de performance ne soit pas pertinent. (Sauf si la valeur scalaire change dans la boucle?)

Comme toujours, vous devriez regarder le code généré par votre compilateur et essayer également de l’exécuter sous un profileur adéquat pour voir où se trouvent réellement les points chauds.

Il n’y a pas d’instruction pour la multiplication d’un vecteur par un scalaire. Là, cependant, quelques instructions pour charger les mêmes valeurs scalaires dans toutes les positions d’un registre vectoriel.

Le jeu d’instructions AVX fournit les _mm_broadcast_ss insortingnsèques _mm_broadcast_ss / _mm256_broadcast_ss / _mm256_broadcast_sd pour le _mm256_broadcast_sd des registres SSE et AVX avec les mêmes valeurs float / double.

Dans le jeu d’instructions SSE3, vous pouvez trouver _mm_loaddup_pd insortingnsèque qui renseigne le registre SSE avec la même valeur double.

Dans les autres versions de SSE, la meilleure option consiste généralement à charger une valeur scalaire à l’aide de _mm_load_ss / _mm_load_sd , puis à la copier dans tous les éléments d’un registre vectoriel avec _mm_shuffle_ps / _mm_unpacklo_pd .

Je ne connais aucune instruction qui fasse ce que vous voulez. Est-ce que l’opération du set est vraiment un goulot d’étranglement? Si vous multipliez un grand vecteur par la même constante, le temps nécessaire pour remplir un registre XMM / YMM avec quatre copies de la constante devrait être une très petite fraction du temps total pris.

En guise d’optimisation simple, si la constante est égale à 2 comme dans votre exemple, vous pouvez remplacer la multiplication par une instruction add à la place, sans requérir aucune constante.