SSE Загрузка и добавление - PullRequest
       37

SSE Загрузка и добавление

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

Предположим, у меня есть два вектора, представленные двумя массивами типа double, каждый размером 2. Я хотел бы добавить соответствующие позиции.Итак, предположим, что векторы i0 и i1, я хотел бы добавить i0[0] + i1[0] и i0[1] + i1[1] вместе.

Поскольку типом является double, мне понадобятся два регистра.Хитрость заключается в том, чтобы поместить i0[0] и i1[0], i0[1] и i1[1] в другое и просто добавить регистр вместе с ним.

Мой вопрос: если я позвоню _mm_load_ps(i0[0])_mm_load_ps(i1[0]), будет ли это помещать их в нижний и верхний 64-разрядные по отдельности или он заменит регистр вторым load?Как бы я поместил оба дабла в один и тот же регистр, чтобы я мог позвонить add_ps после?

Спасибо,

Ответы [ 2 ]

7 голосов
/ 13 февраля 2012

Я думаю, что вы хотите, это:

double i0[2];
double i1[2];

__m128d x1 = _mm_load_pd(i0);
__m128d x2 = _mm_load_pd(i1);
__m128d sum = _mm_add_pd(x1, x2);
// do whatever you want to with "sum" now

Когда вы делаете _mm_load_pd, он помещает первый дубль в младшие 64 бита регистра, а второй - в старшие 16 бит. Таким образом, после указанных выше нагрузок x1 содержит два значения double i0[0] и i0[1] (и аналогично для x2). Вызов _mm_add_pd по вертикали добавляет соответствующие элементы в x1 и x2, поэтому после сложения sum содержит i0[0] + i1[0] в своих младших 64 битах и ​​i0[1] + i1[1] в своих старших 64 битах.

Редактировать: Я должен отметить, что использование _mm_load_pd вместо _mm_load_ps не имеет смысла. Как показывают названия функций, разновидность pd явно загружает два упакованных типа double, а версия ps загружает четыре упакованных числа с одинарной точностью. Поскольку это чисто побитовые перемещения памяти, и они оба используют единицу с плавающей запятой SSE, использование _mm_load_ps для загрузки данных double не штрафует. И у _mm_load_ps есть преимущество: его кодирование команд на один байт короче _mm_load_pd, поэтому оно более эффективно с точки зрения кэша команд (и, возможно, декодирования команд; я не эксперт по всем сложностям современных процессоров x86). Код выше с использованием _mm_load_ps будет выглядеть так:

double i0[2];
double i1[2];

__m128d x1 = (__m128d) _mm_load_ps((float *) i0);
__m128d x2 = (__m128d) _mm_load_ps((float *) i1);
__m128d sum = _mm_add_pd(x1, x2);
// do whatever you want to with "sum" now

Приведения не подразумевают никакой функции; он просто заставляет компилятор переосмысливать содержимое регистра SSE как удерживающее double вместо плавающих, так что его можно передать в арифметическую функцию двойной точности _mm_add_pd.

3 голосов
/ 13 февраля 2012

Префикс _ps является аббревиатурой для «упакованный одинарный» , что означает, что он используется с плавающей точкой одинарной точности, а не с двойной точностью.

Вместо этого вы хотите _mm_load_pd(). Эта функция берет 16-байтовый выровненный указатель на первый член массива из двух double s и загружает их обоих. Так что вы бы использовали это так:

__m128d v0 = _mm_load_pd(i0);
__m128d v1 = _mm_load_pd(i1);

v0 = _mm_add_pd(v0, v1);
...