首页 > 解决方案 > 当有条件地在 uint64_t * 内存区域中设置一个位时,为什么 gcc 将 btq 与 btcq 结合使用

问题描述

基本上我试图理解代码: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);
    }
}

编译为:

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

基于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

包含的原因是btq什么?

我正在调整 x86_64 / intel skylake 芯片

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

标签: cassemblygccx86-64micro-optimization

解决方案


推荐阅读