Сдвиги AVX2 (16 бит)
Существуют ли встроенные инструкции для выполнения операций сдвига вправо и влево для (16-разрядных) целочисленных элементов в AVX2?
Как следующие примеры:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] --> [16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
а также
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] --> [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
где _mm_srli_si128(H,14)
а также _mm_slli_si128(H,2)
хорошо работают на 16-битных элементах SSE3. Я спрашиваю, потому что производительность (время работы) имеет решающее значение для меня.
1 ответ
К сожалению, в AVX2 таких инструкций нет. Все инструкции AVX2 расширены до 256 бит SSE2 с учетом совместимости при использовании в 128 бит SSE2.
Если вам известно число 16-разрядных целых чисел, которые нужно сдвинуть во время компиляции, вы можете использовать комбинацию перестановок и сдвигов. Например, вы можете логически разбить значение на 64-битные порции, выполнить перестановку и сдвиги этих блоков, а затем объединить их.
Вот как я делаю это в моем коде
static __m256i m256_srl16_1(__m256i i) {
// suppose i is [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
//[4, 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5]
__m256i srl64_q = _mm256_permute4x64_epi64(i, _MM_SHUFFLE(0,3,2,1));
//[ 1, 0, 0, 0 13, 0, 0, 0 9, 0, 0, 0 5, 0, 0, 0]
__m256i srl64_m = _mm256_slli_epi64(srl64_q, 3*16);
//[ 0, 16, 15, 14, 0, 12, 11, 10, 0, 8, 7, 6, 0, 4, 3, 2]
__m256i srl16_z = _mm256_srli_epi64(i, 1*16);
__m256i srl64 = _mm256_and_si256(srl64_m, _mm256_set_epi64x(0, ~0, ~0, ~0));
__m256i r = _mm256_or_si256(srl64, srl16_z);
return r;
}
Если вам нужно перейти на более чем 64 бита, вам нужна дополнительная перестановка исходного значения и маскировка ненужных битов