首页 >后端开发 >C++ >AVX2和BMI2指令如何高效实现基于掩码的左打包?

AVX2和BMI2指令如何高效实现基于掩码的左打包?

Susan Sarandon
Susan Sarandon原创
2024-12-29 19:34:11246浏览

How Can AVX2 and BMI2 Instructions Efficiently Implement Left Packing Based on a Mask?

基于掩码打包左的高效 AVX2 实现

与 SSE 不同,AVX 缺乏基于掩码打包左的专用指令。然而,结合使用 AVX2 和 BMI2 指令可以有效地完成此任务。

使用 AVX2 和 BMI2

该方法利用 vpermps (_mm256_permutevar8x32_ps) 指令,它执行车道交叉变量洗牌,并且 pdep来自 BMI2 的 (_pdep_u64) 指令,它提供按位提取。

算法步骤

  1. 使用表示所需排列的压缩 3 位索引创建一个常量。
  2. 使用 pdep 从mask。
  3. 将索引解压缩为每个字节一个。
  4. 将解压缩的索引转换为 vpermps 的控制掩码。
  5. 使用 vpermps 执行变量洗牌。

实施详细信息

下面的代码提供了 AVX2 BMI2 中的实现:

#include <immintrin.h>

__m256 compress256(__m256 src, unsigned int mask)
{
  uint64_t expanded_mask = _pdep_u64(mask, 0x0101010101010101);  // unpack each bit to a byte
  expanded_mask *= 0xFF;    // mask |= mask<<1 | mask<<2 | ... | mask<<7;
  // ABC... -> AAAAAAAABBBBBBBBCCCCCCCC...: replicate each bit to fill its byte

  const uint64_t identity_indices = 0x0706050403020100;    // the identity shuffle for vpermps, packed to one index per byte
  uint64_t wanted_indices = _pext_u64(identity_indices, expanded_mask);

  __m128i bytevec = _mm_cvtsi64_si128(wanted_indices);
  __m256i shufmask = _mm256_cvtepu8_epi32(bytevec);

  return _mm256_permutevar8x32_ps(src, shufmask);
}

性能分析

此实现需要 6 uops,16c延迟。它有可能维持每 4 个周期一次迭代的吞吐量,从而保持多个迭代的运行。

替代方法

对于 Zen 3 之前的 AMD CPU,pext/pdep速度非常慢,因此替代方法可能更好。对于 16 位元素,可以采用 128 位向量方法。对于 8 位元素,可以使用涉及多个重叠块的不同技术。

以上是AVX2和BMI2指令如何高效实现基于掩码的左打包?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn