Sir Jo Black
Sir Jo Black

Reputation: 2096

Does anyone know why gcc 4.8.4 optimizes this code in a infinite loop?

I find very strange the differences between the assembler results of the following code compiled without optimization and with -Os optimization.

#include <stdio.h>

int main(){
    int i;

    for(i=3;i>2;i++);

    printf("%d\n",i);

    return 0;
}

Without optimization the code results:

000000000040052d <main>:
  40052d:   55                      push   %rbp
  40052e:   48 89 e5                mov    %rsp,%rbp
  400531:   48 83 ec 10             sub    $0x10,%rsp
  400535:   c7 45 fc 03 00 00 00    movl   $0x3,-0x4(%rbp)
  40053c:   c7 45 fc 03 00 00 00    movl   $0x3,-0x4(%rbp)
  400543:   eb 04                   jmp    400549 <main+0x1c>
  400545:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
  400549:   83 7d fc 02             cmpl   $0x2,-0x4(%rbp)
  40054d:   7f f6                   jg     400545 <main+0x18>
  40054f:   8b 45 fc                mov    -0x4(%rbp),%eax
  400552:   89 c6                   mov    %eax,%esi
  400554:   bf f4 05 40 00          mov    $0x4005f4,%edi
  400559:   b8 00 00 00 00          mov    $0x0,%eax
  40055e:   e8 ad fe ff ff          callq  400410 <printf@plt>
  400563:   b8 00 00 00 00          mov    $0x0,%eax
  400568:   c9                      leaveq 
  400569:   c3                      retq  

and the output is: -2147483648 (as I expect on a PC)

With -Os the code results:

0000000000400400 <main>:
  400400:   eb fe                   jmp    400400 <main>

I think the second result is an error!!! I think the compiler should have compiled something corresponding to the code:

printf("%d\n",-2147483648);

Upvotes: 1

Views: 215

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 149085

Well, the compiler is allowed to assume that the program will never exhibit undefined behaviour.

You get INT_MIN in the first case, because you have an overflow when INT_MAX + 1 gives INT_MIN (*), but this is undefined behaviour. And the C99 draft (n1556) says at 6.5 Expressions §5: If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

So compiler can say:

  • loop starts with an index value greater than the limit
  • index is always increased
  • if no UB occurs, index will always be greater than the limit => this is an infinite loop

With the as-if rule (5.1.2.3 Program execution §3 An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced), it can replace your loop with an infinite loop. Following instructions can no longer be reached and can be removed.

You invoked undefined behaviour and got... undefined behaviour.

(*) and even this is plainly implementation dependant, INT_MIN could be -2147483647if you had 1's complement, 8000000 could be a negative 0, or overflow could raise a signal...

Upvotes: 4

user694733
user694733

Reputation: 16047

Compiler is working as it should.

Signed integer overflow is illegal in C, and results in undefined behaviour. Any program that relies on it is broken.


Compiler replaces for(i=3;i>2;i++); with while(1);, because it sees that i starts from 3 and only increases, so value can never be less than 3.

Only overflow could result in loop exit. But that is illegal and compiler assumes that you would never do such a dirty thing.

Because there is infinite loop, printf is never reached and can be removed.


Unoptimized version worked only by accident. Compiler could have done the same thing there and it would have been equally valid.

Upvotes: 7

Related Questions