Index: clang/include/clang/Basic/Cuda.h =================================================================== --- clang/include/clang/Basic/Cuda.h +++ clang/include/clang/Basic/Cuda.h @@ -11,6 +11,7 @@ namespace llvm { class StringRef; +class VersionTuple; } // namespace llvm namespace clang { @@ -27,9 +28,8 @@ 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 @@ /// 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 Index: clang/include/clang/Basic/TargetOptions.h =================================================================== --- clang/include/clang/Basic/TargetOptions.h +++ clang/include/clang/Basic/TargetOptions.h @@ -75,6 +75,11 @@ 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; }; Index: clang/lib/Basic/Cuda.cpp =================================================================== --- clang/lib/Basic/Cuda.cpp +++ 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 @@ 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 @@ } } +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 Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -3464,13 +3464,25 @@ 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)); } Index: clang/lib/Driver/ToolChains/Cuda.cpp =================================================================== --- clang/lib/Driver/ToolChains/Cuda.cpp +++ clang/lib/Driver/ToolChains/Cuda.cpp @@ -661,9 +661,13 @@ 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()); Index: clang/test/Driver/cuda-detect.cu =================================================================== --- clang/test/Driver/cuda-detect.cu +++ 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{{.*}}"