好的,所以我一直在玩__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,即使它指定它需要很长时间吗?
答案 0 :(得分:5)
来自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)) { ... }