我一直在使用 Godbolt 编译器并输入以下代码:
constexpr int func(int x)
{
return x > 3 ? x * 2 : (x < -4 ? x - 4 : x / 2);
}
int main(int argc)
{
return func(argc);
}
代码有点简单。这里重要的部分是最后除以2func(int x)
。由于 x 是一个整数,基本上任何编译器都会将其简化为移位以避免除法指令。
x86-64 gcc 12.2 的汇编-O3
(对于 Linux,因此 System V ABI)如下所示:
main:
cmp edi, 3
jle .L2
lea eax, [rdi+rdi]
ret
.L2:
cmp edi, -4
jge .L4
lea eax, [rdi-4]
ret
.L4:
mov eax, edi
mov ecx, 2
cdq
idiv ecx
ret
你可以看到决赛idiv ecx
命令不是移位,而是实际除以 2。我还测试了 clang,clang 实际上将其减少为移位。
main: # @main
mov eax, edi
cmp edi, 4
jl .LBB0_2
add eax, eax
ret
.LBB0_2:
cmp eax, -5
jg .LBB0_4
add eax, -4
ret
.LBB0_4:
mov ecx, eax
shr cl, 7
add cl, al
sar cl
movsx eax, cl
ret
这可能是由于内联吗?我很好奇这里发生了什么。