Исходный код, который вы цитируете, основан на свойстве _mm256_sad_epu8
и предназначен для суммирования байтов в 64-битных словах.
Чтобы получить тот же результат с суммами 32-битных слов, вам нужно сделать что-то немного другое. Должно работать следующее:
__m256i popcount_pshufb32(__m256i v) {
__m256i lookup = = _mm256_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2,
2, 3, 2, 3, 3, 4, 0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4);
__m256i low_mask = _mm256_set1_epi8(0x0f);
__m256i lo = _mm256_and_si256(v, low_mask);
__m256i hi = _mm256_and_si256(_mm256_srli_epi16(v, 4), low_mask);
__m256i popcnt1 = _mm256_shuffle_epi8(lookup, lo);
__m256i popcnt2 = _mm256_shuffle_epi8(lookup, hi);
__m256i sum8 = _mm256_add_epi8(popcnt1, popcnt2);
return _mm256_srli_epi32(
_mm256_mullo_epi32(sum8, _mm256_set1_epi32(0x01010101)), 24);
}
Итак, мы заменили _mm256_sad_epu8
умножением и сдвигом. Это должно быть разумно. В моих тестах он немного медленнее, чем оригинальная 64-битная версия, но разница относительно мала .
Вы можете получить чуть лучшую производительность за счет использования большего количества встроенных функций:
__m256i popcount_pshufb32(__m256i v) {
__m256i lookup = = _mm256_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2,
2, 3, 2, 3, 3, 4, 0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4);
__m256i low_mask = _mm256_set1_epi8(0x0f);
__m256i lo = _mm256_and_si256(v, low_mask);
__m256i hi = _mm256_and_si256(_mm256_srli_epi16(v, 4), low_mask);
__m256i popcnt1 = _mm256_shuffle_epi8(lookup, lo);
__m256i popcnt2 = _mm256_shuffle_epi8(lookup, hi);
__m256i sum8 = _mm256_add_epi8(popcnt1, popcnt2);
return _mm256_madd_epi16(_mm256_maddubs_epi16(sum8, _mm256_set1_epi8(1)),
_mm256_set1_epi16(1));
}