From 3db8e486e560183f064e31a228aada52fdeac5d6 Mon Sep 17 00:00:00 2001 From: Artem Belevich Date: Tue, 17 Aug 2021 12:32:05 -0700 Subject: [PATCH] [CUDA] Improve CUDA version detection and diagnostics. Always use cuda.h to detect CUDA version. It's a more universal approach compared to version.txt which is no longer present in recent CUDA versions. Split the 'unknown CUDA version' warning in two: * when detected CUDA version is partially supported by clang. It's expected to work in general, at the feature parity with the latest supported CUDA version. and may be missing support for the new features/instructions/GPU variants. Clang will issue a warning. * when detected version is new. Recent CUDA versions have been working with clang reasonably well, and will likely to work similarly to the partially supported ones above. Or it may not work at all. Clang will issue a warning and proceed as if the latest known CUDA version was detected. Differential Revision: https://reviews.llvm.org/D108247 --- clang/include/clang/Basic/Cuda.h | 6 +- clang/include/clang/Basic/DiagnosticDriverKinds.td | 7 +- clang/lib/Basic/Cuda.cpp | 6 +- clang/lib/Driver/ToolChains/Cuda.cpp | 75 ++++++++-------------- clang/lib/Driver/ToolChains/Cuda.h | 7 +- .../Inputs/CUDA-new/usr/local/cuda/bin/.keep | 0 .../Inputs/CUDA-new/usr/local/cuda/include/.keep | 0 .../Inputs/CUDA-new/usr/local/cuda/include/cuda.h | 7 ++ .../Inputs/CUDA-new/usr/local/cuda/lib/.keep | 0 .../Inputs/CUDA-new/usr/local/cuda/lib64/.keep | 0 .../usr/local/cuda/nvvm/libdevice/libdevice.10.bc | 0 .../Inputs/CUDA-unknown/usr/local/cuda/version.txt | 1 - .../Inputs/CUDA_80/usr/local/cuda/include/cuda.h | 7 ++ .../Inputs/CUDA_80/usr/local/cuda/version.txt | 1 - .../Inputs/CUDA_90/usr/local/cuda/include/cuda.h | 7 ++ clang/test/Driver/cuda-version-check.cu | 18 +++--- 16 files changed, 71 insertions(+), 71 deletions(-) create mode 100644 clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/bin/.keep create mode 100644 clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/.keep create mode 100644 clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/cuda.h create mode 100644 clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib/.keep create mode 100644 clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib64/.keep create mode 100644 clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/nvvm/libdevice/libdevice.10.bc delete mode 100644 clang/test/Driver/Inputs/CUDA-unknown/usr/local/cuda/version.txt create mode 100644 clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/include/cuda.h delete mode 100644 clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/version.txt create mode 100644 clang/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/cuda.h diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 1bdb007..1aa24d8 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -33,8 +33,10 @@ enum class CudaVersion { CUDA_112, CUDA_113, CUDA_114, - LATEST = CUDA_114, - LATEST_SUPPORTED = CUDA_101, + FULLY_SUPPORTED = CUDA_101, + PARTIALLY_SUPPORTED = + CUDA_114, // Partially supported. Proceed with a warning. + NEW = 10000, // Too new. Issue a warning, but allow using it. }; const char *CudaVersionToString(CudaVersion V); // Input is "Major.Minor" diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 660f7e4..57e91bf 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -77,8 +77,11 @@ def err_drv_cuda_version_unsupported : Error< "but installation at %3 is %4; use '--cuda-path' to specify a different CUDA " "install, pass a different GPU arch with '--cuda-gpu-arch', or pass " "'--no-cuda-version-check'">; -def warn_drv_unknown_cuda_version: Warning< - "unknown CUDA version: %0; assuming the latest supported version %1">, +def warn_drv_new_cuda_version: Warning< + "CUDA version%0 is newer than the latest%select{| partially}1 supported version %2">, + InGroup; +def warn_drv_partially_supported_cuda_version: Warning< + "CUDA version %0 is only partially supported">, InGroup; def err_drv_cuda_host_arch : Error< "unsupported architecture '%0' for host compilation">; diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index 2e34da7..f5ee1fb 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -40,6 +40,8 @@ const char *CudaVersionToString(CudaVersion V) { return "11.3"; case CudaVersion::CUDA_114: return "11.4"; + case CudaVersion::NEW: + return ""; } llvm_unreachable("invalid enum"); } @@ -192,7 +194,7 @@ CudaVersion MinVersionForCudaArch(CudaArch A) { CudaVersion MaxVersionForCudaArch(CudaArch A) { // AMD GPUs do not depend on CUDA versions. if (IsAMDGpuArch(A)) - return CudaVersion::LATEST; + return CudaVersion::NEW; switch (A) { case CudaArch::UNKNOWN: @@ -203,7 +205,7 @@ CudaVersion MaxVersionForCudaArch(CudaArch A) { case CudaArch::SM_30: return CudaVersion::CUDA_110; default: - return CudaVersion::LATEST; + return CudaVersion::NEW; } } diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 0d94ad0..47c1228 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -17,6 +17,7 @@ #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -34,25 +35,6 @@ using namespace clang; using namespace llvm::opt; namespace { -struct CudaVersionInfo { - std::string DetectedVersion; - CudaVersion Version; -}; -// Parses the contents of version.txt in an CUDA installation. It should -// contain one line of the from e.g. "CUDA Version 7.5.2". -CudaVersionInfo parseCudaVersionFile(llvm::StringRef V) { - V = V.trim(); - if (!V.startswith("CUDA Version ")) - return {V.str(), CudaVersion::UNKNOWN}; - V = V.substr(strlen("CUDA Version ")); - SmallVector VersionParts; - V.split(VersionParts, '.'); - return {"version.txt: " + V.str() + ".", - VersionParts.size() < 2 - ? CudaVersion::UNKNOWN - : CudaStringToVersion( - join_items(".", VersionParts[0], VersionParts[1]))}; -} CudaVersion getCudaVersion(uint32_t raw_version) { if (raw_version < 7050) @@ -83,10 +65,10 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_113; if (raw_version < 11050) return CudaVersion::CUDA_114; - return CudaVersion::LATEST; + return CudaVersion::NEW; } -CudaVersionInfo parseCudaHFile(llvm::StringRef Input) { +CudaVersion parseCudaHFile(llvm::StringRef Input) { // Helper lambda which skips the words if the line starts with them or returns // None otherwise. auto StartsWithWords = @@ -106,21 +88,27 @@ CudaVersionInfo parseCudaHFile(llvm::StringRef Input) { StartsWithWords(Input.ltrim(), {"#", "define", "CUDA_VERSION"})) { uint32_t RawVersion; Line->consumeInteger(10, RawVersion); - return {"cuda.h: CUDA_VERSION=" + Twine(RawVersion).str() + ".", - getCudaVersion(RawVersion)}; + return getCudaVersion(RawVersion); } // Find next non-empty line. Input = Input.drop_front(Input.find_first_of("\n\r")).ltrim(); } - return {"cuda.h: CUDA_VERSION not found.", CudaVersion::UNKNOWN}; + return CudaVersion::UNKNOWN; } } // namespace void CudaInstallationDetector::WarnIfUnsupportedVersion() { - if (DetectedVersionIsNotSupported) - D.Diag(diag::warn_drv_unknown_cuda_version) - << DetectedVersion - << CudaVersionToString(CudaVersion::LATEST_SUPPORTED); + if (Version > CudaVersion::PARTIALLY_SUPPORTED) { + std::string VersionString = CudaVersionToString(Version); + if (!VersionString.empty()) + VersionString.insert(0, " "); + D.Diag(diag::warn_drv_new_cuda_version) + << VersionString + << (CudaVersion::PARTIALLY_SUPPORTED != CudaVersion::FULLY_SUPPORTED) + << CudaVersionToString(CudaVersion::PARTIALLY_SUPPORTED); + } else if (Version > CudaVersion::FULLY_SUPPORTED) + D.Diag(diag::warn_drv_partially_supported_cuda_version) + << CudaVersionToString(Version); } CudaInstallationDetector::CudaInstallationDetector( @@ -212,30 +200,17 @@ CudaInstallationDetector::CudaInstallationDetector( else continue; - CudaVersionInfo VersionInfo = {"", CudaVersion::UNKNOWN}; - if (auto VersionFile = FS.getBufferForFile(InstallPath + "/version.txt")) - VersionInfo = parseCudaVersionFile((*VersionFile)->getBuffer()); - // If version file didn't give us the version, try to find it in cuda.h - if (VersionInfo.Version == CudaVersion::UNKNOWN) - if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) - VersionInfo = parseCudaHFile((*CudaHFile)->getBuffer()); - // As the last resort, make an educated guess between CUDA-7.0, (which had - // no version.txt file and had old-style libdevice bitcode ) and an unknown - // recent CUDA version (no version.txt, new style bitcode). - if (VersionInfo.Version == CudaVersion::UNKNOWN) { - VersionInfo.Version = (FS.exists(LibDevicePath + "/libdevice.10.bc")) - ? Version = CudaVersion::LATEST - : Version = CudaVersion::CUDA_70; - VersionInfo.DetectedVersion = "no version found in version.txt or cuda.h"; + Version = CudaVersion::UNKNOWN; + if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) + Version = parseCudaHFile((*CudaHFile)->getBuffer()); + // As the last resort, make an educated guess between CUDA-7.0, which had + // old-style libdevice bitcode, and an unknown recent CUDA version. + if (Version == CudaVersion::UNKNOWN) { + Version = FS.exists(LibDevicePath + "/libdevice.10.bc") + ? CudaVersion::NEW + : CudaVersion::CUDA_70; } - Version = VersionInfo.Version; - DetectedVersion = VersionInfo.DetectedVersion; - - // TODO(tra): remove the warning once we have all features of 10.2 - // and 11.0 implemented. - DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED; - if (Version >= CudaVersion::CUDA_90) { // CUDA-9+ uses single libdevice file for all GPU variants. std::string FilePath = LibDevicePath + "/libdevice.10.bc"; diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 6ae4415..483fc30 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -30,8 +30,6 @@ private: const Driver &D; bool IsValid = false; CudaVersion Version = CudaVersion::UNKNOWN; - std::string DetectedVersion; - bool DetectedVersionIsNotSupported = false; std::string InstallPath; std::string BinPath; std::string LibPath; @@ -62,7 +60,10 @@ public: void print(raw_ostream &OS) const; /// Get the detected Cuda install's version. - CudaVersion version() const { return Version; } + CudaVersion version() const { + return Version == CudaVersion::NEW ? CudaVersion::PARTIALLY_SUPPORTED + : Version; + } /// Get the detected Cuda installation path. StringRef getInstallPath() const { return InstallPath; } /// Get the detected path to Cuda's bin directory. diff --git a/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/bin/.keep b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/bin/.keep new file mode 100644 index 0000000..e69de29 diff --git a/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/.keep b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/.keep new file mode 100644 index 0000000..e69de29 diff --git a/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/cuda.h b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/cuda.h new file mode 100644 index 0000000..e122489 --- /dev/null +++ b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/cuda.h @@ -0,0 +1,7 @@ +// +// Placeholder file for testing CUDA version detection +// + +#define CUDA_VERSION 99010 + +// diff --git a/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib/.keep b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib/.keep new file mode 100644 index 0000000..e69de29 diff --git a/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib64/.keep b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib64/.keep new file mode 100644 index 0000000..e69de29 diff --git a/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/nvvm/libdevice/libdevice.10.bc b/clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/nvvm/libdevice/libdevice.10.bc new file mode 100644 index 0000000..e69de29 diff --git a/clang/test/Driver/Inputs/CUDA-unknown/usr/local/cuda/version.txt b/clang/test/Driver/Inputs/CUDA-unknown/usr/local/cuda/version.txt deleted file mode 100644 index 20e55f7..0000000 --- a/clang/test/Driver/Inputs/CUDA-unknown/usr/local/cuda/version.txt +++ /dev/null @@ -1 +0,0 @@ -CUDA Version 999.999.999 diff --git a/clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/include/cuda.h b/clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/include/cuda.h new file mode 100644 index 0000000..c00fee1 --- /dev/null +++ b/clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/include/cuda.h @@ -0,0 +1,7 @@ +// +// Placeholder file for testing CUDA version detection +// + +#define CUDA_VERSION 8000 + +// diff --git a/clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/version.txt b/clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/version.txt deleted file mode 100644 index ee238af..0000000 --- a/clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/version.txt +++ /dev/null @@ -1 +0,0 @@ -CUDA Version 8.0.42 diff --git a/clang/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/cuda.h b/clang/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/cuda.h new file mode 100644 index 0000000..d38cfaa --- /dev/null +++ b/clang/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/cuda.h @@ -0,0 +1,7 @@ +// +// Placeholder file for testing CUDA version detection +// + +#define CUDA_VERSION 9000 + +// diff --git a/clang/test/Driver/cuda-version-check.cu b/clang/test/Driver/cuda-version-check.cu index 5844763..d6924c8 100644 --- a/clang/test/Driver/cuda-version-check.cu +++ b/clang/test/Driver/cuda-version-check.cu @@ -8,15 +8,12 @@ // RUN: FileCheck %s --check-prefix=OK // RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_80/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=OK -// Test version guess when no version.txt or cuda.h are found +// Test version guess when cuda.h has not been found // RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA-unknown/usr/local/cuda 2>&1 %s | \ // RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION -// Unknown version with version.txt present -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda 2>&1 %s | \ -// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION_V -// Unknown version with no version.txt but with version info present in cuda.h -// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda 2>&1 %s | \ -// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION_H +// Unknown version info present in cuda.h +// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA-new/usr/local/cuda 2>&1 %s | \ +// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION // Make sure that we don't warn about CUDA version during C++ compilation. // RUN: %clang --target=x86_64-linux -v -### -x c++ --cuda-gpu-arch=sm_60 \ // RUN: --cuda-path=%S/Inputs/CUDA-unknown/usr/local/cuda 2>&1 %s | \ @@ -66,13 +63,14 @@ // OK_SM35-NOT: error: GPU arch sm_35 // We should only get one error per architecture. +// ERR_SM20: error: GPU arch sm_20 {{.*}} +// ERR_SM20-NOT: error: GPU arch sm_20 + // ERR_SM60: error: GPU arch sm_60 {{.*}} // ERR_SM60-NOT: error: GPU arch sm_60 // ERR_SM61: error: GPU arch sm_61 {{.*}} // ERR_SM61-NOT: error: GPU arch sm_61 -// UNKNOWN_VERSION_V: unknown CUDA version: version.txt:{{.*}}; assuming the latest supported version -// UNKNOWN_VERSION_H: unknown CUDA version: cuda.h: CUDA_VERSION={{.*}}; assuming the latest supported version -// UNKNOWN_VERSION: unknown CUDA version: no version found in version.txt or cuda.h; assuming the latest supported version +// UNKNOWN_VERSION: CUDA version is newer than the latest{{.*}} supported version // UNKNOWN_VERSION_CXX-NOT: unknown CUDA version -- 2.7.4