avx2寄存器位反转

时间:2017-09-20 08:55:06

标签: c++ x86 simd avx2

是否有(快速)方法在avx2寄存器中执行32位int值的位反转? E.g。

_mm256_set1_epi32(2732370386); 
<do something here>
//binary: 10100010110111001010100111010010 => 1001011100101010011101101000101
//register contains 1268071237 which is decimal representation of 1001011100101010011101101000101

1 个答案:

答案 0 :(得分:5)

由于我找不到合适的傻瓜,我会发布它。

这里的主要思想是利用pshufb的双重使用并行16项表查找来反转每个半字节的位。反转字节很明显。在每个字节中反转两个半字节的顺序可以通过将其构建到查找表(保存移位)或通过明确地移动低部分半字节(保存LUT)来完成。

总共这样的东西,没有经过测试:

__m256i rbit32(__m256i x) {
    __m256i shufbytes = _mm256_setr_epi8(3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12);
    __m256i luthigh = _mm256_setr_epi8(0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15, 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15);
    __m256i lutlow = _mm256_slli_epi16(luthigh, 4);
    __m256i lowmask = _mm256_set1_epi8(15);
    __m256i rbytes = _mm256_shuffle_epi8(x, shufbytes);
    __m256i high = _mm256_shuffle_epi8(lutlow, _mm256_and_si256(rbytes, lowmask));
    __m256i low = _mm256_shuffle_epi8(luthigh, _mm256_and_si256(_mm256_srli_epi16(rbytes, 4), lowmask));
    return _mm256_or_si256(low, high);
}

在循环中的典型上下文中,应该提升这些负载。

好奇地Clang uses 4 shuffles,它重复了第一次洗牌。