#include "clang/Basic/Cuda.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/VersionTuple.h" namespace clang { const char *CudaVersionToString(CudaVersion V) { switch (V) { case CudaVersion::UNKNOWN: return "unknown"; case CudaVersion::CUDA_70: return "7.0"; case CudaVersion::CUDA_75: return "7.5"; case CudaVersion::CUDA_80: return "8.0"; case CudaVersion::CUDA_90: return "9.0"; case CudaVersion::CUDA_91: return "9.1"; case CudaVersion::CUDA_92: return "9.2"; case CudaVersion::CUDA_100: return "10.0"; case CudaVersion::CUDA_101: return "10.1"; case CudaVersion::CUDA_102: return "10.2"; case CudaVersion::CUDA_110: return "11.0"; } llvm_unreachable("invalid enum"); } CudaVersion CudaStringToVersion(const llvm::Twine &S) { return llvm::StringSwitch(S.str()) .Case("7.0", CudaVersion::CUDA_70) .Case("7.5", CudaVersion::CUDA_75) .Case("8.0", CudaVersion::CUDA_80) .Case("9.0", CudaVersion::CUDA_90) .Case("9.1", CudaVersion::CUDA_91) .Case("9.2", CudaVersion::CUDA_92) .Case("10.0", CudaVersion::CUDA_100) .Case("10.1", CudaVersion::CUDA_101) .Case("10.2", CudaVersion::CUDA_102) .Case("11.0", CudaVersion::CUDA_110) .Default(CudaVersion::UNKNOWN); } struct CudaArchToStringMap { CudaArch arch; const char *arch_name; const char *virtual_arch_name; }; #define SM2(sm, ca) \ { CudaArch::SM_##sm, "sm_" #sm, ca } #define SM(sm) SM2(sm, "compute_" #sm) #define GFX(gpu) \ { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" } CudaArchToStringMap arch_names[] = { // clang-format off {CudaArch::UNUSED, "", ""}, SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi SM(30), SM(32), SM(35), SM(37), // Kepler SM(50), SM(52), SM(53), // Maxwell SM(60), SM(61), SM(62), // Pascal SM(70), SM(72), // Volta SM(75), // Turing SM(80), // Ampere GFX(600), // gfx600 GFX(601), // gfx601 GFX(602), // gfx602 GFX(700), // gfx700 GFX(701), // gfx701 GFX(702), // gfx702 GFX(703), // gfx703 GFX(704), // gfx704 GFX(705), // gfx705 GFX(801), // gfx801 GFX(802), // gfx802 GFX(803), // gfx803 GFX(805), // gfx805 GFX(810), // gfx810 GFX(900), // gfx900 GFX(902), // gfx902 GFX(904), // gfx903 GFX(906), // gfx906 GFX(908), // gfx908 GFX(909), // gfx909 GFX(90c), // gfx90c GFX(1010), // gfx1010 GFX(1011), // gfx1011 GFX(1012), // gfx1012 GFX(1030), // gfx1030 GFX(1031), // gfx1031 GFX(1032), // gfx1032 GFX(1033), // gfx1033 // clang-format on }; #undef SM #undef SM2 #undef GFX const char *CudaArchToString(CudaArch A) { auto result = std::find_if( std::begin(arch_names), std::end(arch_names), [A](const CudaArchToStringMap &map) { return A == map.arch; }); if (result == std::end(arch_names)) return "unknown"; return result->arch_name; } const char *CudaArchToVirtualArchString(CudaArch A) { auto result = std::find_if( std::begin(arch_names), std::end(arch_names), [A](const CudaArchToStringMap &map) { return A == map.arch; }); if (result == std::end(arch_names)) return "unknown"; return result->virtual_arch_name; } CudaArch StringToCudaArch(llvm::StringRef S) { auto result = std::find_if( std::begin(arch_names), std::end(arch_names), [S](const CudaArchToStringMap &map) { return S == map.arch_name; }); if (result == std::end(arch_names)) return CudaArch::UNKNOWN; return result->arch; } CudaVersion MinVersionForCudaArch(CudaArch A) { if (A == CudaArch::UNKNOWN) return CudaVersion::UNKNOWN; // AMD GPUs do not depend on CUDA versions. if (IsAMDGpuArch(A)) return CudaVersion::CUDA_70; switch (A) { case CudaArch::SM_20: case CudaArch::SM_21: case CudaArch::SM_30: case CudaArch::SM_32: case CudaArch::SM_35: case CudaArch::SM_37: case CudaArch::SM_50: case CudaArch::SM_52: case CudaArch::SM_53: return CudaVersion::CUDA_70; case CudaArch::SM_60: case CudaArch::SM_61: case CudaArch::SM_62: return CudaVersion::CUDA_80; case CudaArch::SM_70: return CudaVersion::CUDA_90; case CudaArch::SM_72: return CudaVersion::CUDA_91; case CudaArch::SM_75: return CudaVersion::CUDA_100; case CudaArch::SM_80: return CudaVersion::CUDA_110; default: llvm_unreachable("invalid enum"); } } CudaVersion MaxVersionForCudaArch(CudaArch A) { // AMD GPUs do not depend on CUDA versions. if (IsAMDGpuArch(A)) return CudaVersion::LATEST; switch (A) { case CudaArch::UNKNOWN: return CudaVersion::UNKNOWN; case CudaArch::SM_20: case CudaArch::SM_21: return CudaVersion::CUDA_80; default: return CudaVersion::LATEST; } } CudaVersion ToCudaVersion(llvm::VersionTuple Version) { int IVer = Version.getMajor() * 10 + Version.getMinor().getValueOr(0); switch(IVer) { case 70: return CudaVersion::CUDA_70; case 75: return CudaVersion::CUDA_75; case 80: return CudaVersion::CUDA_80; case 90: return CudaVersion::CUDA_90; case 91: return CudaVersion::CUDA_91; case 92: return CudaVersion::CUDA_92; case 100: return CudaVersion::CUDA_100; case 101: return CudaVersion::CUDA_101; case 102: return CudaVersion::CUDA_102; case 110: return CudaVersion::CUDA_110; default: return CudaVersion::UNKNOWN; } } bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) { return CudaFeatureEnabled(ToCudaVersion(Version), Feature); } bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) { switch (Feature) { case CudaFeature::CUDA_USES_NEW_LAUNCH: return Version >= CudaVersion::CUDA_92; case CudaFeature::CUDA_USES_FATBIN_REGISTER_END: return Version >= CudaVersion::CUDA_101; } llvm_unreachable("Unknown CUDA feature."); } } // namespace clang