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