_mm_alignr_epi8 (PALIGNR) эквивалент в AVX2 - PullRequest
7 голосов
/ 15 декабря 2011

В SSE3 инструкция PALIGNR выполняет следующее:

PALIGNR объединяет операнд назначения (первый операнд) и исходный операнд (второй операнд) в промежуточную композицию, сдвигает композицию с байтовой гранулярностью вправо на постоянную немедленную и извлекает результат выравнивания по правому краю в место назначения.

Сейчас я в процессе переноса своего кода SSE4 для использования инструкций AVX2 и работы над 256-битными регистрами вместо 128-битных. Наивно полагал, что встроенная функция _mm256_alignr_epi8 (VPALIGNR) выполняет ту же операцию, что и _mm_alignr_epi8 только для 256-битных регистров. К сожалению, это не совсем так. Фактически, _mm256_alignr_epi8 обрабатывает 256-битный регистр как 2 128-битных регистра и выполняет 2 операции «выравнивания» в двух соседних 128-битных регистрах. Эффективно выполняет ту же операцию, что и _mm_alignr_epi8, но на 2 регистрах одновременно. Это наиболее четко показано здесь: _mm256_alignr_epi8

В настоящее время мое решение состоит в том, чтобы продолжать использовать _mm_alignr_epi8, разделив регистры ymm (256bit) на два регистра xmm (128bit) (high и low), например:

__m128i xmm_ymm1_hi = _mm256_extractf128_si256(ymm1, 0);
__m128i xmm_ymm1_lo = _mm256_extractf128_si256(ymm1, 1);
__m128i xmm_ymm2_hi = _mm256_extractf128_si256(ymm2, 0);
__m128i xmm_ymm_aligned_lo = _mm_alignr_epi8(xmm_ymm1_lo, xmm_ymm1_hi, 1);
__m128i xmm_ymm_aligned_hi = _mm_alignr_epi8(xmm_ymm2_hi, xmm_ymm1_lo, 1);
__m256i xmm_ymm_aligned = _mm256_set_m128i(xmm_ymm_aligned_lo, xmm_ymm_aligned_hi);

Это работает, но должен быть лучший способ, верно? Существует ли, возможно, более «общая» инструкция AVX2, которую следует использовать для получения того же результата?

Ответы [ 3 ]

4 голосов
/ 26 декабря 2011

Для чего вы используете palignr?Если это только для обработки несоответствия данных, просто используйте вместо этого выровненные нагрузки;они, как правило, «достаточно быстры» на современных архитектурах Intel µ (и сэкономят вам большой объем кода).

Если вам нужно поведение, подобное palignr, по какой-то другой причине, вы можете просто воспользоватьсяподдержки невыровненной нагрузки, чтобы сделать это без ветвления.Если вы не полностью привязаны к хранилищу, это, вероятно, предпочтительная идиома.

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n)
{
    // Do whatever your compiler needs to make this buffer 64-byte aligned.
    // You want to avoid the possibility of a page-boundary crossing load.
    char buffer[64];

    // Two aligned stores to fill the buffer.
    _mm256_store_si256((__m256i *)&buffer[0], v0);
    _mm256_store_si256((__m256i *)&buffer[32], v1);

    // Misaligned load to get the data we want.
    return _mm256_loadu_si256((__m256i *)&buffer[n]);
}

Если вы можете предоставить больше информации о как точно вы используете palignr, явозможно, будет более полезным.

3 голосов
/ 10 августа 2015

Нам нужны 2 инструкции: «vperm2i128» и «vpalignr», чтобы расширить «palignr» на 256 бит.

См .: https://software.intel.com/en-us/blogs/2015/01/13/programming-using-avx2-permutations

2 голосов
/ 15 декабря 2011

Единственное решение, которое мне удалось найти для этого:

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n)
{
  if (n < 16)
  {
    __m128i v0h = _mm256_extractf128_si256(v0, 0);
    __m128i v0l = _mm256_extractf128_si256(v0, 1);
    __m128i v1h = _mm256_extractf128_si256(v1, 0);
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n);
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n);
    __m256i vout = _mm256_set_m128i(voutl, vouth);
    return vout;
  }
  else
  {
    __m128i v0h = _mm256_extractf128_si256(v0, 1);
    __m128i v0l = _mm256_extractf128_si256(v1, 0);
    __m128i v1h = _mm256_extractf128_si256(v1, 1);
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n - 16);
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n - 16);
    __m256i vout = _mm256_set_m128i(voutl, vouth);
    return vout;
  }
}

, которое, я думаю, в значительной степени идентично вашему решению, за исключением того, что оно также обрабатывает сдвиги> = 16 байт.

...