由于我找不到合适的重复内容,所以我会发布它。
这里的主要想法是利用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使用4个洗牌指令,它会复制第一个洗牌指令。
pshufb
反转4个字节的组,或者使用OR运算)可以推广到AVX2,但我暂时找不到重复的内容。 - harold