为什么较新的 clang 比 popcntl 多生成一条指令来计算 haswell 架构上 int 的位数?

Enr*_*lis 8 c++ assembly x86-64 clang bitcount

观看时Matt Godbolt 的演讲时时,我惊讶地发现,如果指示 Clang 针对 Haswell\xc2\xb9 架构进行编译,则会得出以下代码

\n
int foo(int a) {\n    int count = 0;\n    while (a) {\n        ++count;\n        a &= a - 1;\n    }\n    return count;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

用于计算设置位int(我不知道我自己需要多长时间才能计算出来),所以它只使用该指令:

\n
foo(int):                                # @foo(int)\n        popcntl %edi, %eax\n        retq\n
Run Code Online (Sandbox Code Playgroud)\n

我想自己尝试一下,但我发现生成的代码是

\n
foo(int):                                # @foo(int)\n        popcntl %edi, %eax\n        cmovel  %edi, %eax\n        retq\n
Run Code Online (Sandbox Code Playgroud)\n

事实证明,生成的代码在 Clang 10.0.1 和 Clang 11.0.0 之间发生了变化

\n

为什么较新的 Clang 又发出了一条以前不需要的指令?代码是如此简单,以至于我无法理解多一条指令除了使代码变慢之外还能做什么(即使速度可能非常小,我不知道)。

\n
\n

\xc2\xb9 作为一个附带问题,事实上不指定-march=haswell会导致更长、更人性化的代码这一事实是否仅仅意味着该选项所针对的物理 CPU 具有用于执行设置位计数和其他操作的电路(好吧,不管 clang 默认是什么)不?

\n