I have been playing around with the Godbolt Compiler and typed this code:
constexpr int func(int x)
{
return x > 3 ? x * 2 : (x < -4 ? x - 4 : x / 2);
}
int main(int argc)
{
return func(argc);
}
The code is somewhat straight forward. The important part here is the final division by 2 inside func(int x). Since x is an integer, basically any compiler would simplify this to a shift to avoid division instructions.
The assembly from x86-64 gcc 12.2 -O3 (for Linux, thus System V ABI) looks like this:
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
You can see the final idiv ecx command which is not a shift but an actual division by 2. I also tested clang and clang does actually reduce this to a shift.
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
Could this be due to inlining maybe? I am very curious about whats going on here.