# - Check the username performing the build, as well as date and time
#
-# gmx_detect_simd(GMX_SUGGESTED_SIMD)
+# gmx_detect_simd(_suggested_simd_)
#
-# Try to detect CPU information and suggest SIMD instruction set
+# Try to detect CPU features and suggest a SIMD instruction set
# that fits the current CPU. This should work on all architectures
# where we are not cross-compiling; depending on the architecture the
# detection will either use special assembly instructions (like cpuid),
# preprocessor defines, or probing /proc/cpuinfo on Linux.
#
-# This assumes gmx_detect_target_architecture() has already been run,
-# so that things like GMX_TARGET_X86 are already available.
-# (otherwise we cannot use inline ASM on x86).
-#
-# Sets ${GMX_SUGGESTED_SIMD} in the parent scope if
-# GMX_SIMD is not set (e.g. by the user, or a previous run
-# of CMake).
+# Sets ${suggested_simd} in the parent scope if GMX_SIMD is not set
+# (e.g. by the user, or a previous run of CMake).
#
# we rely on inline asm support for GNU!
include(gmxTestInlineASM)
+# Ensure things like GMX_TARGET_X86 are available
+include(gmxDetectTargetArchitecture)
+gmx_detect_target_architecture()
+include(gmxDetectCpu)
function(gmx_suggest_simd _suggested_simd)
- if(${_suggested_simd})
- # There's already been a suggestion made, which can't change
- return()
- endif()
-
- # for x86 we need inline asm to use cpuid
- gmx_test_inline_asm_gcc_x86(GMX_X86_GCC_INLINE_ASM)
-
- if(GMX_X86_GCC_INLINE_ASM)
- set(GCC_INLINE_ASM_DEFINE "-DGMX_X86_GCC_INLINE_ASM=1")
- else()
- set(GCC_INLINE_ASM_DEFINE "-DGMX_X86_GCC_INLINE_ASM=0")
+ if (NOT SUGGEST_SIMD_QUIETLY)
+ message(STATUS "Detecting best SIMD instructions for this CPU")
endif()
- message(STATUS "Detecting best SIMD instructions for this CPU")
-
- # Get CPU SIMD properties information
- if(GMX_TARGET_X86)
- set(GMX_TARGET_X86_VALUE 1)
- else()
- set(GMX_TARGET_X86_VALUE 0)
- endif()
- set(_compile_definitions "${GCC_INLINE_ASM_DEFINE} -I${CMAKE_SOURCE_DIR}/src -DGMX_CPUINFO_STANDALONE ${GMX_STDLIB_CXX_FLAGS} -DGMX_TARGET_X86=${GMX_TARGET_X86_VALUE}")
-
# Prepare a default suggestion
set(OUTPUT_SIMD "None")
- # We need to execute the binary, so this only works if not cross-compiling.
- # However, note that we are NOT limited to x86.
- if(NOT CMAKE_CROSSCOMPILING)
- # TODO Extract this try_compile to a helper function, because
- # it duplicates code in gmxSetBuildInformation.cmake
- set(GMX_DETECTSIMD_BINARY "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/GmxDetectSimd${CMAKE_EXECUTABLE_SUFFIX}")
- set(LINK_LIBRARIES "${GMX_STDLIB_LIBRARIES}")
- try_compile(GMX_DETECTSIMD_COMPILED
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/gromacs/hardware/cpuinfo.cpp"
- COMPILE_DEFINITIONS "${_compile_definitions}"
- CMAKE_FLAGS "-DLINK_LIBRARIES=${LINK_LIBRARIES}"
- OUTPUT_VARIABLE GMX_DETECTSIMD_COMPILED_OUTPUT
- COPY_FILE ${GMX_DETECTSIMD_BINARY})
- unset(_compile_definitions)
+ # Detect CPU features and place the string in CPU_DETECTION_FEATURES
+ # Note that we are NOT limited to x86.
+ gmx_run_cpu_detection(features)
+
+ if (DEFINED CPU_DETECTION_FEATURES)
+ # Make a concrete suggestion of SIMD level if a feature flag
+ # matches. Make sure that the match strings below work even if
+ # the feature is first or last.
+ set(CPU_DETECTION_FEATURES " ${CPU_DETECTION_FEATURES} ")
- if(GMX_DETECTSIMD_COMPILED)
- if(NOT DEFINED GMX_DETECTSIMD_RUN)
- execute_process(COMMAND ${GMX_DETECTSIMD_BINARY} "-features"
- RESULT_VARIABLE GMX_DETECTSIMD_RUN
- OUTPUT_VARIABLE OUTPUT_TMP
- ERROR_QUIET)
- set(GMX_DETECTSIMD_RUN "${GMX_DETECTSIMD_RUN}" CACHE INTERNAL "Result of running cpuinfo code to detect SIMD support")
- if(GMX_DETECTSIMD_RUN EQUAL 0)
- # Make a concrete suggestion of SIMD level
- if(GMX_TARGET_X86)
- if(OUTPUT_TMP MATCHES " avx512er ")
- set(OUTPUT_SIMD "AVX_512_KNL")
- elseif(OUTPUT_TMP MATCHES " avx512f ")
- set(OUTPUT_SIMD "AVX_512")
- elseif(OUTPUT_TMP MATCHES " avx2 ")
- set(OUTPUT_SIMD "AVX2_256")
- elseif(OUTPUT_TMP MATCHES " avx ")
- if(OUTPUT_TMP MATCHES " fma4 ")
- # AMD that works better with avx-128-fma
- set(OUTPUT_SIMD "AVX_128_FMA")
- else()
- # Intel
- set(OUTPUT_SIMD "AVX_256")
- endif()
- elseif(OUTPUT_TMP MATCHES " sse4.1 ")
- set(OUTPUT_SIMD "SSE4.1")
- elseif(OUTPUT_TMP MATCHES " sse2 ")
- set(OUTPUT_SIMD "SSE2")
- endif()
- else()
- if(OUTPUT_TMP MATCHES " vsx ")
- set(OUTPUT_SIMD "IBM_VSX")
- elseif(OUTPUT_TMP MATCHES " vmx ")
- set(OUTPUT_SIMD "IBM_VMX")
- elseif(OUTPUT_TMP MATCHES " qpx ")
- set(OUTPUT_SIMD "IBM_QPX")
- elseif(OUTPUT_TMP MATCHES " neon_asimd ")
- set(OUTPUT_SIMD "ARM_NEON_ASIMD")
- elseif(OUTPUT_TMP MATCHES " neon " AND NOT GMX_DOUBLE)
- set(OUTPUT_SIMD "ARM_NEON")
- endif()
- endif()
- message(STATUS "Detected best SIMD instructions for this CPU - ${OUTPUT_SIMD}")
+ if(GMX_TARGET_X86)
+ if(CPU_DETECTION_FEATURES MATCHES " avx512er ")
+ set(OUTPUT_SIMD "AVX_512_KNL")
+ elseif(CPU_DETECTION_FEATURES MATCHES " avx512f ")
+ set(OUTPUT_SIMD "AVX_512")
+ elseif(CPU_DETECTION_FEATURES MATCHES " avx2 ")
+ if(CPU_DETECTION_FEATURES MATCHES " amd ")
+ set(OUTPUT_SIMD "AVX2_128")
+ else()
+ set(OUTPUT_SIMD "AVX2_256")
+ endif()
+ elseif(CPU_DETECTION_FEATURES MATCHES " avx ")
+ if(CPU_DETECTION_FEATURES MATCHES " fma4 ")
+ # AMD that works better with avx-128-fma
+ set(OUTPUT_SIMD "AVX_128_FMA")
else()
- message(WARNING "Cannot run cpuinfo code, which means no SIMD suggestion can be made.")
- message(STATUS "Run output: ${OUTPUT_TMP}")
+ # Intel
+ set(OUTPUT_SIMD "AVX_256")
endif()
+ elseif(CPU_DETECTION_FEATURES MATCHES " sse4.1 ")
+ set(OUTPUT_SIMD "SSE4.1")
+ elseif(CPU_DETECTION_FEATURES MATCHES " sse2 ")
+ set(OUTPUT_SIMD "SSE2")
endif()
else()
- message(WARNING "Cannot compile cpuinfo code, which means no SIMD instructions.")
- message(STATUS "Compile output: ${GMX_DETECTSIMD_COMPILED_OUTPUT}")
+ if(CPU_DETECTION_FEATURES MATCHES " vsx ")
+ set(OUTPUT_SIMD "IBM_VSX")
+ elseif(CPU_DETECTION_FEATURES MATCHES " vmx ")
+ set(OUTPUT_SIMD "IBM_VMX")
+ elseif(CPU_DETECTION_FEATURES MATCHES " qpx ")
+ set(OUTPUT_SIMD "IBM_QPX")
+ elseif(CPU_DETECTION_FEATURES MATCHES " neon_asimd ")
+ set(OUTPUT_SIMD "ARM_NEON_ASIMD")
+ elseif(CPU_DETECTION_FEATURES MATCHES " neon " AND NOT GMX_DOUBLE)
+ set(OUTPUT_SIMD "ARM_NEON")
+ endif()
+ endif()
+ if (NOT SUGGEST_SIMD_QUIETLY)
+ message(STATUS "Detected best SIMD instructions for this CPU - ${OUTPUT_SIMD}")
endif()
else()
- message(WARNING "Cannot detect SIMD architecture for this cross-compile; you should check it manually.")
+ if (NOT SUGGEST_SIMD_QUIETLY)
+ message(STATUS "Detection for best SIMD instructions failed, using SIMD - ${OUTPUT_SIMD}")
+ endif()
endif()
- set(${_suggested_simd} "${OUTPUT_SIMD}" CACHE INTERNAL "Suggested SIMD")
+ set(${_suggested_simd} "${OUTPUT_SIMD}" PARENT_SCOPE)
+ set(SUGGEST_SIMD_QUIETLY TRUE CACHE INTERNAL "Be quiet during future construction of SIMD suggestions")
endfunction()
function(gmx_detect_simd _suggested_simd)
- if(NOT DEFINED GMX_SIMD)
+ if(GMX_SIMD STREQUAL "AUTO")
if(GMX_TARGET_BGQ)
+ # BG/Q requires cross-compilation, so needs this
+ # logic. While the qpx feature flag in cpuinfo works, it
+ # can't be returned by cpuinfo running on the build host.
set(${_suggested_simd} "IBM_QPX")
elseif(GMX_TARGET_FUJITSU_SPARC64)
# HPC-ACE is always present. In the future we