Reputation: 2096
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
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:
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 -2147483647
if you had 1's complement, 8000000
could be a negative 0, or overflow could raise a signal...
Upvotes: 4
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