Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is /=2 different from >>=1 for signed integers, and compiles to different asm?

unsigned int a=200;
//mov   dword ptr [a],0C8h  
a >>= 1;
//mov   eax,dword ptr [a]  
//shr   eax,1  
//mov   dword ptr [a],eax  
a /= 2;
//mov   eax,dword ptr [a]  
//shr   eax,1  
//mov   dword ptr [a],eax  
int b = -200;
//mov   dword ptr [b],0FFFFFF38h  
b /= 2;
//mov   eax,dword ptr [b]  
//cdq  
//sub   eax,edx  
//sar   eax,1  
//mov   dword ptr [b],eax  
b >>= 1;
//mov   eax,dword ptr [b]  
//sar   eax,1  
//mov   dword ptr [b],eax 

im using msvc, // is the assembly for that C statement.

Why is signed int /=2 is different from >>=1? What are cdq and sub doing? Are they necessary?

like image 682
sunkue Avatar asked Jan 25 '23 23:01

sunkue


1 Answers

Dividing a negative integer by 2 is not the same as shifting it to the right by 1. For example

-7 / 2 = -3

With shifts:

11111001b >> 1 = 11111100b which is -4

Thus the compiler has to take care of the case when the integer is negative

What are cdq and sub doing? Are they necessary?

cdq performs the following EDX:EAX ← sign-extend of EAX.

Thus if the value in EAX is negative, EDX will get 0xFFFFFFFF (which is -1), otherwise it will be 0 (due to the sign extension of EAX).

sub eax, edx ; will either result in 'eax - 0' (if EAX is positive) or
             ;                       'eax - (-1)' (if EAX is negative)

Which in case of the above example will normalize the -7 to -7 - (-1) = -6 and then -6 >> 1 = -3.

like image 65
Alex Lop. Avatar answered Jan 29 '23 11:01

Alex Lop.