1121 lines · cpp
1//===--- AMDGPU.cpp - AMDGPU ToolChain Implementations ----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "AMDGPU.h"10#include "clang/Basic/TargetID.h"11#include "clang/Config/config.h"12#include "clang/Driver/CommonArgs.h"13#include "clang/Driver/Compilation.h"14#include "clang/Driver/InputInfo.h"15#include "clang/Driver/SanitizerArgs.h"16#include "clang/Options/Options.h"17#include "llvm/ADT/StringExtras.h"18#include "llvm/Option/ArgList.h"19#include "llvm/Support/Error.h"20#include "llvm/Support/LineIterator.h"21#include "llvm/Support/Path.h"22#include "llvm/Support/Process.h"23#include "llvm/Support/VirtualFileSystem.h"24#include "llvm/TargetParser/Host.h"25#include "llvm/TargetParser/TargetParser.h"26#include <optional>27#include <system_error>28 29using namespace clang::driver;30using namespace clang::driver::tools;31using namespace clang::driver::toolchains;32using namespace clang;33using namespace llvm::opt;34 35RocmInstallationDetector::CommonBitcodeLibsPreferences::36 CommonBitcodeLibsPreferences(const Driver &D,37 const llvm::opt::ArgList &DriverArgs,38 StringRef GPUArch,39 const Action::OffloadKind DeviceOffloadingKind,40 const bool NeedsASanRT)41 : ABIVer(DeviceLibABIVersion::fromCodeObjectVersion(42 tools::getAMDGPUCodeObjectVersion(D, DriverArgs))) {43 const auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch);44 const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);45 46 IsOpenMP = DeviceOffloadingKind == Action::OFK_OpenMP;47 48 const bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32);49 Wave64 =50 !HasWave32 || DriverArgs.hasFlag(options::OPT_mwavefrontsize64,51 options::OPT_mno_wavefrontsize64, false);52 53 const bool IsKnownOffloading = DeviceOffloadingKind == Action::OFK_OpenMP ||54 DeviceOffloadingKind == Action::OFK_HIP;55 56 // Default to enabling f32 denormals on subtargets where fma is fast with57 // denormals58 const bool DefaultDAZ =59 (Kind == llvm::AMDGPU::GK_NONE)60 ? false61 : !((ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) &&62 (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32));63 // TODO: There are way too many flags that change this. Do we need to64 // check them all?65 DAZ = IsKnownOffloading66 ? DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero,67 options::OPT_fno_gpu_flush_denormals_to_zero,68 DefaultDAZ)69 : DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) || DefaultDAZ;70 71 FiniteOnly = DriverArgs.hasArg(options::OPT_cl_finite_math_only) ||72 DriverArgs.hasFlag(options::OPT_ffinite_math_only,73 options::OPT_fno_finite_math_only, false);74 75 UnsafeMathOpt =76 DriverArgs.hasArg(options::OPT_cl_unsafe_math_optimizations) ||77 DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations,78 options::OPT_fno_unsafe_math_optimizations, false);79 80 FastRelaxedMath = DriverArgs.hasArg(options::OPT_cl_fast_relaxed_math) ||81 DriverArgs.hasFlag(options::OPT_ffast_math,82 options::OPT_fno_fast_math, false);83 84 const bool DefaultSqrt = IsKnownOffloading ? true : false;85 CorrectSqrt =86 DriverArgs.hasArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt) ||87 DriverArgs.hasFlag(88 options::OPT_fhip_fp32_correctly_rounded_divide_sqrt,89 options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt, DefaultSqrt);90 // GPU Sanitizer currently only supports ASan and is enabled through host91 // ASan.92 GPUSan = (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,93 options::OPT_fno_gpu_sanitize, true) &&94 NeedsASanRT);95}96 97void RocmInstallationDetector::scanLibDevicePath(llvm::StringRef Path) {98 assert(!Path.empty());99 100 const StringRef Suffix(".bc");101 const StringRef Suffix2(".amdgcn.bc");102 103 std::error_code EC;104 for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE;105 !EC && LI != LE; LI = LI.increment(EC)) {106 StringRef FilePath = LI->path();107 StringRef FileName = llvm::sys::path::filename(FilePath);108 if (!FileName.ends_with(Suffix))109 continue;110 111 StringRef BaseName;112 if (FileName.ends_with(Suffix2))113 BaseName = FileName.drop_back(Suffix2.size());114 else if (FileName.ends_with(Suffix))115 BaseName = FileName.drop_back(Suffix.size());116 117 const StringRef ABIVersionPrefix = "oclc_abi_version_";118 if (BaseName == "ocml") {119 OCML = FilePath;120 } else if (BaseName == "ockl") {121 OCKL = FilePath;122 } else if (BaseName == "opencl") {123 OpenCL = FilePath;124 } else if (BaseName == "asanrtl") {125 AsanRTL = FilePath;126 } else if (BaseName == "oclc_finite_only_off") {127 FiniteOnly.Off = FilePath;128 } else if (BaseName == "oclc_finite_only_on") {129 FiniteOnly.On = FilePath;130 } else if (BaseName == "oclc_daz_opt_on") {131 DenormalsAreZero.On = FilePath;132 } else if (BaseName == "oclc_daz_opt_off") {133 DenormalsAreZero.Off = FilePath;134 } else if (BaseName == "oclc_correctly_rounded_sqrt_on") {135 CorrectlyRoundedSqrt.On = FilePath;136 } else if (BaseName == "oclc_correctly_rounded_sqrt_off") {137 CorrectlyRoundedSqrt.Off = FilePath;138 } else if (BaseName == "oclc_unsafe_math_on") {139 UnsafeMath.On = FilePath;140 } else if (BaseName == "oclc_unsafe_math_off") {141 UnsafeMath.Off = FilePath;142 } else if (BaseName == "oclc_wavefrontsize64_on") {143 WavefrontSize64.On = FilePath;144 } else if (BaseName == "oclc_wavefrontsize64_off") {145 WavefrontSize64.Off = FilePath;146 } else if (BaseName.starts_with(ABIVersionPrefix)) {147 unsigned ABIVersionNumber;148 if (BaseName.drop_front(ABIVersionPrefix.size())149 .getAsInteger(/*Redex=*/0, ABIVersionNumber))150 continue;151 ABIVersionMap[ABIVersionNumber] = FilePath.str();152 } else {153 // Process all bitcode filenames that look like154 // ocl_isa_version_XXX.amdgcn.bc155 const StringRef DeviceLibPrefix = "oclc_isa_version_";156 if (!BaseName.starts_with(DeviceLibPrefix))157 continue;158 159 StringRef IsaVersionNumber =160 BaseName.drop_front(DeviceLibPrefix.size());161 162 llvm::Twine GfxName = Twine("gfx") + IsaVersionNumber;163 SmallString<8> Tmp;164 LibDeviceMap.insert(165 std::make_pair(GfxName.toStringRef(Tmp), FilePath.str()));166 }167 }168}169 170// Parse and extract version numbers from `.hipVersion`. Return `true` if171// the parsing fails.172bool RocmInstallationDetector::parseHIPVersionFile(llvm::StringRef V) {173 SmallVector<StringRef, 4> VersionParts;174 V.split(VersionParts, '\n');175 unsigned Major = ~0U;176 unsigned Minor = ~0U;177 for (auto Part : VersionParts) {178 auto Splits = Part.rtrim().split('=');179 if (Splits.first == "HIP_VERSION_MAJOR") {180 if (Splits.second.getAsInteger(0, Major))181 return true;182 } else if (Splits.first == "HIP_VERSION_MINOR") {183 if (Splits.second.getAsInteger(0, Minor))184 return true;185 } else if (Splits.first == "HIP_VERSION_PATCH")186 VersionPatch = Splits.second.str();187 }188 if (Major == ~0U || Minor == ~0U)189 return true;190 VersionMajorMinor = llvm::VersionTuple(Major, Minor);191 DetectedVersion =192 (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str();193 return false;194}195 196/// \returns a list of candidate directories for ROCm installation, which is197/// cached and populated only once.198const SmallVectorImpl<RocmInstallationDetector::Candidate> &199RocmInstallationDetector::getInstallationPathCandidates() {200 201 // Return the cached candidate list if it has already been populated.202 if (!ROCmSearchDirs.empty())203 return ROCmSearchDirs;204 205 auto DoPrintROCmSearchDirs = [&]() {206 if (PrintROCmSearchDirs)207 for (auto Cand : ROCmSearchDirs) {208 llvm::errs() << "ROCm installation search path: " << Cand.Path << '\n';209 }210 };211 212 // For candidate specified by --rocm-path we do not do strict check, i.e.,213 // checking existence of HIP version file and device library files.214 if (!RocmPathArg.empty()) {215 ROCmSearchDirs.emplace_back(RocmPathArg.str());216 DoPrintROCmSearchDirs();217 return ROCmSearchDirs;218 } else if (std::optional<std::string> RocmPathEnv =219 llvm::sys::Process::GetEnv("ROCM_PATH")) {220 if (!RocmPathEnv->empty()) {221 ROCmSearchDirs.emplace_back(std::move(*RocmPathEnv));222 DoPrintROCmSearchDirs();223 return ROCmSearchDirs;224 }225 }226 227 // Try to find relative to the compiler binary.228 StringRef InstallDir = D.Dir;229 230 // Check both a normal Unix prefix position of the clang binary, as well as231 // the Windows-esque layout the ROCm packages use with the host architecture232 // subdirectory of bin.233 auto DeduceROCmPath = [](StringRef ClangPath) {234 // Strip off directory (usually bin)235 StringRef ParentDir = llvm::sys::path::parent_path(ClangPath);236 StringRef ParentName = llvm::sys::path::filename(ParentDir);237 238 // Some builds use bin/{host arch}, so go up again.239 if (ParentName == "bin") {240 ParentDir = llvm::sys::path::parent_path(ParentDir);241 ParentName = llvm::sys::path::filename(ParentDir);242 }243 244 // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin245 // Some versions of the aomp package install to /opt/rocm/aomp/bin246 if (ParentName == "llvm" || ParentName.starts_with("aomp")) {247 ParentDir = llvm::sys::path::parent_path(ParentDir);248 ParentName = llvm::sys::path::filename(ParentDir);249 250 // Some versions of the rocm llvm package install to251 // /opt/rocm/lib/llvm/bin, so also back up if within the lib dir still252 if (ParentName == "lib")253 ParentDir = llvm::sys::path::parent_path(ParentDir);254 }255 256 return Candidate(ParentDir.str(), /*StrictChecking=*/true);257 };258 259 // Deduce ROCm path by the path used to invoke clang. Do not resolve symbolic260 // link of clang itself.261 ROCmSearchDirs.emplace_back(DeduceROCmPath(InstallDir));262 263 // Deduce ROCm path by the real path of the invoked clang, resolving symbolic264 // link of clang itself.265 llvm::SmallString<256> RealClangPath;266 llvm::sys::fs::real_path(D.getClangProgramPath(), RealClangPath);267 auto ParentPath = llvm::sys::path::parent_path(RealClangPath);268 if (ParentPath != InstallDir)269 ROCmSearchDirs.emplace_back(DeduceROCmPath(ParentPath));270 271 // Device library may be installed in clang or resource directory.272 auto ClangRoot = llvm::sys::path::parent_path(InstallDir);273 auto RealClangRoot = llvm::sys::path::parent_path(ParentPath);274 ROCmSearchDirs.emplace_back(ClangRoot.str(), /*StrictChecking=*/true);275 if (RealClangRoot != ClangRoot)276 ROCmSearchDirs.emplace_back(RealClangRoot.str(), /*StrictChecking=*/true);277 ROCmSearchDirs.emplace_back(D.ResourceDir,278 /*StrictChecking=*/true);279 280 ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/rocm",281 /*StrictChecking=*/true);282 283 // Find the latest /opt/rocm-{release} directory.284 std::error_code EC;285 std::string LatestROCm;286 llvm::VersionTuple LatestVer;287 // Get ROCm version from ROCm directory name.288 auto GetROCmVersion = [](StringRef DirName) {289 llvm::VersionTuple V;290 std::string VerStr = DirName.drop_front(strlen("rocm-")).str();291 // The ROCm directory name follows the format of292 // rocm-{major}.{minor}.{subMinor}[-{build}]293 llvm::replace(VerStr, '-', '.');294 V.tryParse(VerStr);295 return V;296 };297 for (llvm::vfs::directory_iterator298 File = D.getVFS().dir_begin(D.SysRoot + "/opt", EC),299 FileEnd;300 File != FileEnd && !EC; File.increment(EC)) {301 llvm::StringRef FileName = llvm::sys::path::filename(File->path());302 if (!FileName.starts_with("rocm-"))303 continue;304 if (LatestROCm.empty()) {305 LatestROCm = FileName.str();306 LatestVer = GetROCmVersion(LatestROCm);307 continue;308 }309 auto Ver = GetROCmVersion(FileName);310 if (LatestVer < Ver) {311 LatestROCm = FileName.str();312 LatestVer = Ver;313 }314 }315 if (!LatestROCm.empty())316 ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm,317 /*StrictChecking=*/true);318 319 ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local",320 /*StrictChecking=*/true);321 ROCmSearchDirs.emplace_back(D.SysRoot + "/usr",322 /*StrictChecking=*/true);323 324 DoPrintROCmSearchDirs();325 return ROCmSearchDirs;326}327 328RocmInstallationDetector::RocmInstallationDetector(329 const Driver &D, const llvm::Triple &HostTriple,330 const llvm::opt::ArgList &Args, bool DetectHIPRuntime, bool DetectDeviceLib)331 : D(D) {332 Verbose = Args.hasArg(options::OPT_v);333 RocmPathArg = Args.getLastArgValue(options::OPT_rocm_path_EQ);334 PrintROCmSearchDirs = Args.hasArg(options::OPT_print_rocm_search_dirs);335 RocmDeviceLibPathArg =336 Args.getAllArgValues(options::OPT_rocm_device_lib_path_EQ);337 HIPPathArg = Args.getLastArgValue(options::OPT_hip_path_EQ);338 HIPStdParPathArg = Args.getLastArgValue(options::OPT_hipstdpar_path_EQ);339 HasHIPStdParLibrary =340 !HIPStdParPathArg.empty() && D.getVFS().exists(HIPStdParPathArg +341 "/hipstdpar_lib.hpp");342 HIPRocThrustPathArg =343 Args.getLastArgValue(options::OPT_hipstdpar_thrust_path_EQ);344 HasRocThrustLibrary = !HIPRocThrustPathArg.empty() &&345 D.getVFS().exists(HIPRocThrustPathArg + "/thrust");346 HIPRocPrimPathArg = Args.getLastArgValue(options::OPT_hipstdpar_prim_path_EQ);347 HasRocPrimLibrary = !HIPRocPrimPathArg.empty() &&348 D.getVFS().exists(HIPRocPrimPathArg + "/rocprim");349 350 if (auto *A = Args.getLastArg(options::OPT_hip_version_EQ)) {351 HIPVersionArg = A->getValue();352 unsigned Major = ~0U;353 unsigned Minor = ~0U;354 SmallVector<StringRef, 3> Parts;355 HIPVersionArg.split(Parts, '.');356 if (Parts.size())357 Parts[0].getAsInteger(0, Major);358 if (Parts.size() > 1)359 Parts[1].getAsInteger(0, Minor);360 if (Parts.size() > 2)361 VersionPatch = Parts[2].str();362 if (VersionPatch.empty())363 VersionPatch = "0";364 if (Major != ~0U && Minor == ~0U)365 Minor = 0;366 if (Major == ~0U || Minor == ~0U)367 D.Diag(diag::err_drv_invalid_value)368 << A->getAsString(Args) << HIPVersionArg;369 370 VersionMajorMinor = llvm::VersionTuple(Major, Minor);371 DetectedVersion =372 (Twine(Major) + "." + Twine(Minor) + "." + VersionPatch).str();373 } else {374 VersionPatch = DefaultVersionPatch;375 VersionMajorMinor =376 llvm::VersionTuple(DefaultVersionMajor, DefaultVersionMinor);377 DetectedVersion = (Twine(DefaultVersionMajor) + "." +378 Twine(DefaultVersionMinor) + "." + VersionPatch)379 .str();380 }381 382 if (DetectHIPRuntime)383 detectHIPRuntime();384 if (DetectDeviceLib)385 detectDeviceLibrary();386}387 388void RocmInstallationDetector::detectDeviceLibrary() {389 assert(LibDevicePath.empty());390 391 if (!RocmDeviceLibPathArg.empty())392 LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1];393 else if (std::optional<std::string> LibPathEnv =394 llvm::sys::Process::GetEnv("HIP_DEVICE_LIB_PATH"))395 LibDevicePath = std::move(*LibPathEnv);396 397 auto &FS = D.getVFS();398 if (!LibDevicePath.empty()) {399 // Maintain compatability with HIP flag/envvar pointing directly at the400 // bitcode library directory. This points directly at the library path instead401 // of the rocm root installation.402 if (!FS.exists(LibDevicePath))403 return;404 405 scanLibDevicePath(LibDevicePath);406 HasDeviceLibrary = allGenericLibsValid() && !LibDeviceMap.empty();407 return;408 }409 410 // Check device library exists at the given path.411 auto CheckDeviceLib = [&](StringRef Path, bool StrictChecking) {412 bool CheckLibDevice = (!NoBuiltinLibs || StrictChecking);413 if (CheckLibDevice && !FS.exists(Path))414 return false;415 416 scanLibDevicePath(Path);417 418 if (!NoBuiltinLibs) {419 // Check that the required non-target libraries are all available.420 if (!allGenericLibsValid())421 return false;422 423 // Check that we have found at least one libdevice that we can link in424 // if -nobuiltinlib hasn't been specified.425 if (LibDeviceMap.empty())426 return false;427 }428 return true;429 };430 431 // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/amdgcn/bitcode432 LibDevicePath = D.ResourceDir;433 llvm::sys::path::append(LibDevicePath, CLANG_INSTALL_LIBDIR_BASENAME,434 "amdgcn", "bitcode");435 HasDeviceLibrary = CheckDeviceLib(LibDevicePath, true);436 if (HasDeviceLibrary)437 return;438 439 // Find device libraries in a legacy ROCm directory structure440 // ${ROCM_ROOT}/amdgcn/bitcode/*441 auto &ROCmDirs = getInstallationPathCandidates();442 for (const auto &Candidate : ROCmDirs) {443 LibDevicePath = Candidate.Path;444 llvm::sys::path::append(LibDevicePath, "amdgcn", "bitcode");445 HasDeviceLibrary = CheckDeviceLib(LibDevicePath, Candidate.StrictChecking);446 if (HasDeviceLibrary)447 return;448 }449}450 451void RocmInstallationDetector::detectHIPRuntime() {452 SmallVector<Candidate, 4> HIPSearchDirs;453 if (!HIPPathArg.empty())454 HIPSearchDirs.emplace_back(HIPPathArg.str());455 else if (std::optional<std::string> HIPPathEnv =456 llvm::sys::Process::GetEnv("HIP_PATH")) {457 if (!HIPPathEnv->empty())458 HIPSearchDirs.emplace_back(std::move(*HIPPathEnv));459 }460 if (HIPSearchDirs.empty())461 HIPSearchDirs.append(getInstallationPathCandidates());462 auto &FS = D.getVFS();463 464 for (const auto &Candidate : HIPSearchDirs) {465 InstallPath = Candidate.Path;466 if (InstallPath.empty() || !FS.exists(InstallPath))467 continue;468 469 BinPath = InstallPath;470 llvm::sys::path::append(BinPath, "bin");471 IncludePath = InstallPath;472 llvm::sys::path::append(IncludePath, "include");473 LibPath = InstallPath;474 llvm::sys::path::append(LibPath, "lib");475 SharePath = InstallPath;476 llvm::sys::path::append(SharePath, "share");477 478 // Get parent of InstallPath and append "share"479 SmallString<0> ParentSharePath = llvm::sys::path::parent_path(InstallPath);480 llvm::sys::path::append(ParentSharePath, "share");481 482 auto Append = [](SmallString<0> &path, const Twine &a, const Twine &b = "",483 const Twine &c = "", const Twine &d = "") {484 SmallString<0> newpath = path;485 llvm::sys::path::append(newpath, a, b, c, d);486 return newpath;487 };488 // If HIP version file can be found and parsed, use HIP version from there.489 std::vector<SmallString<0>> VersionFilePaths = {490 Append(SharePath, "hip", "version"),491 InstallPath != D.SysRoot + "/usr/local"492 ? Append(ParentSharePath, "hip", "version")493 : SmallString<0>(),494 Append(BinPath, ".hipVersion")};495 496 for (const auto &VersionFilePath : VersionFilePaths) {497 if (VersionFilePath.empty())498 continue;499 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =500 FS.getBufferForFile(VersionFilePath);501 if (!VersionFile)502 continue;503 if (HIPVersionArg.empty() && VersionFile)504 if (parseHIPVersionFile((*VersionFile)->getBuffer()))505 continue;506 507 HasHIPRuntime = true;508 return;509 }510 // Otherwise, if -rocm-path is specified (no strict checking), use the511 // default HIP version or specified by --hip-version.512 if (!Candidate.StrictChecking) {513 HasHIPRuntime = true;514 return;515 }516 }517 HasHIPRuntime = false;518}519 520void RocmInstallationDetector::print(raw_ostream &OS) const {521 if (hasHIPRuntime())522 OS << "Found HIP installation: " << InstallPath << ", version "523 << DetectedVersion << '\n';524}525 526void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs,527 ArgStringList &CC1Args) const {528 bool UsesRuntimeWrapper = VersionMajorMinor > llvm::VersionTuple(3, 5) &&529 !DriverArgs.hasArg(options::OPT_nohipwrapperinc);530 bool HasHipStdPar = DriverArgs.hasArg(options::OPT_hipstdpar);531 532 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {533 // HIP header includes standard library wrapper headers under clang534 // cuda_wrappers directory. Since these wrapper headers include_next535 // standard C++ headers, whereas libc++ headers include_next other clang536 // headers. The include paths have to follow this order:537 // - wrapper include path538 // - standard C++ include path539 // - other clang include path540 // Since standard C++ and other clang include paths are added in other541 // places after this function, here we only need to make sure wrapper542 // include path is added.543 //544 // ROCm 3.5 does not fully support the wrapper headers. Therefore it needs545 // a workaround.546 SmallString<128> P(D.ResourceDir);547 if (UsesRuntimeWrapper)548 llvm::sys::path::append(P, "include", "cuda_wrappers");549 CC1Args.push_back("-internal-isystem");550 CC1Args.push_back(DriverArgs.MakeArgString(P));551 }552 553 const auto HandleHipStdPar = [=, &DriverArgs, &CC1Args]() {554 StringRef Inc = getIncludePath();555 auto &FS = D.getVFS();556 557 if (!hasHIPStdParLibrary())558 if (!HIPStdParPathArg.empty() ||559 !FS.exists(Inc + "/thrust/system/hip/hipstdpar/hipstdpar_lib.hpp")) {560 D.Diag(diag::err_drv_no_hipstdpar_lib);561 return;562 }563 if (!HasRocThrustLibrary && !FS.exists(Inc + "/thrust")) {564 D.Diag(diag::err_drv_no_hipstdpar_thrust_lib);565 return;566 }567 if (!HasRocPrimLibrary && !FS.exists(Inc + "/rocprim")) {568 D.Diag(diag::err_drv_no_hipstdpar_prim_lib);569 return;570 }571 const char *ThrustPath;572 if (HasRocThrustLibrary)573 ThrustPath = DriverArgs.MakeArgString(HIPRocThrustPathArg);574 else575 ThrustPath = DriverArgs.MakeArgString(Inc + "/thrust");576 577 const char *HIPStdParPath;578 if (hasHIPStdParLibrary())579 HIPStdParPath = DriverArgs.MakeArgString(HIPStdParPathArg);580 else581 HIPStdParPath = DriverArgs.MakeArgString(StringRef(ThrustPath) +582 "/system/hip/hipstdpar");583 584 const char *PrimPath;585 if (HasRocPrimLibrary)586 PrimPath = DriverArgs.MakeArgString(HIPRocPrimPathArg);587 else588 PrimPath = DriverArgs.MakeArgString(getIncludePath() + "/rocprim");589 590 CC1Args.append({"-idirafter", ThrustPath, "-idirafter", PrimPath,591 "-idirafter", HIPStdParPath, "-include",592 "hipstdpar_lib.hpp"});593 };594 595 if (!DriverArgs.hasFlag(options::OPT_offload_inc, options::OPT_no_offload_inc,596 true)) {597 if (HasHipStdPar)598 HandleHipStdPar();599 600 return;601 }602 603 if (!hasHIPRuntime()) {604 D.Diag(diag::err_drv_no_hip_runtime);605 return;606 }607 608 CC1Args.push_back("-idirafter");609 CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath()));610 if (UsesRuntimeWrapper)611 CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"});612 if (HasHipStdPar)613 HandleHipStdPar();614}615 616void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,617 const InputInfo &Output,618 const InputInfoList &Inputs,619 const ArgList &Args,620 const char *LinkingOutput) const {621 std::string Linker = getToolChain().GetLinkerPath();622 ArgStringList CmdArgs;623 if (!Args.hasArg(options::OPT_r)) {624 CmdArgs.push_back("--no-undefined");625 CmdArgs.push_back("-shared");626 }627 628 if (C.getDriver().isUsingLTO()) {629 const bool ThinLTO = (C.getDriver().getLTOMode() == LTOK_Thin);630 addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs, ThinLTO);631 } else if (Args.hasArg(options::OPT_mcpu_EQ)) {632 CmdArgs.push_back(Args.MakeArgString(633 "-plugin-opt=mcpu=" +634 getProcessorFromTargetID(getToolChain().getTriple(),635 Args.getLastArgValue(options::OPT_mcpu_EQ))));636 }637 addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs);638 getToolChain().AddFilePathLibArgs(Args, CmdArgs);639 Args.AddAllArgs(CmdArgs, options::OPT_L);640 AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);641 642 // Always pass the target-id features to the LTO job.643 std::vector<StringRef> Features;644 getAMDGPUTargetFeatures(C.getDriver(), getToolChain().getTriple(), Args,645 Features);646 if (!Features.empty()) {647 CmdArgs.push_back(648 Args.MakeArgString("-plugin-opt=-mattr=" + llvm::join(Features, ",")));649 }650 651 if (Args.hasArg(options::OPT_stdlib))652 CmdArgs.append({"-lc", "-lm"});653 if (Args.hasArg(options::OPT_startfiles)) {654 std::optional<std::string> IncludePath = getToolChain().getStdlibPath();655 if (!IncludePath)656 IncludePath = "/lib";657 SmallString<128> P(*IncludePath);658 llvm::sys::path::append(P, "crt1.o");659 CmdArgs.push_back(Args.MakeArgString(P));660 }661 662 CmdArgs.push_back("-o");663 CmdArgs.push_back(Output.getFilename());664 C.addCommand(std::make_unique<Command>(665 JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker),666 CmdArgs, Inputs, Output));667}668 669void amdgpu::getAMDGPUTargetFeatures(const Driver &D,670 const llvm::Triple &Triple,671 const llvm::opt::ArgList &Args,672 std::vector<StringRef> &Features) {673 // Add target ID features to -target-feature options. No diagnostics should674 // be emitted here since invalid target ID is diagnosed at other places.675 StringRef TargetID;676 if (Args.hasArg(options::OPT_mcpu_EQ))677 TargetID = Args.getLastArgValue(options::OPT_mcpu_EQ);678 else if (Args.hasArg(options::OPT_march_EQ))679 TargetID = Args.getLastArgValue(options::OPT_march_EQ);680 if (!TargetID.empty()) {681 llvm::StringMap<bool> FeatureMap;682 auto OptionalGpuArch = parseTargetID(Triple, TargetID, &FeatureMap);683 if (OptionalGpuArch) {684 StringRef GpuArch = *OptionalGpuArch;685 // Iterate through all possible target ID features for the given GPU.686 // If it is mapped to true, add +feature.687 // If it is mapped to false, add -feature.688 // If it is not in the map (default), do not add it689 for (auto &&Feature : getAllPossibleTargetIDFeatures(Triple, GpuArch)) {690 auto Pos = FeatureMap.find(Feature);691 if (Pos == FeatureMap.end())692 continue;693 Features.push_back(Args.MakeArgStringRef(694 (Twine(Pos->second ? "+" : "-") + Feature).str()));695 }696 }697 }698 699 if (Args.hasFlag(options::OPT_mwavefrontsize64,700 options::OPT_mno_wavefrontsize64, false))701 Features.push_back("+wavefrontsize64");702 703 if (Args.hasFlag(options::OPT_mamdgpu_precise_memory_op,704 options::OPT_mno_amdgpu_precise_memory_op, false))705 Features.push_back("+precise-memory");706 707 handleTargetFeaturesGroup(D, Triple, Args, Features,708 options::OPT_m_amdgpu_Features_Group);709}710 711/// AMDGPU Toolchain712AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,713 const ArgList &Args)714 : Generic_ELF(D, Triple, Args),715 OptionsDefault(716 {{options::OPT_O, "3"}, {options::OPT_cl_std_EQ, "CL1.2"}}) {717 // Check code object version options. Emit warnings for legacy options718 // and errors for the last invalid code object version options.719 // It is done here to avoid repeated warning or error messages for720 // each tool invocation.721 checkAMDGPUCodeObjectVersion(D, Args);722}723 724Tool *AMDGPUToolChain::buildLinker() const {725 return new tools::amdgpu::Linker(*this);726}727 728DerivedArgList *729AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,730 Action::OffloadKind DeviceOffloadKind) const {731 732 DerivedArgList *DAL =733 Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind);734 735 const OptTable &Opts = getDriver().getOpts();736 737 if (!DAL)738 DAL = new DerivedArgList(Args.getBaseArgs());739 740 for (Arg *A : Args)741 DAL->append(A);742 743 // Replace -mcpu=native with detected GPU.744 Arg *LastMCPUArg = DAL->getLastArg(options::OPT_mcpu_EQ);745 if (LastMCPUArg && StringRef(LastMCPUArg->getValue()) == "native") {746 DAL->eraseArg(options::OPT_mcpu_EQ);747 auto GPUsOrErr = getSystemGPUArchs(Args);748 if (!GPUsOrErr) {749 getDriver().Diag(diag::err_drv_undetermined_gpu_arch)750 << llvm::Triple::getArchTypeName(getArch())751 << llvm::toString(GPUsOrErr.takeError()) << "-mcpu";752 } else {753 auto &GPUs = *GPUsOrErr;754 if (GPUs.size() > 1) {755 getDriver().Diag(diag::warn_drv_multi_gpu_arch)756 << llvm::Triple::getArchTypeName(getArch())757 << llvm::join(GPUs, ", ") << "-mcpu";758 }759 DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ),760 Args.MakeArgString(GPUs.front()));761 }762 }763 764 checkTargetID(*DAL);765 766 if (Args.getLastArgValue(options::OPT_x) != "cl")767 return DAL;768 769 // Phase 1 (.cl -> .bc)770 if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) {771 DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit()772 ? options::OPT_m64773 : options::OPT_m32));774 775 // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately776 // as they defined that way in Options.td777 if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4,778 options::OPT_Ofast))779 DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O),780 getOptionDefault(options::OPT_O));781 }782 783 return DAL;784}785 786bool AMDGPUToolChain::getDefaultDenormsAreZeroForTarget(787 llvm::AMDGPU::GPUKind Kind) {788 789 // Assume nothing without a specific target.790 if (Kind == llvm::AMDGPU::GK_NONE)791 return false;792 793 const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);794 795 // Default to enabling f32 denormals by default on subtargets where fma is796 // fast with denormals797 const bool BothDenormAndFMAFast =798 (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) &&799 (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32);800 return !BothDenormAndFMAFast;801}802 803llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType(804 const llvm::opt::ArgList &DriverArgs, const JobAction &JA,805 const llvm::fltSemantics *FPType) const {806 // Denormals should always be enabled for f16 and f64.807 if (!FPType || FPType != &llvm::APFloat::IEEEsingle())808 return llvm::DenormalMode::getIEEE();809 810 if (JA.getOffloadingDeviceKind() == Action::OFK_HIP ||811 JA.getOffloadingDeviceKind() == Action::OFK_Cuda) {812 auto Arch = getProcessorFromTargetID(getTriple(), JA.getOffloadingArch());813 auto Kind = llvm::AMDGPU::parseArchAMDGCN(Arch);814 if (FPType && FPType == &llvm::APFloat::IEEEsingle() &&815 DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero,816 options::OPT_fno_gpu_flush_denormals_to_zero,817 getDefaultDenormsAreZeroForTarget(Kind)))818 return llvm::DenormalMode::getPreserveSign();819 820 return llvm::DenormalMode::getIEEE();821 }822 823 const StringRef GpuArch = getGPUArch(DriverArgs);824 auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);825 826 // TODO: There are way too many flags that change this. Do we need to check827 // them all?828 bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) ||829 getDefaultDenormsAreZeroForTarget(Kind);830 831 // Outputs are flushed to zero (FTZ), preserving sign. Denormal inputs are832 // also implicit treated as zero (DAZ).833 return DAZ ? llvm::DenormalMode::getPreserveSign() :834 llvm::DenormalMode::getIEEE();835}836 837bool AMDGPUToolChain::isWave64(const llvm::opt::ArgList &DriverArgs,838 llvm::AMDGPU::GPUKind Kind) {839 const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind);840 bool HasWave32 = (ArchAttr & llvm::AMDGPU::FEATURE_WAVE32);841 842 return !HasWave32 || DriverArgs.hasFlag(843 options::OPT_mwavefrontsize64, options::OPT_mno_wavefrontsize64, false);844}845 846 847/// ROCM Toolchain848ROCMToolChain::ROCMToolChain(const Driver &D, const llvm::Triple &Triple,849 const ArgList &Args)850 : AMDGPUToolChain(D, Triple, Args) {851 RocmInstallation->detectDeviceLibrary();852}853 854void AMDGPUToolChain::addClangTargetOptions(855 const llvm::opt::ArgList &DriverArgs,856 llvm::opt::ArgStringList &CC1Args,857 Action::OffloadKind DeviceOffloadingKind) const {858 // Default to "hidden" visibility, as object level linking will not be859 // supported for the foreseeable future.860 if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,861 options::OPT_fvisibility_ms_compat)) {862 CC1Args.push_back("-fvisibility=hidden");863 CC1Args.push_back("-fapply-global-visibility-to-externs");864 }865 866 // For SPIR-V we want to retain the pristine output of Clang CodeGen, since867 // optimizations might lose structure / information that is necessary for868 // generating optimal concrete AMDGPU code.869 // TODO: using the below option is a temporary placeholder until Clang870 // provides the required functionality, which essentially boils down to871 // -O0 being refactored / reworked to not imply optnone / remove TBAA.872 // Once that is added, we should pivot to that functionality, being873 // mindful to not corrupt the user provided and subsequently embedded874 // command-line (i.e. if the user asks for -O3 this is what the875 // finalisation should use).876 if (getTriple().isSPIRV() &&877 !DriverArgs.hasArg(options::OPT_disable_llvm_optzns))878 CC1Args.push_back("-disable-llvm-optzns");879 880 if (DeviceOffloadingKind == Action::OFK_None)881 addOpenCLBuiltinsLib(getDriver(), DriverArgs, CC1Args);882}883 884void AMDGPUToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {885 // AMDGPU does not support atomic lib call. Treat atomic alignment886 // warnings as errors.887 CC1Args.push_back("-Werror=atomic-alignment");888}889 890void AMDGPUToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,891 ArgStringList &CC1Args) const {892 if (DriverArgs.hasArg(options::OPT_nostdinc) ||893 DriverArgs.hasArg(options::OPT_nostdlibinc))894 return;895 896 if (std::optional<std::string> Path = getStdlibIncludePath())897 addSystemInclude(DriverArgs, CC1Args, *Path);898}899 900StringRef901AMDGPUToolChain::getGPUArch(const llvm::opt::ArgList &DriverArgs) const {902 return getProcessorFromTargetID(903 getTriple(), DriverArgs.getLastArgValue(options::OPT_mcpu_EQ));904}905 906AMDGPUToolChain::ParsedTargetIDType907AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const {908 StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);909 if (TargetID.empty())910 return {std::nullopt, std::nullopt, std::nullopt};911 912 llvm::StringMap<bool> FeatureMap;913 auto OptionalGpuArch = parseTargetID(getTriple(), TargetID, &FeatureMap);914 if (!OptionalGpuArch)915 return {TargetID.str(), std::nullopt, std::nullopt};916 917 return {TargetID.str(), OptionalGpuArch->str(), FeatureMap};918}919 920void AMDGPUToolChain::checkTargetID(921 const llvm::opt::ArgList &DriverArgs) const {922 auto PTID = getParsedTargetID(DriverArgs);923 if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {924 getDriver().Diag(clang::diag::err_drv_bad_target_id)925 << *PTID.OptionalTargetID;926 }927}928 929Expected<SmallVector<std::string>>930AMDGPUToolChain::getSystemGPUArchs(const ArgList &Args) const {931 // Detect AMD GPUs availible on the system.932 std::string Program;933 if (Arg *A = Args.getLastArg(options::OPT_offload_arch_tool_EQ))934 Program = A->getValue();935 else936 Program = GetProgramPath("amdgpu-arch");937 938 auto StdoutOrErr = getDriver().executeProgram({Program});939 if (!StdoutOrErr)940 return StdoutOrErr.takeError();941 942 SmallVector<std::string, 1> GPUArchs;943 for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n"))944 if (!Arch.empty())945 GPUArchs.push_back(Arch.str());946 947 if (GPUArchs.empty())948 return llvm::createStringError(std::error_code(),949 "No AMD GPU detected in the system");950 951 return std::move(GPUArchs);952}953 954void ROCMToolChain::addClangTargetOptions(955 const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,956 Action::OffloadKind DeviceOffloadingKind) const {957 AMDGPUToolChain::addClangTargetOptions(DriverArgs, CC1Args,958 DeviceOffloadingKind);959 960 // For the OpenCL case where there is no offload target, accept -nostdlib to961 // disable bitcode linking.962 if (DeviceOffloadingKind == Action::OFK_None &&963 DriverArgs.hasArg(options::OPT_nostdlib))964 return;965 966 if (!DriverArgs.hasFlag(options::OPT_offloadlib, options::OPT_no_offloadlib,967 true))968 return;969 970 // Get the device name and canonicalize it971 const StringRef GpuArch = getGPUArch(DriverArgs);972 auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);973 const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);974 StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch);975 auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion(976 getAMDGPUCodeObjectVersion(getDriver(), DriverArgs));977 if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile,978 ABIVer))979 return;980 981 // Add the OpenCL specific bitcode library.982 llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;983 BCLibs.emplace_back(RocmInstallation->getOpenCLPath().str());984 985 // Add the generic set of libraries.986 BCLibs.append(RocmInstallation->getCommonBitcodeLibs(987 DriverArgs, LibDeviceFile, GpuArch, DeviceOffloadingKind,988 getSanitizerArgs(DriverArgs).needsAsanRt()));989 990 for (auto [BCFile, Internalize] : BCLibs) {991 if (Internalize)992 CC1Args.push_back("-mlink-builtin-bitcode");993 else994 CC1Args.push_back("-mlink-bitcode-file");995 CC1Args.push_back(DriverArgs.MakeArgString(BCFile));996 }997}998 999bool RocmInstallationDetector::checkCommonBitcodeLibs(1000 StringRef GPUArch, StringRef LibDeviceFile,1001 DeviceLibABIVersion ABIVer) const {1002 if (!hasDeviceLibrary()) {1003 D.Diag(diag::err_drv_no_rocm_device_lib) << 0;1004 return false;1005 }1006 if (LibDeviceFile.empty()) {1007 D.Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch;1008 return false;1009 }1010 if (ABIVer.requiresLibrary() && getABIVersionPath(ABIVer).empty()) {1011 // Starting from COV6, we will report minimum ROCm version requirement in1012 // the error message.1013 if (ABIVer.getAsCodeObjectVersion() < 6)1014 D.Diag(diag::err_drv_no_rocm_device_lib) << 2 << ABIVer.toString() << 0;1015 else1016 D.Diag(diag::err_drv_no_rocm_device_lib)1017 << 2 << ABIVer.toString() << 1 << "6.3";1018 return false;1019 }1020 return true;1021}1022 1023llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>1024RocmInstallationDetector::getCommonBitcodeLibs(1025 const llvm::opt::ArgList &DriverArgs, StringRef LibDeviceFile,1026 StringRef GPUArch, const Action::OffloadKind DeviceOffloadingKind,1027 const bool NeedsASanRT) const {1028 llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs;1029 1030 CommonBitcodeLibsPreferences Pref{D, DriverArgs, GPUArch,1031 DeviceOffloadingKind, NeedsASanRT};1032 1033 auto AddBCLib = [&](ToolChain::BitCodeLibraryInfo BCLib,1034 bool Internalize = true) {1035 BCLib.ShouldInternalize = Internalize;1036 BCLibs.emplace_back(BCLib);1037 };1038 auto AddSanBCLibs = [&]() {1039 if (Pref.GPUSan)1040 AddBCLib(getAsanRTLPath(), false);1041 };1042 1043 AddSanBCLibs();1044 AddBCLib(getOCMLPath());1045 if (!Pref.IsOpenMP)1046 AddBCLib(getOCKLPath());1047 else if (Pref.GPUSan && Pref.IsOpenMP)1048 AddBCLib(getOCKLPath(), false);1049 AddBCLib(getDenormalsAreZeroPath(Pref.DAZ));1050 AddBCLib(getUnsafeMathPath(Pref.UnsafeMathOpt || Pref.FastRelaxedMath));1051 AddBCLib(getFiniteOnlyPath(Pref.FiniteOnly || Pref.FastRelaxedMath));1052 AddBCLib(getCorrectlyRoundedSqrtPath(Pref.CorrectSqrt));1053 AddBCLib(getWavefrontSize64Path(Pref.Wave64));1054 AddBCLib(LibDeviceFile);1055 auto ABIVerPath = getABIVersionPath(Pref.ABIVer);1056 if (!ABIVerPath.empty())1057 AddBCLib(ABIVerPath);1058 1059 return BCLibs;1060}1061 1062llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>1063ROCMToolChain::getCommonDeviceLibNames(1064 const llvm::opt::ArgList &DriverArgs, const std::string &GPUArch,1065 Action::OffloadKind DeviceOffloadingKind) const {1066 auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch);1067 const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);1068 1069 StringRef LibDeviceFile = RocmInstallation->getLibDeviceFile(CanonArch);1070 auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion(1071 getAMDGPUCodeObjectVersion(getDriver(), DriverArgs));1072 if (!RocmInstallation->checkCommonBitcodeLibs(CanonArch, LibDeviceFile,1073 ABIVer))1074 return {};1075 1076 return RocmInstallation->getCommonBitcodeLibs(1077 DriverArgs, LibDeviceFile, GPUArch, DeviceOffloadingKind,1078 getSanitizerArgs(DriverArgs).needsAsanRt());1079}1080 1081bool AMDGPUToolChain::shouldSkipSanitizeOption(1082 const ToolChain &TC, const llvm::opt::ArgList &DriverArgs,1083 StringRef TargetID, const llvm::opt::Arg *A) const {1084 auto &Diags = TC.getDriver().getDiags();1085 bool IsExplicitDevice =1086 A->getBaseArg().getOption().matches(options::OPT_Xarch_device);1087 1088 // Check 'xnack+' availability by default1089 llvm::StringRef Processor =1090 getProcessorFromTargetID(TC.getTriple(), TargetID);1091 auto ProcKind = TC.getTriple().isAMDGCN()1092 ? llvm::AMDGPU::parseArchAMDGCN(Processor)1093 : llvm::AMDGPU::parseArchR600(Processor);1094 auto Features = TC.getTriple().isAMDGCN()1095 ? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind)1096 : llvm::AMDGPU::getArchAttrR600(ProcKind);1097 if (Features & llvm::AMDGPU::FEATURE_XNACK_ALWAYS)1098 return false;1099 1100 // Look for the xnack feature in TargetID1101 llvm::StringMap<bool> FeatureMap;1102 auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap);1103 assert(OptionalGpuArch && "Invalid Target ID");1104 (void)OptionalGpuArch;1105 auto Loc = FeatureMap.find("xnack");1106 if (Loc == FeatureMap.end() || !Loc->second) {1107 if (IsExplicitDevice) {1108 Diags.Report(1109 clang::diag::err_drv_unsupported_option_for_offload_arch_req_feature)1110 << A->getAsString(DriverArgs) << TargetID << "xnack+";1111 } else {1112 Diags.Report(1113 clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature)1114 << A->getAsString(DriverArgs) << TargetID << "xnack+";1115 }1116 return true;1117 }1118 1119 return false;1120}1121