使用带有向量优化的 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 列表初始化器语法吗?