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