Преобразование (векторизация) кода с 32-битным условным элементом в SSE2 SSE3

Я хочу векторизовать код для Core2. Я думаю, я могу использовать встроенные функции из gcc или icc, и разрешены инструкции SSE, SSE2, SSE3, SSSE3.

Мой код работает с массивами из 8 элементов uint32_t, и он такой (здесь только точка доступа):

const uint32_t p[8] = {2147483743, 2147483713, 2147483693, 2147483659, 
 2147483647, 2147483629, 2147483587, 2147483579};
void vector_mod_add(uint32_t *a /* a[8] */, uint32_t *b /* b[8] */) {
    int n;
    for(n=0;n<8;n++)
        a[n]+=b[n];
    for(n=0;n<8;n++)
        if(a[n]>=p[n])
            a[n]-=p[n];
}

Сложение довольно просто, но я не знаю, как можно сделать условное вычитание.

Также у меня нет опыта ручной векторизации с SSE2, поэтому, пожалуйста, подскажите, как мне определить здесь все типы.


person osgx    schedule 13.03.2011    source источник


Ответы (1)


Вы можете написать это как a[n] -= p[n] & ~(a[n] < p[n]). Обратите внимание, что < здесь не C, а SSE (pcmpltd), который возвращает -1 в каждом истинном элементе и 0 в каждом ложном элементе (чтобы разрешить операцию И), а &~ равно pandn. Вот попытка кода:

__m128i a, p;
a = _mm_sub_epi32(a, _mm_andnot_si128(_mm_cmplt_epi32(a, p), p));

Обратите внимание, что при этом используются операции со знаком, поэтому ваши числа должны оставаться ниже 2^31 - 1, чтобы все работало правильно. Если вам нужно пойти дальше, измените _mm_cmplt_epi32(a, p) на _mm_cmplt_epi32(_mm_xor_si128(a, signs), _mm_xor_si128(p, signs)), где signs — это вектор 32-битных слов, все элементы которого равны 0x80000000. Вот версия, которая, похоже, будет более эффективно обрабатывать более широкие диапазоны:

__m128i a, p;
a = _mm_sub_epi32(a, p);
a = _mm_add_epi32(a, _mm_and_si128(_mm_srai_epi32(a, 31), p));
person Jeremiah Willcock    schedule 13.03.2011
comment
но это вычтет a[n] из a[n], превратив его в ноль. Я хочу, чтобы каждый a[i] и b[i] находился в диапазоне 0..p[n]-1. Я могу закодировать это как if(a[n]>p[n]) или как a[n]=a[n]%p[n] - person osgx; 13.03.2011
comment
Также есть MINPD/MINSD, но он только для чисел с плавающей запятой, а у меня есть целые числа. - person osgx; 13.03.2011
comment
Можете ли вы перевести этот код с функциями из xmmintrin.h или других *intrin.h? - person osgx; 13.03.2011
comment
@osgx: Посмотрите, на что я только что это изменил. - person Jeremiah Willcock; 13.03.2011
comment
Хм... подписано - это плохая новость, так как я хочу использовать p почти такого же размера, как (2^31)-1. Сумма a и b часто больше 2^31. - person osgx; 13.03.2011
comment
@osgx: у меня есть версия, которая сейчас работает для этого случая, но она нуждается в некоторой оптимизации. Я подумаю об этом еще. - person Jeremiah Willcock; 13.03.2011
comment
@osgx: я только что добавил в конец кое-что новое; посмотрите, работает ли это. - person Jeremiah Willcock; 13.03.2011