16
16
#include " clang/Driver/Driver.h"
17
17
#include " clang/Driver/DriverDiagnostic.h"
18
18
#include " clang/Driver/Options.h"
19
+ #include " llvm/ADT/Optional.h"
19
20
#include " llvm/Option/ArgList.h"
20
21
#include " llvm/Support/FileSystem.h"
21
22
#include " llvm/Support/Host.h"
@@ -32,29 +33,80 @@ using namespace clang::driver::tools;
32
33
using namespace clang ;
33
34
using namespace llvm ::opt;
34
35
36
+ namespace {
37
+ struct CudaVersionInfo {
38
+ std::string DetectedVersion;
39
+ CudaVersion Version;
40
+ };
35
41
// Parses the contents of version.txt in an CUDA installation. It should
36
42
// 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 () ;
39
45
if (!V.startswith (" CUDA Version " ))
40
- return ;
46
+ return {V. str (), CudaVersion::UNKNOWN} ;
41
47
V = V.substr (strlen (" CUDA Version " ));
42
48
SmallVector<StringRef,4 > VersionParts;
43
49
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
+ }
54
80
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};
57
108
}
109
+ } // namespace
58
110
59
111
void CudaInstallationDetector::WarnIfUnsupportedVersion () {
60
112
if (DetectedVersionIsNotSupported)
@@ -152,21 +204,31 @@ CudaInstallationDetector::CudaInstallationDetector(
152
204
else
153
205
continue ;
154
206
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." ;
168
223
}
169
224
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
+
170
232
if (Version >= CudaVersion::CUDA_90) {
171
233
// CUDA-9+ uses single libdevice file for all GPU variants.
172
234
std::string FilePath = LibDevicePath + " /libdevice.10.bc" ;
0 commit comments