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