Tyk*_*ker 5 c++ assembly gcc x86-64 micro-optimization
int test1(int a, int b) {
if (__builtin_expect(a < b, 0))
return a / b;
return b;
}
Run Code Online (Sandbox Code Playgroud)
被铛编译-O3 -march=native到
test1(int, int): # @test1(int, int)
cmp edi, esi
jl .LBB0_1
mov eax, esi
ret
.LBB0_1:
mov eax, edi
cdq
idiv esi
mov esi, eax
mov eax, esi # moving eax back and forth
ret
Run Code Online (Sandbox Code Playgroud)
为什么eax在之后来回移动idiv?
gcc具有类似的行为,因此这似乎是有意的。
gcc -O3 -march=native符合代码
test1(int, int):
mov r8d, esi
cmp edi, esi
jl .L4
mov eax, r8d
ret
.L4:
mov eax, edi
cdq
idiv esi
mov r8d, eax
mov eax, r8d #back and forth mov
ret
Run Code Online (Sandbox Code Playgroud)
这并不是这个难题的完整解决方案,但应该提供一些线索。
如果没有__builtin_expect, clang 会生成:
test2(int, int): # @test2(int, int)
mov ecx, esi
cmp edi, esi
jge .LBB1_2
mov eax, edi
cdq
idiv ecx
mov ecx, eax
.LBB1_2:
mov eax, ecx
ret
Run Code Online (Sandbox Code Playgroud)
虽然这里的寄存器分配仍然很奇怪,但它至少是有意义的:如果采用分支,则bin的值ecx将被传输eax为返回值。如果不采用,则除法的结果(在 中eax)必须转移到ecx与其他情况相同的寄存器中。
可能是 a__builtin_expect说服编译器处理特殊情况,即在编译过程中较晚采取分支的情况,孤立标签.LBB1_2并导致它最终从程序集中消失。