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), 44*0fca6ea1SDimitry Andric CUDA_ENTRY(12, 4), 45*0fca6ea1SDimitry Andric CUDA_ENTRY(12, 5), 46bdd1243dSDimitry Andric {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())}, 47bdd1243dSDimitry Andric {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone. 48bdd1243dSDimitry Andric }; 49bdd1243dSDimitry Andric #undef CUDA_ENTRY 50bdd1243dSDimitry Andric 51bdd1243dSDimitry Andric const char *CudaVersionToString(CudaVersion V) { 52bdd1243dSDimitry Andric for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I) 53bdd1243dSDimitry Andric if (I->Version == V) 54bdd1243dSDimitry Andric return I->Name; 55bdd1243dSDimitry Andric 56bdd1243dSDimitry Andric return CudaVersionToString(CudaVersion::UNKNOWN); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 5913138422SDimitry Andric CudaVersion CudaStringToVersion(const llvm::Twine &S) { 60bdd1243dSDimitry Andric std::string VS = S.str(); 61bdd1243dSDimitry Andric for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I) 62bdd1243dSDimitry Andric if (I->Name == VS) 63bdd1243dSDimitry Andric return I->Version; 64bdd1243dSDimitry Andric return CudaVersion::UNKNOWN; 65bdd1243dSDimitry Andric } 66bdd1243dSDimitry Andric 67bdd1243dSDimitry Andric CudaVersion ToCudaVersion(llvm::VersionTuple Version) { 68bdd1243dSDimitry Andric for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I) 69bdd1243dSDimitry Andric if (I->TVersion == Version) 70bdd1243dSDimitry Andric return I->Version; 71bdd1243dSDimitry Andric return CudaVersion::UNKNOWN; 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 74fe6060f1SDimitry Andric namespace { 75*0fca6ea1SDimitry Andric struct OffloadArchToStringMap { 76*0fca6ea1SDimitry Andric OffloadArch arch; 775ffd83dbSDimitry Andric const char *arch_name; 785ffd83dbSDimitry Andric const char *virtual_arch_name; 795ffd83dbSDimitry Andric }; 80fe6060f1SDimitry Andric } // namespace 815ffd83dbSDimitry Andric 82*0fca6ea1SDimitry Andric #define SM2(sm, ca) {OffloadArch::SM_##sm, "sm_" #sm, ca} 835ffd83dbSDimitry Andric #define SM(sm) SM2(sm, "compute_" #sm) 84*0fca6ea1SDimitry Andric #define GFX(gpu) {OffloadArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn"} 85*0fca6ea1SDimitry Andric static const OffloadArchToStringMap arch_names[] = { 865ffd83dbSDimitry Andric // clang-format off 87*0fca6ea1SDimitry Andric {OffloadArch::UNUSED, "", ""}, 885ffd83dbSDimitry Andric SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi 89*0fca6ea1SDimitry Andric SM(30), {OffloadArch::SM_32_, "sm_32", "compute_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 113*0fca6ea1SDimitry Andric {OffloadArch::GFX9_GENERIC, "gfx9-generic", "compute_amdgcn"}, 114e8d8bef9SDimitry Andric GFX(900), // gfx900 115e8d8bef9SDimitry Andric GFX(902), // gfx902 116e8d8bef9SDimitry Andric GFX(904), // gfx903 117e8d8bef9SDimitry Andric GFX(906), // gfx906 118e8d8bef9SDimitry Andric GFX(908), // gfx908 119e8d8bef9SDimitry Andric GFX(909), // gfx909 120fe6060f1SDimitry Andric GFX(90a), // gfx90a 121e8d8bef9SDimitry Andric GFX(90c), // gfx90c 12281ad6265SDimitry Andric GFX(940), // gfx940 12306c3fb27SDimitry Andric GFX(941), // gfx941 12406c3fb27SDimitry Andric GFX(942), // gfx942 125*0fca6ea1SDimitry Andric {OffloadArch::GFX10_1_GENERIC, "gfx10-1-generic", "compute_amdgcn"}, 126e8d8bef9SDimitry Andric GFX(1010), // gfx1010 127e8d8bef9SDimitry Andric GFX(1011), // gfx1011 128e8d8bef9SDimitry Andric GFX(1012), // gfx1012 129fe6060f1SDimitry Andric GFX(1013), // gfx1013 130*0fca6ea1SDimitry Andric {OffloadArch::GFX10_3_GENERIC, "gfx10-3-generic", "compute_amdgcn"}, 131e8d8bef9SDimitry Andric GFX(1030), // gfx1030 132e8d8bef9SDimitry Andric GFX(1031), // gfx1031 133e8d8bef9SDimitry Andric GFX(1032), // gfx1032 134e8d8bef9SDimitry Andric GFX(1033), // gfx1033 135fe6060f1SDimitry Andric GFX(1034), // gfx1034 136fe6060f1SDimitry Andric GFX(1035), // gfx1035 13781ad6265SDimitry Andric GFX(1036), // gfx1036 138*0fca6ea1SDimitry Andric {OffloadArch::GFX11_GENERIC, "gfx11-generic", "compute_amdgcn"}, 13981ad6265SDimitry Andric GFX(1100), // gfx1100 14081ad6265SDimitry Andric GFX(1101), // gfx1101 14181ad6265SDimitry Andric GFX(1102), // gfx1102 14281ad6265SDimitry Andric GFX(1103), // gfx1103 14306c3fb27SDimitry Andric GFX(1150), // gfx1150 14406c3fb27SDimitry Andric GFX(1151), // gfx1151 145*0fca6ea1SDimitry Andric GFX(1152), // gfx1152 146*0fca6ea1SDimitry Andric {OffloadArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"}, 1475f757f3fSDimitry Andric GFX(1200), // gfx1200 1485f757f3fSDimitry Andric GFX(1201), // gfx1201 149*0fca6ea1SDimitry Andric {OffloadArch::AMDGCNSPIRV, "amdgcnspirv", "compute_amdgcn"}, 150*0fca6ea1SDimitry Andric {OffloadArch::Generic, "generic", ""}, 1515ffd83dbSDimitry Andric // clang-format on 1525ffd83dbSDimitry Andric }; 1535ffd83dbSDimitry Andric #undef SM 1545ffd83dbSDimitry Andric #undef SM2 1555ffd83dbSDimitry Andric #undef GFX 1565ffd83dbSDimitry Andric 157*0fca6ea1SDimitry Andric const char *OffloadArchToString(OffloadArch A) { 1585ffd83dbSDimitry Andric auto result = std::find_if( 1595ffd83dbSDimitry Andric std::begin(arch_names), std::end(arch_names), 160*0fca6ea1SDimitry Andric [A](const OffloadArchToStringMap &map) { return A == map.arch; }); 1615ffd83dbSDimitry Andric if (result == std::end(arch_names)) 1620b57cec5SDimitry Andric return "unknown"; 1635ffd83dbSDimitry Andric return result->arch_name; 1640b57cec5SDimitry Andric } 1655ffd83dbSDimitry Andric 166*0fca6ea1SDimitry Andric const char *OffloadArchToVirtualArchString(OffloadArch A) { 1675ffd83dbSDimitry Andric auto result = std::find_if( 1685ffd83dbSDimitry Andric std::begin(arch_names), std::end(arch_names), 169*0fca6ea1SDimitry Andric [A](const OffloadArchToStringMap &map) { return A == map.arch; }); 1705ffd83dbSDimitry Andric if (result == std::end(arch_names)) 1715ffd83dbSDimitry Andric return "unknown"; 1725ffd83dbSDimitry Andric return result->virtual_arch_name; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 175*0fca6ea1SDimitry Andric OffloadArch StringToOffloadArch(llvm::StringRef S) { 1765ffd83dbSDimitry Andric auto result = std::find_if( 1775ffd83dbSDimitry Andric std::begin(arch_names), std::end(arch_names), 178*0fca6ea1SDimitry Andric [S](const OffloadArchToStringMap &map) { return S == map.arch_name; }); 1795ffd83dbSDimitry Andric if (result == std::end(arch_names)) 180*0fca6ea1SDimitry Andric return OffloadArch::UNKNOWN; 1815ffd83dbSDimitry Andric return result->arch; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 184*0fca6ea1SDimitry Andric CudaVersion MinVersionForOffloadArch(OffloadArch A) { 185*0fca6ea1SDimitry Andric if (A == OffloadArch::UNKNOWN) 1860b57cec5SDimitry Andric return CudaVersion::UNKNOWN; 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric // AMD GPUs do not depend on CUDA versions. 189*0fca6ea1SDimitry Andric if (IsAMDOffloadArch(A)) 1905ffd83dbSDimitry Andric return CudaVersion::CUDA_70; 1915ffd83dbSDimitry Andric 1925ffd83dbSDimitry Andric switch (A) { 193*0fca6ea1SDimitry Andric case OffloadArch::SM_20: 194*0fca6ea1SDimitry Andric case OffloadArch::SM_21: 195*0fca6ea1SDimitry Andric case OffloadArch::SM_30: 196*0fca6ea1SDimitry Andric case OffloadArch::SM_32_: 197*0fca6ea1SDimitry Andric case OffloadArch::SM_35: 198*0fca6ea1SDimitry Andric case OffloadArch::SM_37: 199*0fca6ea1SDimitry Andric case OffloadArch::SM_50: 200*0fca6ea1SDimitry Andric case OffloadArch::SM_52: 201*0fca6ea1SDimitry Andric case OffloadArch::SM_53: 2020b57cec5SDimitry Andric return CudaVersion::CUDA_70; 203*0fca6ea1SDimitry Andric case OffloadArch::SM_60: 204*0fca6ea1SDimitry Andric case OffloadArch::SM_61: 205*0fca6ea1SDimitry Andric case OffloadArch::SM_62: 2060b57cec5SDimitry Andric return CudaVersion::CUDA_80; 207*0fca6ea1SDimitry Andric case OffloadArch::SM_70: 2080b57cec5SDimitry Andric return CudaVersion::CUDA_90; 209*0fca6ea1SDimitry Andric case OffloadArch::SM_72: 2100b57cec5SDimitry Andric return CudaVersion::CUDA_91; 211*0fca6ea1SDimitry Andric case OffloadArch::SM_75: 2120b57cec5SDimitry Andric return CudaVersion::CUDA_100; 213*0fca6ea1SDimitry Andric case OffloadArch::SM_80: 2145ffd83dbSDimitry Andric return CudaVersion::CUDA_110; 215*0fca6ea1SDimitry Andric case OffloadArch::SM_86: 216fe6060f1SDimitry Andric return CudaVersion::CUDA_111; 217*0fca6ea1SDimitry Andric case OffloadArch::SM_87: 218bdd1243dSDimitry Andric return CudaVersion::CUDA_114; 219*0fca6ea1SDimitry Andric case OffloadArch::SM_89: 220*0fca6ea1SDimitry Andric case OffloadArch::SM_90: 221bdd1243dSDimitry Andric return CudaVersion::CUDA_118; 222*0fca6ea1SDimitry Andric case OffloadArch::SM_90a: 2235f757f3fSDimitry Andric return CudaVersion::CUDA_120; 2245ffd83dbSDimitry Andric default: 2250b57cec5SDimitry Andric llvm_unreachable("invalid enum"); 2260b57cec5SDimitry Andric } 2275ffd83dbSDimitry Andric } 2280b57cec5SDimitry Andric 229*0fca6ea1SDimitry Andric CudaVersion MaxVersionForOffloadArch(OffloadArch A) { 2305ffd83dbSDimitry Andric // AMD GPUs do not depend on CUDA versions. 231*0fca6ea1SDimitry Andric if (IsAMDOffloadArch(A)) 232349cc55cSDimitry Andric return CudaVersion::NEW; 2335ffd83dbSDimitry Andric 2340b57cec5SDimitry Andric switch (A) { 235*0fca6ea1SDimitry Andric case OffloadArch::UNKNOWN: 2360b57cec5SDimitry Andric return CudaVersion::UNKNOWN; 237*0fca6ea1SDimitry Andric case OffloadArch::SM_20: 238*0fca6ea1SDimitry Andric case OffloadArch::SM_21: 2390b57cec5SDimitry Andric return CudaVersion::CUDA_80; 240*0fca6ea1SDimitry Andric case OffloadArch::SM_30: 241*0fca6ea1SDimitry Andric case OffloadArch::SM_32_: 24206c3fb27SDimitry Andric return CudaVersion::CUDA_102; 243*0fca6ea1SDimitry Andric case OffloadArch::SM_35: 244*0fca6ea1SDimitry Andric case OffloadArch::SM_37: 24506c3fb27SDimitry Andric return CudaVersion::CUDA_118; 2460b57cec5SDimitry Andric default: 247349cc55cSDimitry Andric return CudaVersion::NEW; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) { 2520b57cec5SDimitry Andric return CudaFeatureEnabled(ToCudaVersion(Version), Feature); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) { 2560b57cec5SDimitry Andric switch (Feature) { 2570b57cec5SDimitry Andric case CudaFeature::CUDA_USES_NEW_LAUNCH: 2580b57cec5SDimitry Andric return Version >= CudaVersion::CUDA_92; 2590b57cec5SDimitry Andric case CudaFeature::CUDA_USES_FATBIN_REGISTER_END: 2600b57cec5SDimitry Andric return Version >= CudaVersion::CUDA_101; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric llvm_unreachable("Unknown CUDA feature."); 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric } // namespace clang 265