3

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 test1 = (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 :)

nielsj
  • 1,499
  • 12
  • 24
  • Shift, as said earlier, generates a SHL instruction which is logical instead of arithmetic. That seems wrong, but *256 does exactly the same in this piece. – nielsj Aug 20 '11 at 12:43

2 Answers2

7

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..

Roland Illig
  • 40,703
  • 10
  • 88
  • 121
1

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.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • This is implementation-dependent by standard and it works in VS8. I did actually step through the asm and checked intermediate results. – nielsj Aug 20 '11 at 18:48
  • I just checked ISO C99 6.5.7p4, and it clearly speaks of *undefined behavior*. – Roland Illig Aug 20 '11 at 19:00
  • I know and so does MS, that's why they speak of 'implementation-dependent'. VC does a SHL resulting in the desired *256 in this particular case, so it's besides the point. – nielsj Aug 20 '11 at 21:01