1 #include "clang/Basic/Cuda.h" 2 3 #include "llvm/ADT/StringRef.h" 4 #include "llvm/ADT/Twine.h" 5 #include "llvm/Support/ErrorHandling.h" 6 #include "llvm/Support/VersionTuple.h" 7 8 namespace clang { 9 10 struct CudaVersionMapEntry { 11 const char *Name; 12 CudaVersion Version; 13 llvm::VersionTuple TVersion; 14 }; 15 #define CUDA_ENTRY(major, minor) \ 16 { \ 17 #major "." #minor, CudaVersion::CUDA_##major##minor, \ 18 llvm::VersionTuple(major, minor) \ 19 } 20 21 static const CudaVersionMapEntry CudaNameVersionMap[] = { 22 CUDA_ENTRY(7, 0), 23 CUDA_ENTRY(7, 5), 24 CUDA_ENTRY(8, 0), 25 CUDA_ENTRY(9, 0), 26 CUDA_ENTRY(9, 1), 27 CUDA_ENTRY(9, 2), 28 CUDA_ENTRY(10, 0), 29 CUDA_ENTRY(10, 1), 30 CUDA_ENTRY(10, 2), 31 CUDA_ENTRY(11, 0), 32 CUDA_ENTRY(11, 1), 33 CUDA_ENTRY(11, 2), 34 CUDA_ENTRY(11, 3), 35 CUDA_ENTRY(11, 4), 36 CUDA_ENTRY(11, 5), 37 CUDA_ENTRY(11, 6), 38 CUDA_ENTRY(11, 7), 39 CUDA_ENTRY(11, 8), 40 {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())}, 41 {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone. 42 }; 43 #undef CUDA_ENTRY 44 45 const char *CudaVersionToString(CudaVersion V) { 46 for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I) 47 if (I->Version == V) 48 return I->Name; 49 50 return CudaVersionToString(CudaVersion::UNKNOWN); 51 } 52 53 CudaVersion CudaStringToVersion(const llvm::Twine &S) { 54 std::string VS = S.str(); 55 for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I) 56 if (I->Name == VS) 57 return I->Version; 58 return CudaVersion::UNKNOWN; 59 } 60 61 CudaVersion ToCudaVersion(llvm::VersionTuple Version) { 62 for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I) 63 if (I->TVersion == Version) 64 return I->Version; 65 return CudaVersion::UNKNOWN; 66 } 67 68 namespace { 69 struct CudaArchToStringMap { 70 CudaArch arch; 71 const char *arch_name; 72 const char *virtual_arch_name; 73 }; 74 } // namespace 75 76 #define SM2(sm, ca) \ 77 { CudaArch::SM_##sm, "sm_" #sm, ca } 78 #define SM(sm) SM2(sm, "compute_" #sm) 79 #define GFX(gpu) \ 80 { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" } 81 static const CudaArchToStringMap arch_names[] = { 82 // clang-format off 83 {CudaArch::UNUSED, "", ""}, 84 SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi 85 SM(30), SM(32), SM(35), SM(37), // Kepler 86 SM(50), SM(52), SM(53), // Maxwell 87 SM(60), SM(61), SM(62), // Pascal 88 SM(70), SM(72), // Volta 89 SM(75), // Turing 90 SM(80), SM(86), // Ampere 91 SM(87), // Jetson/Drive AGX Orin 92 SM(89), // Ada Lovelace 93 SM(90), // Hopper 94 GFX(600), // gfx600 95 GFX(601), // gfx601 96 GFX(602), // gfx602 97 GFX(700), // gfx700 98 GFX(701), // gfx701 99 GFX(702), // gfx702 100 GFX(703), // gfx703 101 GFX(704), // gfx704 102 GFX(705), // gfx705 103 GFX(801), // gfx801 104 GFX(802), // gfx802 105 GFX(803), // gfx803 106 GFX(805), // gfx805 107 GFX(810), // gfx810 108 GFX(900), // gfx900 109 GFX(902), // gfx902 110 GFX(904), // gfx903 111 GFX(906), // gfx906 112 GFX(908), // gfx908 113 GFX(909), // gfx909 114 GFX(90a), // gfx90a 115 GFX(90c), // gfx90c 116 GFX(940), // gfx940 117 GFX(941), // gfx941 118 GFX(1010), // gfx1010 119 GFX(1011), // gfx1011 120 GFX(1012), // gfx1012 121 GFX(1013), // gfx1013 122 GFX(1030), // gfx1030 123 GFX(1031), // gfx1031 124 GFX(1032), // gfx1032 125 GFX(1033), // gfx1033 126 GFX(1034), // gfx1034 127 GFX(1035), // gfx1035 128 GFX(1036), // gfx1036 129 GFX(1100), // gfx1100 130 GFX(1101), // gfx1101 131 GFX(1102), // gfx1102 132 GFX(1103), // gfx1103 133 {CudaArch::Generic, "generic", ""}, 134 // clang-format on 135 }; 136 #undef SM 137 #undef SM2 138 #undef GFX 139 140 const char *CudaArchToString(CudaArch A) { 141 auto result = std::find_if( 142 std::begin(arch_names), std::end(arch_names), 143 [A](const CudaArchToStringMap &map) { return A == map.arch; }); 144 if (result == std::end(arch_names)) 145 return "unknown"; 146 return result->arch_name; 147 } 148 149 const char *CudaArchToVirtualArchString(CudaArch A) { 150 auto result = std::find_if( 151 std::begin(arch_names), std::end(arch_names), 152 [A](const CudaArchToStringMap &map) { return A == map.arch; }); 153 if (result == std::end(arch_names)) 154 return "unknown"; 155 return result->virtual_arch_name; 156 } 157 158 CudaArch StringToCudaArch(llvm::StringRef S) { 159 auto result = std::find_if( 160 std::begin(arch_names), std::end(arch_names), 161 [S](const CudaArchToStringMap &map) { return S == map.arch_name; }); 162 if (result == std::end(arch_names)) 163 return CudaArch::UNKNOWN; 164 return result->arch; 165 } 166 167 CudaVersion MinVersionForCudaArch(CudaArch A) { 168 if (A == CudaArch::UNKNOWN) 169 return CudaVersion::UNKNOWN; 170 171 // AMD GPUs do not depend on CUDA versions. 172 if (IsAMDGpuArch(A)) 173 return CudaVersion::CUDA_70; 174 175 switch (A) { 176 case CudaArch::SM_20: 177 case CudaArch::SM_21: 178 case CudaArch::SM_30: 179 case CudaArch::SM_32: 180 case CudaArch::SM_35: 181 case CudaArch::SM_37: 182 case CudaArch::SM_50: 183 case CudaArch::SM_52: 184 case CudaArch::SM_53: 185 return CudaVersion::CUDA_70; 186 case CudaArch::SM_60: 187 case CudaArch::SM_61: 188 case CudaArch::SM_62: 189 return CudaVersion::CUDA_80; 190 case CudaArch::SM_70: 191 return CudaVersion::CUDA_90; 192 case CudaArch::SM_72: 193 return CudaVersion::CUDA_91; 194 case CudaArch::SM_75: 195 return CudaVersion::CUDA_100; 196 case CudaArch::SM_80: 197 return CudaVersion::CUDA_110; 198 case CudaArch::SM_86: 199 return CudaVersion::CUDA_111; 200 case CudaArch::SM_87: 201 return CudaVersion::CUDA_114; 202 case CudaArch::SM_89: 203 case CudaArch::SM_90: 204 return CudaVersion::CUDA_118; 205 default: 206 llvm_unreachable("invalid enum"); 207 } 208 } 209 210 CudaVersion MaxVersionForCudaArch(CudaArch A) { 211 // AMD GPUs do not depend on CUDA versions. 212 if (IsAMDGpuArch(A)) 213 return CudaVersion::NEW; 214 215 switch (A) { 216 case CudaArch::UNKNOWN: 217 return CudaVersion::UNKNOWN; 218 case CudaArch::SM_20: 219 case CudaArch::SM_21: 220 return CudaVersion::CUDA_80; 221 case CudaArch::SM_30: 222 return CudaVersion::CUDA_110; 223 default: 224 return CudaVersion::NEW; 225 } 226 } 227 228 bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) { 229 return CudaFeatureEnabled(ToCudaVersion(Version), Feature); 230 } 231 232 bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) { 233 switch (Feature) { 234 case CudaFeature::CUDA_USES_NEW_LAUNCH: 235 return Version >= CudaVersion::CUDA_92; 236 case CudaFeature::CUDA_USES_FATBIN_REGISTER_END: 237 return Version >= CudaVersion::CUDA_101; 238 } 239 llvm_unreachable("Unknown CUDA feature."); 240 } 241 } // namespace clang 242