Как создать 8-битную маску из lsb значения __m64?

У меня есть случай использования, где у меня есть массив битов, каждый бит представлен как 8-битное целое число, например uint8_t data[] = {0,1,0,1,0,1,0,1}; Я хочу создать одно целое число, извлекая только lsb каждого значения. Я знаю что используя int _mm_movemask_pi8 (__m64 a) Функция Я могу создать маску, но эта внутренняя занимает только байт байта, а не lsb. Существует ли подобный внутренний или эффективный метод для извлечения lsb для создания одного 8-битного целого числа?

-1

Решение

Нет прямого способа сделать это, но, очевидно, вы можете просто сдвинуть lsb в msb и затем извлечь его:

_mm_movemask_pi8(_mm_slli_si64(x, 7))

Использование MMX в наши дни странно, и его, вероятно, следует избегать.

Вот версия SSE2, все еще читающая только 8 байтов:

int lsb_mask8(uint8_t* bits) {
__m128i x = _mm_loadl_epi64((__m128i*)bits);
return _mm_movemask_epi8(_mm_slli_epi64(x, 7));
}

Использование SSE2 вместо MMX избавляет от необходимости EMMS

5

Другие решения

Если у вас эффективный ИМТ2 pext (например, Haswell и новее, такой же, как AVX2), затем используйте обратный ответ @ wim на ваш вопрос о движении в другом направлении (Как эффективно преобразовать 8-битное растровое изображение в массив целых чисел 0/1 с x86 SIMD).

unsigned extract8LSB(uint8_t *arr) {
uint64_t bytes;
memcpy(&bytes, arr, 8);
unsigned LSBs = _pext_u64(bytes ,0x0101010101010101);
return LSBs;
}

это компилируется так, как вы ожидаете к словесной нагрузке + а pext инструкция. Компиляторы поднимут 0x01... постоянная настройка вне цикла после встраивания.


pext / pdep эффективны на процессорах Intel, которые их поддерживают (задержка 3 цикла / пропускная способность 1с, 1 моп, то же, что и умножение). Но они не эффективный на AMD, как задержка 18c и пропускная способность. (https://agner.org/optimize/). Если вы заботитесь о AMD, вам обязательно стоит использовать @ harold’s pmovmskb ответ.

Или, если у вас есть несколько смежных блоков по 8 байт, сделайте их с одним широким вектором и получите 32-битное растровое изображение. Вы можете разделить это, если необходимо, или развернуть цикл, используя 4, чтобы сместить вправо растровое изображение и получить все 4 однобайтовых результата.

Если вы просто сохраняете это в памяти сразу, то вам, вероятно, следовало бы выполнить это извлечение в цикле, который записывал исходные данные, а не в отдельном цикле, поэтому он все еще будет горячим в кеше. AVX2 _mm256_movemask_epi8 это один моп (на процессорах Intel) с низкой задержкой, поэтому, если ваши данные не находятся в кэш-памяти L1d, то цикл, который просто делает это не будет держать свои исполнительные блоки заняты в ожидании памяти.

2

По вопросам рекламы [email protected]