From 8fa28a0db058eb53970f7eca3aaf71c86357e478 Mon Sep 17 00:00:00 2001 From: Artem Belevich Date: Thu, 31 Jan 2019 21:32:24 +0000 Subject: [PATCH] [CUDA] Propagate detected version of CUDA to cc1 ..and use it to control that parts of CUDA compilation that depend on the specific version of CUDA SDK. This patch has a placeholder for a 'new launch API' support which is in a separate patch. The list will be further extended in the upcoming patch to support CUDA-10.1. Differential Revision: https://reviews.llvm.org/D57487 llvm-svn: 352798 --- clang/include/clang/Basic/Cuda.h | 15 ++++++-- clang/include/clang/Basic/TargetOptions.h | 5 +++ clang/lib/Basic/Cuda.cpp | 46 +++++++++++++++++++++++ clang/lib/Driver/ToolChains/Clang.cpp | 16 +++++++- clang/lib/Driver/ToolChains/Cuda.cpp | 6 ++- clang/test/Driver/cuda-detect.cu | 22 +++++++++++ 6 files changed, 104 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 7c8ca8da42ff..532c23098eef 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -11,6 +11,7 @@ namespace llvm { class StringRef; +class VersionTuple; } // namespace llvm namespace clang { @@ -27,9 +28,8 @@ enum class CudaVersion { LATEST = CUDA_100, }; const char *CudaVersionToString(CudaVersion V); - -// No string -> CudaVersion conversion function because there's no canonical -// spelling of the various CUDA versions. +// Input is "Major.Minor" +CudaVersion CudaStringToVersion(llvm::StringRef S); enum class CudaArch { UNKNOWN, @@ -103,6 +103,15 @@ CudaVersion MinVersionForCudaArch(CudaArch A); /// Get the latest CudaVersion that supports the given CudaArch. CudaVersion MaxVersionForCudaArch(CudaArch A); +// Various SDK-dependent features that affect CUDA compilation +enum class CudaFeature { + // CUDA-9.2+ uses a new API for launching kernels. + CUDA_USES_NEW_LAUNCH, +}; + +bool CudaFeatureEnabled(llvm::VersionTuple, CudaFeature); +bool CudaFeatureEnabled(CudaVersion, CudaFeature); + } // namespace clang #endif diff --git a/clang/include/clang/Basic/TargetOptions.h b/clang/include/clang/Basic/TargetOptions.h index 45ecda1c2f99..bbe86aebb074 100644 --- a/clang/include/clang/Basic/TargetOptions.h +++ b/clang/include/clang/Basic/TargetOptions.h @@ -75,6 +75,11 @@ public: std::string CodeModel; /// The version of the SDK which was used during the compilation. + /// The option is used for two different purposes: + /// * on darwin the version is propagated to LLVM where it's used + /// to support SDK Version metadata (See D55673). + /// * CUDA compilation uses it to control parts of CUDA compilation + /// in clang that depend on specific version of the CUDA SDK. llvm::VersionTuple SDKVersion; }; diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index 6c34856dfdf7..6ba9a8437e2c 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -3,6 +3,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/VersionTuple.h" namespace clang { @@ -28,6 +29,17 @@ const char *CudaVersionToString(CudaVersion V) { llvm_unreachable("invalid enum"); } +CudaVersion CudaStringToVersion(llvm::StringRef S) { + return llvm::StringSwitch(S) + .Case("7.0", CudaVersion::CUDA_70) + .Case("7.5", CudaVersion::CUDA_75) + .Case("8.0", CudaVersion::CUDA_80) + .Case("9.0", CudaVersion::CUDA_90) + .Case("9.1", CudaVersion::CUDA_91) + .Case("9.2", CudaVersion::CUDA_92) + .Case("10.0", CudaVersion::CUDA_100); +} + const char *CudaArchToString(CudaArch A) { switch (A) { case CudaArch::LAST: @@ -322,4 +334,38 @@ CudaVersion MaxVersionForCudaArch(CudaArch A) { } } +static CudaVersion ToCudaVersion(llvm::VersionTuple Version) { + int IVer = + Version.getMajor() * 10 + Version.getMinor().getValueOr(0); + switch(IVer) { + case 70: + return CudaVersion::CUDA_70; + case 75: + return CudaVersion::CUDA_75; + case 80: + return CudaVersion::CUDA_80; + case 90: + return CudaVersion::CUDA_90; + case 91: + return CudaVersion::CUDA_91; + case 92: + return CudaVersion::CUDA_92; + case 100: + return CudaVersion::CUDA_100; + default: + return CudaVersion::UNKNOWN; + } +} + +bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) { + return CudaFeatureEnabled(ToCudaVersion(Version), Feature); +} + +bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) { + switch (Feature) { + case CudaFeature::CUDA_USES_NEW_LAUNCH: + return Version >= CudaVersion::CUDA_92; + } + llvm_unreachable("Unknown CUDA feature."); +} } // namespace clang diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2b668f76b581..c02446bcd5e5 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3464,13 +3464,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, NormalizedTriple = C.getSingleOffloadToolChain() ->getTriple() .normalize(); - else + else { + // Host-side compilation. NormalizedTriple = (IsCuda ? C.getSingleOffloadToolChain() : C.getSingleOffloadToolChain()) ->getTriple() .normalize(); - + if (IsCuda) { + // We need to figure out which CUDA version we're compiling for, as that + // determines how we load and launch GPU kernels. + auto *CTC = static_cast( + C.getSingleOffloadToolChain()); + assert(CTC && "Expected valid CUDA Toolchain."); + if (CTC && CTC->CudaInstallation.version() != CudaVersion::UNKNOWN) + CmdArgs.push_back(Args.MakeArgString( + Twine("-target-sdk-version=") + + CudaVersionToString(CTC->CudaInstallation.version()))); + } + } CmdArgs.push_back("-aux-triple"); CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); } diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 119c9fcd0d9e..e3fe84b10181 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -661,9 +661,13 @@ void CudaToolChain::addClangTargetOptions( options::OPT_fno_cuda_short_ptr, false)) CC1Args.append({"-mllvm", "--nvptx-short-ptr"}); + if (CudaInstallation.version() >= CudaVersion::UNKNOWN) + CC1Args.push_back(DriverArgs.MakeArgString( + Twine("-target-sdk-version=") + + CudaVersionToString(CudaInstallation.version()))); + if (DeviceOffloadingKind == Action::OFK_OpenMP) { SmallVector LibraryPaths; - if (const Arg *A = DriverArgs.getLastArg(options::OPT_libomptarget_nvptx_path_EQ)) LibraryPaths.push_back(A->getValue()); diff --git a/clang/test/Driver/cuda-detect.cu b/clang/test/Driver/cuda-detect.cu index e5dfe36571a7..7fff62c123b4 100644 --- a/clang/test/Driver/cuda-detect.cu +++ b/clang/test/Driver/cuda-detect.cu @@ -137,6 +137,16 @@ // RUN: --gcc-toolchain="" 2>&1 \ // RUN: | FileCheck %s --check-prefix CHECK-CXXINCLUDE +// Verify that CUDA SDK version is propagated to the CC1 compilations. +// RUN: %clang -### -v -target x86_64-linux-gnu --cuda-gpu-arch=sm_50 \ +// RUN: --cuda-path=%S/Inputs/CUDA_80/usr/local/cuda %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix CUDA80 + +// Verify that if no version file is found, we report the default of 7.0. +// RUN: %clang -### -v -target x86_64-linux-gnu --cuda-gpu-arch=sm_50 \ +// RUN: --cuda-path=%S/Inputs/CUDA/usr/local/cuda %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix CUDA70 + // CHECK: Found CUDA installation: {{.*}}/Inputs/CUDA/usr/local/cuda // NO-LIBDEVICE: Found CUDA installation: {{.*}}/Inputs/CUDA-nolibdevice/usr/local/cuda // NOCUDA-NOT: Found CUDA installation: @@ -167,3 +177,15 @@ // CHECK-CXXINCLUDE: clang{{.*}} "-cc1" "-triple" "x86_64-unknown-linux-gnu" // CHECK-CXXINCLUDE-SAME: {{.*}}"-internal-isystem" "{{.+}}/include/c++/4.8" // CHECK-CXXINCLUDE: ld{{.*}}" + +// CUDA80: clang{{.*}} "-cc1" "-triple" "nvptx64-nvidia-cuda" +// CUDA80-SAME: -target-sdk-version=8.0 +// CUDA80: clang{{.*}} "-cc1" "-triple" "x86_64-unknown-linux-gnu" +// CUDA80-SAME: -target-sdk-version=8.0 +// CUDA80: ld{{.*}}" + +// CUDA70: clang{{.*}} "-cc1" "-triple" "nvptx64-nvidia-cuda" +// CUDA70-SAME: -target-sdk-version=7.0 +// CUDA70: clang{{.*}} "-cc1" "-triple" "x86_64-unknown-linux-gnu" +// CUDA70-SAME: -target-sdk-version=7.0 +// CUDA70: ld{{.*}}"