SSE (SIMD): умножить вектор на скаляр - PullRequest
19 голосов
/ 31 января 2012

Обычная операция, которую я выполняю в своей программе, - это масштабирование векторов скаляром (V * s, например, [1,2,3,4] * 2 == [2,4,6,8]).Есть ли для этого инструкция SSE (или AVX), кроме первой загрузки скаляра в каждой позиции в векторе (например, _mm_set_ps (2,2,2,2)), а затем умножения?

Эточто я делаю сейчас:

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

Я ищу что-то вроде ...

__m128 _result = _mm_scale_ps(_vector, s);

Ответы [ 3 ]

13 голосов
/ 31 января 2012

В зависимости от вашего компилятора вы можете немного улучшить генерацию кода, используя _mm_set1_ps:

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

Однако подобные скалярные константы нужно инициализировать только один раз, вне каких-либо циклов,поэтому стоимость работы должна быть неактуальной.(Если скалярное значение не изменяется в цикле?)

Как всегда, вы должны посмотреть на код, сгенерированный вашим компилятором, а также попробовать запустить код под приличным профилировщиком, чтобы увидеть, где в действительности находятся горячие точки.

4 голосов
/ 02 февраля 2012

Нет инструкции по умножению вектора на скаляр.Однако есть некоторые инструкции для загрузки одинаковых скалярных значений во все позиции в векторном регистре.

Набор команд AVX обеспечивает _mm_broadcast_ss / _mm256_broadcast_ss / _mm256_broadcast_sd встроенных функций для заполнения регистров SSE и AVX с помощьюто же самое число с плавающей запятой / double.

В наборе команд SSE3 вы можете найти _mm_loaddup_pd intrinsic, который заполняет регистр SSE тем же двойным значением.

В других версиях SSE обычно лучшим вариантом являетсязагрузите скалярное значение, используя _mm_load_ss / _mm_load_sd, а затем скопируйте его во все элементы векторного регистра с помощью _mm_shuffle_ps / _mm_unpacklo_pd.

1 голос
/ 31 января 2012

Я не знаю ни одной инструкции, которая делает то, что вы хотите.Является ли операция множества узким местом?Если вы умножаете большой вектор на одну и ту же константу, то время, необходимое для заполнения регистра XMM / YMM четырьмя копиями константы, должно составлять очень небольшую долю общего времени, затраченного на это.

Какпростая оптимизация, если константа равна 2, как это было в вашем примере, вы можете заменить умножение на инструкцию add, не требуя никакой константы.

...