int test1(int a, int b) {
if (__builtin_expect(a < b, 0))
return a / b;
return b;
}
由 clang 使用 -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
为什么 eax
在 idiv
之后来回移动?
gcc 有类似的行为,所以这似乎是有意为之。
gcc with -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
最佳答案
这不是拼图的完整解决方案,但应该提供一些线索。
没有 __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
虽然寄存器分配在这里仍然很奇怪,但它至少是有道理的:如果分支被采用,ecx
中的 b
的值被转移到 eax
作为返回值。如果不采用,则除法结果(在 eax
中)必须传输到 ecx
以与其他情况相同的寄存器中。
可能是 __builtin_expect
说服编译器处理特殊情况,即在编译过程中分支被延迟的情况,孤立 .LBB1_2
标签并导致它最终缺席 assembly 。
关于c++ - 编译器在 eax 上来回生成 mov,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55166749/