Я оптимизирую некоторый код для микроархитектуры Intel x86 Nehalem, используя встроенные функции SSE.
Часть моей программы вычисляет 4 скалярных произведения и добавляет каждый результат к предыдущим значениям в непрерывной части массива. В частности,
tmp0 = _mm_dp_ps(A_0m, B_0m, 0xF1);
tmp1 = _mm_dp_ps(A_1m, B_0m, 0xF2);
tmp2 = _mm_dp_ps(A_2m, B_0m, 0xF4);
tmp3 = _mm_dp_ps(A_3m, B_0m, 0xF8);
tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);
tmp0 = _mm_add_ps(tmp0, C_0n);
_mm_storeu_ps(C_2, tmp0);
Обратите внимание, что я собираюсь использовать 4 временных регистра xmm для хранения результата каждого скалярного произведения. В каждом регистре xmm результат помещается в уникальные 32 бита относительно других временных регистров xmm, так что конечный результат выглядит следующим образом:
tmp0= R0-ноль-ноль-ноль
tmp1=ноль-R1-ноль-ноль
tmp2=ноль-ноль-R2-ноль
tmp3=ноль-ноль-ноль-R3
Я объединяю значения, содержащиеся в каждой переменной tmp, в одну переменную xmm, суммируя их со следующими инструкциями:
tmp0 = _mm_add_ps(tmp0, tmp1);
tmp0 = _mm_add_ps(tmp0, tmp2);
tmp0 = _mm_add_ps(tmp0, tmp3);
Наконец, я добавляю регистр, содержащий все 4 результата скалярных произведений, в непрерывную часть массива, чтобы индексы массива увеличивались на скалярное произведение, например так (C_0n — это 4 значения, которые в настоящее время находятся в массиве, который необходимо обновить ; C_2 — это адрес, указывающий на эти 4 значения):
tmp0 = _mm_add_ps(tmp0, C_0n);
_mm_storeu_ps(C_2, tmp0);
Я хочу знать, есть ли менее окольный, более эффективный способ взять результаты точечных произведений и добавить их к непрерывному фрагменту массива. Таким образом, я делаю 3 сложения между регистрами, в которых есть только одно ненулевое значение. Кажется, должен быть более эффективный способ сделать это.
Я ценю любую помощь. Спасибо.