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), 42*5f757f3fSDimitry Andric CUDA_ENTRY(12, 2), 43*5f757f3fSDimitry 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 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 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 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 98*5f757f3fSDimitry 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 141*5f757f3fSDimitry Andric GFX(1200), // gfx1200 142*5f757f3fSDimitry 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 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 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 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 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; 215*5f757f3fSDimitry Andric case CudaArch::SM_90a: 216*5f757f3fSDimitry Andric return CudaVersion::CUDA_120; 2175ffd83dbSDimitry Andric default: 2180b57cec5SDimitry Andric llvm_unreachable("invalid enum"); 2190b57cec5SDimitry Andric } 2205ffd83dbSDimitry Andric } 2210b57cec5SDimitry Andric 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 2440b57cec5SDimitry Andric bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) { 2450b57cec5SDimitry Andric return CudaFeatureEnabled(ToCudaVersion(Version), Feature); 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 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