10b57cec5SDimitry Andric #include "clang/Basic/Cuda.h"
20b57cec5SDimitry Andric
30b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
413138422SDimitry Andric #include "llvm/ADT/Twine.h"
50b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
60b57cec5SDimitry Andric #include "llvm/Support/VersionTuple.h"
70b57cec5SDimitry Andric
80b57cec5SDimitry Andric namespace clang {
90b57cec5SDimitry Andric
10bdd1243dSDimitry Andric struct CudaVersionMapEntry {
11bdd1243dSDimitry Andric const char *Name;
12bdd1243dSDimitry Andric CudaVersion Version;
13bdd1243dSDimitry Andric llvm::VersionTuple TVersion;
14bdd1243dSDimitry Andric };
15bdd1243dSDimitry Andric #define CUDA_ENTRY(major, minor) \
16bdd1243dSDimitry Andric { \
17bdd1243dSDimitry Andric #major "." #minor, CudaVersion::CUDA_##major##minor, \
18bdd1243dSDimitry Andric llvm::VersionTuple(major, minor) \
190b57cec5SDimitry Andric }
20bdd1243dSDimitry Andric
21bdd1243dSDimitry Andric static const CudaVersionMapEntry CudaNameVersionMap[] = {
22bdd1243dSDimitry Andric CUDA_ENTRY(7, 0),
23bdd1243dSDimitry Andric CUDA_ENTRY(7, 5),
24bdd1243dSDimitry Andric CUDA_ENTRY(8, 0),
25bdd1243dSDimitry Andric CUDA_ENTRY(9, 0),
26bdd1243dSDimitry Andric CUDA_ENTRY(9, 1),
27bdd1243dSDimitry Andric CUDA_ENTRY(9, 2),
28bdd1243dSDimitry Andric CUDA_ENTRY(10, 0),
29bdd1243dSDimitry Andric CUDA_ENTRY(10, 1),
30bdd1243dSDimitry Andric CUDA_ENTRY(10, 2),
31bdd1243dSDimitry Andric CUDA_ENTRY(11, 0),
32bdd1243dSDimitry Andric CUDA_ENTRY(11, 1),
33bdd1243dSDimitry Andric CUDA_ENTRY(11, 2),
34bdd1243dSDimitry Andric CUDA_ENTRY(11, 3),
35bdd1243dSDimitry Andric CUDA_ENTRY(11, 4),
36bdd1243dSDimitry Andric CUDA_ENTRY(11, 5),
37bdd1243dSDimitry Andric CUDA_ENTRY(11, 6),
38bdd1243dSDimitry Andric CUDA_ENTRY(11, 7),
39bdd1243dSDimitry Andric CUDA_ENTRY(11, 8),
4006c3fb27SDimitry Andric CUDA_ENTRY(12, 0),
4106c3fb27SDimitry Andric CUDA_ENTRY(12, 1),
425f757f3fSDimitry Andric CUDA_ENTRY(12, 2),
435f757f3fSDimitry Andric CUDA_ENTRY(12, 3),
44bdd1243dSDimitry Andric {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())},
45bdd1243dSDimitry Andric {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone.
46bdd1243dSDimitry Andric };
47bdd1243dSDimitry Andric #undef CUDA_ENTRY
48bdd1243dSDimitry Andric
CudaVersionToString(CudaVersion V)49bdd1243dSDimitry Andric const char *CudaVersionToString(CudaVersion V) {
50bdd1243dSDimitry Andric for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
51bdd1243dSDimitry Andric if (I->Version == V)
52bdd1243dSDimitry Andric return I->Name;
53bdd1243dSDimitry Andric
54bdd1243dSDimitry Andric return CudaVersionToString(CudaVersion::UNKNOWN);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
CudaStringToVersion(const llvm::Twine & S)5713138422SDimitry Andric CudaVersion CudaStringToVersion(const llvm::Twine &S) {
58bdd1243dSDimitry Andric std::string VS = S.str();
59bdd1243dSDimitry Andric for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
60bdd1243dSDimitry Andric if (I->Name == VS)
61bdd1243dSDimitry Andric return I->Version;
62bdd1243dSDimitry Andric return CudaVersion::UNKNOWN;
63bdd1243dSDimitry Andric }
64bdd1243dSDimitry Andric
ToCudaVersion(llvm::VersionTuple Version)65bdd1243dSDimitry Andric CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
66bdd1243dSDimitry Andric for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
67bdd1243dSDimitry Andric if (I->TVersion == Version)
68bdd1243dSDimitry Andric return I->Version;
69bdd1243dSDimitry Andric return CudaVersion::UNKNOWN;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
72fe6060f1SDimitry Andric namespace {
735ffd83dbSDimitry Andric struct CudaArchToStringMap {
745ffd83dbSDimitry Andric CudaArch arch;
755ffd83dbSDimitry Andric const char *arch_name;
765ffd83dbSDimitry Andric const char *virtual_arch_name;
775ffd83dbSDimitry Andric };
78fe6060f1SDimitry Andric } // namespace
795ffd83dbSDimitry Andric
805ffd83dbSDimitry Andric #define SM2(sm, ca) \
815ffd83dbSDimitry Andric { CudaArch::SM_##sm, "sm_" #sm, ca }
825ffd83dbSDimitry Andric #define SM(sm) SM2(sm, "compute_" #sm)
835ffd83dbSDimitry Andric #define GFX(gpu) \
845ffd83dbSDimitry Andric { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" }
85fe6060f1SDimitry Andric static const CudaArchToStringMap arch_names[] = {
865ffd83dbSDimitry Andric // clang-format off
87e8d8bef9SDimitry Andric {CudaArch::UNUSED, "", ""},
885ffd83dbSDimitry Andric SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi
895ffd83dbSDimitry Andric SM(30), SM(32), SM(35), SM(37), // Kepler
905ffd83dbSDimitry Andric SM(50), SM(52), SM(53), // Maxwell
915ffd83dbSDimitry Andric SM(60), SM(61), SM(62), // Pascal
925ffd83dbSDimitry Andric SM(70), SM(72), // Volta
935ffd83dbSDimitry Andric SM(75), // Turing
94fe6060f1SDimitry Andric SM(80), SM(86), // Ampere
95bdd1243dSDimitry Andric SM(87), // Jetson/Drive AGX Orin
96bdd1243dSDimitry Andric SM(89), // Ada Lovelace
97bdd1243dSDimitry Andric SM(90), // Hopper
985f757f3fSDimitry Andric SM(90a), // Hopper
99e8d8bef9SDimitry Andric GFX(600), // gfx600
100e8d8bef9SDimitry Andric GFX(601), // gfx601
101e8d8bef9SDimitry Andric GFX(602), // gfx602
102e8d8bef9SDimitry Andric GFX(700), // gfx700
103e8d8bef9SDimitry Andric GFX(701), // gfx701
104e8d8bef9SDimitry Andric GFX(702), // gfx702
105e8d8bef9SDimitry Andric GFX(703), // gfx703
106e8d8bef9SDimitry Andric GFX(704), // gfx704
107e8d8bef9SDimitry Andric GFX(705), // gfx705
108e8d8bef9SDimitry Andric GFX(801), // gfx801
109e8d8bef9SDimitry Andric GFX(802), // gfx802
110e8d8bef9SDimitry Andric GFX(803), // gfx803
111e8d8bef9SDimitry Andric GFX(805), // gfx805
112e8d8bef9SDimitry Andric GFX(810), // gfx810
113e8d8bef9SDimitry Andric GFX(900), // gfx900
114e8d8bef9SDimitry Andric GFX(902), // gfx902
115e8d8bef9SDimitry Andric GFX(904), // gfx903
116e8d8bef9SDimitry Andric GFX(906), // gfx906
117e8d8bef9SDimitry Andric GFX(908), // gfx908
118e8d8bef9SDimitry Andric GFX(909), // gfx909
119fe6060f1SDimitry Andric GFX(90a), // gfx90a
120e8d8bef9SDimitry Andric GFX(90c), // gfx90c
12181ad6265SDimitry Andric GFX(940), // gfx940
12206c3fb27SDimitry Andric GFX(941), // gfx941
12306c3fb27SDimitry Andric GFX(942), // gfx942
124e8d8bef9SDimitry Andric GFX(1010), // gfx1010
125e8d8bef9SDimitry Andric GFX(1011), // gfx1011
126e8d8bef9SDimitry Andric GFX(1012), // gfx1012
127fe6060f1SDimitry Andric GFX(1013), // gfx1013
128e8d8bef9SDimitry Andric GFX(1030), // gfx1030
129e8d8bef9SDimitry Andric GFX(1031), // gfx1031
130e8d8bef9SDimitry Andric GFX(1032), // gfx1032
131e8d8bef9SDimitry Andric GFX(1033), // gfx1033
132fe6060f1SDimitry Andric GFX(1034), // gfx1034
133fe6060f1SDimitry Andric GFX(1035), // gfx1035
13481ad6265SDimitry Andric GFX(1036), // gfx1036
13581ad6265SDimitry Andric GFX(1100), // gfx1100
13681ad6265SDimitry Andric GFX(1101), // gfx1101
13781ad6265SDimitry Andric GFX(1102), // gfx1102
13881ad6265SDimitry Andric GFX(1103), // gfx1103
13906c3fb27SDimitry Andric GFX(1150), // gfx1150
14006c3fb27SDimitry Andric GFX(1151), // gfx1151
1415f757f3fSDimitry Andric GFX(1200), // gfx1200
1425f757f3fSDimitry Andric GFX(1201), // gfx1201
1430eae32dcSDimitry Andric {CudaArch::Generic, "generic", ""},
1445ffd83dbSDimitry Andric // clang-format on
1455ffd83dbSDimitry Andric };
1465ffd83dbSDimitry Andric #undef SM
1475ffd83dbSDimitry Andric #undef SM2
1485ffd83dbSDimitry Andric #undef GFX
1495ffd83dbSDimitry Andric
CudaArchToString(CudaArch A)1500b57cec5SDimitry Andric const char *CudaArchToString(CudaArch A) {
1515ffd83dbSDimitry Andric auto result = std::find_if(
1525ffd83dbSDimitry Andric std::begin(arch_names), std::end(arch_names),
1535ffd83dbSDimitry Andric [A](const CudaArchToStringMap &map) { return A == map.arch; });
1545ffd83dbSDimitry Andric if (result == std::end(arch_names))
1550b57cec5SDimitry Andric return "unknown";
1565ffd83dbSDimitry Andric return result->arch_name;
1570b57cec5SDimitry Andric }
1585ffd83dbSDimitry Andric
CudaArchToVirtualArchString(CudaArch A)1595ffd83dbSDimitry Andric const char *CudaArchToVirtualArchString(CudaArch A) {
1605ffd83dbSDimitry Andric auto result = std::find_if(
1615ffd83dbSDimitry Andric std::begin(arch_names), std::end(arch_names),
1625ffd83dbSDimitry Andric [A](const CudaArchToStringMap &map) { return A == map.arch; });
1635ffd83dbSDimitry Andric if (result == std::end(arch_names))
1645ffd83dbSDimitry Andric return "unknown";
1655ffd83dbSDimitry Andric return result->virtual_arch_name;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
StringToCudaArch(llvm::StringRef S)1680b57cec5SDimitry Andric CudaArch StringToCudaArch(llvm::StringRef S) {
1695ffd83dbSDimitry Andric auto result = std::find_if(
1705ffd83dbSDimitry Andric std::begin(arch_names), std::end(arch_names),
1715ffd83dbSDimitry Andric [S](const CudaArchToStringMap &map) { return S == map.arch_name; });
1725ffd83dbSDimitry Andric if (result == std::end(arch_names))
1735ffd83dbSDimitry Andric return CudaArch::UNKNOWN;
1745ffd83dbSDimitry Andric return result->arch;
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
MinVersionForCudaArch(CudaArch A)1770b57cec5SDimitry Andric CudaVersion MinVersionForCudaArch(CudaArch A) {
1785ffd83dbSDimitry Andric if (A == CudaArch::UNKNOWN)
1790b57cec5SDimitry Andric return CudaVersion::UNKNOWN;
1805ffd83dbSDimitry Andric
1815ffd83dbSDimitry Andric // AMD GPUs do not depend on CUDA versions.
1825ffd83dbSDimitry Andric if (IsAMDGpuArch(A))
1835ffd83dbSDimitry Andric return CudaVersion::CUDA_70;
1845ffd83dbSDimitry Andric
1855ffd83dbSDimitry Andric switch (A) {
1860b57cec5SDimitry Andric case CudaArch::SM_20:
1870b57cec5SDimitry Andric case CudaArch::SM_21:
1880b57cec5SDimitry Andric case CudaArch::SM_30:
1890b57cec5SDimitry Andric case CudaArch::SM_32:
1900b57cec5SDimitry Andric case CudaArch::SM_35:
1910b57cec5SDimitry Andric case CudaArch::SM_37:
1920b57cec5SDimitry Andric case CudaArch::SM_50:
1930b57cec5SDimitry Andric case CudaArch::SM_52:
1940b57cec5SDimitry Andric case CudaArch::SM_53:
1950b57cec5SDimitry Andric return CudaVersion::CUDA_70;
1960b57cec5SDimitry Andric case CudaArch::SM_60:
1970b57cec5SDimitry Andric case CudaArch::SM_61:
1980b57cec5SDimitry Andric case CudaArch::SM_62:
1990b57cec5SDimitry Andric return CudaVersion::CUDA_80;
2000b57cec5SDimitry Andric case CudaArch::SM_70:
2010b57cec5SDimitry Andric return CudaVersion::CUDA_90;
2020b57cec5SDimitry Andric case CudaArch::SM_72:
2030b57cec5SDimitry Andric return CudaVersion::CUDA_91;
2040b57cec5SDimitry Andric case CudaArch::SM_75:
2050b57cec5SDimitry Andric return CudaVersion::CUDA_100;
2065ffd83dbSDimitry Andric case CudaArch::SM_80:
2075ffd83dbSDimitry Andric return CudaVersion::CUDA_110;
208fe6060f1SDimitry Andric case CudaArch::SM_86:
209fe6060f1SDimitry Andric return CudaVersion::CUDA_111;
210bdd1243dSDimitry Andric case CudaArch::SM_87:
211bdd1243dSDimitry Andric return CudaVersion::CUDA_114;
212bdd1243dSDimitry Andric case CudaArch::SM_89:
213bdd1243dSDimitry Andric case CudaArch::SM_90:
214bdd1243dSDimitry Andric return CudaVersion::CUDA_118;
2155f757f3fSDimitry Andric case CudaArch::SM_90a:
2165f757f3fSDimitry Andric return CudaVersion::CUDA_120;
2175ffd83dbSDimitry Andric default:
2180b57cec5SDimitry Andric llvm_unreachable("invalid enum");
2190b57cec5SDimitry Andric }
2205ffd83dbSDimitry Andric }
2210b57cec5SDimitry Andric
MaxVersionForCudaArch(CudaArch A)2220b57cec5SDimitry Andric CudaVersion MaxVersionForCudaArch(CudaArch A) {
2235ffd83dbSDimitry Andric // AMD GPUs do not depend on CUDA versions.
2245ffd83dbSDimitry Andric if (IsAMDGpuArch(A))
225349cc55cSDimitry Andric return CudaVersion::NEW;
2265ffd83dbSDimitry Andric
2270b57cec5SDimitry Andric switch (A) {
2280b57cec5SDimitry Andric case CudaArch::UNKNOWN:
2290b57cec5SDimitry Andric return CudaVersion::UNKNOWN;
2300b57cec5SDimitry Andric case CudaArch::SM_20:
2310b57cec5SDimitry Andric case CudaArch::SM_21:
2320b57cec5SDimitry Andric return CudaVersion::CUDA_80;
233349cc55cSDimitry Andric case CudaArch::SM_30:
23406c3fb27SDimitry Andric case CudaArch::SM_32:
23506c3fb27SDimitry Andric return CudaVersion::CUDA_102;
23606c3fb27SDimitry Andric case CudaArch::SM_35:
23706c3fb27SDimitry Andric case CudaArch::SM_37:
23806c3fb27SDimitry Andric return CudaVersion::CUDA_118;
2390b57cec5SDimitry Andric default:
240349cc55cSDimitry Andric return CudaVersion::NEW;
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric
CudaFeatureEnabled(llvm::VersionTuple Version,CudaFeature Feature)2440b57cec5SDimitry Andric bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
2450b57cec5SDimitry Andric return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric
CudaFeatureEnabled(CudaVersion Version,CudaFeature Feature)2480b57cec5SDimitry Andric bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) {
2490b57cec5SDimitry Andric switch (Feature) {
2500b57cec5SDimitry Andric case CudaFeature::CUDA_USES_NEW_LAUNCH:
2510b57cec5SDimitry Andric return Version >= CudaVersion::CUDA_92;
2520b57cec5SDimitry Andric case CudaFeature::CUDA_USES_FATBIN_REGISTER_END:
2530b57cec5SDimitry Andric return Version >= CudaVersion::CUDA_101;
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric llvm_unreachable("Unknown CUDA feature.");
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric } // namespace clang
258