1#include "clang/Basic/Cuda.h"
2
3#include "llvm/ADT/StringRef.h"
4#include "llvm/ADT/StringSwitch.h"
5#include "llvm/ADT/Twine.h"
6#include "llvm/Support/ErrorHandling.h"
7#include "llvm/Support/VersionTuple.h"
8
9namespace clang {
10
11const char *CudaVersionToString(CudaVersion V) {
12  switch (V) {
13  case CudaVersion::UNKNOWN:
14    return "unknown";
15  case CudaVersion::CUDA_70:
16    return "7.0";
17  case CudaVersion::CUDA_75:
18    return "7.5";
19  case CudaVersion::CUDA_80:
20    return "8.0";
21  case CudaVersion::CUDA_90:
22    return "9.0";
23  case CudaVersion::CUDA_91:
24    return "9.1";
25  case CudaVersion::CUDA_92:
26    return "9.2";
27  case CudaVersion::CUDA_100:
28    return "10.0";
29  case CudaVersion::CUDA_101:
30    return "10.1";
31  case CudaVersion::CUDA_102:
32    return "10.2";
33  case CudaVersion::CUDA_110:
34    return "11.0";
35  }
36  llvm_unreachable("invalid enum");
37}
38
39CudaVersion CudaStringToVersion(const llvm::Twine &S) {
40  return llvm::StringSwitch<CudaVersion>(S.str())
41      .Case("7.0", CudaVersion::CUDA_70)
42      .Case("7.5", CudaVersion::CUDA_75)
43      .Case("8.0", CudaVersion::CUDA_80)
44      .Case("9.0", CudaVersion::CUDA_90)
45      .Case("9.1", CudaVersion::CUDA_91)
46      .Case("9.2", CudaVersion::CUDA_92)
47      .Case("10.0", CudaVersion::CUDA_100)
48      .Case("10.1", CudaVersion::CUDA_101)
49      .Case("10.2", CudaVersion::CUDA_102)
50      .Case("11.0", CudaVersion::CUDA_110)
51      .Default(CudaVersion::UNKNOWN);
52}
53
54struct CudaArchToStringMap {
55  CudaArch arch;
56  const char *arch_name;
57  const char *virtual_arch_name;
58};
59
60#define SM2(sm, ca)                                                            \
61  { CudaArch::SM_##sm, "sm_" #sm, ca }
62#define SM(sm) SM2(sm, "compute_" #sm)
63#define GFX(gpu)                                                               \
64  { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" }
65CudaArchToStringMap arch_names[] = {
66    // clang-format off
67    SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi
68    SM(30), SM(32), SM(35), SM(37),  // Kepler
69    SM(50), SM(52), SM(53),          // Maxwell
70    SM(60), SM(61), SM(62),          // Pascal
71    SM(70), SM(72),                  // Volta
72    SM(75),                          // Turing
73    SM(80),                          // Ampere
74    GFX(600), // tahiti
75    GFX(601), // pitcairn, verde, oland,hainan
76    GFX(700), // kaveri
77    GFX(701), // hawaii
78    GFX(702), // 290,290x,R390,R390x
79    GFX(703), // kabini mullins
80    GFX(704), // bonaire
81    GFX(801), // carrizo
82    GFX(802), // tonga,iceland
83    GFX(803), // fiji,polaris10
84    GFX(810), // stoney
85    GFX(900), // vega, instinct
86    GFX(902), GFX(904), GFX(906), GFX(908), GFX(909),
87    GFX(1010), GFX(1011), GFX(1012),
88    // clang-format on
89};
90#undef SM
91#undef SM2
92#undef GFX
93
94const char *CudaArchToString(CudaArch A) {
95  auto result = std::find_if(
96      std::begin(arch_names), std::end(arch_names),
97      [A](const CudaArchToStringMap &map) { return A == map.arch; });
98  if (result == std::end(arch_names))
99    return "unknown";
100  return result->arch_name;
101}
102
103const char *CudaArchToVirtualArchString(CudaArch A) {
104  auto result = std::find_if(
105      std::begin(arch_names), std::end(arch_names),
106      [A](const CudaArchToStringMap &map) { return A == map.arch; });
107  if (result == std::end(arch_names))
108    return "unknown";
109  return result->virtual_arch_name;
110}
111
112CudaArch StringToCudaArch(llvm::StringRef S) {
113  auto result = std::find_if(
114      std::begin(arch_names), std::end(arch_names),
115      [S](const CudaArchToStringMap &map) { return S == map.arch_name; });
116  if (result == std::end(arch_names))
117    return CudaArch::UNKNOWN;
118  return result->arch;
119}
120
121CudaVersion MinVersionForCudaArch(CudaArch A) {
122  if (A == CudaArch::UNKNOWN)
123    return CudaVersion::UNKNOWN;
124
125  // AMD GPUs do not depend on CUDA versions.
126  if (IsAMDGpuArch(A))
127    return CudaVersion::CUDA_70;
128
129  switch (A) {
130  case CudaArch::SM_20:
131  case CudaArch::SM_21:
132  case CudaArch::SM_30:
133  case CudaArch::SM_32:
134  case CudaArch::SM_35:
135  case CudaArch::SM_37:
136  case CudaArch::SM_50:
137  case CudaArch::SM_52:
138  case CudaArch::SM_53:
139    return CudaVersion::CUDA_70;
140  case CudaArch::SM_60:
141  case CudaArch::SM_61:
142  case CudaArch::SM_62:
143    return CudaVersion::CUDA_80;
144  case CudaArch::SM_70:
145    return CudaVersion::CUDA_90;
146  case CudaArch::SM_72:
147    return CudaVersion::CUDA_91;
148  case CudaArch::SM_75:
149    return CudaVersion::CUDA_100;
150  case CudaArch::SM_80:
151    return CudaVersion::CUDA_110;
152  default:
153    llvm_unreachable("invalid enum");
154  }
155}
156
157CudaVersion MaxVersionForCudaArch(CudaArch A) {
158  // AMD GPUs do not depend on CUDA versions.
159  if (IsAMDGpuArch(A))
160    return CudaVersion::LATEST;
161
162  switch (A) {
163  case CudaArch::UNKNOWN:
164    return CudaVersion::UNKNOWN;
165  case CudaArch::SM_20:
166  case CudaArch::SM_21:
167    return CudaVersion::CUDA_80;
168  default:
169    return CudaVersion::LATEST;
170  }
171}
172
173CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
174  int IVer =
175      Version.getMajor() * 10 + Version.getMinor().getValueOr(0);
176  switch(IVer) {
177  case 70:
178    return CudaVersion::CUDA_70;
179  case 75:
180    return CudaVersion::CUDA_75;
181  case 80:
182    return CudaVersion::CUDA_80;
183  case 90:
184    return CudaVersion::CUDA_90;
185  case 91:
186    return CudaVersion::CUDA_91;
187  case 92:
188    return CudaVersion::CUDA_92;
189  case 100:
190    return CudaVersion::CUDA_100;
191  case 101:
192    return CudaVersion::CUDA_101;
193  case 102:
194    return CudaVersion::CUDA_102;
195  case 110:
196    return CudaVersion::CUDA_110;
197  default:
198    return CudaVersion::UNKNOWN;
199  }
200}
201
202bool CudaFeatureEnabled(llvm::VersionTuple  Version, CudaFeature Feature) {
203  return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
204}
205
206bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
207  switch (Feature) {
208  case CudaFeature::CUDA_USES_NEW_LAUNCH:
209    return Version >= CudaVersion::CUDA_92;
210  case CudaFeature::CUDA_USES_FATBIN_REGISTER_END:
211    return Version >= CudaVersion::CUDA_101;
212  }
213  llvm_unreachable("Unknown CUDA feature.");
214}
215} // namespace clang
216