【问题标题】:avx2 register bits reverseavx2 寄存器位反转
【发布时间】:2017-09-20 08:55:05
【问题描述】:

是否有一种(快速)方法可以在 avx2 寄存器中执行 32 位 int 值的位反转? 例如

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

【问题讨论】:

  • 您想要反转 AVX2 整数寄存器中单个 int32 的位,或者您想要反转 8 个此类整数中的每一个的位?
  • @JohnZwinck,这并不重要:一旦我知道如何做到这一点,我可以以任何我喜欢的方式随机播放寄存器中的 32 位值。
  • 旧方法(反向字节,反向 4 组与 pshufb,或结果)推广到 AVX2,但我无法立即找到欺骗
  • 您可以使用任何标准的位旋转技巧来反转字节,然后打乱字节(参见例如 Hacker's Delightthis list)。

标签: c++ x86 simd avx2


【解决方案1】:

由于找不到合适的骗子,我就发布它。

这里的主要思想是利用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,它正在复制第一次洗牌。

【讨论】:

  • @LưuVĩnhPhúc 链接中的解决方案是翻转字节而不是 32 位整数。
  • Gcc7.2 在这里也相当脑残。它将lutlow 转换为一个单独的内存常量,但在加载后会对其进行移动。 (没有将它用于其他任何事情)。我认为它只是创建了luthigh 的副本,但使用.value 汇编程序指令(16 位块)而不是.byte
猜你喜欢
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多