A few days ago, I encountered what I believe to be a bug in g++ 5.3 concerning the nesting of for loops at higher -OX
optimization levels. (Been experiencing it
As @hvd pointed out, the problem is in your invalid code, not in the compiler.
During your program execution, the sum
value overflows int
range. Since int
is by default signed
and overflow of signed
values causes undefined behavior* in C, the compiler is free to do anything. As someone noted somewhere, dragons could be flying out of your nose. The result is just undefined.
The difference -O2
causes is in testing the end condition. When the compiler optimizes your loop, it realizes that it can optimize away the inner loop, making it
int sum = 0;
for(int i = 0; i < maxOuter; i++) {
sum += maxInner;
std::cout<<"i = "<
and wrapped this replacement with #ifndef ORIG
, so I could have both versions. Then I ran 8 compilations: {gcc
,g++
} x {-O2
, ""
} x {-DORIG=1
,""
}. This yields following results:
gcc
, -O2
, -DORIG=1
: Won't compile, missing
. Not surprising.
gcc
, -O2
, ""
: Produces compiler warning and behaves "normally". A look in the assembly shows that the inner loop is optimized out (j
being incremented by 100000000) and the outer loop variable is compared with hardcoded value -1294967296. So, GCC can detect this and do some clever things while the program is working expectably. More importantly, warning is emitted to warn user about undefined behavior.
gcc
, ""
, -DORIG=1
: Won't compile, missing
. Not surprising.
gcc
, ""
, ""
: Compiles without warning. No optimizations, program runs as expected.
g++
, -O2
, -DORIG=1
: Compiles without warning, runs in endless loop. This is OP's original code running. C++ assembly is tough to follow for me. Addition of 100000000 is there though.
g++
, -O2
, ""
: Compiles with warning. It is enough to change how the output is printed to change compiler warning emiting. Runs "normally". By the assembly, AFAIK the inner loop gets optimized out. At least there is again comparison against -1294967296 and incrementation by 100000000.
g++
, ""
, -DORIG=1
: Compiles without warning. No optimization, runs "normally".
g++
, ""
, ""
: dtto
The most interesting part for me was to find out the difference upon change of printing. Actually from all the combinations, only the one used by OP produces endless-loop program, the others fail to compile, do not optimize or optimize with warning and preserve sanity.
Follows example build command and my full code
$ gcc -x c -Wall -Wextra -O2 -DORIG=1 -o gcc_opt_orig main.cpp
main.cpp:
#ifdef ORIG
#include
#else
#include
#endif
int main(){
int sum = 0;
// Value of 100 million. (2047483648 less than int32 max.)
int maxInner = 100000000;
int maxOuter = 30;
// 100million * 30 = 3 billion. (Larger than int32 max)
for(int i = 0; i < maxOuter; ++i)
{
for(int j = 0; j < maxInner; ++j)
{
++sum;
}
#ifdef ORIG
std::cout<<"i = "<