Author: Artem Belevich Date: 2021-08-23T13:24:48-07:00 New Revision: 3db8e486e560183f064e31a228aada52fdeac5d6
URL: https://github.com/llvm/llvm-project/commit/3db8e486e560183f064e31a228aada52fdeac5d6 DIFF: https://github.com/llvm/llvm-project/commit/3db8e486e560183f064e31a228aada52fdeac5d6.diff LOG: [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 Added: clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/bin/.keep clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/.keep clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/include/cuda.h clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib/.keep clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/lib64/.keep clang/test/Driver/Inputs/CUDA-new/usr/local/cuda/nvvm/libdevice/libdevice.10.bc clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/include/cuda.h clang/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/cuda.h Modified: clang/include/clang/Basic/Cuda.h clang/include/clang/Basic/DiagnosticDriverKinds.td clang/lib/Basic/Cuda.cpp clang/lib/Driver/ToolChains/Cuda.cpp clang/lib/Driver/ToolChains/Cuda.h clang/test/Driver/cuda-version-check.cu Removed: clang/test/Driver/Inputs/CUDA-unknown/usr/local/cuda/version.txt clang/test/Driver/Inputs/CUDA_80/usr/local/cuda/version.txt ################################################################################ diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 1bdb0077b8ef..1aa24d8060cf 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 660f7e418b9e..57e91bf52ef1 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 diff erent CUDA " "install, pass a diff erent 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<CudaUnknownVersion>; +def warn_drv_partially_supported_cuda_version: Warning< + "CUDA version %0 is only partially supported">, InGroup<CudaUnknownVersion>; 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 2e34da7fa867..f5ee1fb4c228 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 0d94ad0e66d7..47c1228b030f 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<StringRef,4> 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 6ae4415a563a..483fc302970b 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -30,8 +30,6 @@ class CudaInstallationDetector { 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 @@ class CudaInstallationDetector { 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e1224899c74a --- /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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 20e55f71b6ca..000000000000 --- 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 000000000000..c00fee1d10b7 --- /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 ee238af951a0..000000000000 --- 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 000000000000..d38cfaa08d3a --- /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 58447637ec3a..d6924c883c5b 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits