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
9 namespace clang {
10
CudaVersionToString(CudaVersion V)11 const 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 case CudaVersion::CUDA_111:
36 return "11.1";
37 case CudaVersion::CUDA_112:
38 return "11.2";
39 }
40 llvm_unreachable("invalid enum");
41 }
42
CudaStringToVersion(const llvm::Twine & S)43 CudaVersion CudaStringToVersion(const llvm::Twine &S) {
44 return llvm::StringSwitch<CudaVersion>(S.str())
45 .Case("7.0", CudaVersion::CUDA_70)
46 .Case("7.5", CudaVersion::CUDA_75)
47 .Case("8.0", CudaVersion::CUDA_80)
48 .Case("9.0", CudaVersion::CUDA_90)
49 .Case("9.1", CudaVersion::CUDA_91)
50 .Case("9.2", CudaVersion::CUDA_92)
51 .Case("10.0", CudaVersion::CUDA_100)
52 .Case("10.1", CudaVersion::CUDA_101)
53 .Case("10.2", CudaVersion::CUDA_102)
54 .Case("11.0", CudaVersion::CUDA_110)
55 .Case("11.1", CudaVersion::CUDA_111)
56 .Case("11.2", CudaVersion::CUDA_112)
57 .Default(CudaVersion::UNKNOWN);
58 }
59
60 namespace {
61 struct CudaArchToStringMap {
62 CudaArch arch;
63 const char *arch_name;
64 const char *virtual_arch_name;
65 };
66 } // namespace
67
68 #define SM2(sm, ca) \
69 { CudaArch::SM_##sm, "sm_" #sm, ca }
70 #define SM(sm) SM2(sm, "compute_" #sm)
71 #define GFX(gpu) \
72 { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" }
73 static const CudaArchToStringMap arch_names[] = {
74 // clang-format off
75 {CudaArch::UNUSED, "", ""},
76 SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi
77 SM(30), SM(32), SM(35), SM(37), // Kepler
78 SM(50), SM(52), SM(53), // Maxwell
79 SM(60), SM(61), SM(62), // Pascal
80 SM(70), SM(72), // Volta
81 SM(75), // Turing
82 SM(80), SM(86), // Ampere
83 GFX(600), // gfx600
84 GFX(601), // gfx601
85 GFX(602), // gfx602
86 GFX(700), // gfx700
87 GFX(701), // gfx701
88 GFX(702), // gfx702
89 GFX(703), // gfx703
90 GFX(704), // gfx704
91 GFX(705), // gfx705
92 GFX(801), // gfx801
93 GFX(802), // gfx802
94 GFX(803), // gfx803
95 GFX(805), // gfx805
96 GFX(810), // gfx810
97 GFX(900), // gfx900
98 GFX(902), // gfx902
99 GFX(904), // gfx903
100 GFX(906), // gfx906
101 GFX(908), // gfx908
102 GFX(909), // gfx909
103 GFX(90a), // gfx90a
104 GFX(90c), // gfx90c
105 GFX(1010), // gfx1010
106 GFX(1011), // gfx1011
107 GFX(1012), // gfx1012
108 GFX(1013), // gfx1013
109 GFX(1030), // gfx1030
110 GFX(1031), // gfx1031
111 GFX(1032), // gfx1032
112 GFX(1033), // gfx1033
113 GFX(1034), // gfx1034
114 GFX(1035), // gfx1035
115 // clang-format on
116 };
117 #undef SM
118 #undef SM2
119 #undef GFX
120
CudaArchToString(CudaArch A)121 const char *CudaArchToString(CudaArch A) {
122 auto result = std::find_if(
123 std::begin(arch_names), std::end(arch_names),
124 [A](const CudaArchToStringMap &map) { return A == map.arch; });
125 if (result == std::end(arch_names))
126 return "unknown";
127 return result->arch_name;
128 }
129
CudaArchToVirtualArchString(CudaArch A)130 const char *CudaArchToVirtualArchString(CudaArch A) {
131 auto result = std::find_if(
132 std::begin(arch_names), std::end(arch_names),
133 [A](const CudaArchToStringMap &map) { return A == map.arch; });
134 if (result == std::end(arch_names))
135 return "unknown";
136 return result->virtual_arch_name;
137 }
138
StringToCudaArch(llvm::StringRef S)139 CudaArch StringToCudaArch(llvm::StringRef S) {
140 auto result = std::find_if(
141 std::begin(arch_names), std::end(arch_names),
142 [S](const CudaArchToStringMap &map) { return S == map.arch_name; });
143 if (result == std::end(arch_names))
144 return CudaArch::UNKNOWN;
145 return result->arch;
146 }
147
MinVersionForCudaArch(CudaArch A)148 CudaVersion MinVersionForCudaArch(CudaArch A) {
149 if (A == CudaArch::UNKNOWN)
150 return CudaVersion::UNKNOWN;
151
152 // AMD GPUs do not depend on CUDA versions.
153 if (IsAMDGpuArch(A))
154 return CudaVersion::CUDA_70;
155
156 switch (A) {
157 case CudaArch::SM_20:
158 case CudaArch::SM_21:
159 case CudaArch::SM_30:
160 case CudaArch::SM_32:
161 case CudaArch::SM_35:
162 case CudaArch::SM_37:
163 case CudaArch::SM_50:
164 case CudaArch::SM_52:
165 case CudaArch::SM_53:
166 return CudaVersion::CUDA_70;
167 case CudaArch::SM_60:
168 case CudaArch::SM_61:
169 case CudaArch::SM_62:
170 return CudaVersion::CUDA_80;
171 case CudaArch::SM_70:
172 return CudaVersion::CUDA_90;
173 case CudaArch::SM_72:
174 return CudaVersion::CUDA_91;
175 case CudaArch::SM_75:
176 return CudaVersion::CUDA_100;
177 case CudaArch::SM_80:
178 return CudaVersion::CUDA_110;
179 case CudaArch::SM_86:
180 return CudaVersion::CUDA_111;
181 default:
182 llvm_unreachable("invalid enum");
183 }
184 }
185
MaxVersionForCudaArch(CudaArch A)186 CudaVersion MaxVersionForCudaArch(CudaArch A) {
187 // AMD GPUs do not depend on CUDA versions.
188 if (IsAMDGpuArch(A))
189 return CudaVersion::LATEST;
190
191 switch (A) {
192 case CudaArch::UNKNOWN:
193 return CudaVersion::UNKNOWN;
194 case CudaArch::SM_20:
195 case CudaArch::SM_21:
196 return CudaVersion::CUDA_80;
197 default:
198 return CudaVersion::LATEST;
199 }
200 }
201
ToCudaVersion(llvm::VersionTuple Version)202 CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
203 int IVer =
204 Version.getMajor() * 10 + Version.getMinor().getValueOr(0);
205 switch(IVer) {
206 case 70:
207 return CudaVersion::CUDA_70;
208 case 75:
209 return CudaVersion::CUDA_75;
210 case 80:
211 return CudaVersion::CUDA_80;
212 case 90:
213 return CudaVersion::CUDA_90;
214 case 91:
215 return CudaVersion::CUDA_91;
216 case 92:
217 return CudaVersion::CUDA_92;
218 case 100:
219 return CudaVersion::CUDA_100;
220 case 101:
221 return CudaVersion::CUDA_101;
222 case 102:
223 return CudaVersion::CUDA_102;
224 case 110:
225 return CudaVersion::CUDA_110;
226 case 111:
227 return CudaVersion::CUDA_111;
228 case 112:
229 return CudaVersion::CUDA_112;
230 default:
231 return CudaVersion::UNKNOWN;
232 }
233 }
234
CudaFeatureEnabled(llvm::VersionTuple Version,CudaFeature Feature)235 bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
236 return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
237 }
238
CudaFeatureEnabled(CudaVersion Version,CudaFeature Feature)239 bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
240 switch (Feature) {
241 case CudaFeature::CUDA_USES_NEW_LAUNCH:
242 return Version >= CudaVersion::CUDA_92;
243 case CudaFeature::CUDA_USES_FATBIN_REGISTER_END:
244 return Version >= CudaVersion::CUDA_101;
245 }
246 llvm_unreachable("Unknown CUDA feature.");
247 }
248 } // namespace clang
249