commit 34ee5b9ce2d3ab1ccfb91016ee058949c69c1066 Author: Norvald H. Ryeng Date: Fri May 27 15:19:56 2016 +0200 Bug#23046775 DIFFERENT FLOATING POINT RESULTS ON ARM64 AND POWERPC Backport from trunk. Problem: The -fexpensive-optimizations option to gcc causes ARM64 and PowerPC build to compute floating point operations slightly differently from other platforms. This flag is enabled by -O2 and higher optimization levels. Fix: Check for the unwanted floating point behavior in CMake and disable expensive-optimizations in GCC builds on platforms that experience this behavior. diff --git a/cmake/build_configurations/compiler_options.cmake b/cmake/build_configurations/compiler_options.cmake index 98d553a..f105c7a 100644 --- a/cmake/build_configurations/compiler_options.cmake +++ b/cmake/build_configurations/compiler_options.cmake @@ -15,6 +15,7 @@ INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCXXCompilerFlag) +INCLUDE(cmake/floating_point.cmake) IF(SIZEOF_VOIDP EQUAL 4) SET(32BIT 1) @@ -33,6 +34,10 @@ IF(UNIX) IF(WITH_VALGRIND) SET(COMMON_C_FLAGS "-fno-inline ${COMMON_C_FLAGS}") ENDIF() + # Disable optimizations that change floating point results + IF(HAVE_C_FLOATING_POINT_OPTIMIZATION_PROBLEMS) + SET(COMMON_C_FLAGS "${COMMON_C_FLAGS} -fno-expensive-optimizations") + ENDIF() SET(CMAKE_C_FLAGS_DEBUG "${COMMON_C_FLAGS}") SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 ${COMMON_C_FLAGS}") ENDIF() @@ -48,6 +53,10 @@ IF(UNIX) IF(WITH_VALGRIND) SET(COMMON_CXX_FLAGS "-fno-inline ${COMMON_CXX_FLAGS}") ENDIF() + # Disable optimizations that change floating point results + IF(HAVE_CXX_FLOATING_POINT_OPTIMIZATION_PROBLEMS) + SET(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -fno-expensive-optimizations") + ENDIF() SET(CMAKE_CXX_FLAGS_DEBUG "${COMMON_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 ${COMMON_CXX_FLAGS}") ENDIF() diff --git a/cmake/floating_point.cmake b/cmake/floating_point.cmake new file mode 100644 index 0000000..6db63ad --- /dev/null +++ b/cmake/floating_point.cmake @@ -0,0 +1,56 @@ +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +INCLUDE(CheckCSourceRuns) +INCLUDE(CheckCXXSourceRuns) + +SET(code " + int main (int argc, char **argv) + { + double n[21] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,1 }; + double m= 0, s= 0; + int i; + for(i= 0; i < 21; i++) + { + double m_kminusone= m; + m= m_kminusone + (n[i] - m_kminusone) / (double) (i + 2); + s= s + (n[i] - m_kminusone) * (n[i] - m); + } + /* + s should now be either 5e 74 d1 45 17 5d 14 40 or + 40 14 5d 17 45 d1 74 5e, depending on endianness. If the floating point + operations are over optimized, the least significant byte is 5d instead + of 5e. + */ + return (*(unsigned char*)(&s) == 0x5e || + *((unsigned char*)(&s) + 7) == 0x5e); + }" +) + +SET(SAVE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") +SET(CMAKE_REQUIRED_FLAGS + "${CMAKE_REQUIRED_FLAGS} -O3 -fexpensive-optimizations" +) + +IF(CMAKE_COMPILER_IS_GNUCC) + CHECK_C_SOURCE_RUNS("${code}" HAVE_C_FLOATING_POINT_OPTIMIZATION_PROBLEMS) +ENDIF() + +IF(CMAKE_COMPILER_IS_GNUCXX) + CHECK_CXX_SOURCE_RUNS("${code}" HAVE_CXX_FLOATING_POINT_OPTIMIZATION_PROBLEMS) +ENDIF() + +SET(CMAKE_REQUIRED_FLAGS "${SAVE_CMAKE_REQUIRED_FLAGS}")