https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61781
--- Comment #2 from Geir Johansen <geir at cray dot com> --- Longer version of the test case, along with notes from the original user. T I believe you have an overaggressive optimizer. Which I have turned into the following somewhat block of code (simple-instrumented.c): ======================================================================== /** Demo for a gcc 4.8.1 bug Built with: gcc -O3 -std=c99 simple-instrumented.c */ #include <stdio.h> #include <stdlib.h> #ifdef myrand_unsigned unsigned long myrand (unsigned long x) #else long myrand( long x ) #endif { #ifdef myrand_constants_ul unsigned long c = 6824061905351802757UL; // prime unsigned long d = 5001297291839117257UL; // prime, p - 1 divisible by 4 #else long c = 6824061905351802757L; // prime long d = 5001297291839117257L; // prime, p - 1 divisible by 4 #endif #ifdef printf_sub_start printf(" x-ss: 0x%016ld\n", x); #endif #ifdef simpler x = d*x; #else x = d*x + c; #endif #ifdef printf_sub_end printf(" x-se: 0x%016ld\n", x); #endif return( x ); } int main( int argc, char *argv[] ) { #ifdef unsigned_loop unsigned long x; #else long x; #endif long len; long count = 0; x = 1; len = 1e2; if( argc > 1 ) { len = atof( argv[1] ) + 0.5; } if( argc > 2 ) { x = strtol( argv[2], 0, 0 ); } printf("len = %ld, seed = 0x%016lx\n", len, x); #ifdef unsigned_loop for(unsigned long i=0; i<len; i++ ) { #else for( long i=0; i<len; i++ ) { #endif #ifdef myrand_x x = myrand( x ); // this version seems okay #else x = myrand( i ); // this version breaks gcc #endif printf("%4ld: 0x%016lx\n", i, x); count++; } printf("Count is %ld\n", count); return( 0 ); } ======================================================================== And I've been using the following block of code to exercise the instrumented version of this code (do-it.bash): ======================================================================== #!/bin/bash gcc -v opt_gcc=("-fwrapv" "-fstrict-overflow" "-Wstrict-overflow=5" "-Wall") opt_code=("simpler" "myrand_unsigned" "myrand_constants_ul" "printf_sub_start" "printf_sub_end" "unsigned_loop" "myrand_x") echo gcc options "-fwrapv" "-fstrict-overflow" "-Wstrict-overflow=5" "-Wall" echo code options "simpler" "myrand_unsigned" "myrand_constants_ul" "printf_sub_start" "printf_sub_end" "unsigned_loop" "myrand_x" for ((j=0; j<16; j++)) do optionsx="" if ((j&1)); then optionsx="$optionsx ${opt_gcc[0]}"; fi if ((j&2)); then optionsx="$optionsx ${opt_gcc[1]}"; fi if ((j&4)); then optionsx="$optionsx ${opt_gcc[2]}"; fi if ((j&8)); then optionsx="$optionsx ${opt_gcc[3]}"; fi for ((i=0; i<128; i++)) do options=$optionsx if ((i& 1)); then options="$options -D ${opt_code[0]}"; fi if ((i& 2)); then options="$options -D ${opt_code[1]}"; fi if ((i& 4)); then options="$options -D ${opt_code[2]}"; fi if ((i& 8)); then options="$options -D ${opt_code[3]}"; fi if ((i&16)); then options="$options -D ${opt_code[4]}"; fi if ((i&32)); then options="$options -D ${opt_code[5]}"; fi if ((i&64)); then options="$options -D ${opt_code[6]}"; fi printf -v outfile "s-i-cc-%02d-%03d-d" $j $i time gcc -O3 -std=c99 $options simple-instrumented.c -o ${outfile} echo echo $outfile $options ./$outfile 3 | head -40 done done ======================================================================== I believe the 'bug' in the code is that the multiply in myrand uses a signed integer, and when it overflows, it causes all sorts of fun things to happen in the backend optimizer. How odd that I can 'fix' that problem, occasionally, by adding a printf between the entry to the subroutine and multiply. (It does not seem to matter when it's a 'multiply add'. Apparently, the more complex operation keeps the optimizer confused, and one printf anywhere causes it to fall out of that optimization pass.) I similarly seem to be able to 'defeat' the bug by adding two printf statements s-i-cc-00-000 s-i-cc-00-016 -D printf_sub_end s-i-cc-00-048 -D printf_sub_end -D unsigned_loop s-i-cc-00-032 -D unsigned_loop s-i-cc-00-008 -D printf_sub_start s-i-cc-00-024 -D printf_sub_start -D printf_sub_end s-i-cc-00-001 -D simpler s-i-cc-00-017 -D simpler -D printf_sub_end (It doesn't seem to matter which options are set for flags --- if -fwrapv is set, then the code runs correctly; if it is not, then the rest of the options don't seem to do anything different in terms of making it run or fail.) ... some observations: ... if an unsigned int is passed in, and the variable is printed before it is used, the bug is averted. ... just passing in an unsigned int value does not 'fix' the iteration counter. ... the code likes to run more cleanly if I ask to see the variable with printf before it is used. and I guess I'm not clear on what the type rules are if I pass in an unsigned int to a signed int value --- shouldn't that force all of the computations done with an unsigned int to be unsigned int computations? And if the optimizer is going to take a hit when I overflow the register, shouldn't -Wstrict-overflow=5 (or more) tell me about that?