GCC 的__builtin_expect程序集转储似乎总是下降分支

GCC's __builtin_expect assembly dump seems to always go down branch

本文关键字:分支 转储 builtin expect 程序集 GCC      更新时间:2023-10-16

好的,所以我一直在玩__builtin_expect一点,我刚刚创建了一个简单的测试程序,我通过godbolt.org获得汇编输出(https://godbolt.org/g/FZo5fP)

int main(){
  volatile int num = 4;
  //if(num == 4){
  if(__builtin_expect(num,4)){
    return num*800;
  }else{
    return num*500;
  }
}

当使用- 01或更大的值编译时会产生:

main:
        mov     DWORD PTR [rsp-4], 4
        mov     eax, DWORD PTR [rsp-4]
        test    eax, eax
        mov     eax, DWORD PTR [rsp-4]
        je      .L2
        imul    eax, eax, 800
        ret
.L2:
        imul    eax, eax, 500
        ret

似乎说test eax,eax总是将0标志设置为0,除非num等于0。所以似乎如果num不设为0,它总是乘以800,而不是只有当num=4。我对__builtin_expect的理解是,虽然它将优化假设它将转到该分支,但它仍然应该比较以确保它应该使用该分支。

如果我把__builtin_expect改成==,它会生成

main:
        mov     DWORD PTR [rsp-4], 2
        mov     eax, DWORD PTR [rsp-4]
        cmp     eax, 4
        mov     eax, DWORD PTR [rsp-4]
        je      .L5
        imul    eax, eax, 500
        ret
.L5:
        imul    eax, eax, 800
        ret

这对我来说更有意义,因为它实际上与4比较。我对__builtin_expect的理解是错的吗?__builtin_expect实际上只适用于0或1,即使它指定它需要很长时间?

From the docs:

返回值是exp的值,应该是一个整型表达式。

的逻辑语义是:

if(__builtin_expect(num,4)) { ... }

:

if (num) { ... }

这和你说你想要的不一样。如果你想写你期望num == 4很可能出现,你需要:

if (__builtin_expect(num == 4, 1)) { ... }

通常,您只需将这些内容封装在宏中:

#define likely(expr)   __builtin_expect((expr), 1)
#define unlikely(expr) __builtin_expect((expr), 0)

,然后用法变得更自然:

if (likely(num == 4)) { ... }