xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/HIPAMD.cpp (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
1*0eae32dcSDimitry Andric //===--- HIPAMD.cpp - HIP Tool and ToolChain Implementations ----*- C++ -*-===//
2*0eae32dcSDimitry Andric //
3*0eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0eae32dcSDimitry Andric //
7*0eae32dcSDimitry Andric //===----------------------------------------------------------------------===//
8*0eae32dcSDimitry Andric 
9*0eae32dcSDimitry Andric #include "HIPAMD.h"
10*0eae32dcSDimitry Andric #include "AMDGPU.h"
11*0eae32dcSDimitry Andric #include "CommonArgs.h"
12*0eae32dcSDimitry Andric #include "HIPUtility.h"
13*0eae32dcSDimitry Andric #include "clang/Basic/Cuda.h"
14*0eae32dcSDimitry Andric #include "clang/Basic/TargetID.h"
15*0eae32dcSDimitry Andric #include "clang/Driver/Compilation.h"
16*0eae32dcSDimitry Andric #include "clang/Driver/Driver.h"
17*0eae32dcSDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
18*0eae32dcSDimitry Andric #include "clang/Driver/InputInfo.h"
19*0eae32dcSDimitry Andric #include "clang/Driver/Options.h"
20*0eae32dcSDimitry Andric #include "clang/Driver/SanitizerArgs.h"
21*0eae32dcSDimitry Andric #include "llvm/Support/Alignment.h"
22*0eae32dcSDimitry Andric #include "llvm/Support/FileSystem.h"
23*0eae32dcSDimitry Andric #include "llvm/Support/Path.h"
24*0eae32dcSDimitry Andric #include "llvm/Support/TargetParser.h"
25*0eae32dcSDimitry Andric 
26*0eae32dcSDimitry Andric using namespace clang::driver;
27*0eae32dcSDimitry Andric using namespace clang::driver::toolchains;
28*0eae32dcSDimitry Andric using namespace clang::driver::tools;
29*0eae32dcSDimitry Andric using namespace clang;
30*0eae32dcSDimitry Andric using namespace llvm::opt;
31*0eae32dcSDimitry Andric 
32*0eae32dcSDimitry Andric #if defined(_WIN32) || defined(_WIN64)
33*0eae32dcSDimitry Andric #define NULL_FILE "nul"
34*0eae32dcSDimitry Andric #else
35*0eae32dcSDimitry Andric #define NULL_FILE "/dev/null"
36*0eae32dcSDimitry Andric #endif
37*0eae32dcSDimitry Andric 
38*0eae32dcSDimitry Andric static bool shouldSkipSanitizeOption(const ToolChain &TC,
39*0eae32dcSDimitry Andric                                      const llvm::opt::ArgList &DriverArgs,
40*0eae32dcSDimitry Andric                                      StringRef TargetID,
41*0eae32dcSDimitry Andric                                      const llvm::opt::Arg *A) {
42*0eae32dcSDimitry Andric   // For actions without targetID, do nothing.
43*0eae32dcSDimitry Andric   if (TargetID.empty())
44*0eae32dcSDimitry Andric     return false;
45*0eae32dcSDimitry Andric   Option O = A->getOption();
46*0eae32dcSDimitry Andric   if (!O.matches(options::OPT_fsanitize_EQ))
47*0eae32dcSDimitry Andric     return false;
48*0eae32dcSDimitry Andric 
49*0eae32dcSDimitry Andric   if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
50*0eae32dcSDimitry Andric                           -options::OPT_fno_gpu_sanitize))
51*0eae32dcSDimitry Andric     return true;
52*0eae32dcSDimitry Andric 
53*0eae32dcSDimitry Andric   auto &Diags = TC.getDriver().getDiags();
54*0eae32dcSDimitry Andric 
55*0eae32dcSDimitry Andric   // For simplicity, we only allow -fsanitize=address
56*0eae32dcSDimitry Andric   SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false);
57*0eae32dcSDimitry Andric   if (K != SanitizerKind::Address)
58*0eae32dcSDimitry Andric     return true;
59*0eae32dcSDimitry Andric 
60*0eae32dcSDimitry Andric   llvm::StringMap<bool> FeatureMap;
61*0eae32dcSDimitry Andric   auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap);
62*0eae32dcSDimitry Andric 
63*0eae32dcSDimitry Andric   assert(OptionalGpuArch && "Invalid Target ID");
64*0eae32dcSDimitry Andric   (void)OptionalGpuArch;
65*0eae32dcSDimitry Andric   auto Loc = FeatureMap.find("xnack");
66*0eae32dcSDimitry Andric   if (Loc == FeatureMap.end() || !Loc->second) {
67*0eae32dcSDimitry Andric     Diags.Report(
68*0eae32dcSDimitry Andric         clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature)
69*0eae32dcSDimitry Andric         << A->getAsString(DriverArgs) << TargetID << "xnack+";
70*0eae32dcSDimitry Andric     return true;
71*0eae32dcSDimitry Andric   }
72*0eae32dcSDimitry Andric   return false;
73*0eae32dcSDimitry Andric }
74*0eae32dcSDimitry Andric 
75*0eae32dcSDimitry Andric void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
76*0eae32dcSDimitry Andric                                          const InputInfoList &Inputs,
77*0eae32dcSDimitry Andric                                          const InputInfo &Output,
78*0eae32dcSDimitry Andric                                          const llvm::opt::ArgList &Args) const {
79*0eae32dcSDimitry Andric   // Construct lld command.
80*0eae32dcSDimitry Andric   // The output from ld.lld is an HSA code object file.
81*0eae32dcSDimitry Andric   ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared",
82*0eae32dcSDimitry Andric                         "-plugin-opt=-amdgpu-internalize-symbols"};
83*0eae32dcSDimitry Andric 
84*0eae32dcSDimitry Andric   auto &TC = getToolChain();
85*0eae32dcSDimitry Andric   auto &D = TC.getDriver();
86*0eae32dcSDimitry Andric   assert(!Inputs.empty() && "Must have at least one input.");
87*0eae32dcSDimitry Andric   bool IsThinLTO = D.getLTOMode(/*IsOffload=*/true) == LTOK_Thin;
88*0eae32dcSDimitry Andric   addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], IsThinLTO);
89*0eae32dcSDimitry Andric 
90*0eae32dcSDimitry Andric   // Extract all the -m options
91*0eae32dcSDimitry Andric   std::vector<llvm::StringRef> Features;
92*0eae32dcSDimitry Andric   amdgpu::getAMDGPUTargetFeatures(D, TC.getTriple(), Args, Features);
93*0eae32dcSDimitry Andric 
94*0eae32dcSDimitry Andric   // Add features to mattr such as cumode
95*0eae32dcSDimitry Andric   std::string MAttrString = "-plugin-opt=-mattr=";
96*0eae32dcSDimitry Andric   for (auto OneFeature : unifyTargetFeatures(Features)) {
97*0eae32dcSDimitry Andric     MAttrString.append(Args.MakeArgString(OneFeature));
98*0eae32dcSDimitry Andric     if (OneFeature != Features.back())
99*0eae32dcSDimitry Andric       MAttrString.append(",");
100*0eae32dcSDimitry Andric   }
101*0eae32dcSDimitry Andric   if (!Features.empty())
102*0eae32dcSDimitry Andric     LldArgs.push_back(Args.MakeArgString(MAttrString));
103*0eae32dcSDimitry Andric 
104*0eae32dcSDimitry Andric   // ToDo: Remove this option after AMDGPU backend supports ISA-level linking.
105*0eae32dcSDimitry Andric   // Since AMDGPU backend currently does not support ISA-level linking, all
106*0eae32dcSDimitry Andric   // called functions need to be imported.
107*0eae32dcSDimitry Andric   if (IsThinLTO)
108*0eae32dcSDimitry Andric     LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all"));
109*0eae32dcSDimitry Andric 
110*0eae32dcSDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
111*0eae32dcSDimitry Andric     LldArgs.push_back(
112*0eae32dcSDimitry Andric         Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0)));
113*0eae32dcSDimitry Andric   }
114*0eae32dcSDimitry Andric 
115*0eae32dcSDimitry Andric   if (C.getDriver().isSaveTempsEnabled())
116*0eae32dcSDimitry Andric     LldArgs.push_back("-save-temps");
117*0eae32dcSDimitry Andric 
118*0eae32dcSDimitry Andric   addLinkerCompressDebugSectionsOption(TC, Args, LldArgs);
119*0eae32dcSDimitry Andric 
120*0eae32dcSDimitry Andric   LldArgs.append({"-o", Output.getFilename()});
121*0eae32dcSDimitry Andric   for (auto Input : Inputs)
122*0eae32dcSDimitry Andric     LldArgs.push_back(Input.getFilename());
123*0eae32dcSDimitry Andric 
124*0eae32dcSDimitry Andric   const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
125*0eae32dcSDimitry Andric   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
126*0eae32dcSDimitry Andric                                          Lld, LldArgs, Inputs, Output));
127*0eae32dcSDimitry Andric }
128*0eae32dcSDimitry Andric 
129*0eae32dcSDimitry Andric // For amdgcn the inputs of the linker job are device bitcode and output is
130*0eae32dcSDimitry Andric // object file. It calls llvm-link, opt, llc, then lld steps.
131*0eae32dcSDimitry Andric void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
132*0eae32dcSDimitry Andric                                   const InputInfo &Output,
133*0eae32dcSDimitry Andric                                   const InputInfoList &Inputs,
134*0eae32dcSDimitry Andric                                   const ArgList &Args,
135*0eae32dcSDimitry Andric                                   const char *LinkingOutput) const {
136*0eae32dcSDimitry Andric   if (Inputs.size() > 0 &&
137*0eae32dcSDimitry Andric       Inputs[0].getType() == types::TY_Image &&
138*0eae32dcSDimitry Andric       JA.getType() == types::TY_Object)
139*0eae32dcSDimitry Andric     return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs,
140*0eae32dcSDimitry Andric                                                          Args, JA, *this);
141*0eae32dcSDimitry Andric 
142*0eae32dcSDimitry Andric   if (JA.getType() == types::TY_HIP_FATBIN)
143*0eae32dcSDimitry Andric     return HIP::constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs,
144*0eae32dcSDimitry Andric                                           Args, *this);
145*0eae32dcSDimitry Andric 
146*0eae32dcSDimitry Andric   return constructLldCommand(C, JA, Inputs, Output, Args);
147*0eae32dcSDimitry Andric }
148*0eae32dcSDimitry Andric 
149*0eae32dcSDimitry Andric HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple,
150*0eae32dcSDimitry Andric                                  const ToolChain &HostTC, const ArgList &Args)
151*0eae32dcSDimitry Andric     : ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
152*0eae32dcSDimitry Andric   // Lookup binaries into the driver directory, this is used to
153*0eae32dcSDimitry Andric   // discover the clang-offload-bundler executable.
154*0eae32dcSDimitry Andric   getProgramPaths().push_back(getDriver().Dir);
155*0eae32dcSDimitry Andric 
156*0eae32dcSDimitry Andric   // Diagnose unsupported sanitizer options only once.
157*0eae32dcSDimitry Andric   for (auto A : Args.filtered(options::OPT_fsanitize_EQ)) {
158*0eae32dcSDimitry Andric     SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false);
159*0eae32dcSDimitry Andric     if (K != SanitizerKind::Address)
160*0eae32dcSDimitry Andric       D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target)
161*0eae32dcSDimitry Andric           << A->getAsString(Args) << getTriple().str();
162*0eae32dcSDimitry Andric   }
163*0eae32dcSDimitry Andric }
164*0eae32dcSDimitry Andric 
165*0eae32dcSDimitry Andric void HIPAMDToolChain::addClangTargetOptions(
166*0eae32dcSDimitry Andric     const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
167*0eae32dcSDimitry Andric     Action::OffloadKind DeviceOffloadingKind) const {
168*0eae32dcSDimitry Andric   HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
169*0eae32dcSDimitry Andric 
170*0eae32dcSDimitry Andric   assert(DeviceOffloadingKind == Action::OFK_HIP &&
171*0eae32dcSDimitry Andric          "Only HIP offloading kinds are supported for GPUs.");
172*0eae32dcSDimitry Andric 
173*0eae32dcSDimitry Andric   CC1Args.push_back("-fcuda-is-device");
174*0eae32dcSDimitry Andric 
175*0eae32dcSDimitry Andric   if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
176*0eae32dcSDimitry Andric                          options::OPT_fno_cuda_approx_transcendentals, false))
177*0eae32dcSDimitry Andric     CC1Args.push_back("-fcuda-approx-transcendentals");
178*0eae32dcSDimitry Andric 
179*0eae32dcSDimitry Andric   if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
180*0eae32dcSDimitry Andric                           false))
181*0eae32dcSDimitry Andric     CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"});
182*0eae32dcSDimitry Andric 
183*0eae32dcSDimitry Andric   StringRef MaxThreadsPerBlock =
184*0eae32dcSDimitry Andric       DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ);
185*0eae32dcSDimitry Andric   if (!MaxThreadsPerBlock.empty()) {
186*0eae32dcSDimitry Andric     std::string ArgStr =
187*0eae32dcSDimitry Andric         std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str();
188*0eae32dcSDimitry Andric     CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr));
189*0eae32dcSDimitry Andric   }
190*0eae32dcSDimitry Andric 
191*0eae32dcSDimitry Andric   CC1Args.push_back("-fcuda-allow-variadic-functions");
192*0eae32dcSDimitry Andric 
193*0eae32dcSDimitry Andric   // Default to "hidden" visibility, as object level linking will not be
194*0eae32dcSDimitry Andric   // supported for the foreseeable future.
195*0eae32dcSDimitry Andric   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
196*0eae32dcSDimitry Andric                          options::OPT_fvisibility_ms_compat)) {
197*0eae32dcSDimitry Andric     CC1Args.append({"-fvisibility", "hidden"});
198*0eae32dcSDimitry Andric     CC1Args.push_back("-fapply-global-visibility-to-externs");
199*0eae32dcSDimitry Andric   }
200*0eae32dcSDimitry Andric 
201*0eae32dcSDimitry Andric   llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) {
202*0eae32dcSDimitry Andric     CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
203*0eae32dcSDimitry Andric                                                : "-mlink-bitcode-file");
204*0eae32dcSDimitry Andric     CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
205*0eae32dcSDimitry Andric   });
206*0eae32dcSDimitry Andric }
207*0eae32dcSDimitry Andric 
208*0eae32dcSDimitry Andric llvm::opt::DerivedArgList *
209*0eae32dcSDimitry Andric HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
210*0eae32dcSDimitry Andric                                StringRef BoundArch,
211*0eae32dcSDimitry Andric                                Action::OffloadKind DeviceOffloadKind) const {
212*0eae32dcSDimitry Andric   DerivedArgList *DAL =
213*0eae32dcSDimitry Andric       HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
214*0eae32dcSDimitry Andric   if (!DAL)
215*0eae32dcSDimitry Andric     DAL = new DerivedArgList(Args.getBaseArgs());
216*0eae32dcSDimitry Andric 
217*0eae32dcSDimitry Andric   const OptTable &Opts = getDriver().getOpts();
218*0eae32dcSDimitry Andric 
219*0eae32dcSDimitry Andric   for (Arg *A : Args) {
220*0eae32dcSDimitry Andric     if (!shouldSkipArgument(A) &&
221*0eae32dcSDimitry Andric         !shouldSkipSanitizeOption(*this, Args, BoundArch, A))
222*0eae32dcSDimitry Andric       DAL->append(A);
223*0eae32dcSDimitry Andric   }
224*0eae32dcSDimitry Andric 
225*0eae32dcSDimitry Andric   if (!BoundArch.empty()) {
226*0eae32dcSDimitry Andric     DAL->eraseArg(options::OPT_mcpu_EQ);
227*0eae32dcSDimitry Andric     DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch);
228*0eae32dcSDimitry Andric     checkTargetID(*DAL);
229*0eae32dcSDimitry Andric   }
230*0eae32dcSDimitry Andric 
231*0eae32dcSDimitry Andric   return DAL;
232*0eae32dcSDimitry Andric }
233*0eae32dcSDimitry Andric 
234*0eae32dcSDimitry Andric Tool *HIPAMDToolChain::buildLinker() const {
235*0eae32dcSDimitry Andric   assert(getTriple().getArch() == llvm::Triple::amdgcn);
236*0eae32dcSDimitry Andric   return new tools::AMDGCN::Linker(*this);
237*0eae32dcSDimitry Andric }
238*0eae32dcSDimitry Andric 
239*0eae32dcSDimitry Andric void HIPAMDToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
240*0eae32dcSDimitry Andric   HostTC.addClangWarningOptions(CC1Args);
241*0eae32dcSDimitry Andric }
242*0eae32dcSDimitry Andric 
243*0eae32dcSDimitry Andric ToolChain::CXXStdlibType
244*0eae32dcSDimitry Andric HIPAMDToolChain::GetCXXStdlibType(const ArgList &Args) const {
245*0eae32dcSDimitry Andric   return HostTC.GetCXXStdlibType(Args);
246*0eae32dcSDimitry Andric }
247*0eae32dcSDimitry Andric 
248*0eae32dcSDimitry Andric void HIPAMDToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
249*0eae32dcSDimitry Andric                                                 ArgStringList &CC1Args) const {
250*0eae32dcSDimitry Andric   HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
251*0eae32dcSDimitry Andric }
252*0eae32dcSDimitry Andric 
253*0eae32dcSDimitry Andric void HIPAMDToolChain::AddClangCXXStdlibIncludeArgs(
254*0eae32dcSDimitry Andric     const ArgList &Args, ArgStringList &CC1Args) const {
255*0eae32dcSDimitry Andric   HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
256*0eae32dcSDimitry Andric }
257*0eae32dcSDimitry Andric 
258*0eae32dcSDimitry Andric void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
259*0eae32dcSDimitry Andric                                           ArgStringList &CC1Args) const {
260*0eae32dcSDimitry Andric   HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
261*0eae32dcSDimitry Andric }
262*0eae32dcSDimitry Andric 
263*0eae32dcSDimitry Andric void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
264*0eae32dcSDimitry Andric                                         ArgStringList &CC1Args) const {
265*0eae32dcSDimitry Andric   RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
266*0eae32dcSDimitry Andric }
267*0eae32dcSDimitry Andric 
268*0eae32dcSDimitry Andric SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const {
269*0eae32dcSDimitry Andric   // The HIPAMDToolChain only supports sanitizers in the sense that it allows
270*0eae32dcSDimitry Andric   // sanitizer arguments on the command line if they are supported by the host
271*0eae32dcSDimitry Andric   // toolchain. The HIPAMDToolChain will actually ignore any command line
272*0eae32dcSDimitry Andric   // arguments for any of these "supported" sanitizers. That means that no
273*0eae32dcSDimitry Andric   // sanitization of device code is actually supported at this time.
274*0eae32dcSDimitry Andric   //
275*0eae32dcSDimitry Andric   // This behavior is necessary because the host and device toolchains
276*0eae32dcSDimitry Andric   // invocations often share the command line, so the device toolchain must
277*0eae32dcSDimitry Andric   // tolerate flags meant only for the host toolchain.
278*0eae32dcSDimitry Andric   return HostTC.getSupportedSanitizers();
279*0eae32dcSDimitry Andric }
280*0eae32dcSDimitry Andric 
281*0eae32dcSDimitry Andric VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D,
282*0eae32dcSDimitry Andric                                                  const ArgList &Args) const {
283*0eae32dcSDimitry Andric   return HostTC.computeMSVCVersion(D, Args);
284*0eae32dcSDimitry Andric }
285*0eae32dcSDimitry Andric 
286*0eae32dcSDimitry Andric llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
287*0eae32dcSDimitry Andric HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
288*0eae32dcSDimitry Andric   llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;
289*0eae32dcSDimitry Andric   if (DriverArgs.hasArg(options::OPT_nogpulib))
290*0eae32dcSDimitry Andric     return {};
291*0eae32dcSDimitry Andric   ArgStringList LibraryPaths;
292*0eae32dcSDimitry Andric 
293*0eae32dcSDimitry Andric   // Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
294*0eae32dcSDimitry Andric   for (auto Path : RocmInstallation.getRocmDeviceLibPathArg())
295*0eae32dcSDimitry Andric     LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
296*0eae32dcSDimitry Andric 
297*0eae32dcSDimitry Andric   addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
298*0eae32dcSDimitry Andric 
299*0eae32dcSDimitry Andric   // Maintain compatability with --hip-device-lib.
300*0eae32dcSDimitry Andric   auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ);
301*0eae32dcSDimitry Andric   if (!BCLibArgs.empty()) {
302*0eae32dcSDimitry Andric     llvm::for_each(BCLibArgs, [&](StringRef BCName) {
303*0eae32dcSDimitry Andric       StringRef FullName;
304*0eae32dcSDimitry Andric       for (std::string LibraryPath : LibraryPaths) {
305*0eae32dcSDimitry Andric         SmallString<128> Path(LibraryPath);
306*0eae32dcSDimitry Andric         llvm::sys::path::append(Path, BCName);
307*0eae32dcSDimitry Andric         FullName = Path;
308*0eae32dcSDimitry Andric         if (llvm::sys::fs::exists(FullName)) {
309*0eae32dcSDimitry Andric           BCLibs.push_back(FullName);
310*0eae32dcSDimitry Andric           return;
311*0eae32dcSDimitry Andric         }
312*0eae32dcSDimitry Andric       }
313*0eae32dcSDimitry Andric       getDriver().Diag(diag::err_drv_no_such_file) << BCName;
314*0eae32dcSDimitry Andric     });
315*0eae32dcSDimitry Andric   } else {
316*0eae32dcSDimitry Andric     if (!RocmInstallation.hasDeviceLibrary()) {
317*0eae32dcSDimitry Andric       getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
318*0eae32dcSDimitry Andric       return {};
319*0eae32dcSDimitry Andric     }
320*0eae32dcSDimitry Andric     StringRef GpuArch = getGPUArch(DriverArgs);
321*0eae32dcSDimitry Andric     assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
322*0eae32dcSDimitry Andric 
323*0eae32dcSDimitry Andric     // If --hip-device-lib is not set, add the default bitcode libraries.
324*0eae32dcSDimitry Andric     if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
325*0eae32dcSDimitry Andric                            options::OPT_fno_gpu_sanitize) &&
326*0eae32dcSDimitry Andric         getSanitizerArgs(DriverArgs).needsAsanRt()) {
327*0eae32dcSDimitry Andric       auto AsanRTL = RocmInstallation.getAsanRTLPath();
328*0eae32dcSDimitry Andric       if (AsanRTL.empty()) {
329*0eae32dcSDimitry Andric         unsigned DiagID = getDriver().getDiags().getCustomDiagID(
330*0eae32dcSDimitry Andric             DiagnosticsEngine::Error,
331*0eae32dcSDimitry Andric             "AMDGPU address sanitizer runtime library (asanrtl) is not found. "
332*0eae32dcSDimitry Andric             "Please install ROCm device library which supports address "
333*0eae32dcSDimitry Andric             "sanitizer");
334*0eae32dcSDimitry Andric         getDriver().Diag(DiagID);
335*0eae32dcSDimitry Andric         return {};
336*0eae32dcSDimitry Andric       } else
337*0eae32dcSDimitry Andric         BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false});
338*0eae32dcSDimitry Andric     }
339*0eae32dcSDimitry Andric 
340*0eae32dcSDimitry Andric     // Add the HIP specific bitcode library.
341*0eae32dcSDimitry Andric     BCLibs.push_back(RocmInstallation.getHIPPath());
342*0eae32dcSDimitry Andric 
343*0eae32dcSDimitry Andric     // Add common device libraries like ocml etc.
344*0eae32dcSDimitry Andric     for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str()))
345*0eae32dcSDimitry Andric       BCLibs.push_back(StringRef(N));
346*0eae32dcSDimitry Andric 
347*0eae32dcSDimitry Andric     // Add instrument lib.
348*0eae32dcSDimitry Andric     auto InstLib =
349*0eae32dcSDimitry Andric         DriverArgs.getLastArgValue(options::OPT_gpu_instrument_lib_EQ);
350*0eae32dcSDimitry Andric     if (InstLib.empty())
351*0eae32dcSDimitry Andric       return BCLibs;
352*0eae32dcSDimitry Andric     if (llvm::sys::fs::exists(InstLib))
353*0eae32dcSDimitry Andric       BCLibs.push_back(InstLib);
354*0eae32dcSDimitry Andric     else
355*0eae32dcSDimitry Andric       getDriver().Diag(diag::err_drv_no_such_file) << InstLib;
356*0eae32dcSDimitry Andric   }
357*0eae32dcSDimitry Andric 
358*0eae32dcSDimitry Andric   return BCLibs;
359*0eae32dcSDimitry Andric }
360*0eae32dcSDimitry Andric 
361*0eae32dcSDimitry Andric void HIPAMDToolChain::checkTargetID(
362*0eae32dcSDimitry Andric     const llvm::opt::ArgList &DriverArgs) const {
363*0eae32dcSDimitry Andric   auto PTID = getParsedTargetID(DriverArgs);
364*0eae32dcSDimitry Andric   if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {
365*0eae32dcSDimitry Andric     getDriver().Diag(clang::diag::err_drv_bad_target_id)
366*0eae32dcSDimitry Andric         << PTID.OptionalTargetID.getValue();
367*0eae32dcSDimitry Andric   }
368*0eae32dcSDimitry Andric }
369