1 | //===--- HIPAMD.cpp - HIP Tool and 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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "HIPAMD.h" |
10 | #include "AMDGPU.h" |
11 | #include "CommonArgs.h" |
12 | #include "HIPUtility.h" |
13 | #include "SPIRV.h" |
14 | #include "clang/Basic/Cuda.h" |
15 | #include "clang/Basic/TargetID.h" |
16 | #include "clang/Driver/Compilation.h" |
17 | #include "clang/Driver/Driver.h" |
18 | #include "clang/Driver/DriverDiagnostic.h" |
19 | #include "clang/Driver/InputInfo.h" |
20 | #include "clang/Driver/Options.h" |
21 | #include "clang/Driver/SanitizerArgs.h" |
22 | #include "llvm/Support/Alignment.h" |
23 | #include "llvm/Support/FileSystem.h" |
24 | #include "llvm/Support/Path.h" |
25 | #include "llvm/TargetParser/TargetParser.h" |
26 | |
27 | using namespace clang::driver; |
28 | using namespace clang::driver::toolchains; |
29 | using namespace clang::driver::tools; |
30 | using namespace clang; |
31 | using namespace llvm::opt; |
32 | |
33 | #if defined(_WIN32) || defined(_WIN64) |
34 | #define NULL_FILE "nul" |
35 | #else |
36 | #define NULL_FILE "/dev/null" |
37 | #endif |
38 | |
39 | static bool shouldSkipSanitizeOption(const ToolChain &TC, |
40 | const llvm::opt::ArgList &DriverArgs, |
41 | StringRef TargetID, |
42 | const llvm::opt::Arg *A) { |
43 | // For actions without targetID, do nothing. |
44 | if (TargetID.empty()) |
45 | return false; |
46 | Option O = A->getOption(); |
47 | if (!O.matches(ID: options::OPT_fsanitize_EQ)) |
48 | return false; |
49 | |
50 | if (!DriverArgs.hasFlag(Pos: options::OPT_fgpu_sanitize, |
51 | Neg: options::OPT_fno_gpu_sanitize, Default: true)) |
52 | return true; |
53 | |
54 | auto &Diags = TC.getDriver().getDiags(); |
55 | |
56 | // For simplicity, we only allow -fsanitize=address |
57 | SanitizerMask K = parseSanitizerValue(Value: A->getValue(), /*AllowGroups=*/false); |
58 | if (K != SanitizerKind::Address) |
59 | return true; |
60 | |
61 | llvm::StringMap<bool> FeatureMap; |
62 | auto OptionalGpuArch = parseTargetID(T: TC.getTriple(), OffloadArch: TargetID, FeatureMap: &FeatureMap); |
63 | |
64 | assert(OptionalGpuArch && "Invalid Target ID" ); |
65 | (void)OptionalGpuArch; |
66 | auto Loc = FeatureMap.find(Key: "xnack" ); |
67 | if (Loc == FeatureMap.end() || !Loc->second) { |
68 | Diags.Report( |
69 | DiagID: clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature) |
70 | << A->getAsString(Args: DriverArgs) << TargetID << "xnack+" ; |
71 | return true; |
72 | } |
73 | return false; |
74 | } |
75 | |
76 | void AMDGCN::Linker::constructLlvmLinkCommand(Compilation &C, |
77 | const JobAction &JA, |
78 | const InputInfoList &Inputs, |
79 | const InputInfo &Output, |
80 | const llvm::opt::ArgList &Args) const { |
81 | // Construct llvm-link command. |
82 | // The output from llvm-link is a bitcode file. |
83 | ArgStringList LlvmLinkArgs; |
84 | |
85 | assert(!Inputs.empty() && "Must have at least one input." ); |
86 | |
87 | LlvmLinkArgs.append(IL: {"-o" , Output.getFilename()}); |
88 | for (auto Input : Inputs) |
89 | LlvmLinkArgs.push_back(Elt: Input.getFilename()); |
90 | |
91 | // Look for archive of bundled bitcode in arguments, and add temporary files |
92 | // for the extracted archive of bitcode to inputs. |
93 | auto TargetID = Args.getLastArgValue(Id: options::OPT_mcpu_EQ); |
94 | AddStaticDeviceLibsLinking(C, T: *this, JA, Inputs, DriverArgs: Args, CmdArgs&: LlvmLinkArgs, Arch: "amdgcn" , |
95 | Target: TargetID, /*IsBitCodeSDL=*/isBitCodeSDL: true); |
96 | |
97 | const char *LlvmLink = |
98 | Args.MakeArgString(Str: getToolChain().GetProgramPath(Name: "llvm-link" )); |
99 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(), |
100 | args&: LlvmLink, args&: LlvmLinkArgs, args: Inputs, |
101 | args: Output)); |
102 | } |
103 | |
104 | void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, |
105 | const InputInfoList &Inputs, |
106 | const InputInfo &Output, |
107 | const llvm::opt::ArgList &Args) const { |
108 | // Construct lld command. |
109 | // The output from ld.lld is an HSA code object file. |
110 | ArgStringList LldArgs{"-flavor" , |
111 | "gnu" , |
112 | "-m" , |
113 | "elf64_amdgpu" , |
114 | "--no-undefined" , |
115 | "-shared" , |
116 | "-plugin-opt=-amdgpu-internalize-symbols" }; |
117 | if (Args.hasArg(Ids: options::OPT_hipstdpar)) |
118 | LldArgs.push_back(Elt: "-plugin-opt=-amdgpu-enable-hipstdpar" ); |
119 | |
120 | auto &TC = getToolChain(); |
121 | auto &D = TC.getDriver(); |
122 | assert(!Inputs.empty() && "Must have at least one input." ); |
123 | bool IsThinLTO = D.getLTOMode(/*IsOffload=*/true) == LTOK_Thin; |
124 | addLTOOptions(ToolChain: TC, Args, CmdArgs&: LldArgs, Output, Input: Inputs[0], IsThinLTO); |
125 | |
126 | // Extract all the -m options |
127 | std::vector<llvm::StringRef> Features; |
128 | amdgpu::getAMDGPUTargetFeatures(D, Triple: TC.getTriple(), Args, Features); |
129 | |
130 | // Add features to mattr such as cumode |
131 | std::string MAttrString = "-plugin-opt=-mattr=" ; |
132 | for (auto OneFeature : unifyTargetFeatures(Features)) { |
133 | MAttrString.append(s: Args.MakeArgString(Str: OneFeature)); |
134 | if (OneFeature != Features.back()) |
135 | MAttrString.append(s: "," ); |
136 | } |
137 | if (!Features.empty()) |
138 | LldArgs.push_back(Elt: Args.MakeArgString(Str: MAttrString)); |
139 | |
140 | // ToDo: Remove this option after AMDGPU backend supports ISA-level linking. |
141 | // Since AMDGPU backend currently does not support ISA-level linking, all |
142 | // called functions need to be imported. |
143 | if (IsThinLTO) |
144 | LldArgs.push_back(Elt: Args.MakeArgString(Str: "-plugin-opt=-force-import-all" )); |
145 | |
146 | for (const Arg *A : Args.filtered(Ids: options::OPT_mllvm)) { |
147 | LldArgs.push_back( |
148 | Elt: Args.MakeArgString(Str: Twine("-plugin-opt=" ) + A->getValue(N: 0))); |
149 | } |
150 | |
151 | if (C.getDriver().isSaveTempsEnabled()) |
152 | LldArgs.push_back(Elt: "-save-temps" ); |
153 | |
154 | addLinkerCompressDebugSectionsOption(TC, Args, CmdArgs&: LldArgs); |
155 | |
156 | // Given that host and device linking happen in separate processes, the device |
157 | // linker doesn't always have the visibility as to which device symbols are |
158 | // needed by a program, especially for the device symbol dependencies that are |
159 | // introduced through the host symbol resolution. |
160 | // For example: host_A() (A.obj) --> host_B(B.obj) --> device_kernel_B() |
161 | // (B.obj) In this case, the device linker doesn't know that A.obj actually |
162 | // depends on the kernel functions in B.obj. When linking to static device |
163 | // library, the device linker may drop some of the device global symbols if |
164 | // they aren't referenced. As a workaround, we are adding to the |
165 | // --whole-archive flag such that all global symbols would be linked in. |
166 | LldArgs.push_back(Elt: "--whole-archive" ); |
167 | |
168 | for (auto *Arg : Args.filtered(Ids: options::OPT_Xoffload_linker)) { |
169 | StringRef ArgVal = Arg->getValue(N: 1); |
170 | auto SplitArg = ArgVal.split(Separator: "-mllvm=" ); |
171 | if (!SplitArg.second.empty()) { |
172 | LldArgs.push_back( |
173 | Elt: Args.MakeArgString(Str: Twine("-plugin-opt=" ) + SplitArg.second)); |
174 | } else { |
175 | LldArgs.push_back(Elt: Args.MakeArgString(Str: ArgVal)); |
176 | } |
177 | Arg->claim(); |
178 | } |
179 | |
180 | LldArgs.append(IL: {"-o" , Output.getFilename()}); |
181 | for (auto Input : Inputs) |
182 | LldArgs.push_back(Elt: Input.getFilename()); |
183 | |
184 | // Look for archive of bundled bitcode in arguments, and add temporary files |
185 | // for the extracted archive of bitcode to inputs. |
186 | auto TargetID = Args.getLastArgValue(Id: options::OPT_mcpu_EQ); |
187 | AddStaticDeviceLibsLinking(C, T: *this, JA, Inputs, DriverArgs: Args, CmdArgs&: LldArgs, Arch: "amdgcn" , |
188 | Target: TargetID, /*IsBitCodeSDL=*/isBitCodeSDL: true); |
189 | |
190 | LldArgs.push_back(Elt: "--no-whole-archive" ); |
191 | |
192 | const char *Lld = Args.MakeArgString(Str: getToolChain().GetProgramPath(Name: "lld" )); |
193 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(), |
194 | args&: Lld, args&: LldArgs, args: Inputs, args: Output)); |
195 | } |
196 | |
197 | // For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode |
198 | // and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). It |
199 | // calls llvm-link and then the llvm-spirv translator. Once the SPIR-V BE will |
200 | // be promoted from experimental, we will switch to using that. TODO: consider |
201 | // if we want to run any targeted optimisations over IR here, over generic |
202 | // SPIR-V. |
203 | void AMDGCN::Linker::constructLinkAndEmitSpirvCommand( |
204 | Compilation &C, const JobAction &JA, const InputInfoList &Inputs, |
205 | const InputInfo &Output, const llvm::opt::ArgList &Args) const { |
206 | assert(!Inputs.empty() && "Must have at least one input." ); |
207 | |
208 | constructLlvmLinkCommand(C, JA, Inputs, Output, Args); |
209 | |
210 | // Linked BC is now in Output |
211 | |
212 | // Emit SPIR-V binary. |
213 | llvm::opt::ArgStringList TrArgs{ |
214 | "--spirv-max-version=1.6" , |
215 | "--spirv-ext=+all" , |
216 | "--spirv-allow-extra-diexpressions" , |
217 | "--spirv-allow-unknown-intrinsics" , |
218 | "--spirv-lower-const-expr" , |
219 | "--spirv-preserve-auxdata" , |
220 | "--spirv-debug-info-version=nonsemantic-shader-200" }; |
221 | SPIRV::constructTranslateCommand(C, T: *this, JA, Output, Input: Output, Args: TrArgs); |
222 | } |
223 | |
224 | // For amdgcn the inputs of the linker job are device bitcode and output is |
225 | // either an object file or bitcode (-emit-llvm). It calls llvm-link, opt, |
226 | // llc, then lld steps. |
227 | void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
228 | const InputInfo &Output, |
229 | const InputInfoList &Inputs, |
230 | const ArgList &Args, |
231 | const char *LinkingOutput) const { |
232 | if (Inputs.size() > 0 && |
233 | Inputs[0].getType() == types::TY_Image && |
234 | JA.getType() == types::TY_Object) |
235 | return HIP::constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, |
236 | Args, JA, T: *this); |
237 | |
238 | if (JA.getType() == types::TY_HIP_FATBIN) |
239 | return HIP::constructHIPFatbinCommand(C, JA, OutputFileName: Output.getFilename(), Inputs, |
240 | TCArgs: Args, T: *this); |
241 | |
242 | if (JA.getType() == types::TY_LLVM_BC) |
243 | return constructLlvmLinkCommand(C, JA, Inputs, Output, Args); |
244 | |
245 | if (getToolChain().getTriple().isSPIRV()) |
246 | return constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args); |
247 | |
248 | return constructLldCommand(C, JA, Inputs, Output, Args); |
249 | } |
250 | |
251 | HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple, |
252 | const ToolChain &HostTC, const ArgList &Args) |
253 | : ROCMToolChain(D, Triple, Args), HostTC(HostTC) { |
254 | // Lookup binaries into the driver directory, this is used to |
255 | // discover the clang-offload-bundler executable. |
256 | getProgramPaths().push_back(Elt: getDriver().Dir); |
257 | |
258 | // Diagnose unsupported sanitizer options only once. |
259 | if (!Args.hasFlag(Pos: options::OPT_fgpu_sanitize, Neg: options::OPT_fno_gpu_sanitize, |
260 | Default: true)) |
261 | return; |
262 | for (auto *A : Args.filtered(Ids: options::OPT_fsanitize_EQ)) { |
263 | SanitizerMask K = parseSanitizerValue(Value: A->getValue(), /*AllowGroups=*/false); |
264 | if (K != SanitizerKind::Address) |
265 | D.getDiags().Report(DiagID: clang::diag::warn_drv_unsupported_option_for_target) |
266 | << A->getAsString(Args) << getTriple().str(); |
267 | } |
268 | } |
269 | |
270 | void HIPAMDToolChain::addClangTargetOptions( |
271 | const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, |
272 | Action::OffloadKind DeviceOffloadingKind) const { |
273 | HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadKind: DeviceOffloadingKind); |
274 | |
275 | assert(DeviceOffloadingKind == Action::OFK_HIP && |
276 | "Only HIP offloading kinds are supported for GPUs." ); |
277 | |
278 | CC1Args.push_back(Elt: "-fcuda-is-device" ); |
279 | |
280 | if (!DriverArgs.hasFlag(Pos: options::OPT_fgpu_rdc, Neg: options::OPT_fno_gpu_rdc, |
281 | Default: false)) |
282 | CC1Args.append(IL: {"-mllvm" , "-amdgpu-internalize-symbols" }); |
283 | if (DriverArgs.hasArgNoClaim(Ids: options::OPT_hipstdpar)) |
284 | CC1Args.append(IL: {"-mllvm" , "-amdgpu-enable-hipstdpar" }); |
285 | |
286 | StringRef MaxThreadsPerBlock = |
287 | DriverArgs.getLastArgValue(Id: options::OPT_gpu_max_threads_per_block_EQ); |
288 | if (!MaxThreadsPerBlock.empty()) { |
289 | std::string ArgStr = |
290 | (Twine("--gpu-max-threads-per-block=" ) + MaxThreadsPerBlock).str(); |
291 | CC1Args.push_back(Elt: DriverArgs.MakeArgStringRef(Str: ArgStr)); |
292 | } |
293 | |
294 | CC1Args.push_back(Elt: "-fcuda-allow-variadic-functions" ); |
295 | |
296 | // Default to "hidden" visibility, as object level linking will not be |
297 | // supported for the foreseeable future. |
298 | if (!DriverArgs.hasArg(Ids: options::OPT_fvisibility_EQ, |
299 | Ids: options::OPT_fvisibility_ms_compat)) { |
300 | CC1Args.append(IL: {"-fvisibility=hidden" }); |
301 | CC1Args.push_back(Elt: "-fapply-global-visibility-to-externs" ); |
302 | } |
303 | |
304 | // For SPIR-V we embed the command-line into the generated binary, in order to |
305 | // retrieve it at JIT time and be able to do target specific compilation with |
306 | // options that match the user-supplied ones. |
307 | if (getTriple().isSPIRV() && |
308 | !DriverArgs.hasArg(Ids: options::OPT_fembed_bitcode_marker)) |
309 | CC1Args.push_back(Elt: "-fembed-bitcode=marker" ); |
310 | |
311 | for (auto BCFile : getDeviceLibs(Args: DriverArgs)) { |
312 | CC1Args.push_back(Elt: BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" |
313 | : "-mlink-bitcode-file" ); |
314 | CC1Args.push_back(Elt: DriverArgs.MakeArgString(Str: BCFile.Path)); |
315 | } |
316 | } |
317 | |
318 | llvm::opt::DerivedArgList * |
319 | HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, |
320 | StringRef BoundArch, |
321 | Action::OffloadKind DeviceOffloadKind) const { |
322 | DerivedArgList *DAL = |
323 | HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); |
324 | if (!DAL) |
325 | DAL = new DerivedArgList(Args.getBaseArgs()); |
326 | |
327 | const OptTable &Opts = getDriver().getOpts(); |
328 | |
329 | for (Arg *A : Args) { |
330 | if (!shouldSkipSanitizeOption(TC: *this, DriverArgs: Args, TargetID: BoundArch, A)) |
331 | DAL->append(A); |
332 | } |
333 | |
334 | if (!BoundArch.empty()) { |
335 | DAL->eraseArg(Id: options::OPT_mcpu_EQ); |
336 | DAL->AddJoinedArg(BaseArg: nullptr, Opt: Opts.getOption(Opt: options::OPT_mcpu_EQ), Value: BoundArch); |
337 | checkTargetID(DriverArgs: *DAL); |
338 | } |
339 | |
340 | return DAL; |
341 | } |
342 | |
343 | Tool *HIPAMDToolChain::buildLinker() const { |
344 | assert(getTriple().getArch() == llvm::Triple::amdgcn || |
345 | getTriple().getArch() == llvm::Triple::spirv64); |
346 | return new tools::AMDGCN::Linker(*this); |
347 | } |
348 | |
349 | void HIPAMDToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { |
350 | AMDGPUToolChain::addClangWarningOptions(CC1Args); |
351 | HostTC.addClangWarningOptions(CC1Args); |
352 | } |
353 | |
354 | ToolChain::CXXStdlibType |
355 | HIPAMDToolChain::GetCXXStdlibType(const ArgList &Args) const { |
356 | return HostTC.GetCXXStdlibType(Args); |
357 | } |
358 | |
359 | void HIPAMDToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
360 | ArgStringList &CC1Args) const { |
361 | HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); |
362 | } |
363 | |
364 | void HIPAMDToolChain::AddClangCXXStdlibIncludeArgs( |
365 | const ArgList &Args, ArgStringList &CC1Args) const { |
366 | HostTC.AddClangCXXStdlibIncludeArgs(DriverArgs: Args, CC1Args); |
367 | } |
368 | |
369 | void HIPAMDToolChain::AddIAMCUIncludeArgs(const ArgList &Args, |
370 | ArgStringList &CC1Args) const { |
371 | HostTC.AddIAMCUIncludeArgs(DriverArgs: Args, CC1Args); |
372 | } |
373 | |
374 | void HIPAMDToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, |
375 | ArgStringList &CC1Args) const { |
376 | RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args); |
377 | } |
378 | |
379 | SanitizerMask HIPAMDToolChain::getSupportedSanitizers() const { |
380 | // The HIPAMDToolChain only supports sanitizers in the sense that it allows |
381 | // sanitizer arguments on the command line if they are supported by the host |
382 | // toolchain. The HIPAMDToolChain will actually ignore any command line |
383 | // arguments for any of these "supported" sanitizers. That means that no |
384 | // sanitization of device code is actually supported at this time. |
385 | // |
386 | // This behavior is necessary because the host and device toolchains |
387 | // invocations often share the command line, so the device toolchain must |
388 | // tolerate flags meant only for the host toolchain. |
389 | return HostTC.getSupportedSanitizers(); |
390 | } |
391 | |
392 | VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D, |
393 | const ArgList &Args) const { |
394 | return HostTC.computeMSVCVersion(D, Args); |
395 | } |
396 | |
397 | llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> |
398 | HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { |
399 | llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs; |
400 | if (DriverArgs.hasArg(Ids: options::OPT_nogpulib) || |
401 | (getTriple().getArch() == llvm::Triple::spirv64 && |
402 | getTriple().getVendor() == llvm::Triple::AMD)) |
403 | return {}; |
404 | ArgStringList LibraryPaths; |
405 | |
406 | // Find in --hip-device-lib-path and HIP_LIBRARY_PATH. |
407 | for (StringRef Path : RocmInstallation->getRocmDeviceLibPathArg()) |
408 | LibraryPaths.push_back(Elt: DriverArgs.MakeArgString(Str: Path)); |
409 | |
410 | addDirectoryList(Args: DriverArgs, CmdArgs&: LibraryPaths, ArgName: "" , EnvVar: "HIP_DEVICE_LIB_PATH" ); |
411 | |
412 | // Maintain compatability with --hip-device-lib. |
413 | auto BCLibArgs = DriverArgs.getAllArgValues(Id: options::OPT_hip_device_lib_EQ); |
414 | if (!BCLibArgs.empty()) { |
415 | llvm::for_each(Range&: BCLibArgs, F: [&](StringRef BCName) { |
416 | StringRef FullName; |
417 | for (StringRef LibraryPath : LibraryPaths) { |
418 | SmallString<128> Path(LibraryPath); |
419 | llvm::sys::path::append(path&: Path, a: BCName); |
420 | FullName = Path; |
421 | if (llvm::sys::fs::exists(Path: FullName)) { |
422 | BCLibs.push_back(Elt: FullName); |
423 | return; |
424 | } |
425 | } |
426 | getDriver().Diag(DiagID: diag::err_drv_no_such_file) << BCName; |
427 | }); |
428 | } else { |
429 | if (!RocmInstallation->hasDeviceLibrary()) { |
430 | getDriver().Diag(DiagID: diag::err_drv_no_rocm_device_lib) << 0; |
431 | return {}; |
432 | } |
433 | StringRef GpuArch = getGPUArch(DriverArgs); |
434 | assert(!GpuArch.empty() && "Must have an explicit GPU arch." ); |
435 | |
436 | // If --hip-device-lib is not set, add the default bitcode libraries. |
437 | if (DriverArgs.hasFlag(Pos: options::OPT_fgpu_sanitize, |
438 | Neg: options::OPT_fno_gpu_sanitize, Default: true) && |
439 | getSanitizerArgs(JobArgs: DriverArgs).needsAsanRt()) { |
440 | auto AsanRTL = RocmInstallation->getAsanRTLPath(); |
441 | if (AsanRTL.empty()) { |
442 | unsigned DiagID = getDriver().getDiags().getCustomDiagID( |
443 | L: DiagnosticsEngine::Error, |
444 | FormatString: "AMDGPU address sanitizer runtime library (asanrtl) is not found. " |
445 | "Please install ROCm device library which supports address " |
446 | "sanitizer" ); |
447 | getDriver().Diag(DiagID); |
448 | return {}; |
449 | } else |
450 | BCLibs.emplace_back(Args&: AsanRTL, /*ShouldInternalize=*/Args: false); |
451 | } |
452 | |
453 | // Add the HIP specific bitcode library. |
454 | BCLibs.push_back(Elt: RocmInstallation->getHIPPath()); |
455 | |
456 | // Add common device libraries like ocml etc. |
457 | for (StringRef N : getCommonDeviceLibNames(DriverArgs, GPUArch: GpuArch.str())) |
458 | BCLibs.emplace_back(Args&: N); |
459 | |
460 | // Add instrument lib. |
461 | auto InstLib = |
462 | DriverArgs.getLastArgValue(Id: options::OPT_gpu_instrument_lib_EQ); |
463 | if (InstLib.empty()) |
464 | return BCLibs; |
465 | if (llvm::sys::fs::exists(Path: InstLib)) |
466 | BCLibs.push_back(Elt: InstLib); |
467 | else |
468 | getDriver().Diag(DiagID: diag::err_drv_no_such_file) << InstLib; |
469 | } |
470 | |
471 | return BCLibs; |
472 | } |
473 | |
474 | void HIPAMDToolChain::checkTargetID( |
475 | const llvm::opt::ArgList &DriverArgs) const { |
476 | auto PTID = getParsedTargetID(DriverArgs); |
477 | if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { |
478 | getDriver().Diag(DiagID: clang::diag::err_drv_bad_target_id) |
479 | << *PTID.OptionalTargetID; |
480 | } |
481 | } |
482 | |