Skip to content

Commit 06f479c

Browse files
Artem-Btstellar
authored andcommitted
[CUDA] Extract CUDA version from cuda.h if version.txt is not found
If CUDA version can not be determined based on version.txt file, attempt to find CUDA_VERSION macro in cuda.h. This is a follow-up to D89752, Differntial Revision: https://reviews.llvm.org/D89832 (cherry picked from commit e7fe125)
1 parent d50044e commit 06f479c

File tree

11 files changed

+108
-37
lines changed

11 files changed

+108
-37
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def err_drv_cuda_version_unsupported : Error<
6969
"install, pass a different GPU arch with --cuda-gpu-arch, or pass "
7070
"--no-cuda-version-check.">;
7171
def warn_drv_unknown_cuda_version: Warning<
72-
"Unknown CUDA version %0. Assuming the latest supported version %1">,
72+
"Unknown CUDA version. %0 Assuming the latest supported version %1">,
7373
InGroup<CudaUnknownVersion>;
7474
def err_drv_cuda_host_arch : Error<"unsupported architecture '%0' for host compilation.">;
7575
def err_drv_mix_cuda_hip : Error<"Mixed Cuda and HIP compilation is not supported.">;

clang/lib/Driver/ToolChains/Cuda.cpp

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/Driver/Driver.h"
1717
#include "clang/Driver/DriverDiagnostic.h"
1818
#include "clang/Driver/Options.h"
19+
#include "llvm/ADT/Optional.h"
1920
#include "llvm/Option/ArgList.h"
2021
#include "llvm/Support/FileSystem.h"
2122
#include "llvm/Support/Host.h"
@@ -32,29 +33,80 @@ using namespace clang::driver::tools;
3233
using namespace clang;
3334
using namespace llvm::opt;
3435

36+
namespace {
37+
struct CudaVersionInfo {
38+
std::string DetectedVersion;
39+
CudaVersion Version;
40+
};
3541
// Parses the contents of version.txt in an CUDA installation. It should
3642
// contain one line of the from e.g. "CUDA Version 7.5.2".
37-
void CudaInstallationDetector::ParseCudaVersionFile(llvm::StringRef V) {
38-
Version = CudaVersion::UNKNOWN;
43+
CudaVersionInfo parseCudaVersionFile(llvm::StringRef V) {
44+
V = V.trim();
3945
if (!V.startswith("CUDA Version "))
40-
return;
46+
return {V.str(), CudaVersion::UNKNOWN};
4147
V = V.substr(strlen("CUDA Version "));
4248
SmallVector<StringRef,4> VersionParts;
4349
V.split(VersionParts, '.');
44-
if (VersionParts.size() < 2)
45-
return;
46-
DetectedVersion = join_items(".", VersionParts[0], VersionParts[1]);
47-
Version = CudaStringToVersion(DetectedVersion);
48-
if (Version != CudaVersion::UNKNOWN) {
49-
// TODO(tra): remove the warning once we have all features of 10.2 and 11.0
50-
// implemented.
51-
DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED;
52-
return;
53-
}
50+
return {"version.txt: " + V.str() + ".",
51+
VersionParts.size() < 2
52+
? CudaVersion::UNKNOWN
53+
: CudaStringToVersion(
54+
join_items(".", VersionParts[0], VersionParts[1]))};
55+
}
56+
57+
CudaVersion getCudaVersion(uint32_t raw_version) {
58+
if (raw_version < 7050)
59+
return CudaVersion::CUDA_70;
60+
if (raw_version < 8000)
61+
return CudaVersion::CUDA_75;
62+
if (raw_version < 9000)
63+
return CudaVersion::CUDA_80;
64+
if (raw_version < 9010)
65+
return CudaVersion::CUDA_90;
66+
if (raw_version < 9020)
67+
return CudaVersion::CUDA_91;
68+
if (raw_version < 10000)
69+
return CudaVersion::CUDA_92;
70+
if (raw_version < 10010)
71+
return CudaVersion::CUDA_100;
72+
if (raw_version < 10020)
73+
return CudaVersion::CUDA_101;
74+
if (raw_version < 11000)
75+
return CudaVersion::CUDA_102;
76+
if (raw_version < 11010)
77+
return CudaVersion::CUDA_110;
78+
return CudaVersion::LATEST;
79+
}
5480

55-
Version = CudaVersion::LATEST_SUPPORTED;
56-
DetectedVersionIsNotSupported = true;
81+
CudaVersionInfo parseCudaHFile(llvm::StringRef Input) {
82+
// Helper lambda which skips the words if the line starts with them or returns
83+
// None otherwise.
84+
auto StartsWithWords =
85+
[](llvm::StringRef Line,
86+
const SmallVector<StringRef, 3> words) -> llvm::Optional<StringRef> {
87+
for (StringRef word : words) {
88+
if (!Line.consume_front(word))
89+
return {};
90+
Line = Line.ltrim();
91+
}
92+
return Line;
93+
};
94+
95+
Input = Input.ltrim();
96+
while (!Input.empty()) {
97+
if (auto Line =
98+
StartsWithWords(Input.ltrim(), {"#", "define", "CUDA_VERSION"})) {
99+
uint32_t RawVersion;
100+
Line->consumeInteger(10, RawVersion);
101+
return {"cuda.h: CUDA_VERSION=" + Twine(RawVersion).str() + ".",
102+
getCudaVersion(RawVersion)};
103+
}
104+
// Find next non-empty line.
105+
Input = Input.drop_front(Input.find_first_of("\n\r")).ltrim();
106+
}
107+
return {"cuda.h: CUDA_VERSION not found.", CudaVersion::UNKNOWN};
57108
}
109+
} // namespace
58110

59111
void CudaInstallationDetector::WarnIfUnsupportedVersion() {
60112
if (DetectedVersionIsNotSupported)
@@ -152,21 +204,31 @@ CudaInstallationDetector::CudaInstallationDetector(
152204
else
153205
continue;
154206

155-
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
156-
FS.getBufferForFile(InstallPath + "/version.txt");
157-
if (!VersionFile) {
158-
// CUDA 7.0 and CUDA 11.1+ do not have version.txt file.
159-
// Use libdevice file to distinguish 7.0 from the new versions.
160-
if (FS.exists(LibDevicePath + "/libdevice.10.bc")) {
161-
Version = CudaVersion::LATEST;
162-
DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED;
163-
} else {
164-
Version = CudaVersion::CUDA_70;
165-
}
166-
} else {
167-
ParseCudaVersionFile((*VersionFile)->getBuffer());
207+
CudaVersionInfo VersionInfo = {"", CudaVersion::UNKNOWN};
208+
if (auto VersionFile = FS.getBufferForFile(InstallPath + "/version.txt"))
209+
VersionInfo = parseCudaVersionFile((*VersionFile)->getBuffer());
210+
// If version file didn't give us the version, try to find it in cuda.h
211+
if (VersionInfo.Version == CudaVersion::UNKNOWN)
212+
if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h"))
213+
VersionInfo = parseCudaHFile((*CudaHFile)->getBuffer());
214+
// As the last resort, make an educated guess between CUDA-7.0, (which had
215+
// no version.txt file and had old-style libdevice bitcode ) and an unknown
216+
// recent CUDA version (no version.txt, new style bitcode).
217+
if (VersionInfo.Version == CudaVersion::UNKNOWN) {
218+
VersionInfo.Version = (FS.exists(LibDevicePath + "/libdevice.10.bc"))
219+
? Version = CudaVersion::LATEST
220+
: Version = CudaVersion::CUDA_70;
221+
VersionInfo.DetectedVersion =
222+
"No version found in version.txt or cuda.h.";
168223
}
169224

225+
Version = VersionInfo.Version;
226+
DetectedVersion = VersionInfo.DetectedVersion;
227+
228+
// TODO(tra): remove the warning once we have all features of 10.2
229+
// and 11.0 implemented.
230+
DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED;
231+
170232
if (Version >= CudaVersion::CUDA_90) {
171233
// CUDA-9+ uses single libdevice file for all GPU variants.
172234
std::string FilePath = LibDevicePath + "/libdevice.10.bc";

clang/lib/Driver/ToolChains/Cuda.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ class CudaInstallationDetector {
7878
return LibDeviceMap.lookup(Gpu);
7979
}
8080
void WarnIfUnsupportedVersion();
81-
82-
private:
83-
void ParseCudaVersionFile(llvm::StringRef V);
8481
};
8582

8683
namespace tools {

clang/test/Driver/Inputs/CUDA_102/usr/local/cuda/bin/.keep

Whitespace-only changes.

clang/test/Driver/Inputs/CUDA_102/usr/local/cuda/include/.keep

Whitespace-only changes.

clang/test/Driver/Inputs/CUDA_102/usr/local/cuda/lib/.keep

Whitespace-only changes.

clang/test/Driver/Inputs/CUDA_102/usr/local/cuda/lib64/.keep

Whitespace-only changes.

clang/test/Driver/Inputs/CUDA_102/usr/local/cuda/nvvm/libdevice/libdevice.10.bc

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CUDA Version 10.2.333
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//
2+
// Placeholder file for testing CUDA version detection
3+
//
4+
5+
#define CUDA_VERSION 11010
6+
7+
//

clang/test/Driver/cuda-version-check.cu

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
// RUN: FileCheck %s --check-prefix=OK
99
// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_80/usr/local/cuda 2>&1 %s | \
1010
// RUN: FileCheck %s --check-prefix=OK
11+
// Test version guess when no version.txt or cuda.h are found
1112
// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA-unknown/usr/local/cuda 2>&1 %s | \
1213
// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION
13-
// CUDA versions after 11.0 (update 1) do not carry version.txt file. Make sure
14-
// we still detect them as a new version and handle them the same as we handle
15-
// other new CUDA versions.
14+
// Unknown version with version.txt present
15+
// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda 2>&1 %s | \
16+
// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION_V
17+
// Unknown version with no version.txt but with version info present in cuda.h
1618
// RUN: %clang --target=x86_64-linux -v -### --cuda-gpu-arch=sm_60 --cuda-path=%S/Inputs/CUDA_111/usr/local/cuda 2>&1 %s | \
17-
// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION
19+
// RUN: FileCheck %s --check-prefix=UNKNOWN_VERSION_H
1820
// Make sure that we don't warn about CUDA version during C++ compilation.
1921
// RUN: %clang --target=x86_64-linux -v -### -x c++ --cuda-gpu-arch=sm_60 \
2022
// RUN: --cuda-path=%S/Inputs/CUDA-unknown/usr/local/cuda 2>&1 %s | \
@@ -70,5 +72,7 @@
7072
// ERR_SM61: error: GPU arch sm_61 {{.*}}
7173
// ERR_SM61-NOT: error: GPU arch sm_61
7274

73-
// UNKNOWN_VERSION: Unknown CUDA version {{.*}}. Assuming the latest supported version
75+
// UNKNOWN_VERSION_V: Unknown CUDA version. version.txt:{{.*}}. Assuming the latest supported version
76+
// UNKNOWN_VERSION_H: Unknown CUDA version. cuda.h: CUDA_VERSION={{.*}}. Assuming the latest supported version
77+
// UNKNOWN_VERSION: Unknown CUDA version. No version found in version.txt or cuda.h. Assuming the latest supported version
7478
// UNKNOWN_VERSION_CXX-NOT: Unknown CUDA version

0 commit comments

Comments
 (0)