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

Posted

技术标签:

【中文标题】GCC 的 __builtin_expect 程序集转储似乎总是走下分支【英文标题】:GCC's __builtin_expect assembly dump seems to always go down branch 【发布时间】:2016-11-02 22:02:25 【问题描述】:

好的,所以我一直在玩 __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;
  

当使用 -O1 或更高版本编译时:

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,除非 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,即使它指定需要很长时间?

【问题讨论】:

【参考方案1】:

来自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))  ... 

【讨论】:

所以说它的第二部分应该很长的文档只是布尔不是一等公民时的遗产?因为那么第二个参数不是 1 或 0 没有意义? @legion 请注意,这也是 C 内置的。但是,是的,传递 0 或 1 以外的值没有多大意义。 我很确定宏应该是 #define likely(expr) __builtin_expect(!!(expr), 1)#define unlikely(expr) __builtin_expect(!!(expr), 0),即使 expr 不完全是零或一,也可以写成 if (likely(expr)) @Barry:至少不在 if 语句中。另一方面,在开关中,其他值可能有用。 @EOF (bool)!! 好吗?

以上是关于GCC 的 __builtin_expect 程序集转储似乎总是走下分支的主要内容,如果未能解决你的问题,请参考以下文章

HERD--GCC宏

likely(x)与unlikely(x)函数,即__builtin_expect的使用

《C语言杂记》编译优化之__builtin_expect

likely, unlikely的作用

为啥 GCC 编译的应用程序总是包含 _mcount 符号?

ubuntukylin基础 使用gcc编译一个C语言 helloworld程序 预编译 汇编 编译 链接