https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64490
Bug ID: 64490 Summary: incorrect -O2 and -O3 optimization of the slightly different template functions Product: gcc Version: 4.9.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: ask at skidin dot org Created attachment 34373 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=34373&action=edit source code and small build scripts Source code: -------------- #include <iostream> #include <stdint.h> template <class T> void buggy_code_x64(T &dest) { // THIS CODE IS EXECUTED CORRECTLY ONLY IN O0 OR O1 OPTIMIZATION MODES dest=0x08; // L1 for (size_t k=0; k<7; k++) dest=(dest*16); // L2 // Here dest=0x80000000, this number cannot be represented by a signed 32-bit integer value. if (dest<0) std::cout << "Negative number, dest=" << dest; else std::cout << "Non-negative number, dest=" << dest; } template <class T> void correct_code_x64(T &dest) { // THIS CODE IS ALWAYS EXECUTED CORRECTLY. dest=0x0800; // L1 for (size_t k=0; k<5; k++) dest=(dest*16); // L2 // Here dest=0x80000000, this number cannot be represented by a signed 32-bit integer value. if (dest<0) std::cout << "Negative number, dest=" << dest; else std::cout << "Non-negative number, dest=" << dest; } int main() { int32_t val1; std::cout << "int32 test:" << std::endl; buggy_code_x64<int32_t>(val1); std::cout << std::endl; int32_t val2; std::cout << "int32 test:" << std::endl; correct_code_x64<int32_t>(val1); std::cout << std::endl; } -------------- Build keys: g++ -m64 -O0 -L"/usr/lib64" -pedantic -Werror -x c++ -o"bug-o0.exe" "bug.cpp" g++ -m64 -O1 -L"/usr/lib64" -pedantic -Werror -x c++ -o"bug-o1.exe" "bug.cpp" g++ -m64 -O2 -L"/usr/lib64" -pedantic -Werror -x c++ -o"bug-o2.exe" "bug.cpp" g++ -m64 -O3 -L"/usr/lib64" -pedantic -Werror -x c++ -o"bug-o3.exe" "bug.cpp" -------------- Behaviour when using -O0 and -O1 optimization: as expected, no error occured. Behaviour when using -O2, -O3 optimization levels on intel x64 architecture: buggy_code_x64<int32_t>(val1) prints incorrect statement "Non-negative number, dest=-2147483648". Expected behaviour: buggy_code_x64<int32_t>(val1) must print "Negative number, dest=-2147483648". -------------- G++ Versions: 1) 4.8.3 (OPENSUSE) Target: x86_64-suse-linux Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.8 --enable-ssp --disable-libssp --disable-plugin --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --disable-libmudflap --with-slibdir=/lib64 --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --enable-linker-build-id --enable-linux-futex --program-suffix=-4.8 --without-system-libunwind --with-arch-32=i586 --with-tune=generic --build=x86_64-suse-linux --host=x86_64-suse-linux Thread model: posix gcc version 4.8.3 20140627 [gcc-4_8-branch revision 212064] (SUSE Linux) 2) 4.9.2 (FEDORA) Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20141101/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20141101/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC) Additional information: 1. When replacing lines L1 and L2 by the following lines the error disappears: dest=0x800; // L1 for (k=0; k<5; k++) dest=(dest*16); // L2 The following variations of lines L1 and L2 are also error-free: dest=0x80000; // L1 for (k=0; k<3; k++) dest=(dest*16); // L2 dest=0x8000000; // L1 for (k=0; k<1; k++) dest=(dest*16); // L2 As it can be easily seen, the differences between these lines and those given in the source file should not affect the results. However they do. 2. The representation of function "buggy_code_x64" as a template function does matter, since the error appears only if the function is a template. 3. The function function "buggy_code_x64" was not found in the disassembly listing for -O2 and -O3 cases. Obviously, the compiler has predicted (incorrectly) the result that the function would return and did not include the function body to the binary executable. Of course, there is an integer overflow in the code and theoretically its behaviour could depend on the hardware it is executed on. However, the compiler should at least produce the same results for the same command line argument and for the equivalent parts of the code. P.S.: The similar error also exists for x86 architecture code (buggy_code<int64_t>, where dest=0x8000000000000000).