Использование множества встроенных функций, таких как _mm_set_epi32
для всех элементов, неэффективно. Лучше использовать функции загрузки. См. Это обсуждение для получения более подробной информации об этом Where does the SSE instructions outperform normal instructions. Если массивы выровнены по 16 байт, вы можете использовать либо _mm_load_si128
, либо _mm_loadu_si128
(для выравниваемой памяти они имеют почти такую же эффективность), в противном случае используйте _mm_loadu_si128
. Но выровненная память намного эффективнее. Чтобы получить выровненную память, я рекомендую _mm_malloc
и _mm_free
, или C11 aligned_alloc
, поэтому вы можете использовать обычный free
.
Чтобы ответить на остальную часть вашего вопроса, предположим, у вас есть два вектора, загруженные в SSE регистры __m128i a
и __m128i b
Для SSE версии> = SSE4.1 использовать
_mm_mullo_epi32(a, b);
Без SSE4.1:
Этот код копируется из Agner Туман-х Vector Class Library (и была списана первоначальным автором этого ответа):
// Vec4i operator * (Vec4i const & a, Vec4i const & b) {
// #ifdef
__m128i a13 = _mm_shuffle_epi32(a, 0xF5); // (-,a3,-,a1)
__m128i b13 = _mm_shuffle_epi32(b, 0xF5); // (-,b3,-,b1)
__m128i prod02 = _mm_mul_epu32(a, b); // (-,a2*b2,-,a0*b0)
__m128i prod13 = _mm_mul_epu32(a13, b13); // (-,a3*b3,-,a1*b1)
__m128i prod01 = _mm_unpacklo_epi32(prod02,prod13); // (-,-,a1*b1,a0*b0)
__m128i prod23 = _mm_unpackhi_epi32(prod02,prod13); // (-,-,a3*b3,a2*b2)
__m128i prod = _mm_unpacklo_epi64(prod01,prod23); // (ab3,ab2,ab1,ab0)
Даже если компилятор * может * сделать вывод о размере, выравнивании и т. Д., Чтобы удовлетворить векторизацию, я сомневаюсь, что он будет использовать SSE здесь из-за нагрузки/затраты на хранение. –
Вы знаете о '_mm_mul_ps'? – rwols
@rwols: 'mulps' делает однократное умножение, OP хочет беззнаковое целочисленное умножение. – Skizz