1#include "clang/Basic/Cuda.h"
2
3#include "llvm/ADT/Twine.h"
4#include "llvm/Support/ErrorHandling.h"
5#include "llvm/Support/VersionTuple.h"
6#include "llvm/TargetParser/NVPTXTargetParser.h"
7#include <cassert>
8
9namespace clang {
10
11struct 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
22static 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 CUDA_ENTRY(11, 6),
39 CUDA_ENTRY(11, 7),
40 CUDA_ENTRY(11, 8),
41 CUDA_ENTRY(12, 0),
42 CUDA_ENTRY(12, 1),
43 CUDA_ENTRY(12, 2),
44 CUDA_ENTRY(12, 3),
45 CUDA_ENTRY(12, 4),
46 CUDA_ENTRY(12, 5),
47 CUDA_ENTRY(12, 6),
48 CUDA_ENTRY(12, 8),
49 CUDA_ENTRY(12, 9),
50 CUDA_ENTRY(13, 0),
51 CUDA_ENTRY(13, 1),
52 CUDA_ENTRY(13, 2),
53 CUDA_ENTRY(13, 3),
54 CUDA_ENTRY(13, 4),
55 {.Name: "", .Version: CudaVersion::NEW, .TVersion: llvm::VersionTuple(std::numeric_limits<int>::max())},
56 {.Name: "unknown", .Version: CudaVersion::UNKNOWN, .TVersion: {}} // End of list tombstone.
57};
58#undef CUDA_ENTRY
59
60const char *CudaVersionToString(CudaVersion V) {
61 for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
62 if (I->Version == V)
63 return I->Name;
64
65 return CudaVersionToString(V: CudaVersion::UNKNOWN);
66}
67
68CudaVersion CudaStringToVersion(const llvm::Twine &S) {
69 std::string VS = S.str();
70 for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
71 if (I->Name == VS)
72 return I->Version;
73 return CudaVersion::UNKNOWN;
74}
75
76CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
77 for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
78 if (I->TVersion == Version)
79 return I->Version;
80 return CudaVersion::UNKNOWN;
81}
82
83CudaVersion MinVersionForOffloadArch(OffloadArch A) {
84 if (A.isUnknown())
85 return CudaVersion::UNKNOWN;
86
87 // AMD GPUs do not depend on CUDA versions.
88 if (A.isAMDGPU() || A.isAMDGCNSPIRV())
89 return CudaVersion::CUDA_70;
90
91 switch (A.nvptxKind()) {
92#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX) \
93 case llvm::NVPTX::GK_##KIND: \
94 return CudaVersion::MIN_VER;
95#include "llvm/TargetParser/NVPTXTargetParser.def"
96 default:
97 llvm_unreachable("invalid enum");
98 }
99}
100
101CudaVersion MaxVersionForOffloadArch(OffloadArch A) {
102 // AMD GPUs do not depend on CUDA versions.
103 if (A.isAMDGPU() || A.isAMDGCNSPIRV())
104 return CudaVersion::NEW;
105
106 if (!A.isNVPTX())
107 return CudaVersion::UNKNOWN;
108
109 switch (A.nvptxKind()) {
110#define NVPTX_GPU(NAME, KIND, VIRTUAL, SM_ID, MIN_VER, MAX_VER, SUFFIX) \
111 case llvm::NVPTX::GK_##KIND: \
112 return CudaVersion::MAX_VER;
113#include "llvm/TargetParser/NVPTXTargetParser.def"
114 default:
115 return CudaVersion::NEW;
116 }
117}
118
119bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
120 return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
121}
122
123bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
124 switch (Feature) {
125 case CudaFeature::CUDA_USES_NEW_LAUNCH:
126 return Version >= CudaVersion::CUDA_92;
127 case CudaFeature::CUDA_USES_FATBIN_REGISTER_END:
128 return Version >= CudaVersion::CUDA_101;
129 }
130 llvm_unreachable("Unknown CUDA feature.");
131}
132
133unsigned CudaArchToID(OffloadArch Arch) {
134 assert(Arch.isNVPTX() && "invalid NVIDIA GPU architecture");
135 return llvm::NVPTX::getSmVersion(Kind: Arch.nvptxKind());
136}
137
138bool IsNVIDIAAcceleratedOffloadArch(OffloadArch Arch) {
139 return Arch.isNVPTX() && llvm::NVPTX::isAcceleratedArch(Kind: Arch.nvptxKind());
140}
141
142bool IsNVIDIAFamilySpecificOffloadArch(OffloadArch Arch) {
143 return Arch.isNVPTX() && llvm::NVPTX::isFamilySpecificArch(Kind: Arch.nvptxKind());
144}
145} // namespace clang
146