开发者

Visual C++ generates DIV instead of IDIV (x86, integer arithmetic)

开发者 https://www.devze.com 2023-03-29 05:41 出处:网络
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

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:

  1. int / short: the right hand side is promoted to int, therefore the idiv instruction.
  2. int / unsigned short: the right hand side is promoted to int, therefore the idiv instruction.
  3. int / unsigned int: the left hand side is promoted to unsigned int, therefore the div instruction.
  4. int / int: nothing is promoted, therefore the idiv 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 an int; otherwise, it is converted to an unsigned 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号