Visual C++ generates DIV instead of IDIV (x86, integer arithmetic)
I'm working with Visual C++ 2008 here (9.x) and I was preparing a fixed point value when I ran into the compiler generating a DIV instead of an IDIV. I collapsed the code into a tiny piece to exactly reproduce:
short a = -255;
short divisor16 = 640; // unsigned, 16-bit
unsigned int divisor32 = 640; // unsigned, 32-bit
unsigned short s_divisor16 = 640; // signed, 16-bit
int s_divisor32 = 640; // signed, 32-bit
int16_t test开发者_StackOverflow中文版1 = (a<<8)/divisor16; // == -102, generates IDIV -> OK
int16_t test2 = (a<<8)/s_divisor16; // == -102, generates IDIV -> OK
int16_t test3 = (a<<8)/divisor32; // == bogus, generates DIV -> FAIL!
int16_t test4 = (a<<8)/s_divisor32; // == -102, generates IDIV -> OK
int bitte_ein_breakpoint=1;
I won't bother you with the simple disassembly.
Now instead of taking the shortcut and just changing the divisor's type (it is a function parameter, unsigned int numPixels), I wonder what makes the compiler pick DIV over IDIV in the third (test3) case, since it does not do so with an unsigned 16-bit divisor and there really isn't anything that would call for unsigned arithmetic anyway. At least that's what I think and I hope I'm wrong :)
The code that is generated for the /
operator depends on the operands.
First, the expression (a << 8)
has type int
, since the integer promotions are performed on each of the operands (ISO C99, 6.5.7p3), and then the operation is int << int
, which results in an int
.
Now there are four expressions:
int / short
: the right hand side is promoted toint
, therefore theidiv
instruction.int / unsigned short
: the right hand side is promoted toint
, therefore theidiv
instruction.int / unsigned int
: the left hand side is promoted tounsigned int
, therefore thediv
instruction.int / int
: nothing is promoted, therefore theidiv
instruction is appropriate.
The integer promotions are defined in ISO C99 6.3.1.1p3:
If an
int
can represent all values of the original type, the value is converted to anint
; otherwise, it is converted to anunsigned int
. These are called the integer promotions..
Left-shifting a negative value results in undefined behaviour. So I'm not sure you can draw many conclusions from what the compiler chooses to do in this scenario.
精彩评论