Где хранятся результаты SSE2? - PullRequest
0 голосов
/ 12 декабря 2018

Я перемещаю первые шаги в SSE2 в C ++. Вот встроенное, которое я изучаю прямо сейчас:

__m128d _mm_add_pd (__m128d a, __m128d b)

В документе говорится: Добавление упакованных элементов с плавающей запятой двойной точности (64-разрядных) в a и bи сохраните результаты в формате dst.

Но я никогда не передаю dst этой функции.Так как же добавить два двойных I прохода (через указатель) к результирующему массиву, если я не передаю его?

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

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

Здесь важно отметить, что большинство инструкций SIMD не работают напрямую спамяти, но вам нужно явно загрузить (_mm_load(u)_pd) и сохранить (_mm_store(u)_pd) двойные значения, как, например, при сборке.Промежуточные значения, скорее всего, будут храниться в регистрах SSE или, если используется слишком много регистров, в стеке.

Поэтому, если вы хотите суммировать два двойных массива, вы должны сделать что-то вроде

double a[N];
double b[N];
double c[N];
for (int i = 0; i < N; i += 2) {  // We load two doubles every time
    auto x = _mm_loadu_pd(a + i); // We don't know anything about alignment
    auto y = _mm_loadu_pd(b + i); // So I assume the load is unaligned
    auto sum = _mm_add_pd(x, y);  // Compute the vector sum
    _mm_storeu_pd(c + i, sum);    // The store is unaligned as well
}
0 голосов
/ 12 декабря 2018

Описание "хранить результаты в dst" немного вводит в заблуждение.Встроенная функция возвращает результат добавления вектора в виде значения типа __m128d.

__m128d arg1 = ...;
__m128d arg2 = ...;
__m128d result = _mm_add_pd(arg1, arg2);

Если вы вызываете переменную dst вместо result, то у вас есть код, который соответствует описанию,(Но вы можете называть это как хотите.)

Базовая инструкция SSE, ADDPD, сохраняет результат операции в выбранном регистре XMM.Компилятор выполняет распределение регистров (и даже сохраняет / перезагружает переменные вектора C, если у него заканчиваются регистры, или вокруг вызова функции, которая блокирует векторные регистры).

Встроенные функции работают с переменными C, как и + и * с типами int или float.Обычно они компилируются в asm-инструкции, которые работают с регистрами (или, может быть, операндом источника памяти, если он объединяет нагрузку и добавляет встроенную функцию), но оставляя все это компилятору - это смысл использования встроенных функций.

Вы действительно хотитенаписать свой код так, чтобы он мог эффективно компилироваться, хотя: если более 16 __m128 переменных «живы» одновременно, компилятору придется пролить / перезагрузить их.

...