2013-10-06 8 views
2

Каков самый быстрый способ выполнить операцию поворота во всем регистре YMM на сумму, известную только во время выполнения?SIMD вращаться переменной

Вращение известно кратным 64 битам.

ответ

3

С AVX2 вы можете использовать _mm256_permutevar8x32_epi32. Псевдокод (не проверенный, константы, скорее всего, неверны):

static inline __m256i rotate(__m256i x, unsigned n) { 
    static const __m256i rotspec[4] = { 
     _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7), 
     _mm256_set_epi32(6, 7, 0, 1, 2, 3, 4, 5), 
     _mm256_set_epi32(4, 5, 6, 7, 0, 1, 2, 3), 
     _mm256_set_epi32(2, 3, 4, 5, 6, 7, 0, 1) 
    }; 
    return _mm256_permutevar8x32_epi32(x, rotspec[n]); 
} 
+1

Просто чтобы быть ясно, что это 'rotate_right (__ m256i х, неподписанные п) '. – TheCodeArtist

+0

как насчет только AVX? мой компьютер имеет только процессор моста из плюща. – Demi

+0

Вы можете использовать переключатель с 4 корпусами. Я не думаю, что есть эффективный способ сделать это с помощью AVX. –

1

Вы можете повернуть направо с помощью AVX следующим образом. Предположим, что ваш вклад составляет x:

__m256d t0 = _mm256_permute_pd(x, 0x05);   // [x2 x3 x0 x1] 
__m256d t1 = _mm256_permute2f128_pd(t0, t0, 0x01); // [x0 x1 x2 x3] 
__m256d y = _mm256_blend_pd(t0, t1, 0x0a);   // [x0 x3 x2 x1] 

В результате в y. Обращая маску смешивания можно повернуть налево:

__m256d t0 = _mm256_permute_pd(x, 0x05);   // [x2 x3 x0 x1] 
__m256d t1 = _mm256_permute2f128_pd(t0, t0, 0x01); // [x0 x1 x2 x3] 
__m256d y = _mm256_blend_pd(t0, t1, 0x05);   // [x2 x1 x0 x3] 
0

Есть четыре вращаетса: 0-бит, 64-бит, 128 бит и 192 бит. 0-бит тривиально. Решение Felix Whyss отлично подходит для 64-битных и 192-битных для AVX. Но для 128-битных оборотов вы можете просто поменять высокие и низкие 128-битные слова. Это лучшее решение для AVX и AVX2.

_mm256_permute2f128_pd (х, х, 0x01)

+0

Мне это действительно не нужно - только в остальных 3 случаях – Demi

1

Если вы ограничены в инструкции AVX, вы все еще можете использовать условную инструкцию смешивания (VBLENDVPD), чтобы выбрать правильное направление вращения без использования переключателя. Это, вероятно, быстрее, особенно если условие не может быть легко предсказано.

Полная реализация правого вращения (проверено):

// rotate packed double vector right by n 
__m256d rotate_pd_right(__m256d x, int n) { 
    __m128i c = _mm_cvtsi32_si128(n); 
    __m128i cc = _mm_unpacklo_epi64(c,c); 

    // create blend masks (highest bit) 
    __m128d half_low = _mm_castsi128_pd(_mm_slli_epi64(cc, 63)); 
    __m128d swap_low = _mm_castsi128_pd(_mm_slli_epi64(cc, 62)); 
    __m256d half = _mm256_insertf128_pd(_mm256_castpd128_pd256(half_low), half_low, 1); 
    __m256d swap = _mm256_insertf128_pd(_mm256_castpd128_pd256(swap_low), swap_low, 1); 

    // compute rotations 
    __m256d t0 = _mm256_permute_pd(x, 0x05);   // [2 3 0 1] 
    __m256d t1 = _mm256_permute2f128_pd(t0, t0, 0x01); // [1 0 2 3] 

    __m256d y0 = x;          // [3 2 1 0] 
    __m256d y1 = _mm256_blend_pd(t0, t1, 0x0a);   // [0 3 2 1] 
    __m256d y2 = _mm256_permute2f128_pd(x, x, 0x01); // [1 0 3 2] 
    __m256d y3 = _mm256_blend_pd(t0, t1, 0x05);   // [2 1 0 3] 

    // select correct rotation 
    __m256d y01 = _mm256_blendv_pd(y0, y1, half); 
    __m256d y23 = _mm256_blendv_pd(y2, y3, half); 
    __m256d yn = _mm256_blendv_pd(y01, y23, swap); 

    return yn; 
} 

Левый поворот может быть сделано просто как

__m256d rotate_pd_left(__m256d x, int n) { 
    return rotate_pd_right(x, -n); 
} 
Смежные вопросы