1e5dd7070Spatrick #include "clang/Basic/Cuda.h"
2e5dd7070Spatrick
3e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
4e5dd7070Spatrick #include "llvm/ADT/Twine.h"
5e5dd7070Spatrick #include "llvm/Support/ErrorHandling.h"
6e5dd7070Spatrick #include "llvm/Support/VersionTuple.h"
7e5dd7070Spatrick
8e5dd7070Spatrick namespace clang {
9e5dd7070Spatrick
10*12c85518Srobert struct CudaVersionMapEntry {
11*12c85518Srobert const char *Name;
12*12c85518Srobert CudaVersion Version;
13*12c85518Srobert llvm::VersionTuple TVersion;
14*12c85518Srobert };
15*12c85518Srobert #define CUDA_ENTRY(major, minor) \
16*12c85518Srobert { \
17*12c85518Srobert #major "." #minor, CudaVersion::CUDA_##major##minor, \
18*12c85518Srobert llvm::VersionTuple(major, minor) \
19e5dd7070Spatrick }
20*12c85518Srobert
21*12c85518Srobert static const CudaVersionMapEntry CudaNameVersionMap[] = {
22*12c85518Srobert CUDA_ENTRY(7, 0),
23*12c85518Srobert CUDA_ENTRY(7, 5),
24*12c85518Srobert CUDA_ENTRY(8, 0),
25*12c85518Srobert CUDA_ENTRY(9, 0),
26*12c85518Srobert CUDA_ENTRY(9, 1),
27*12c85518Srobert CUDA_ENTRY(9, 2),
28*12c85518Srobert CUDA_ENTRY(10, 0),
29*12c85518Srobert CUDA_ENTRY(10, 1),
30*12c85518Srobert CUDA_ENTRY(10, 2),
31*12c85518Srobert CUDA_ENTRY(11, 0),
32*12c85518Srobert CUDA_ENTRY(11, 1),
33*12c85518Srobert CUDA_ENTRY(11, 2),
34*12c85518Srobert CUDA_ENTRY(11, 3),
35*12c85518Srobert CUDA_ENTRY(11, 4),
36*12c85518Srobert CUDA_ENTRY(11, 5),
37*12c85518Srobert CUDA_ENTRY(11, 6),
38*12c85518Srobert CUDA_ENTRY(11, 7),
39*12c85518Srobert CUDA_ENTRY(11, 8),
40*12c85518Srobert {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())},
41*12c85518Srobert {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone.
42*12c85518Srobert };
43*12c85518Srobert #undef CUDA_ENTRY
44*12c85518Srobert
CudaVersionToString(CudaVersion V)45*12c85518Srobert const char *CudaVersionToString(CudaVersion V) {
46*12c85518Srobert for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
47*12c85518Srobert if (I->Version == V)
48*12c85518Srobert return I->Name;
49*12c85518Srobert
50*12c85518Srobert return CudaVersionToString(CudaVersion::UNKNOWN);
51e5dd7070Spatrick }
52e5dd7070Spatrick
CudaStringToVersion(const llvm::Twine & S)53e5dd7070Spatrick CudaVersion CudaStringToVersion(const llvm::Twine &S) {
54*12c85518Srobert std::string VS = S.str();
55*12c85518Srobert for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
56*12c85518Srobert if (I->Name == VS)
57*12c85518Srobert return I->Version;
58*12c85518Srobert return CudaVersion::UNKNOWN;
59*12c85518Srobert }
60*12c85518Srobert
ToCudaVersion(llvm::VersionTuple Version)61*12c85518Srobert CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
62*12c85518Srobert for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
63*12c85518Srobert if (I->TVersion == Version)
64*12c85518Srobert return I->Version;
65*12c85518Srobert return CudaVersion::UNKNOWN;
66e5dd7070Spatrick }
67e5dd7070Spatrick
68a9ac8606Spatrick namespace {
69ec727ea7Spatrick struct CudaArchToStringMap {
70ec727ea7Spatrick CudaArch arch;
71ec727ea7Spatrick const char *arch_name;
72ec727ea7Spatrick const char *virtual_arch_name;
73ec727ea7Spatrick };
74a9ac8606Spatrick } // namespace
75ec727ea7Spatrick
76ec727ea7Spatrick #define SM2(sm, ca) \
77ec727ea7Spatrick { CudaArch::SM_##sm, "sm_" #sm, ca }
78ec727ea7Spatrick #define SM(sm) SM2(sm, "compute_" #sm)
79ec727ea7Spatrick #define GFX(gpu) \
80ec727ea7Spatrick { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" }
81a9ac8606Spatrick static const CudaArchToStringMap arch_names[] = {
82ec727ea7Spatrick // clang-format off
83a9ac8606Spatrick {CudaArch::UNUSED, "", ""},
84ec727ea7Spatrick SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi
85ec727ea7Spatrick SM(30), SM(32), SM(35), SM(37), // Kepler
86ec727ea7Spatrick SM(50), SM(52), SM(53), // Maxwell
87ec727ea7Spatrick SM(60), SM(61), SM(62), // Pascal
88ec727ea7Spatrick SM(70), SM(72), // Volta
89ec727ea7Spatrick SM(75), // Turing
90a9ac8606Spatrick SM(80), SM(86), // Ampere
91*12c85518Srobert SM(87), // Jetson/Drive AGX Orin
92*12c85518Srobert SM(89), // Ada Lovelace
93*12c85518Srobert SM(90), // Hopper
94a9ac8606Spatrick GFX(600), // gfx600
95a9ac8606Spatrick GFX(601), // gfx601
96a9ac8606Spatrick GFX(602), // gfx602
97a9ac8606Spatrick GFX(700), // gfx700
98a9ac8606Spatrick GFX(701), // gfx701
99a9ac8606Spatrick GFX(702), // gfx702
100a9ac8606Spatrick GFX(703), // gfx703
101a9ac8606Spatrick GFX(704), // gfx704
102a9ac8606Spatrick GFX(705), // gfx705
103a9ac8606Spatrick GFX(801), // gfx801
104a9ac8606Spatrick GFX(802), // gfx802
105a9ac8606Spatrick GFX(803), // gfx803
106a9ac8606Spatrick GFX(805), // gfx805
107a9ac8606Spatrick GFX(810), // gfx810
108a9ac8606Spatrick GFX(900), // gfx900
109a9ac8606Spatrick GFX(902), // gfx902
110a9ac8606Spatrick GFX(904), // gfx903
111a9ac8606Spatrick GFX(906), // gfx906
112a9ac8606Spatrick GFX(908), // gfx908
113a9ac8606Spatrick GFX(909), // gfx909
114a9ac8606Spatrick GFX(90a), // gfx90a
115a9ac8606Spatrick GFX(90c), // gfx90c
116*12c85518Srobert GFX(940), // gfx940
117a9ac8606Spatrick GFX(1010), // gfx1010
118a9ac8606Spatrick GFX(1011), // gfx1011
119a9ac8606Spatrick GFX(1012), // gfx1012
120a9ac8606Spatrick GFX(1013), // gfx1013
121a9ac8606Spatrick GFX(1030), // gfx1030
122a9ac8606Spatrick GFX(1031), // gfx1031
123a9ac8606Spatrick GFX(1032), // gfx1032
124a9ac8606Spatrick GFX(1033), // gfx1033
125a9ac8606Spatrick GFX(1034), // gfx1034
126a9ac8606Spatrick GFX(1035), // gfx1035
127*12c85518Srobert GFX(1036), // gfx1036
128*12c85518Srobert GFX(1100), // gfx1100
129*12c85518Srobert GFX(1101), // gfx1101
130*12c85518Srobert GFX(1102), // gfx1102
131*12c85518Srobert GFX(1103), // gfx1103
132*12c85518Srobert {CudaArch::Generic, "generic", ""},
133ec727ea7Spatrick // clang-format on
134ec727ea7Spatrick };
135ec727ea7Spatrick #undef SM
136ec727ea7Spatrick #undef SM2
137ec727ea7Spatrick #undef GFX
138ec727ea7Spatrick
CudaArchToString(CudaArch A)139e5dd7070Spatrick const char *CudaArchToString(CudaArch A) {
140ec727ea7Spatrick auto result = std::find_if(
141ec727ea7Spatrick std::begin(arch_names), std::end(arch_names),
142ec727ea7Spatrick [A](const CudaArchToStringMap &map) { return A == map.arch; });
143ec727ea7Spatrick if (result == std::end(arch_names))
144e5dd7070Spatrick return "unknown";
145ec727ea7Spatrick return result->arch_name;
146e5dd7070Spatrick }
147ec727ea7Spatrick
CudaArchToVirtualArchString(CudaArch A)148ec727ea7Spatrick const char *CudaArchToVirtualArchString(CudaArch A) {
149ec727ea7Spatrick auto result = std::find_if(
150ec727ea7Spatrick std::begin(arch_names), std::end(arch_names),
151ec727ea7Spatrick [A](const CudaArchToStringMap &map) { return A == map.arch; });
152ec727ea7Spatrick if (result == std::end(arch_names))
153ec727ea7Spatrick return "unknown";
154ec727ea7Spatrick return result->virtual_arch_name;
155e5dd7070Spatrick }
156e5dd7070Spatrick
StringToCudaArch(llvm::StringRef S)157e5dd7070Spatrick CudaArch StringToCudaArch(llvm::StringRef S) {
158ec727ea7Spatrick auto result = std::find_if(
159ec727ea7Spatrick std::begin(arch_names), std::end(arch_names),
160ec727ea7Spatrick [S](const CudaArchToStringMap &map) { return S == map.arch_name; });
161ec727ea7Spatrick if (result == std::end(arch_names))
162ec727ea7Spatrick return CudaArch::UNKNOWN;
163ec727ea7Spatrick return result->arch;
164e5dd7070Spatrick }
165e5dd7070Spatrick
MinVersionForCudaArch(CudaArch A)166e5dd7070Spatrick CudaVersion MinVersionForCudaArch(CudaArch A) {
167ec727ea7Spatrick if (A == CudaArch::UNKNOWN)
168e5dd7070Spatrick return CudaVersion::UNKNOWN;
169ec727ea7Spatrick
170ec727ea7Spatrick // AMD GPUs do not depend on CUDA versions.
171ec727ea7Spatrick if (IsAMDGpuArch(A))
172ec727ea7Spatrick return CudaVersion::CUDA_70;
173ec727ea7Spatrick
174ec727ea7Spatrick switch (A) {
175e5dd7070Spatrick case CudaArch::SM_20:
176e5dd7070Spatrick case CudaArch::SM_21:
177e5dd7070Spatrick case CudaArch::SM_30:
178e5dd7070Spatrick case CudaArch::SM_32:
179e5dd7070Spatrick case CudaArch::SM_35:
180e5dd7070Spatrick case CudaArch::SM_37:
181e5dd7070Spatrick case CudaArch::SM_50:
182e5dd7070Spatrick case CudaArch::SM_52:
183e5dd7070Spatrick case CudaArch::SM_53:
184e5dd7070Spatrick return CudaVersion::CUDA_70;
185e5dd7070Spatrick case CudaArch::SM_60:
186e5dd7070Spatrick case CudaArch::SM_61:
187e5dd7070Spatrick case CudaArch::SM_62:
188e5dd7070Spatrick return CudaVersion::CUDA_80;
189e5dd7070Spatrick case CudaArch::SM_70:
190e5dd7070Spatrick return CudaVersion::CUDA_90;
191e5dd7070Spatrick case CudaArch::SM_72:
192e5dd7070Spatrick return CudaVersion::CUDA_91;
193e5dd7070Spatrick case CudaArch::SM_75:
194e5dd7070Spatrick return CudaVersion::CUDA_100;
195ec727ea7Spatrick case CudaArch::SM_80:
196ec727ea7Spatrick return CudaVersion::CUDA_110;
197a9ac8606Spatrick case CudaArch::SM_86:
198a9ac8606Spatrick return CudaVersion::CUDA_111;
199*12c85518Srobert case CudaArch::SM_87:
200*12c85518Srobert return CudaVersion::CUDA_114;
201*12c85518Srobert case CudaArch::SM_89:
202*12c85518Srobert case CudaArch::SM_90:
203*12c85518Srobert return CudaVersion::CUDA_118;
204ec727ea7Spatrick default:
205e5dd7070Spatrick llvm_unreachable("invalid enum");
206e5dd7070Spatrick }
207ec727ea7Spatrick }
208e5dd7070Spatrick
MaxVersionForCudaArch(CudaArch A)209e5dd7070Spatrick CudaVersion MaxVersionForCudaArch(CudaArch A) {
210ec727ea7Spatrick // AMD GPUs do not depend on CUDA versions.
211ec727ea7Spatrick if (IsAMDGpuArch(A))
212*12c85518Srobert return CudaVersion::NEW;
213ec727ea7Spatrick
214e5dd7070Spatrick switch (A) {
215e5dd7070Spatrick case CudaArch::UNKNOWN:
216e5dd7070Spatrick return CudaVersion::UNKNOWN;
217e5dd7070Spatrick case CudaArch::SM_20:
218e5dd7070Spatrick case CudaArch::SM_21:
219e5dd7070Spatrick return CudaVersion::CUDA_80;
220*12c85518Srobert case CudaArch::SM_30:
221ec727ea7Spatrick return CudaVersion::CUDA_110;
222e5dd7070Spatrick default:
223*12c85518Srobert return CudaVersion::NEW;
224e5dd7070Spatrick }
225e5dd7070Spatrick }
226e5dd7070Spatrick
CudaFeatureEnabled(llvm::VersionTuple Version,CudaFeature Feature)227e5dd7070Spatrick bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
228e5dd7070Spatrick return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
229e5dd7070Spatrick }
230e5dd7070Spatrick
CudaFeatureEnabled(CudaVersion Version,CudaFeature Feature)231e5dd7070Spatrick bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
232e5dd7070Spatrick switch (Feature) {
233e5dd7070Spatrick case CudaFeature::CUDA_USES_NEW_LAUNCH:
234e5dd7070Spatrick return Version >= CudaVersion::CUDA_92;
235e5dd7070Spatrick case CudaFeature::CUDA_USES_FATBIN_REGISTER_END:
236e5dd7070Spatrick return Version >= CudaVersion::CUDA_101;
237e5dd7070Spatrick }
238e5dd7070Spatrick llvm_unreachable("Unknown CUDA feature.");
239e5dd7070Spatrick }
240e5dd7070Spatrick } // namespace clang
241