使用带有向量优化的 C++20 的 std::popcount 是不是等同于 popcnt 内在函数?

Posted

技术标签:

【中文标题】使用带有向量优化的 C++20 的 std::popcount 是不是等同于 popcnt 内在函数?【英文标题】:Is using C++20's std::popcount with vector optimization is equivalent to popcnt intristic?使用带有向量优化的 C++20 的 std::popcount 是否等同于 popcnt 内在函数? 【发布时间】:2021-01-05 14:39:27 【问题描述】:

C++20 引入了许多新功能,例如std::popcount,我使用Intel Intrinsic 使用相同的功能。

我编译了这两个选项 - 可以在 Compiler Explorer code 中看到:

    使用英特尔的 AVX2 内在函数 使用 std::popcount 和 GCC 编译器标志“-mavx2”

看起来生成的汇编代码是一样的,除了std模板中使用的类型检查。

在与操作系统无关的代码和具有相同优化方面 - 假设使用 std::popcount 和 apt 编译器向量优化标志比直接使用内在函数更好吗?

谢谢。

【问题讨论】:

请注意,popcnt 指令不是 AVX2 的一部分。它是 POPCNT 指令扩展的一部分,自 Nehalem 架构以来,早在 AVX2 推出之前,它就已在所有 Intel 处理器上可用。 可以查看生成的程序集。例如,GCC 生成 popcnt-march=native-O2 在我的例子中:godbolt.org/z/x3e7Wa。 (只是不明白为什么eax先归零;popcnt应该替换rax的全部内容,还是不应该?) 如果你检查一些实现,libstdc++ 中的代码也就是来自 GCC 的 STL 和libc++ 中的代码,也就是来自 LLVM/Clang 的 STL,你会看到他们不直接调用内在函数. @DanielLangr popcnt has a false dependency 在目标寄存器上。 @aqrit 谢谢你的链接;我不知道这个问题,这很有趣。 【参考方案1】:

技术上不。(但实际上,是的)。 C++ 标准只指定popcount行为,而不是实现(参考[bit.count])。

实现者可以做任何他们想做的事情来实现这个行为,包括使用popcnt内在函数,但他们也可以编写一个while循环:

int set_bits = 0;
while(x)

   if (x & 1)
      ++set_bits;
   x >>= 1;

return set_bits;

这是[bit.count] 标准中的完整措辞:

template<class T>
constexpr int popcount(T x) noexcept;

约束T 是无符号整数类型 ([basic.fundamental])。 返回x 的值中1 的位数。

真的吗?编译器编写者非常聪明,并且会对其进行优化以尽可能多地使用内在函数。例如,gcc's implementation 似乎进行了相当大的优化。

【讨论】:

我很困惑。您从 No 开始,但随后您的帖子的其余部分基本上以 Yes 结尾。我的意思是,在 C++ 标准下,int x = 7+3; 在法律上是允许在汇编中实现为 for 循环的,但是您不会看到有人说要使用内在函数或汇编来添加整数,对吗? @Yakk-AdamNevraumont:我想你比我更清楚答案是“技术上不,但实际上是” 我只是说,也许你应该从 Yes 而不是 No 开始;)有人可能会被误导。 呃,当硬件popcnt 可用时,popcount if(__x == 0) return 0; 用 clang 编译得很糟糕,实际上是从 popcnt 中检查 FLAGS 并做了一个无用的 cmov。 godbolt.org/z/KqjPe3。我想可能值得围绕 GCC 的后备 bithack 进行分支,但 gcc 仍然在那里使用 cmov! libc++ 不包含 __x==0,这对编译器来说更糟; clang -stdlib=libc++ 很好 godbolt.org/z/8eo64c (但不会尝试通过 Skylake 避免 popcnt 输出存在于 SnB 上的错误依赖,直到 Ice Lake 才修复。clang 通常会鲁莽地使用错误依赖,这确实会在以下情况下保存指令它们不会造成问题。)我认为__x==0 检查也会破坏clang 对__builtin_popcnt 的自动矢量化(当AVX2 可用时超过数组。)

以上是关于使用带有向量优化的 C++20 的 std::popcount 是不是等同于 popcnt 内在函数?的主要内容,如果未能解决你的问题,请参考以下文章

我可以对带有变量的向量使用 C++11 列表初始化器语法吗?

将矩阵的行乘以向量(低级优化)?

如何在C ++中找到两个向量之间的最小(优化)距离

状态流程图和 C 动作语言。设置数组值以在单个步骤中输出一个向量

带有智能指针的 C++11 向量

使用带有引用的对象向量的 C++ 语法