1 | //===--- Types.cpp - Driver input & temporary type information ------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/Driver/Types.h" |
10 | #include "clang/Driver/Driver.h" |
11 | #include "clang/Driver/DriverDiagnostic.h" |
12 | #include "clang/Driver/Options.h" |
13 | #include "llvm/ADT/STLExtras.h" |
14 | #include "llvm/ADT/SmallVector.h" |
15 | #include "llvm/ADT/StringSwitch.h" |
16 | #include "llvm/Option/Arg.h" |
17 | #include <cassert> |
18 | #include <cstring> |
19 | |
20 | using namespace clang::driver; |
21 | using namespace clang::driver::types; |
22 | |
23 | struct TypeInfo { |
24 | const char *Name; |
25 | const char *TempSuffix; |
26 | ID PreprocessedType; |
27 | class PhasesBitSet { |
28 | unsigned Bits = 0; |
29 | |
30 | public: |
31 | constexpr PhasesBitSet(std::initializer_list<phases::ID> Phases) { |
32 | for (auto Id : Phases) |
33 | Bits |= 1 << Id; |
34 | } |
35 | bool contains(phases::ID Id) const { return Bits & (1 << Id); } |
36 | } Phases; |
37 | }; |
38 | |
39 | static constexpr TypeInfo TypeInfos[] = { |
40 | #define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, ...) \ |
41 | { NAME, TEMP_SUFFIX, TY_##PP_TYPE, { __VA_ARGS__ }, }, |
42 | #include "clang/Driver/Types.def" |
43 | #undef TYPE |
44 | }; |
45 | static const unsigned numTypes = std::size(TypeInfos); |
46 | |
47 | static const TypeInfo &getInfo(unsigned id) { |
48 | assert(id > 0 && id - 1 < numTypes && "Invalid Type ID." ); |
49 | return TypeInfos[id - 1]; |
50 | } |
51 | |
52 | const char *types::getTypeName(ID Id) { |
53 | return getInfo(id: Id).Name; |
54 | } |
55 | |
56 | types::ID types::getPreprocessedType(ID Id) { |
57 | ID PPT = getInfo(id: Id).PreprocessedType; |
58 | assert((getInfo(Id).Phases.contains(phases::Preprocess) != |
59 | (PPT == TY_INVALID)) && |
60 | "Unexpected Preprocess Type." ); |
61 | return PPT; |
62 | } |
63 | |
64 | static bool isPreprocessedModuleType(ID Id) { |
65 | return Id == TY_CXXModule || Id == TY_PP_CXXModule; |
66 | } |
67 | |
68 | static bool (ID Id) { |
69 | return Id == TY_CXXSHeader || Id == TY_CXXUHeader || Id == TY_CXXHUHeader || |
70 | Id == TY_PP_CXXHeaderUnit; |
71 | } |
72 | |
73 | types::ID types::getPrecompiledType(ID Id) { |
74 | if (isPreprocessedModuleType(Id)) |
75 | return TY_ModuleFile; |
76 | if (isPreprocessedHeaderUnitType(Id)) |
77 | return TY_HeaderUnit; |
78 | if (onlyPrecompileType(Id)) |
79 | return TY_PCH; |
80 | return TY_INVALID; |
81 | } |
82 | |
83 | const char *types::getTypeTempSuffix(ID Id, bool CLStyle) { |
84 | if (CLStyle) { |
85 | switch (Id) { |
86 | case TY_Object: |
87 | case TY_LTO_BC: |
88 | return "obj" ; |
89 | case TY_Image: |
90 | return "exe" ; |
91 | case TY_PP_Asm: |
92 | return "asm" ; |
93 | default: |
94 | break; |
95 | } |
96 | } |
97 | return getInfo(id: Id).TempSuffix; |
98 | } |
99 | |
100 | bool types::onlyPrecompileType(ID Id) { |
101 | return getInfo(id: Id).Phases.contains(Id: phases::Precompile) && |
102 | !isPreprocessedModuleType(Id); |
103 | } |
104 | |
105 | bool types::canTypeBeUserSpecified(ID Id) { |
106 | static const clang::driver::types::ID kStaticLangageTypes[] = { |
107 | TY_CUDA_DEVICE, TY_HIP_DEVICE, TY_PP_CHeader, |
108 | TY_PP_ObjCHeader, TY_PP_CXXHeader, TY_PP_ObjCXXHeader, |
109 | TY_PP_CXXModule, TY_LTO_IR, TY_LTO_BC, |
110 | TY_Plist, TY_RewrittenObjC, TY_RewrittenLegacyObjC, |
111 | TY_Remap, TY_PCH, TY_Object, |
112 | TY_Image, TY_dSYM, TY_Dependencies, |
113 | TY_CUDA_FATBIN, TY_HIP_FATBIN}; |
114 | return !llvm::is_contained(Range: kStaticLangageTypes, Element: Id); |
115 | } |
116 | |
117 | bool types::appendSuffixForType(ID Id) { |
118 | return Id == TY_PCH || Id == TY_dSYM || Id == TY_CUDA_FATBIN || |
119 | Id == TY_HIP_FATBIN; |
120 | } |
121 | |
122 | bool types::canLipoType(ID Id) { |
123 | return (Id == TY_Nothing || |
124 | Id == TY_Image || |
125 | Id == TY_Object || |
126 | Id == TY_LTO_BC); |
127 | } |
128 | |
129 | bool types::isAcceptedByClang(ID Id) { |
130 | switch (Id) { |
131 | default: |
132 | return false; |
133 | |
134 | case TY_Asm: |
135 | case TY_C: case TY_PP_C: |
136 | case TY_CL: case TY_PP_CL: case TY_CLCXX: case TY_PP_CLCXX: |
137 | case TY_CUDA: case TY_PP_CUDA: |
138 | case TY_CUDA_DEVICE: |
139 | case TY_HIP: |
140 | case TY_PP_HIP: |
141 | case TY_HIP_DEVICE: |
142 | case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: |
143 | case TY_CXX: case TY_PP_CXX: |
144 | case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: |
145 | case TY_CHeader: case TY_PP_CHeader: |
146 | case TY_CLHeader: |
147 | case TY_ObjCHeader: case TY_PP_ObjCHeader: |
148 | case TY_CXXHeader: case TY_PP_CXXHeader: |
149 | case TY_CXXSHeader: |
150 | case TY_CXXUHeader: |
151 | case TY_CXXHUHeader: |
152 | case TY_PP_CXXHeaderUnit: |
153 | case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: |
154 | case TY_CXXModule: case TY_PP_CXXModule: |
155 | case TY_AST: case TY_ModuleFile: case TY_PCH: |
156 | case TY_LLVM_IR: case TY_LLVM_BC: |
157 | case TY_API_INFO: |
158 | return true; |
159 | } |
160 | } |
161 | |
162 | bool types::isAcceptedByFlang(ID Id) { |
163 | switch (Id) { |
164 | default: |
165 | return false; |
166 | |
167 | case TY_Fortran: |
168 | case TY_PP_Fortran: |
169 | return true; |
170 | case TY_LLVM_IR: |
171 | case TY_LLVM_BC: |
172 | return true; |
173 | } |
174 | } |
175 | |
176 | bool types::isDerivedFromC(ID Id) { |
177 | switch (Id) { |
178 | default: |
179 | return false; |
180 | |
181 | case TY_PP_C: |
182 | case TY_C: |
183 | case TY_CL: |
184 | case TY_PP_CL: |
185 | case TY_CLCXX: |
186 | case TY_PP_CLCXX: |
187 | case TY_PP_CUDA: |
188 | case TY_CUDA: |
189 | case TY_CUDA_DEVICE: |
190 | case TY_PP_HIP: |
191 | case TY_HIP: |
192 | case TY_HIP_DEVICE: |
193 | case TY_PP_ObjC: |
194 | case TY_PP_ObjC_Alias: |
195 | case TY_ObjC: |
196 | case TY_PP_CXX: |
197 | case TY_CXX: |
198 | case TY_PP_ObjCXX: |
199 | case TY_PP_ObjCXX_Alias: |
200 | case TY_ObjCXX: |
201 | case TY_RenderScript: |
202 | case TY_PP_CHeader: |
203 | case TY_CHeader: |
204 | case TY_CLHeader: |
205 | case TY_PP_ObjCHeader: |
206 | case TY_ObjCHeader: |
207 | case TY_PP_CXXHeader: |
208 | case TY_CXXHeader: |
209 | case TY_PP_ObjCXXHeader: |
210 | case TY_ObjCXXHeader: |
211 | case TY_CXXModule: |
212 | case TY_PP_CXXModule: |
213 | return true; |
214 | } |
215 | } |
216 | |
217 | bool types::isObjC(ID Id) { |
218 | switch (Id) { |
219 | default: |
220 | return false; |
221 | |
222 | case TY_ObjC: case TY_PP_ObjC: case TY_PP_ObjC_Alias: |
223 | case TY_ObjCXX: case TY_PP_ObjCXX: |
224 | case TY_ObjCHeader: case TY_PP_ObjCHeader: |
225 | case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: case TY_PP_ObjCXX_Alias: |
226 | return true; |
227 | } |
228 | } |
229 | |
230 | bool types::isOpenCL(ID Id) { return Id == TY_CL || Id == TY_CLCXX; } |
231 | |
232 | bool types::isCXX(ID Id) { |
233 | switch (Id) { |
234 | default: |
235 | return false; |
236 | |
237 | case TY_CXX: case TY_PP_CXX: |
238 | case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: |
239 | case TY_CXXHeader: case TY_PP_CXXHeader: |
240 | case TY_CXXSHeader: |
241 | case TY_CXXUHeader: |
242 | case TY_CXXHUHeader: |
243 | case TY_PP_CXXHeaderUnit: |
244 | case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: |
245 | case TY_CXXModule: case TY_PP_CXXModule: |
246 | case TY_PP_CLCXX: |
247 | case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE: |
248 | case TY_HIP: |
249 | case TY_PP_HIP: |
250 | case TY_HIP_DEVICE: |
251 | return true; |
252 | } |
253 | } |
254 | |
255 | bool types::isLLVMIR(ID Id) { |
256 | switch (Id) { |
257 | default: |
258 | return false; |
259 | |
260 | case TY_LLVM_IR: |
261 | case TY_LLVM_BC: |
262 | case TY_LTO_IR: |
263 | case TY_LTO_BC: |
264 | return true; |
265 | } |
266 | } |
267 | |
268 | bool types::isCuda(ID Id) { |
269 | switch (Id) { |
270 | default: |
271 | return false; |
272 | |
273 | case TY_CUDA: |
274 | case TY_PP_CUDA: |
275 | case TY_CUDA_DEVICE: |
276 | return true; |
277 | } |
278 | } |
279 | |
280 | bool types::isHIP(ID Id) { |
281 | switch (Id) { |
282 | default: |
283 | return false; |
284 | |
285 | case TY_HIP: |
286 | case TY_PP_HIP: |
287 | case TY_HIP_DEVICE: |
288 | return true; |
289 | } |
290 | } |
291 | |
292 | bool types::isHLSL(ID Id) { return Id == TY_HLSL; } |
293 | |
294 | bool types::isSrcFile(ID Id) { |
295 | return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; |
296 | } |
297 | |
298 | types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { |
299 | return llvm::StringSwitch<types::ID>(Ext) |
300 | .Case(S: "c" , Value: TY_C) |
301 | .Case(S: "C" , Value: TY_CXX) |
302 | .Case(S: "F" , Value: TY_Fortran) |
303 | .Case(S: "f" , Value: TY_PP_Fortran) |
304 | .Case(S: "h" , Value: TY_CHeader) |
305 | .Case(S: "H" , Value: TY_CXXHeader) |
306 | .Case(S: "i" , Value: TY_PP_C) |
307 | .Case(S: "m" , Value: TY_ObjC) |
308 | .Case(S: "M" , Value: TY_ObjCXX) |
309 | .Case(S: "o" , Value: TY_Object) |
310 | .Case(S: "S" , Value: TY_Asm) |
311 | .Case(S: "s" , Value: TY_PP_Asm) |
312 | .Case(S: "bc" , Value: TY_LLVM_BC) |
313 | .Case(S: "cc" , Value: TY_CXX) |
314 | .Case(S: "CC" , Value: TY_CXX) |
315 | .Case(S: "cl" , Value: TY_CL) |
316 | .Case(S: "cli" , Value: TY_PP_CL) |
317 | .Case(S: "clcpp" , Value: TY_CLCXX) |
318 | .Case(S: "clii" , Value: TY_PP_CLCXX) |
319 | .Case(S: "cp" , Value: TY_CXX) |
320 | .Case(S: "cu" , Value: TY_CUDA) |
321 | .Case(S: "hh" , Value: TY_CXXHeader) |
322 | .Case(S: "ii" , Value: TY_PP_CXX) |
323 | .Case(S: "ll" , Value: TY_LLVM_IR) |
324 | .Case(S: "mi" , Value: TY_PP_ObjC) |
325 | .Case(S: "mm" , Value: TY_ObjCXX) |
326 | .Case(S: "rs" , Value: TY_RenderScript) |
327 | .Case(S: "adb" , Value: TY_Ada) |
328 | .Case(S: "ads" , Value: TY_Ada) |
329 | .Case(S: "asm" , Value: TY_PP_Asm) |
330 | .Case(S: "ast" , Value: TY_AST) |
331 | .Case(S: "ccm" , Value: TY_CXXModule) |
332 | .Case(S: "cpp" , Value: TY_CXX) |
333 | .Case(S: "CPP" , Value: TY_CXX) |
334 | .Case(S: "c++" , Value: TY_CXX) |
335 | .Case(S: "C++" , Value: TY_CXX) |
336 | .Case(S: "cui" , Value: TY_PP_CUDA) |
337 | .Case(S: "cxx" , Value: TY_CXX) |
338 | .Case(S: "CXX" , Value: TY_CXX) |
339 | .Case(S: "F03" , Value: TY_Fortran) |
340 | .Case(S: "f03" , Value: TY_PP_Fortran) |
341 | .Case(S: "F08" , Value: TY_Fortran) |
342 | .Case(S: "f08" , Value: TY_PP_Fortran) |
343 | .Case(S: "F90" , Value: TY_Fortran) |
344 | .Case(S: "f90" , Value: TY_PP_Fortran) |
345 | .Case(S: "F95" , Value: TY_Fortran) |
346 | .Case(S: "f95" , Value: TY_PP_Fortran) |
347 | .Case(S: "for" , Value: TY_PP_Fortran) |
348 | .Case(S: "FOR" , Value: TY_PP_Fortran) |
349 | .Case(S: "fpp" , Value: TY_Fortran) |
350 | .Case(S: "FPP" , Value: TY_Fortran) |
351 | .Case(S: "gch" , Value: TY_PCH) |
352 | .Case(S: "hip" , Value: TY_HIP) |
353 | .Case(S: "hipi" , Value: TY_PP_HIP) |
354 | .Case(S: "hpp" , Value: TY_CXXHeader) |
355 | .Case(S: "hxx" , Value: TY_CXXHeader) |
356 | .Case(S: "iim" , Value: TY_PP_CXXModule) |
357 | .Case(S: "iih" , Value: TY_PP_CXXHeaderUnit) |
358 | .Case(S: "lib" , Value: TY_Object) |
359 | .Case(S: "mii" , Value: TY_PP_ObjCXX) |
360 | .Case(S: "obj" , Value: TY_Object) |
361 | .Case(S: "ifs" , Value: TY_IFS) |
362 | .Case(S: "pch" , Value: TY_PCH) |
363 | .Case(S: "pcm" , Value: TY_ModuleFile) |
364 | .Case(S: "c++m" , Value: TY_CXXModule) |
365 | .Case(S: "cppm" , Value: TY_CXXModule) |
366 | .Case(S: "cxxm" , Value: TY_CXXModule) |
367 | .Case(S: "hlsl" , Value: TY_HLSL) |
368 | .Default(Value: TY_INVALID); |
369 | } |
370 | |
371 | types::ID types::lookupTypeForTypeSpecifier(const char *Name) { |
372 | for (unsigned i=0; i<numTypes; ++i) { |
373 | types::ID Id = (types::ID) (i + 1); |
374 | if (canTypeBeUserSpecified(Id) && |
375 | strcmp(s1: Name, s2: getInfo(id: Id).Name) == 0) |
376 | return Id; |
377 | } |
378 | // Accept "cu" as an alias for "cuda" for NVCC compatibility |
379 | if (strcmp(s1: Name, s2: "cu" ) == 0) { |
380 | return types::TY_CUDA; |
381 | } |
382 | return TY_INVALID; |
383 | } |
384 | |
385 | llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> |
386 | types::getCompilationPhases(ID Id, phases::ID LastPhase) { |
387 | llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> P; |
388 | const auto &Info = getInfo(id: Id); |
389 | for (int I = 0; I <= LastPhase; ++I) |
390 | if (Info.Phases.contains(Id: static_cast<phases::ID>(I))) |
391 | P.push_back(Elt: static_cast<phases::ID>(I)); |
392 | assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list" ); |
393 | return P; |
394 | } |
395 | |
396 | llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> |
397 | types::getCompilationPhases(const clang::driver::Driver &Driver, |
398 | llvm::opt::DerivedArgList &DAL, ID Id) { |
399 | return types::getCompilationPhases(Id, LastPhase: Driver.getFinalPhase(DAL)); |
400 | } |
401 | |
402 | ID types::lookupCXXTypeForCType(ID Id) { |
403 | switch (Id) { |
404 | default: |
405 | return Id; |
406 | |
407 | case types::TY_C: |
408 | return types::TY_CXX; |
409 | case types::TY_PP_C: |
410 | return types::TY_PP_CXX; |
411 | case types::TY_CHeader: |
412 | return types::TY_CXXHeader; |
413 | case types::TY_PP_CHeader: |
414 | return types::TY_PP_CXXHeader; |
415 | } |
416 | } |
417 | |
418 | ID types::(ID Id) { |
419 | switch (Id) { |
420 | default: |
421 | return Id; |
422 | |
423 | // FIXME: Handle preprocessed input types. |
424 | case types::TY_C: |
425 | return types::TY_CHeader; |
426 | case types::TY_CXX: |
427 | case types::TY_CXXModule: |
428 | return types::TY_CXXHeader; |
429 | case types::TY_ObjC: |
430 | return types::TY_ObjCHeader; |
431 | case types::TY_ObjCXX: |
432 | return types::TY_ObjCXXHeader; |
433 | case types::TY_CL: |
434 | case types::TY_CLCXX: |
435 | return types::TY_CLHeader; |
436 | } |
437 | } |
438 | |