为什么 gcc 在 uint64_t * 内存区域中有条件地设置位时将 btq 与 btcq 结合使用

Noa*_*oah 5 c assembly gcc x86-64 micro-optimization

基本上我试图理解代码:https : //gcc.godbolt.org/z/7xxb3G

void __attribute__((noinline))
cond_unset_bit(uint64_t * v, uint32_t b) {
    if(__builtin_expect(!!(*v & ((1UL) << b)), 1)) {
        *v ^= ((1UL) << b);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译为:

cond_unset_bit(unsigned long*, unsigned int):
        movq    (%rdi), %rax
        btq     %rsi, %rax
        jnc     .L6
        btcq    %rsi, %rax
        movq    %rax, (%rdi)
.L6:
        ret
Run Code Online (Sandbox Code Playgroud)

基于Agner Fog 的指令表(skylake 是第 238 页)btq并且btcq在寄存器上操作时具有完全相同的成本。btcq还将进位标志设置为前一位,因此似乎可以在没有btq指令的情况下实现完全相同的逻辑(具有更好的性能),即:

cond_unset_bit(unsigned long*, unsigned int):
        movq    (%rdi), %rax
        btcq    %rsi, %rax
        jnc     .L6
        movq    %rax, (%rdi)
.L6:
        ret
Run Code Online (Sandbox Code Playgroud)

包括的原因是btq什么?

我正在调整 x86_64 / intel skylake 芯片

编辑:感谢@Peter Cordes(以及对我所有其他帖子的帮助:)