constexpr int func(int x)
{
return x > 3 ? x * 2 : (x < -4 ? x - 4 : x / 2);
}
int main(int argc)
{
return func(argc);
}
代码相对直观。这里重要的部分是在func(int x)
内部最终除以2。由于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
可能是内联导致的吗?我对这里发生的事情非常好奇。
constexpr
与此有关吗?由于输入是变量,因此无法在编译时进行评估。 - Ben Voigtmain()
函数的argc
参数不能为负数,并完全消除< -4
分支。 - Ben Voigt