brintos

brintos / llvm-project-archived public Read only

0
0
Text · 42.2 KiB · 87ccd40 Raw
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