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 程序集转储似乎总是走下分支的主要内容,如果未能解决你的问题,请参考以下文章
likely(x)与unlikely(x)函数,即__builtin_expect的使用