[clang] 3db8e48 - [CUDA] Improve CUDA version detection and diagnostics.

Artem Belevich via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 23 13:26:46 PDT 2021


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


        


More information about the cfe-commits mailing list