2

I tested this code in X86.

void func()
{
  int a, b;
  unsigned int c, d;
  int ret;

  ret = a / b;  // This line use idivl, expected
  ret = c / d;  // this line use idivl, expected
  ret = a / c;  // this line use divl..., surprised 
  ret = c / a;  // this line use divl..., supriised
  ret = a * c;  // this line use imull, expected
}

I paste the assembly code here:

func:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $36, %esp
    movl    -4(%ebp), %eax
    movl    %eax, %edx
    sarl    $31, %edx
    idivl   -8(%ebp)
    movl    %eax, -20(%ebp)
    movl    -12(%ebp), %eax
    movl    $0, %edx
    divl    -16(%ebp)
    movl    %eax, -20(%ebp)
    movl    -4(%ebp), %eax
    movl    $0, %edx
    divl    -12(%ebp)
    movl    %eax, -20(%ebp)
    movl    -4(%ebp), %eax
    movl    %eax, -36(%ebp)
    movl    -12(%ebp), %eax
    movl    $0, %edx
    divl    -36(%ebp)
    movl    %eax, -20(%ebp)
    movl    -4(%ebp), %eax
    imull   -12(%ebp), %eax
    movl    %eax, -20(%ebp)
    leave
    ret

Could you please tell me, why the division between int and unsigned int using divl , instead of idivl ?

Yang Bo
  • 679
  • 2
  • 8
  • 20
  • http://stackoverflow.com/questions/12489098/what-is-the-difference-of-idivl-and-divl – Orwell Nov 18 '12 at 12:08
  • @Orwell: that question explains what those instructions do, not why the compiler picked one over the other. A proper answer in this case would be a citation from the C/C++ standard detailing type conversion/promotion during mathematical operations (dividing signed and unsigned integers). – DCoder Nov 18 '12 at 12:11
  • 4
    I see 3 `divl`s and only one `idivl` in your pasted assembly. Your comments in the C suggest it should be 2 and 2... – Damien_The_Unbeliever Nov 18 '12 at 12:13
  • 3
    The compiler uses unsigned division when unsigned values are involved. What's the surprise? – Bo Persson Nov 18 '12 at 12:16

1 Answers1

6

Since the types of a and c have the same conversion rank, but a is signed and c is unsigned, a is converted to unsigned int before the division, in both a / c and c / a.

The compiler thus emits the unsigned division instruction div for these cases (as well as c / d, where both operands are unsigned).

The multiplication a * c is also an unsigned multiplication. In this case the compiler can get away with using the signed multiplication instruction imull, because the truncated result is identical regardless of whether mull or imull is used - only the flags are different, and the generated code doesn't test those.

caf
  • 233,326
  • 40
  • 323
  • 462
  • It's not "promoted", it's "converted". Conversion is usually more surprising than promotion (e.g. -1 is converted to 4294967295, which cannot happen with promotion) – anatolyg Nov 18 '12 at 13:08
  • I write code to check, it is the case, the int is converted to unsigned int before doing division... printf("%d\n", ((unsigned int)10)/-1); will output ZERO, which seems very strange! caf you are right, thanks a lot ! – Yang Bo Nov 19 '12 at 09:33
  • BTW, this kind of conversion will definitely cause some unexpected behavior, may I know why C choose to do the conversion this way ? Why not converted both to signed, we have widen bits in register anyway .. – Yang Bo Nov 19 '12 at 09:34