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(1030), // gfx1030
109 GFX(1031), // gfx1031
110 GFX(1032), // gfx1032
111 GFX(1033), // gfx1033
112 GFX(1034), // gfx1034
113 // clang-format on
114 };
115 #undef SM
116 #undef SM2
117 #undef GFX
118
CudaArchToString(CudaArch A)119 const char *CudaArchToString(CudaArch A) {
120 auto result = std::find_if(
121 std::begin(arch_names), std::end(arch_names),
122 [A](const CudaArchToStringMap &map) { return A == map.arch; });
123 if (result == std::end(arch_names))
124 return "unknown";
125 return result->arch_name;
126 }
127
CudaArchToVirtualArchString(CudaArch A)128 const char *CudaArchToVirtualArchString(CudaArch A) {
129 auto result = std::find_if(
130 std::begin(arch_names), std::end(arch_names),
131 [A](const CudaArchToStringMap &map) { return A == map.arch; });
132 if (result == std::end(arch_names))
133 return "unknown";
134 return result->virtual_arch_name;
135 }
136
StringToCudaArch(llvm::StringRef S)137 CudaArch StringToCudaArch(llvm::StringRef S) {
138 auto result = std::find_if(
139 std::begin(arch_names), std::end(arch_names),
140 [S](const CudaArchToStringMap &map) { return S == map.arch_name; });
141 if (result == std::end(arch_names))
142 return CudaArch::UNKNOWN;
143 return result->arch;
144 }
145
MinVersionForCudaArch(CudaArch A)146 CudaVersion MinVersionForCudaArch(CudaArch A) {
147 if (A == CudaArch::UNKNOWN)
148 return CudaVersion::UNKNOWN;
149
150 // AMD GPUs do not depend on CUDA versions.
151 if (IsAMDGpuArch(A))
152 return CudaVersion::CUDA_70;
153
154 switch (A) {
155 case CudaArch::SM_20:
156 case CudaArch::SM_21:
157 case CudaArch::SM_30:
158 case CudaArch::SM_32:
159 case CudaArch::SM_35:
160 case CudaArch::SM_37:
161 case CudaArch::SM_50:
162 case CudaArch::SM_52:
163 case CudaArch::SM_53:
164 return CudaVersion::CUDA_70;
165 case CudaArch::SM_60:
166 case CudaArch::SM_61:
167 case CudaArch::SM_62:
168 return CudaVersion::CUDA_80;
169 case CudaArch::SM_70:
170 return CudaVersion::CUDA_90;
171 case CudaArch::SM_72:
172 return CudaVersion::CUDA_91;
173 case CudaArch::SM_75:
174 return CudaVersion::CUDA_100;
175 case CudaArch::SM_80:
176 return CudaVersion::CUDA_110;
177 case CudaArch::SM_86:
178 return CudaVersion::CUDA_111;
179 default:
180 llvm_unreachable("invalid enum");
181 }
182 }
183
MaxVersionForCudaArch(CudaArch A)184 CudaVersion MaxVersionForCudaArch(CudaArch A) {
185 // AMD GPUs do not depend on CUDA versions.
186 if (IsAMDGpuArch(A))
187 return CudaVersion::LATEST;
188
189 switch (A) {
190 case CudaArch::UNKNOWN:
191 return CudaVersion::UNKNOWN;
192 case CudaArch::SM_20:
193 case CudaArch::SM_21:
194 return CudaVersion::CUDA_80;
195 default:
196 return CudaVersion::LATEST;
197 }
198 }
199
ToCudaVersion(llvm::VersionTuple Version)200 CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
201 int IVer =
202 Version.getMajor() * 10 + Version.getMinor().getValueOr(0);
203 switch(IVer) {
204 case 70:
205 return CudaVersion::CUDA_70;
206 case 75:
207 return CudaVersion::CUDA_75;
208 case 80:
209 return CudaVersion::CUDA_80;
210 case 90:
211 return CudaVersion::CUDA_90;
212 case 91:
213 return CudaVersion::CUDA_91;
214 case 92:
215 return CudaVersion::CUDA_92;
216 case 100:
217 return CudaVersion::CUDA_100;
218 case 101:
219 return CudaVersion::CUDA_101;
220 case 102:
221 return CudaVersion::CUDA_102;
222 case 110:
223 return CudaVersion::CUDA_110;
224 case 111:
225 return CudaVersion::CUDA_111;
226 case 112:
227 return CudaVersion::CUDA_112;
228 default:
229 return CudaVersion::UNKNOWN;
230 }
231 }
232
CudaFeatureEnabled(llvm::VersionTuple Version,CudaFeature Feature)233 bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
234 return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
235 }
236
CudaFeatureEnabled(CudaVersion Version,CudaFeature Feature)237 bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
238 switch (Feature) {
239 case CudaFeature::CUDA_USES_NEW_LAUNCH:
240 return Version >= CudaVersion::CUDA_92;
241 case CudaFeature::CUDA_USES_FATBIN_REGISTER_END:
242 return Version >= CudaVersion::CUDA_101;
243 }
244 llvm_unreachable("Unknown CUDA feature.");
245 }
246 } // namespace clang
247