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