Fix warnings with Intel 2021.4
[alexxy/gromacs.git] / cmake / gmxManageSYCL.cmake
index af133a12fabe3ce176fc90104bf769a9f579fa7b..2a9205a35f79cfa0b7afa7506aafd63295cbe817 100644 (file)
@@ -50,12 +50,184 @@ endif()
 
 include(gmxFindFlagsForSource)
 
+# Return all current CMake variables with name starting with "hipsycl" (case-insensitive).
+# Result is in the form of a list of flags ("-Dfoo=bar;-Dbaz=true").
+# Semicolons in values are escaped (needed for HIPSYCL_TARGETS).
+function(_getHipSyclCmakeFlags RETURN_VAR)
+    get_cmake_property(_VARS VARIABLES)
+    list (SORT _VARS)
+    set(RESULT "")
+    foreach (_VARNAME ${_VARS})
+            string(TOLOWER "${_VARNAME}" _VARNAME_LOWER)
+            if (${_VARNAME_LOWER} MATCHES "^hipsycl")
+                # Escape semicolon. The number of backslashes was determined empirically.
+                string(REPLACE ";" "\\\\\\;" _VARVALUE "${${_VARNAME}}")
+                list(APPEND
+                  RESULT
+                  -D${_VARNAME}=${_VARVALUE}
+                )
+            endif()
+    endforeach()
+    set("${RETURN_VAR}" ${RESULT} PARENT_SCOPE)
+endfunction()
+
 if(GMX_SYCL_HIPSYCL)
-    if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-        message(FATAL_ERROR "hipSYCL can only be built with Clang++ compiler")
-    endif()
     set(HIPSYCL_CLANG "${CMAKE_CXX_COMPILER}")
+    # -Wno-unknown-cuda-version because Clang-11 complains about CUDA 11.0-11.2, despite working fine with them.
+    # -Wno-unknown-attributes because hipSYCL does not support reqd_sub_group_size (because it can only do some sub group sizes).
+    set(HIPSYCL_SYCLCC_EXTRA_ARGS "-Wno-unknown-cuda-version -Wno-unknown-attributes")
+
+    # Must be called before find_package to capture all user-set CMake variables, but not those set automatically
+    _getHipSyclCmakeFlags(_ALL_HIPSYCL_CMAKE_FLAGS)
+
     find_package(hipsycl REQUIRED)
+    # Ensure the try_compile projects below find the same hipsycl)
+    list(APPEND _ALL_HIPSYCL_CMAKE_FLAGS -Dhipsycl_DIR=${hipsycl_DIR})
+
+    # If the user-set CMake variables change (e.g. because the user
+    # changed HIPSYCL_TARGETS), then the try_compile tests below need
+    # to be re-run. Set and use an internal cache variable to detect
+    # the change and set a flag to rerun the tests.
+    if (DEFINED GMX_ALL_HIPSYCL_CMAKE_FLAGS_COPY AND "${GMX_ALL_HIPSYCL_CMAKE_FLAGS_COPY}" STREQUAL "${_ALL_HIPSYCL_CMAKE_FLAGS}")
+        set(_rerun_hipsycl_try_compile_tests FALSE)
+    else()
+        # The new value should over-write the previous copy
+        set(GMX_ALL_HIPSYCL_CMAKE_FLAGS_COPY ${_ALL_HIPSYCL_CMAKE_FLAGS} CACHE INTERNAL "Store the list of CMake variables needed for hipSYCL compilation test projects")
+        set(_rerun_hipsycl_try_compile_tests TRUE)
+    endif()
+
+    # Does the hipSYCL compiler work at all for the given targets?
+    if (NOT DEFINED GMX_HIPSYCL_COMPILATION_WORKS OR _rerun_hipsycl_try_compile_tests)
+        message(STATUS "Checking for valid hipSYCL compiler")
+        try_compile(GMX_HIPSYCL_COMPILATION_WORKS "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest" "${CMAKE_SOURCE_DIR}/cmake/HipSyclTest/" "HipSyclTest"
+          OUTPUT_VARIABLE _HIPSYCL_COMPILATION_OUTPUT
+          CMAKE_FLAGS
+            ${_ALL_HIPSYCL_CMAKE_FLAGS})
+        file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest")
+        if(GMX_HIPSYCL_COMPILATION_WORKS)
+            message(STATUS "Checking for valid hipSYCL compiler - Success")
+        endif()
+    endif()
+    if (NOT GMX_HIPSYCL_COMPILATION_WORKS)
+        message(FATAL_ERROR "hipSYCL compiler not working:\n${_HIPSYCL_COMPILATION_OUTPUT}")
+    endif()
+
+    # Does hipSYCL compilation target CUDA devices?
+    if(NOT DEFINED GMX_HIPSYCL_HAVE_CUDA_TARGET OR _rerun_hipsycl_try_compile_tests)
+        message(STATUS "Checking for hipSYCL CUDA target")
+        try_compile(GMX_HIPSYCL_HAVE_CUDA_TARGET "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest" "${CMAKE_SOURCE_DIR}/cmake/HipSyclTest/" "HipSyclTest"
+          CMAKE_FLAGS
+            -DCHECK_CUDA_TARGET=ON
+            ${_ALL_HIPSYCL_CMAKE_FLAGS})
+        file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest")
+        if(GMX_HIPSYCL_HAVE_CUDA_TARGET)
+            message(STATUS "Checking for hipSYCL CUDA target - Success")
+        else()
+            message(STATUS "Checking for hipSYCL CUDA target - Failed")
+        endif()
+    endif()
+
+    # Does hipSYCL compilation target HIP devices?
+    if(NOT DEFINED GMX_HIPSYCL_HAVE_HIP_TARGET OR _rerun_hipsycl_try_compile_tests)
+        message(STATUS "Checking for hipSYCL HIP target")
+        try_compile(GMX_HIPSYCL_HAVE_HIP_TARGET "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest" "${CMAKE_SOURCE_DIR}/cmake/HipSyclTest/" "HipSyclTest"
+          CMAKE_FLAGS
+            -DCHECK_HIP_TARGET=ON
+            ${_ALL_HIPSYCL_CMAKE_FLAGS})
+        file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest")
+        if(GMX_HIPSYCL_HAVE_HIP_TARGET)
+            message(STATUS "Checking for hipSYCL HIP target - Success")
+        else()
+            message(STATUS "Checking for hipSYCL HIP target - Failed")
+        endif()
+    endif()
+
+    # Does hipSYCL compilation target Intel Level0 devices?
+    if(NOT DEFINED GMX_HIPSYCL_HAVE_LEVELZERO_TARGET OR _rerun_hipsycl_try_compile_tests)
+        message(STATUS "Checking for hipSYCL LevelZero target")
+        try_compile(GMX_HIPSYCL_HAVE_LEVELZERO_TARGET "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest" "${CMAKE_SOURCE_DIR}/cmake/HipSyclTest/" "HipSyclTest"
+          CMAKE_FLAGS
+            -DCHECK_LEVELZERO_TARGET=ON
+            ${_ALL_HIPSYCL_CMAKE_FLAGS})
+        file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/CMakeTmpHipSyclTest")
+        if(GMX_HIPSYCL_HAVE_LEVELZERO_TARGET)
+            message(STATUS "Checking for hipSYCL LevelZero target - Success")
+            message(WARNING "GROMACS does not support LevelZero backend of hipSYCL")
+        else()
+            message(STATUS "Checking for hipSYCL LevelZero target - Failed")
+        endif()
+    endif()
+
+    if(NOT GMX_HIPSYCL_HAVE_CUDA_TARGET AND NOT GMX_HIPSYCL_HAVE_HIP_TARGET)
+        message(WARNING "hipSYCL has no GPU targets set! Please, specify target hardware with -DHIPSYCL_TARGETS CMake option")
+    endif()
+    if(GMX_HIPSYCL_HAVE_CUDA_TARGET AND GMX_HIPSYCL_HAVE_HIP_TARGET)
+        message(FATAL_ERROR "hipSYCL cannot have both CUDA and HIP targets active! This would require explicit multipass mode which both decreases performance on NVIDIA devices and has been removed in clang 12. Compile only for either CUDA or HIP targets.")
+    endif()
+    unset(_rerun_hipsycl_try_compile_tests)
+
+    # Find a suitable rocFFT when hipSYCL is targeting AMD devices
+    if (GMX_HIPSYCL_HAVE_HIP_TARGET)
+        # For consistency, we prefer to find rocFFT as part of the
+        # default ROCm distribution that supports the version of
+        # hipSYCL that is being used. Other installations of rocFFT
+        # might work, but could lead to problems that are hard to
+        # trace.
+        #
+        # The hipSYCL find package sets HIPSYCL_SYCLCC which we can
+        # use to find the JSON configuration file that points to the
+        # default ROCm installation used by hipSYCL, which can be used
+        # to find rocFFT.
+        #
+        # If this is unavailable or does not work, the user will need to
+        # set CMAKE_PREFIX_PATH so CMake is able to find the dependencies
+        # of rocFFT (namely hip, AMDDeviceLibs, amd_comgr, hsa-runtime64,
+        # ROCclr).
+        if (HIPSYCL_SYCLCC)
+            get_filename_component(HIPSYCL_SYCLCC_DIR ${HIPSYCL_SYCLCC} DIRECTORY)
+            find_file(HIPSYCL_SYCLCC_JSON syclcc.json
+                HINTS ${HIPSYCL_SYCLCC_DIR}/../etc/hipSYCL
+               DOC "location of hipSYCL JSON configuration file"
+               )
+            if (HIPSYCL_SYCLCC_JSON)
+                if(NOT HIPSYCL_SYCLCC_ROCM_PATH)
+                    file(READ ${HIPSYCL_SYCLCC_JSON} HIPSYCL_SYCLCC_JSON_CONTENTS)
+                    if (CMAKE_VERSION VERSION_LESS 3.19)
+                        # We want the value encoded by the line
+                        # "default-rocm-path" : "/opt/rocm",
+                        # so we use regular expressions to remove everything before
+                        # and after the relevant quotation marks.
+                        #
+                        # Remove this when GROMACS requires CMake 3.19 or higher, as the
+                        # proper JSON parsing below is more robust.
+                        string(REGEX REPLACE ".*\"default-rocm-path\" *: * \"" "" HIPSYCL_SYCLCC_ROCM_PATH_VALUE ${HIPSYCL_SYCLCC_JSON_CONTENTS})
+                        string(REGEX REPLACE "\",.*" "" HIPSYCL_SYCLCC_ROCM_PATH_VALUE ${HIPSYCL_SYCLCC_ROCM_PATH_VALUE})
+                    else()
+                        string(JSON HIPSYCL_SYCLCC_ROCM_PATH_VALUE GET ${HIPSYCL_SYCLCC_JSON_CONTENTS} "default-rocm-path")
+                    endif()
+                    set(HIPSYCL_SYCLCC_ROCM_PATH ${HIPSYCL_SYCLCC_ROCM_PATH_VALUE} CACHE FILEPATH "The default ROCm used by syclcc from hipSYCL")
+                endif()
+
+                if(HIPSYCL_SYCLCC_ROCM_PATH)
+                    # Teach the rocFFT find package how to find the necessary components
+                    # from the ROCm distribution used by hipSYCL.
+                    set(hip_DIR ${HIPSYCL_SYCLCC_ROCM_PATH}/hip/lib/cmake/hip)
+                    set(AMDDeviceLibs_DIR ${HIPSYCL_SYCLCC_ROCM_PATH}/lib/cmake/AMDDeviceLibs)
+                    set(amd_comgr_DIR ${HIPSYCL_SYCLCC_ROCM_PATH}/lib/cmake/amd_comgr)
+                    set(hsa-runtime64_DIR ${HIPSYCL_SYCLCC_ROCM_PATH}/lib/cmake/hsa-runtime64)
+                    set(ROCclr_DIR ${HIPSYCL_SYCLCC_ROCM_PATH}/rocclr/lib/cmake/rocclr)
+                    set(rocfft_DIR ${HIPSYCL_SYCLCC_ROCM_PATH}/rocfft/lib/cmake/rocfft)
+                endif()
+            endif()
+        endif()
+
+        # Find rocFFT, either from the ROCm used by hipSYCL, or as otherwise found on the system
+        find_package(rocfft ${FIND_ROCFFT_QUIETLY} CONFIG HINTS ${HIPSYCL_SYCLCC_ROCM_PATH} PATHS /opt/rocm)
+        if (NOT rocfft_FOUND)
+            message(FATAL_ERROR "rocFFT is required for the hipSYCL build, but was not found")
+        endif()
+        set(FIND_ROCFFT_QUIETLY "QUIET")
+    endif()
 else()
     if(CMAKE_CXX_COMPILER MATCHES "dpcpp")
         # At least Intel dpcpp defaults to having SYCL enabled for all code. This leads to two problems:
@@ -105,7 +277,7 @@ else()
              sycl::queue q(sycl::default_selector{});
              return 0;
          }
-         " "CXX" DISABLE_SYCL_CXX_FLAGS SYCL_CXX_FLAGS "-fsycl -fsycl-device-code-split=per_kernel")
+         " "CXX" DISABLE_SYCL_CXX_FLAGS SYCL_CXX_FLAGS "-fsycl -fsycl-device-code-split=per_kernel -Wno-deprecated-declarations")
     
     if(NOT CHECK_SYCL_CXX_FLAGS_QUIETLY)
         if(SYCL_CXX_FLAGS_RESULT)
@@ -118,6 +290,11 @@ else()
         message(FATAL_ERROR "Cannot compile with SYCL Intel compiler. Try a different compiler or disable SYCL.")
     endif()
 
+    include(gmxManageFFTLibraries)
+    if(NOT GMX_FFT_MKL)
+        message(WARNING "Building SYCL version with ${GMX_FFT_LIBRARY} instead of MKL. GPU FFT is disabled!")
+    endif()
+
     # Add function wrapper similar to the one used by ComputeCPP and hipSYCL
     function(add_sycl_to_target)
         cmake_parse_arguments(