diff --git a/Help/release/dev/clang-cuda-offload-linker.rst b/Help/release/dev/clang-cuda-offload-linker.rst new file mode 100644 index 0000000000..6c229bec29 --- /dev/null +++ b/Help/release/dev/clang-cuda-offload-linker.rst @@ -0,0 +1,6 @@ +clang-cuda-offload-linker +------------------------- + +* Clang compiler version 20 and above use a new offload linker + model for CUDA where device linking is performed as part of the host link + phase. diff --git a/Modules/CMakeCUDACompiler.cmake.in b/Modules/CMakeCUDACompiler.cmake.in index 0643e2b15b..f86897028e 100644 --- a/Modules/CMakeCUDACompiler.cmake.in +++ b/Modules/CMakeCUDACompiler.cmake.in @@ -34,6 +34,10 @@ set(CMAKE_CUDA_COMPILER_LOADED 1) set(CMAKE_CUDA_COMPILER_ID_RUN 1) set(CMAKE_CUDA_SOURCE_FILE_EXTENSIONS cu) set(CMAKE_CUDA_LINKER_PREFERENCE 15) +if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND + CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0) + set(CMAKE_CUDA_LINKER_PREFERENCE 90) +endif() set(CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES 1) set(CMAKE_CUDA_LINKER_DEPFILE_SUPPORTED @CMAKE_CUDA_LINKER_DEPFILE_SUPPORTED@) set(CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED @CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED@) diff --git a/Modules/CMakeTestCUDACompiler.cmake b/Modules/CMakeTestCUDACompiler.cmake index dfea9031a3..c702cb4d7d 100644 --- a/Modules/CMakeTestCUDACompiler.cmake +++ b/Modules/CMakeTestCUDACompiler.cmake @@ -54,6 +54,7 @@ endif() # any makefiles or projects. if(NOT CMAKE_CUDA_COMPILER_WORKS) PrintTestCompilerStatus("CUDA") + __TestCompiler_setTryCompileTargetType() string(CONCAT __TestCompiler_testCudaCompilerSource "#ifndef __CUDACC__\n" "# error \"The CMAKE_CUDA_COMPILER is set to an invalid CUDA compiler\"\n" @@ -69,7 +70,7 @@ if(NOT CMAKE_CUDA_COMPILER_WORKS) NO_CACHE OUTPUT_VARIABLE __CMAKE_CUDA_COMPILER_OUTPUT) unset(__TestCompiler_testCudaCompilerSource) - + __TestCompiler_restoreTryCompileTargetType() if(NOT CMAKE_CUDA_COMPILER_WORKS) PrintTestCompilerResult(CHECK_FAIL "broken") string(REPLACE "\n" "\n " _output "${__CMAKE_CUDA_COMPILER_OUTPUT}") diff --git a/Modules/CMakeTestCompilerCommon.cmake b/Modules/CMakeTestCompilerCommon.cmake index 1b4dd6d1c5..7062dd81a5 100644 --- a/Modules/CMakeTestCompilerCommon.cmake +++ b/Modules/CMakeTestCompilerCommon.cmake @@ -21,6 +21,14 @@ macro(__TestCompiler_setTryCompileTargetType) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE 1) endif() + + if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND + CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0 AND + CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 23.0) + # https://github.com/llvm/llvm-project/issues/191041 + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + set(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE 1) + endif() endif() endmacro() diff --git a/Modules/Compiler/Clang-CUDA.cmake b/Modules/Compiler/Clang-CUDA.cmake index e563a28bba..5eecf1e7e3 100644 --- a/Modules/Compiler/Clang-CUDA.cmake +++ b/Modules/Compiler/Clang-CUDA.cmake @@ -22,6 +22,12 @@ set(_CMAKE_CUDA_WHOLE_FLAG "-c") set(_CMAKE_CUDA_RDC_FLAG "-fgpu-rdc") set(_CMAKE_CUDA_PTX_FLAG "--cuda-device-only -S") +if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0) + # Starting in 20.0, clang supports device linking as part of the host link phase + set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE FALSE) + set(_CMAKE_CUDA_RDC_LINK_FLAG "--offload-link") +endif() + # Device linking is just regular linking so these are the same. set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG ${CMAKE_CUDA_LINKER_WRAPPER_FLAG}) set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ${CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP}) @@ -29,8 +35,8 @@ set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ${CMAKE_CUDA_LINKER_WRAPPER_FLAG_S set(CMAKE_CUDA_DEVICE_LINK_MODE DRIVER) # RulePlaceholderExpander expands crosscompile variables like sysroot and target only for CMAKE__COMPILER. Override the default. -set(CMAKE_CUDA_LINK_EXECUTABLE " -o ${__IMPLICIT_LINKS}") -set(CMAKE_CUDA_CREATE_SHARED_LIBRARY " -o ${__IMPLICIT_LINKS}") +set(CMAKE_CUDA_LINK_EXECUTABLE " ${_CMAKE_CUDA_RDC_LINK_FLAG} -o ${__IMPLICIT_LINKS}") +set(CMAKE_CUDA_CREATE_SHARED_LIBRARY " ${_CMAKE_CUDA_RDC_LINK_FLAG} -o ${__IMPLICIT_LINKS}") set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC") set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "cudadevrt;cudart_static") diff --git a/Modules/Internal/CMakeCUDAArchitecturesAll.cmake b/Modules/Internal/CMakeCUDAArchitecturesAll.cmake index 1c095d1559..1bb4292357 100644 --- a/Modules/Internal/CMakeCUDAArchitecturesAll.cmake +++ b/Modules/Internal/CMakeCUDAArchitecturesAll.cmake @@ -12,6 +12,12 @@ function(cmake_cuda_architectures_all lang lang_var_) # Initial set based on CUDA 13.0. set(CMAKE_CUDA_ARCHITECTURES_ALL 75 80 86 87 88 89 90 100 103 110 120 121) set(CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 75 80 90 100 110 120) + + if((CMAKE_${lang}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 23.0)) + list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 110) + list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 110) + endif() + else() # Initial set based on CUDA 7.0. set(CMAKE_CUDA_ARCHITECTURES_ALL 20 21 30 35 37 50 52 53) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 0a3645eb65..1ff5bd78d1 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2838,19 +2838,40 @@ void cmGeneratorTarget::AddCUDAArchitectureFlagsImpl(cmBuildStep compileOrLink, flags += "]\""; } } else if (compiler == "Clang" && compileOrLink == cmBuildStep::Compile) { - for (CudaArchitecture& architecture : architectures) { - flags = - cmStrCat(std::move(flags), " --cuda-gpu-arch=sm_", architecture.name); + if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + this->Makefile->GetDefinition(cmStrCat( + "CMAKE_", lang, "_COMPILER_VERSION")), + "20.0")) { + for (CudaArchitecture& architecture : architectures) { + flags = + cmStrCat(std::move(flags), " --offload-arch=sm_", architecture.name); - if (!architecture.real) { - this->Makefile->IssueMessage( - MessageType::WARNING, - "Clang doesn't support disabling CUDA real code generation."); + if (!architecture.real) { + this->Makefile->IssueMessage( + MessageType::WARNING, + "Clang doesn't support disabling CUDA real code generation."); + } + + if (architecture.virtual_) { + flags = cmStrCat(std::move(flags), " --cuda-include-ptx=sm_", + architecture.name); + } } - - if (!architecture.virtual_) { - flags = cmStrCat(std::move(flags), " --no-cuda-include-ptx=sm_", + } else { + for (CudaArchitecture& architecture : architectures) { + flags = cmStrCat(std::move(flags), " --cuda-gpu-arch=sm_", architecture.name); + + if (!architecture.real) { + this->Makefile->IssueMessage( + MessageType::WARNING, + "Clang doesn't support disabling CUDA real code generation."); + } + + if (!architecture.virtual_) { + flags = cmStrCat(std::move(flags), " --no-cuda-include-ptx=sm_", + architecture.name); + } } } } diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt index cfe47daa0d..62c58b9e34 100644 --- a/Tests/Cuda/CMakeLists.txt +++ b/Tests/Cuda/CMakeLists.txt @@ -9,7 +9,8 @@ add_cuda_test_macro(Cuda.ObjectLibrary CudaObjectLibrary) add_cuda_test_macro(Cuda.MixedStandardLevels1 MixedStandardLevels1) add_cuda_test_macro(Cuda.MixedStandardLevels2 MixedStandardLevels2) add_cuda_test_macro(Cuda.MixedStandardLevels3 MixedStandardLevels3) -if(NOT WIN32 OR NOT CMake_TEST_CUDA STREQUAL "Clang") # MSVC std lib needs C++14 +if(NOT WIN32 AND CMake_TEST_CUDA STREQUAL "NVIDIA") + # MSVC std lib, and newer clang needs C++14 add_cuda_test_macro(Cuda.MixedStandardLevels4 MixedStandardLevels4) add_cuda_test_macro(Cuda.MixedStandardLevels5 MixedStandardLevels5) endif() diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt index 396f6d38ab..6cfd8421d8 100644 --- a/Tests/CudaOnly/CMakeLists.txt +++ b/Tests/CudaOnly/CMakeLists.txt @@ -13,7 +13,8 @@ add_cuda_test_macro(CudaOnly.EnableStandard CudaOnlyEnableStandard) add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX) add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit) add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit) -if(NOT WIN32 OR NOT CMake_TEST_CUDA STREQUAL "Clang") # MSVC std lib needs C++14 +if(NOT WIN32 AND CMake_TEST_CUDA STREQUAL "NVIDIA") + # MSVC std lib, and newer clang needs C++14 add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98) endif() set(CudaOnly.Toolkit_BUILD_OPTIONS -DHAS_CUPTI:BOOL=${CMake_TEST_CUDA_CUPTI}) @@ -24,12 +25,13 @@ add_cuda_test_macro(CudaOnly.TryCompileTargetStatic CudaOnlyTryCompileTargetStat add_cuda_test_macro(CudaOnly.Unity CudaOnlyUnity) add_cuda_test_macro(CudaOnly.WithDefs CudaOnlyWithDefs) add_cuda_test_macro(CudaOnly.CircularLinkLine CudaOnlyCircularLinkLine) -add_cuda_test_macro(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols) add_cuda_test_macro(CudaOnly.SeparateCompilation main/CudaOnlySeparateCompilation) add_cuda_test_macro(CudaOnly.SeparateCompilationPTX CudaOnlySeparateCompilationPTX) add_cuda_test_macro(CudaOnly.SeparateCompilationTargetObjects CudaOnlySeparateCompilationTargetObjects) if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang") + add_cuda_test_macro(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols) + # Clang doesn't have flags for selecting the runtime. add_cuda_test_macro(CudaOnly.SharedRuntimeViaCUDAFlags CudaOnlySharedRuntimeViaCUDAFlags) diff --git a/Tests/CudaOnly/SeparateCompilationPTX/main.cu b/Tests/CudaOnly/SeparateCompilationPTX/main.cu index 1c0482201f..dc07b923f5 100644 --- a/Tests/CudaOnly/SeparateCompilationPTX/main.cu +++ b/Tests/CudaOnly/SeparateCompilationPTX/main.cu @@ -4,6 +4,13 @@ #include "embedded_objs.h" +#if defined(CUDA_VERSION) && \ + CUDA_VERSION >= 13000 // get version from cuda.h header (clang cuda) +# define CUDA_13_OR_GREATER +#elif defined(__CUDACC_VER_MAJOR__) && \ + __CUDACC_VER_MAJOR__ >= 13 // get version from nvcc compiler defines +# define CUDA_13_OR_GREATER +#endif int main() { cuInit(0); @@ -18,7 +25,7 @@ int main() cuDeviceGet(&device, 0); CUcontext context; -#if defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ >= 13 +#if defined(CUDA_13_OR_GREATER) CUctxCreateParams params = {}; params.execAffinityParams = nullptr; params.numExecAffinityParams = 0; diff --git a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake index 45ef4a3f07..d71d608ee0 100644 --- a/Tests/RunCMake/target_link_options/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_link_options/RunCMakeTest.cmake @@ -61,14 +61,19 @@ if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel") run_cmake_target(genex_LINK_LANG_AND_ID exe LinkOptions_exe --config Release) run_cmake(genex_DEVICE_LINK) + if (CMake_TEST_CUDA) + include("${RunCMake_BINARY_DIR}/genex_DEVICE_LINK-build/info.cmake" OPTIONAL) + endif() run_cmake_target(genex_DEVICE_LINK interface LinkOptions_shared_interface --config Release) run_cmake_target(genex_DEVICE_LINK private LinkOptions_private --config Release) if (CMake_TEST_CUDA) run_cmake_target(genex_DEVICE_LINK CMP0105_UNSET LinkOptions_CMP0105_UNSET --config Release) run_cmake_target(genex_DEVICE_LINK CMP0105_OLD LinkOptions_CMP0105_OLD --config Release) - run_cmake_target(genex_DEVICE_LINK CMP0105_NEW LinkOptions_CMP0105_NEW --config Release) - run_cmake_target(genex_DEVICE_LINK device LinkOptions_device --config Release) + if (CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE) + run_cmake_target(genex_DEVICE_LINK CMP0105_NEW LinkOptions_CMP0105_NEW --config Release) + run_cmake_target(genex_DEVICE_LINK device LinkOptions_device --config Release) + endif() if (RunCMake_GENERATOR MATCHES "(Ninja|Unix Makefiles)") run_cmake_target(genex_DEVICE_LINK host_link_options LinkOptions_host_link_options --config Release ${VERBOSE}) diff --git a/Tests/RunCMake/target_link_options/genex_DEVICE_LINK.cmake b/Tests/RunCMake/target_link_options/genex_DEVICE_LINK.cmake index b6c9ee67bf..e9afe8f1d1 100644 --- a/Tests/RunCMake/target_link_options/genex_DEVICE_LINK.cmake +++ b/Tests/RunCMake/target_link_options/genex_DEVICE_LINK.cmake @@ -36,7 +36,6 @@ if (CMake_TEST_CUDA) target_link_options(LinkOptions_CMP0105_OLD PRIVATE $) cmake_policy(SET CMP0105 NEW) - add_executable(LinkOptions_CMP0105_NEW LinkOptionsDevice.cu) set_property(TARGET LinkOptions_CMP0105_NEW PROPERTY CUDA_SEPARABLE_COMPILATION ON) target_link_options(LinkOptions_CMP0105_NEW PRIVATE $) @@ -45,7 +44,6 @@ if (CMake_TEST_CUDA) set_property(TARGET LinkOptions_device PROPERTY CUDA_SEPARABLE_COMPILATION ON) target_link_options(LinkOptions_device PRIVATE $ $) - add_executable(LinkOptions_host_link_options LinkOptionsDevice.cu) set_property(TARGET LinkOptions_host_link_options PROPERTY CUDA_SEPARABLE_COMPILATION ON) if(CMake_TEST_CUDA STREQUAL "NVIDIA") @@ -57,4 +55,8 @@ if (CMake_TEST_CUDA) add_executable(LinkOptions_no_device LinkOptionsDevice.cu) target_link_options(LinkOptions_no_device PRIVATE $ $) + + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" + "set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE \"${CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE}\")\n" + ) endif() diff --git a/Tests/RunCMake/try_compile/CudaStandard-stderr.txt b/Tests/RunCMake/try_compile/CudaStandard-stderr.txt index e99f5389d0..3ce4588a65 100644 --- a/Tests/RunCMake/try_compile/CudaStandard-stderr.txt +++ b/Tests/RunCMake/try_compile/CudaStandard-stderr.txt @@ -1,4 +1,4 @@ -^CMake Error at .*/Tests/RunCMake/try_compile/CudaStandard-build/CMakeFiles/CMake(Tmp|Scratch/TryCompile-[^/]+)/CMakeLists\.txt:[0-9]+ \(add_executable\): +^CMake Error at .*/Tests/RunCMake/try_compile/CudaStandard-build/CMakeFiles/CMake(Tmp|Scratch/TryCompile-[^/]+)/CMakeLists\.txt:[0-9]+ \(.*\): CUDA_STANDARD is set to invalid value '4' + CMake Error at CudaStandard\.cmake:[0-9]+ \(try_compile\):