1//===-- clang-linker-wrapper/ClangLinkerWrapper.cpp -----------------------===//
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// This tool works as a wrapper over a linking job. This tool is used to create
10// linked device images for offloading. It scans the linker's input for embedded
11// device offloading data stored in sections `.llvm.offloading` and extracts it
12// as a temporary file. The extracted device files will then be passed to a
13// device linking job to create a final device image.
14//
15//===----------------------------------------------------------------------===//
16
17#include "clang/Basic/TargetID.h"
18#include "clang/Basic/Version.h"
19#include "llvm/ADT/MapVector.h"
20#include "llvm/BinaryFormat/Magic.h"
21#include "llvm/Bitcode/BitcodeWriter.h"
22#include "llvm/CodeGen/CommandFlags.h"
23#include "llvm/Frontend/Offloading/OffloadWrapper.h"
24#include "llvm/Frontend/Offloading/Utility.h"
25#include "llvm/IR/DiagnosticPrinter.h"
26#include "llvm/IR/Module.h"
27#include "llvm/IRReader/IRReader.h"
28#include "llvm/LTO/LTO.h"
29#include "llvm/MC/TargetRegistry.h"
30#include "llvm/Object/Binary.h"
31#include "llvm/Object/IRObjectFile.h"
32#include "llvm/Object/ObjectFile.h"
33#include "llvm/Object/OffloadBinary.h"
34#include "llvm/Option/ArgList.h"
35#include "llvm/Option/OptTable.h"
36#include "llvm/Option/Option.h"
37#include "llvm/Plugins/PassPlugin.h"
38#include "llvm/Remarks/HotnessThresholdParser.h"
39#include "llvm/Support/CommandLine.h"
40#include "llvm/Support/FileOutputBuffer.h"
41#include "llvm/Support/FileSystem.h"
42#include "llvm/Support/InitLLVM.h"
43#include "llvm/Support/MemoryBuffer.h"
44#include "llvm/Support/Parallel.h"
45#include "llvm/Support/Path.h"
46#include "llvm/Support/Program.h"
47#include "llvm/Support/Signals.h"
48#include "llvm/Support/SourceMgr.h"
49#include "llvm/Support/StringSaver.h"
50#include "llvm/Support/TargetSelect.h"
51#include "llvm/Support/TimeProfiler.h"
52#include "llvm/Support/WithColor.h"
53#include "llvm/Support/raw_ostream.h"
54#include "llvm/Target/TargetMachine.h"
55#include "llvm/TargetParser/Host.h"
56#include <optional>
57
58using namespace llvm;
59using namespace llvm::opt;
60using namespace llvm::object;
61
62// Various tools (e.g., llc and opt) duplicate this series of declarations for
63// options related to passes and remarks.
64
65static cl::opt<bool> RemarksWithHotness(
66 "pass-remarks-with-hotness",
67 cl::desc("With PGO, include profile count in optimization remarks"),
68 cl::Hidden);
69
70static cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
71 RemarksHotnessThreshold(
72 "pass-remarks-hotness-threshold",
73 cl::desc("Minimum profile count required for "
74 "an optimization remark to be output. "
75 "Use 'auto' to apply the threshold from profile summary."),
76 cl::value_desc("N or 'auto'"), cl::init(Val: 0), cl::Hidden);
77
78static cl::opt<std::string>
79 RemarksFilename("pass-remarks-output",
80 cl::desc("Output filename for pass remarks"),
81 cl::value_desc("filename"));
82
83static cl::opt<std::string>
84 RemarksPasses("pass-remarks-filter",
85 cl::desc("Only record optimization remarks from passes whose "
86 "names match the given regular expression"),
87 cl::value_desc("regex"));
88
89static cl::opt<std::string> RemarksFormat(
90 "pass-remarks-format",
91 cl::desc("The format used for serializing remarks (default: YAML)"),
92 cl::value_desc("format"), cl::init(Val: "yaml"));
93
94static cl::list<std::string>
95 PassPlugins("load-pass-plugin",
96 cl::desc("Load passes from plugin library"));
97
98static cl::opt<std::string> PassPipeline(
99 "passes",
100 cl::desc(
101 "A textual description of the pass pipeline. To have analysis passes "
102 "available before a certain pass, add 'require<foo-analysis>'. "
103 "'-passes' overrides the pass pipeline (but not all effects) from "
104 "specifying '--opt-level=O?' (O2 is the default) to "
105 "clang-linker-wrapper. Be sure to include the corresponding "
106 "'default<O?>' in '-passes'."));
107static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline),
108 cl::desc("Alias for -passes"));
109
110/// Path of the current binary.
111static const char *LinkerExecutable;
112
113/// Save intermediary results.
114static bool SaveTemps = false;
115
116/// Print arguments without executing.
117static bool DryRun = false;
118
119/// Print verbose output.
120static bool Verbose = false;
121
122/// Filename of the executable being created.
123static StringRef ExecutableName;
124
125/// Binary path for the CUDA installation.
126static std::string CudaBinaryPath;
127
128/// Mutex lock to protect writes to shared TempFiles in parallel.
129static std::mutex TempFilesMutex;
130
131/// Temporary files created by the linker wrapper.
132static std::list<SmallString<128>> TempFiles;
133
134/// Codegen flags for LTO backend.
135static codegen::RegisterCodeGenFlags CodeGenFlags;
136
137/// Whether or not to look through symlinks when resolving binaries.
138static bool CanonicalPrefixes = true;
139
140using OffloadingImage = OffloadBinary::OffloadingImage;
141
142static bool usesLLVMOffloadWrapper(ArrayRef<OffloadingImage> Images) {
143 return llvm::any_of(Range&: Images, P: [](const OffloadingImage &Image) {
144 return Triple(Image.StringData.lookup(Key: "triple")).getEnvironment() ==
145 Triple::LLVM;
146 });
147}
148
149namespace llvm {
150// Provide DenseMapInfo so that OffloadKind can be used in a DenseMap.
151template <> struct DenseMapInfo<OffloadKind> {
152 static unsigned getHashValue(const OffloadKind &Val) { return Val; }
153
154 static bool isEqual(const OffloadKind &LHS, const OffloadKind &RHS) {
155 return LHS == RHS;
156 }
157};
158} // namespace llvm
159
160namespace {
161using std::error_code;
162
163/// Must not overlap with llvm::opt::DriverFlag.
164enum WrapperFlags {
165 WrapperOnlyOption = (1 << 4), // Options only used by the linker wrapper.
166 DeviceOnlyOption = (1 << 5), // Options only used for device linking.
167};
168
169enum ID {
170 OPT_INVALID = 0, // This is not an option ID.
171#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
172#include "LinkerWrapperOpts.inc"
173 LastOption
174#undef OPTION
175};
176
177#define OPTTABLE_CODE
178#include "LinkerWrapperOpts.inc"
179
180class WrapperOptTable : public opt::OptTable {
181public:
182 WrapperOptTable() : opt::OptTable(optionTables()) {}
183};
184
185const OptTable &getOptTable() {
186 static const WrapperOptTable Table;
187 return Table;
188}
189
190void printCommands(ArrayRef<StringRef> CmdArgs) {
191 if (CmdArgs.empty())
192 return;
193
194 llvm::errs() << " \"" << CmdArgs.front() << "\" ";
195 for (auto IC = std::next(x: CmdArgs.begin()), IE = CmdArgs.end(); IC != IE; ++IC)
196 llvm::errs() << *IC << (std::next(x: IC) != IE ? " " : "\n");
197}
198
199[[noreturn]] void reportError(Error E) {
200 outs().flush();
201 logAllUnhandledErrors(E: std::move(E),
202 OS&: WithColor::error(OS&: errs(), Prefix: LinkerExecutable));
203 exit(EXIT_FAILURE);
204}
205
206std::string getExecutableDir(const char *Name) {
207 if (!CanonicalPrefixes)
208 return sys::path::parent_path(path: LinkerExecutable).str();
209 void *Ptr = reinterpret_cast<void *>(&getExecutableDir);
210 return sys::path::parent_path(path: sys::fs::getMainExecutable(argv0: Name, MainExecAddr: Ptr)).str();
211}
212
213/// Get a temporary filename suitable for output.
214Expected<StringRef> createOutputFile(const Twine &Prefix, StringRef Extension) {
215 std::scoped_lock<decltype(TempFilesMutex)> Lock(TempFilesMutex);
216 SmallString<128> OutputFile;
217 std::string PrefixStr = clang::sanitizeTargetIDInFileName(TargetID: Prefix.str());
218
219 if (SaveTemps) {
220 (PrefixStr + "." + Extension).toNullTerminatedStringRef(Out&: OutputFile);
221 } else {
222 if (std::error_code EC = sys::fs::createTemporaryFile(
223 Prefix: sys::path::filename(path: PrefixStr), Suffix: Extension, ResultPath&: OutputFile))
224 return createFileError(F: OutputFile, EC);
225 }
226
227 TempFiles.emplace_back(args: std::move(OutputFile));
228 return TempFiles.back();
229}
230
231/// Execute the command \p ExecutablePath with the arguments \p Args.
232Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args) {
233 if (Verbose || DryRun)
234 printCommands(CmdArgs: Args);
235
236 if (DryRun)
237 return Error::success();
238
239 // If the command line fits within system limits, execute directly.
240 if (sys::commandLineFitsWithinSystemLimits(Program: ExecutablePath, Args)) {
241 if (sys::ExecuteAndWait(Program: ExecutablePath, Args))
242 return createStringError(
243 Fmt: "'%s' failed", Vals: sys::path::filename(path: ExecutablePath).str().c_str());
244 return Error::success();
245 }
246
247 // Write the arguments to a response file and pass that instead.
248 auto TempFileOrErr = createOutputFile(Prefix: "response", Extension: "rsp");
249 if (!TempFileOrErr)
250 return TempFileOrErr.takeError();
251
252 SmallString<256> Contents;
253 raw_svector_ostream OS(Contents);
254 for (StringRef Arg : llvm::drop_begin(RangeOrContainer&: Args)) {
255 sys::printArg(OS, Arg, /*Quote=*/true);
256 OS << " ";
257 }
258
259 if (std::error_code EC = sys::writeFileWithEncoding(FileName: *TempFileOrErr, Contents))
260 return createStringError(Fmt: "failed to write response file: %s",
261 Vals: EC.message().c_str());
262
263 std::string ResponseFile = ("@" + *TempFileOrErr).str();
264 SmallVector<StringRef, 2> NewArgs = {Args.front(), ResponseFile};
265 if (sys::ExecuteAndWait(Program: ExecutablePath, Args: NewArgs))
266 return createStringError(Fmt: "'%s' failed",
267 Vals: sys::path::filename(path: ExecutablePath).str().c_str());
268 return Error::success();
269}
270
271Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) {
272
273 ErrorOr<std::string> Path = sys::findProgramByName(Name, Paths);
274 if (!Path)
275 Path = sys::findProgramByName(Name);
276 if (!Path && DryRun)
277 return Name.str();
278 if (!Path)
279 return createStringError(EC: Path.getError(),
280 S: "Unable to find '" + Name + "' in path");
281 return *Path;
282}
283
284bool linkerSupportsLTO(const ArgList &Args) {
285 llvm::Triple Triple(Args.getLastArgValue(Id: OPT_triple_EQ));
286 return Triple.isNVPTX() || Triple.isAMDGPU() ||
287 (!Triple.isGPU() &&
288 Args.getLastArgValue(Id: OPT_linker_path_EQ).ends_with(Suffix: "lld"));
289}
290
291/// Returns the hashed value for a constant string.
292std::string getHash(StringRef Str) {
293 llvm::MD5 Hasher;
294 llvm::MD5::MD5Result Hash;
295 Hasher.update(Str);
296 Hasher.final(Result&: Hash);
297 return llvm::utohexstr(X: Hash.low(), /*LowerCase=*/true);
298}
299
300/// Renames offloading entry sections in a relocatable link so they do not
301/// conflict with a later link job.
302Error relocateOffloadSection(const ArgList &Args, StringRef Output) {
303 llvm::Triple Triple(
304 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
305 if (Triple.isOSWindows())
306 return createStringError(
307 Fmt: "Relocatable linking is not supported on COFF targets");
308
309 Expected<std::string> ObjcopyPath =
310 findProgram(Name: "llvm-objcopy", Paths: {getExecutableDir(Name: "llvm-objcopy")});
311 if (!ObjcopyPath)
312 return ObjcopyPath.takeError();
313
314 // Use the linker output file to get a unique hash. This creates a unique
315 // identifier to rename the sections to that is deterministic to the contents.
316 auto BufferOrErr = DryRun ? MemoryBuffer::getMemBuffer(InputData: "")
317 : MemoryBuffer::getFileOrSTDIN(Filename: Output);
318 if (!BufferOrErr)
319 return createStringError(Fmt: "Failed to open %s", Vals: Output.str().c_str());
320 std::string Suffix = "_" + getHash(Str: (*BufferOrErr)->getBuffer());
321
322 SmallVector<StringRef> ObjcopyArgs = {
323 *ObjcopyPath,
324 Output,
325 };
326
327 // Remove the old .llvm.offloading section to prevent further linking.
328 ObjcopyArgs.emplace_back(Args: "--remove-section");
329 ObjcopyArgs.emplace_back(Args: ".llvm.offloading");
330 StringRef Prefix = "llvm";
331 auto Section = (Prefix + "_offload_entries").str();
332 // Rename the offloading entries to make them private to this link unit.
333 ObjcopyArgs.emplace_back(Args: "--rename-section");
334 ObjcopyArgs.emplace_back(
335 Args: Args.MakeArgString(Str: Section + "=" + Section + Suffix));
336
337 // Rename the __start_ / __stop_ symbols appropriately to iterate over the
338 // newly renamed section containing the offloading entries.
339 ObjcopyArgs.emplace_back(Args: "--redefine-sym");
340 ObjcopyArgs.emplace_back(Args: Args.MakeArgString(Str: "__start_" + Section + "=" +
341 "__start_" + Section + Suffix));
342 ObjcopyArgs.emplace_back(Args: "--redefine-sym");
343 ObjcopyArgs.emplace_back(Args: Args.MakeArgString(Str: "__stop_" + Section + "=" +
344 "__stop_" + Section + Suffix));
345
346 if (Error Err = executeCommands(ExecutablePath: *ObjcopyPath, Args: ObjcopyArgs))
347 return Err;
348
349 return Error::success();
350}
351
352/// Runs the wrapped linker job with the newly created input.
353Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
354 llvm::TimeTraceScope TimeScope("Execute host linker");
355
356 // Render the linker arguments and add the newly created image. We add it
357 // after the output file to ensure it is linked with the correct libraries.
358 StringRef LinkerPath = Args.getLastArgValue(Id: OPT_linker_path_EQ);
359 if (LinkerPath.empty())
360 return createStringError(Fmt: "linker path missing, must pass 'linker-path'");
361 ArgStringList NewLinkerArgs;
362 for (const opt::Arg *Arg : Args) {
363 // Do not forward arguments only intended for the linker wrapper.
364 if (Arg->getOption().hasFlag(Val: WrapperOnlyOption))
365 continue;
366
367 Arg->render(Args, Output&: NewLinkerArgs);
368 if (Arg->getOption().matches(ID: OPT_o) || Arg->getOption().matches(ID: OPT_out))
369 llvm::transform(Range&: Files, d_first: std::back_inserter(x&: NewLinkerArgs),
370 F: [&](StringRef A) { return Args.MakeArgString(Str: A); });
371 }
372
373 SmallVector<StringRef> LinkerArgs({LinkerPath});
374 for (StringRef Arg : NewLinkerArgs)
375 LinkerArgs.push_back(Elt: Arg);
376 if (Error Err = executeCommands(ExecutablePath: LinkerPath, Args: LinkerArgs))
377 return Err;
378
379 if (Args.hasArg(Ids: OPT_relocatable))
380 return relocateOffloadSection(Args, Output: ExecutableName);
381
382 return Error::success();
383}
384
385void printVersion(raw_ostream &OS) {
386 OS << clang::getClangToolFullVersion(ToolName: "clang-linker-wrapper") << '\n';
387}
388
389namespace nvptx {
390Expected<StringRef>
391fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,
392 const ArgList &Args) {
393 llvm::TimeTraceScope TimeScope("NVPTX fatbinary");
394 // NVPTX uses the fatbinary program to bundle the linked images.
395 Expected<std::string> FatBinaryPath =
396 findProgram(Name: "fatbinary", Paths: {CudaBinaryPath + "/bin"});
397 if (!FatBinaryPath)
398 return FatBinaryPath.takeError();
399
400 llvm::Triple Triple(
401 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
402
403 // Create a new file to write the linked device image to.
404 auto TempFileOrErr = createOutputFile(Prefix: ExecutableName, Extension: "fatbin");
405 if (!TempFileOrErr)
406 return TempFileOrErr.takeError();
407
408 SmallVector<StringRef, 16> CmdArgs;
409 CmdArgs.push_back(Elt: *FatBinaryPath);
410 CmdArgs.push_back(Elt: Triple.isArch64Bit() ? "-64" : "-32");
411 CmdArgs.push_back(Elt: "--create");
412 CmdArgs.push_back(Elt: *TempFileOrErr);
413 for (const auto &[File, Arch] : InputFiles)
414 CmdArgs.push_back(Elt: Args.MakeArgString(
415 Str: "--image3=kind=elf,sm=" + Arch.drop_front(N: 3) + ",file=" + File));
416
417 if (Error Err = executeCommands(ExecutablePath: *FatBinaryPath, Args: CmdArgs))
418 return std::move(Err);
419
420 return *TempFileOrErr;
421}
422} // namespace nvptx
423
424namespace amdgcn {
425
426// Constructs a triple string for clang offload bundler.
427// NOTE: copied from HIPUtility.cpp.
428static std::string normalizeForBundler(const llvm::Triple &T,
429 bool HasTargetID) {
430 // FIXME: Short-term hack, mirrors HIPUtility.cpp. The HIP runtime (CLR)
431 // hardcodes the legacy "amdgcn-amd-amdhsa" spelling when parsing the target
432 // IDs embedded in the fatbin bundle. The new amdgpu subarch triples (e.g.
433 // "amdgpu9.00-amd-amdhsa"), and the plain canonical "amdgpu" arch name, do
434 // not match, producing hipErrorInvalidImage at load time. Force the legacy
435 // "amdgcn-amd-amdhsa" spelling in the bundle entry until CLR stops
436 // hardcoding this.
437 if (HasTargetID && T.isAMDGCN())
438 return ("amdgcn-" + T.getVendorName() + "-" + T.getOSName() + "-" +
439 T.getEnvironmentName())
440 .str();
441
442 return HasTargetID ? (T.getArchName() + "-" + T.getVendorName() + "-" +
443 T.getOSName() + "-" + T.getEnvironmentName())
444 .str()
445 : T.normalize(Form: llvm::Triple::CanonicalForm::FOUR_IDENT);
446}
447
448Expected<StringRef>
449fatbinary(ArrayRef<std::tuple<StringRef, StringRef, StringRef>> InputFiles,
450 const ArgList &Args) {
451 llvm::TimeTraceScope TimeScope("AMDGPU Fatbinary");
452
453 // AMDGPU uses the clang-offload-bundler to bundle the linked images.
454 Expected<std::string> OffloadBundlerPath = findProgram(
455 Name: "clang-offload-bundler", Paths: {getExecutableDir(Name: "clang-offload-bundler")});
456 if (!OffloadBundlerPath)
457 return OffloadBundlerPath.takeError();
458
459 // Create a new file to write the linked device image to.
460 auto TempFileOrErr = createOutputFile(Prefix: ExecutableName, Extension: "hipfb");
461 if (!TempFileOrErr)
462 return TempFileOrErr.takeError();
463
464 BumpPtrAllocator Alloc;
465 StringSaver Saver(Alloc);
466
467 SmallVector<StringRef, 16> CmdArgs;
468 CmdArgs.push_back(Elt: *OffloadBundlerPath);
469 CmdArgs.push_back(Elt: "-type=o");
470 CmdArgs.push_back(Elt: "-bundle-align=4096");
471
472 if (Args.hasArg(Ids: OPT_compress))
473 CmdArgs.push_back(Elt: "-compress");
474 if (auto *Arg = Args.getLastArg(Ids: OPT_compression_level_eq))
475 CmdArgs.push_back(
476 Elt: Args.MakeArgString(Str: Twine("-compression-level=") + Arg->getValue()));
477
478 llvm::Triple HostTriple(
479 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
480 SmallVector<StringRef> Targets = {
481 Saver.save(S: "-targets=host-" + HostTriple.normalize())};
482 for (const auto &[File, TripleRef, Arch] : InputFiles) {
483 std::string NormalizedTriple =
484 normalizeForBundler(T: Triple(TripleRef), HasTargetID: !Arch.empty());
485 Targets.push_back(Elt: Saver.save(S: "hip-" + NormalizedTriple + "-" + Arch));
486 }
487 CmdArgs.push_back(Elt: Saver.save(S: llvm::join(R&: Targets, Separator: ",")));
488
489#ifdef _WIN32
490 CmdArgs.push_back("-input=NUL");
491#else
492 CmdArgs.push_back(Elt: "-input=/dev/null");
493#endif
494 for (const auto &[File, Triple, Arch] : InputFiles)
495 CmdArgs.push_back(Elt: Saver.save(S: "-input=" + File));
496
497 CmdArgs.push_back(Elt: Saver.save(S: "-output=" + *TempFileOrErr));
498
499 if (Error Err = executeCommands(ExecutablePath: *OffloadBundlerPath, Args: CmdArgs))
500 return std::move(Err);
501
502 return *TempFileOrErr;
503}
504} // namespace amdgcn
505
506namespace generic {
507Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args,
508 uint16_t ActiveOffloadKindMask) {
509 llvm::TimeTraceScope TimeScope("Clang");
510 // Use `clang` to invoke the appropriate device tools.
511 Expected<std::string> ClangPath =
512 findProgram(Name: "clang", Paths: {getExecutableDir(Name: "clang")});
513 if (!ClangPath)
514 return ClangPath.takeError();
515
516 const llvm::Triple Triple(Args.getLastArgValue(Id: OPT_triple_EQ));
517 StringRef Arch = Args.getLastArgValue(Id: OPT_arch_EQ);
518 // Create a new file to write the linked device image to. Assume that the
519 // input filename already has the device and architecture.
520 std::string OutputFileBase =
521 "." + Triple.getArchName().str() + "." + Arch.str();
522 auto TempFileOrErr = createOutputFile(Prefix: ExecutableName + OutputFileBase, Extension: "img");
523 if (!TempFileOrErr)
524 return TempFileOrErr.takeError();
525
526 SmallVector<StringRef, 16> CmdArgs{
527 *ClangPath,
528 "--no-default-config",
529 "-o",
530 *TempFileOrErr,
531 // Without -dumpdir, Clang will place auxiliary output files in the
532 // temporary directory of TempFileOrErr, where they will not easily be
533 // found by the user and might eventually be automatically removed. Tell
534 // Clang to instead place them alongside the final executable.
535 "-dumpdir",
536 Args.MakeArgString(Str: ExecutableName + OutputFileBase + ".img."),
537 Args.MakeArgString(Str: "--target=" + Triple.getTriple()),
538 };
539
540 if (!Arch.empty())
541 Triple.isAMDGPU() ? CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mcpu=" + Arch))
542 : CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-march=" + Arch));
543
544 // Forward all of the `--offload-opt` and `-mllvm` options to the device.
545 for (auto &Arg : Args.filtered(Ids: OPT_offload_opt_eq_minus, Ids: OPT_mllvm))
546 CmdArgs.append(
547 IL: {"-Xlinker",
548 Args.MakeArgString(Str: "--plugin-opt=" + StringRef(Arg->getValue()))});
549
550 if (!Triple.isNVPTX() && !Triple.isSPIRV())
551 CmdArgs.push_back(Elt: "-Wl,--no-undefined");
552
553 for (StringRef InputFile : InputFiles)
554 CmdArgs.push_back(Elt: InputFile);
555
556 // If this is CPU offloading we copy the input libraries.
557 if (!Triple.isGPU()) {
558 CmdArgs.push_back(Elt: "-Wl,-Bsymbolic");
559 CmdArgs.push_back(Elt: "-shared");
560 ArgStringList LinkerArgs;
561 for (const opt::Arg *Arg :
562 Args.filtered(Ids: OPT_INPUT, Ids: OPT_library, Ids: OPT_library_path, Ids: OPT_rpath,
563 Ids: OPT_whole_archive, Ids: OPT_no_whole_archive)) {
564 // Sometimes needed libraries are passed by name, such as when using
565 // sanitizers. We need to check the file magic for any libraries.
566 if (Arg->getOption().matches(ID: OPT_INPUT)) {
567 if (!sys::fs::exists(Path: Arg->getValue()) ||
568 sys::fs::is_directory(Path: Arg->getValue()))
569 continue;
570
571 file_magic Magic;
572 if (auto EC = identify_magic(path: Arg->getValue(), result&: Magic))
573 return createStringError(Fmt: "Failed to open %s", Vals: Arg->getValue());
574 if (Magic != file_magic::archive &&
575 Magic != file_magic::elf_shared_object)
576 continue;
577 }
578 if (Arg->getOption().matches(ID: OPT_whole_archive))
579 LinkerArgs.push_back(Elt: Args.MakeArgString(Str: "-Wl,--whole-archive"));
580 else if (Arg->getOption().matches(ID: OPT_no_whole_archive))
581 LinkerArgs.push_back(Elt: Args.MakeArgString(Str: "-Wl,--no-whole-archive"));
582 else
583 Arg->render(Args, Output&: LinkerArgs);
584 }
585 llvm::append_range(C&: CmdArgs, R&: LinkerArgs);
586 }
587
588 // Pass on -mllvm options to the linker invocation.
589 for (const opt::Arg *Arg : Args.filtered(Ids: OPT_mllvm))
590 CmdArgs.append(IL: {"-Xlinker", Args.MakeArgString(
591 Str: "-mllvm=" + StringRef(Arg->getValue()))});
592
593 if (SaveTemps && linkerSupportsLTO(Args))
594 CmdArgs.push_back(Elt: "-Wl,--save-temps");
595
596 if (Args.hasArg(Ids: OPT_embed_bitcode)) {
597 // SPIR-V does not use the LTO linker path, it links bitcode via llvm-link.
598 if (Triple.isSPIRV())
599 CmdArgs.push_back(Elt: "-emit-llvm");
600 else
601 CmdArgs.push_back(Elt: "-Wl,--lto-emit-llvm");
602 }
603
604 // For linking device code with the SYCL offload kind, special handling is
605 // required. Passing --sycl-link to clang results in a call to
606 // clang-sycl-linker.
607 if (ActiveOffloadKindMask & OFK_SYCL)
608 CmdArgs.push_back(Elt: "--sycl-link");
609
610 for (StringRef Arg : Args.getAllArgValues(Id: OPT_linker_arg_EQ))
611 CmdArgs.append(IL: {"-Xlinker", Args.MakeArgString(Str: Arg)});
612 for (StringRef Arg : Args.getAllArgValues(Id: OPT_compiler_arg_EQ))
613 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Arg));
614
615 if (Error Err = executeCommands(ExecutablePath: *ClangPath, Args: CmdArgs))
616 return std::move(Err);
617
618 return *TempFileOrErr;
619}
620} // namespace generic
621
622Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
623 const ArgList &Args,
624 uint16_t ActiveOffloadKindMask) {
625 const llvm::Triple Triple(Args.getLastArgValue(Id: OPT_triple_EQ));
626 switch (Triple.getArch()) {
627 case Triple::nvptx:
628 case Triple::nvptx64:
629 case Triple::amdgpu:
630 case Triple::x86:
631 case Triple::x86_64:
632 case Triple::aarch64:
633 case Triple::aarch64_be:
634 case Triple::ppc64:
635 case Triple::ppc64le:
636 case Triple::spirv64:
637 case Triple::systemz:
638 case Triple::loongarch64:
639 return generic::clang(InputFiles, Args, ActiveOffloadKindMask);
640 default:
641 return createStringError(S: Triple.getArchName() +
642 " linking is not supported");
643 }
644}
645
646Error containerizeRawImage(std::unique_ptr<MemoryBuffer> &Img, OffloadKind Kind,
647 const ArgList &Args) {
648 llvm::Triple Triple(Args.getLastArgValue(Id: OPT_triple_EQ));
649 if (Kind == OFK_OpenMP && Triple.isSPIRV() &&
650 Triple.getVendor() == llvm::Triple::Intel &&
651 !Args.hasArg(Ids: OPT_embed_bitcode))
652 return offloading::intel::containerizeOpenMPSPIRVImage(Binary&: Img, Triple);
653 return Error::success();
654}
655
656Expected<StringRef> writeOffloadFile(const OffloadFile &File) {
657 const OffloadBinary &Binary = *File.getBinary();
658
659 StringRef Prefix =
660 sys::path::stem(path: Binary.getMemoryBufferRef().getBufferIdentifier());
661 SmallString<128> Filename;
662 (Prefix + "-" + Binary.getTriple() + "-" + Binary.getArch())
663 .toVector(Out&: Filename);
664 auto TempFileOrErr = createOutputFile(Prefix: Filename, Extension: "o");
665 if (!TempFileOrErr)
666 return TempFileOrErr.takeError();
667
668 Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
669 FileOutputBuffer::create(FilePath: *TempFileOrErr, Size: Binary.getImage().size());
670 if (!OutputOrErr)
671 return OutputOrErr.takeError();
672 std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
673 llvm::copy(Range: Binary.getImage(), Out: Output->getBufferStart());
674 if (Error E = Output->commit())
675 return std::move(E);
676
677 return *TempFileOrErr;
678}
679
680// Compile the module to an object file using the appropriate target machine for
681// the host triple.
682Expected<StringRef> compileModule(Module &M, OffloadKind Kind) {
683 llvm::TimeTraceScope TimeScope("Compile module");
684 std::string Msg;
685 const Target *T = TargetRegistry::lookupTarget(TheTriple: M.getTargetTriple(), Error&: Msg);
686 if (!T)
687 return createStringError(S: Msg);
688
689 auto Options =
690 codegen::InitTargetOptionsFromCodeGenFlags(TheTriple: M.getTargetTriple());
691 StringRef CPU = "";
692 StringRef Features = "";
693 std::unique_ptr<TargetMachine> TM(
694 T->createTargetMachine(TT: M.getTargetTriple(), CPU, Features, Options,
695 RM: Reloc::PIC_, CM: M.getCodeModel()));
696
697 int FD = -1;
698 auto TempFileOrErr = createOutputFile(
699 Prefix: ExecutableName + "." + getOffloadKindName(Name: Kind) + ".image.wrapper", Extension: "o");
700 if (!TempFileOrErr)
701 return TempFileOrErr.takeError();
702 if (std::error_code EC = sys::fs::openFileForWrite(Name: *TempFileOrErr, ResultFD&: FD))
703 return errorCodeToError(EC);
704
705 auto OS = std::make_unique<llvm::raw_fd_ostream>(args&: FD, args: true);
706
707 legacy::PassManager CodeGenPasses;
708 TargetLibraryInfoImpl TLII(M.getTargetTriple());
709 CodeGenPasses.add(P: new TargetLibraryInfoWrapperPass(TLII));
710 if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr,
711 CodeGenFileType::ObjectFile))
712 return createStringError(Fmt: "Failed to execute host backend");
713 CodeGenPasses.run(M);
714
715 return *TempFileOrErr;
716}
717
718/// Performs the wrapping stage with individual tool invocations for verbose
719/// printing.
720Expected<StringRef>
721wrapDeviceImagesVerbose(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
722 const ArgList &Args, OffloadKind Kind) {
723 Expected<std::string> WrapperPath = findProgram(
724 Name: "llvm-offload-wrapper", Paths: {getExecutableDir(Name: "llvm-offload-wrapper")});
725 if (!WrapperPath)
726 return WrapperPath.takeError();
727
728 llvm::Triple Triple(
729 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
730
731 // Generate the runtime registration bitcode from the bundled images.
732 auto BitcodeOrErr = createOutputFile(
733 Prefix: ExecutableName + "." + getOffloadKindName(Name: Kind) + ".image.wrapper", Extension: "bc");
734 if (!BitcodeOrErr)
735 return BitcodeOrErr.takeError();
736
737 SmallVector<StringRef> WrapperArgs = {
738 *WrapperPath,
739 Args.MakeArgString(Str: "--kind=" + getOffloadKindName(Name: Kind)),
740 Args.MakeArgString(Str: "--triple=" + Triple.getTriple()),
741 "-o",
742 *BitcodeOrErr,
743 };
744 if (Kind == OFK_OpenMP && Args.hasArg(Ids: OPT_relocatable))
745 WrapperArgs.push_back(Elt: "--relocatable");
746 for (const auto &Buffer : Buffers)
747 WrapperArgs.push_back(Elt: Buffer->getBufferIdentifier());
748
749 if (Error Err = executeCommands(ExecutablePath: *WrapperPath, Args: WrapperArgs))
750 return std::move(Err);
751
752 // Compile the generated registration bitcode into a host object.
753 Expected<std::string> ClangPath =
754 findProgram(Name: "clang", Paths: {getExecutableDir(Name: "clang")});
755 if (!ClangPath)
756 return ClangPath.takeError();
757
758 auto ObjectOrErr = createOutputFile(
759 Prefix: ExecutableName + "." + getOffloadKindName(Name: Kind) + ".image.wrapper", Extension: "o");
760 if (!ObjectOrErr)
761 return ObjectOrErr.takeError();
762
763 const StringRef ClangArgs[] = {
764 *ClangPath,
765 "--no-default-config",
766 Args.MakeArgString(Str: "--target=" + Triple.getTriple()),
767 "-c",
768 "-fPIC",
769 "-o",
770 *ObjectOrErr,
771 *BitcodeOrErr,
772 };
773 if (Error Err = executeCommands(ExecutablePath: *ClangPath, Args: ClangArgs))
774 return std::move(Err);
775
776 return *ObjectOrErr;
777}
778
779/// Creates the object file containing the device image and runtime
780/// registration code from the device images stored in \p Images.
781Expected<StringRef>
782wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
783 const ArgList &Args, OffloadKind Kind) {
784 llvm::TimeTraceScope TimeScope("Wrap bundled images");
785
786 // We use the discrete tools if we are in verbose mode with '--save-temps'.
787 if (Verbose && SaveTemps && !Args.hasArg(Ids: OPT_print_wrapped_module))
788 return wrapDeviceImagesVerbose(Buffers, Args, Kind);
789
790 SmallVector<ArrayRef<char>, 4> BuffersToWrap;
791 for (const auto &Buffer : Buffers)
792 BuffersToWrap.emplace_back(
793 Args: ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize()));
794
795 LLVMContext Context;
796 Module M("offload.wrapper.module", Context);
797 Triple TheTriple(
798 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
799 M.setTargetTriple(TheTriple);
800 M.setDataLayout(TheTriple.computeDataLayout());
801
802 switch (Kind) {
803 case OFK_OpenMP:
804 if (Error Err = offloading::wrapOpenMPBinaries(
805 M, Images: BuffersToWrap, EntryArray: offloading::getOffloadEntryArray(M),
806 /*Suffix=*/"", /*Relocatable=*/Args.hasArg(Ids: OPT_relocatable)))
807 return std::move(Err);
808 break;
809 case OFK_Cuda:
810 if (Error Err = offloading::wrapCudaBinary(
811 M, Images: BuffersToWrap.front(), EntryArray: offloading::getOffloadEntryArray(M),
812 /*Suffix=*/"", /*EmitSurfacesAndTextures=*/false))
813 return std::move(Err);
814 break;
815 case OFK_HIP:
816 if (Error Err = offloading::wrapHIPBinary(
817 M, Images: BuffersToWrap.front(), EntryArray: offloading::getOffloadEntryArray(M)))
818 return std::move(Err);
819 break;
820 case OFK_SYCL: {
821 // TODO: fill these options once the Driver supports them.
822 offloading::SYCLJITOptions Options;
823 if (Error Err =
824 offloading::wrapSYCLBinaries(M, Buffer: BuffersToWrap.front(), Options))
825 return std::move(Err);
826 break;
827 }
828 default:
829 return createStringError(S: getOffloadKindName(Name: Kind) +
830 " wrapping is not supported");
831 }
832
833 if (Args.hasArg(Ids: OPT_print_wrapped_module))
834 errs() << M;
835 if (Args.hasArg(Ids: OPT_save_temps)) {
836 int FD = -1;
837 auto TempFileOrErr = createOutputFile(
838 Prefix: ExecutableName + "." + getOffloadKindName(Name: Kind) + ".image.wrapper",
839 Extension: "bc");
840 if (!TempFileOrErr)
841 return TempFileOrErr.takeError();
842 if (std::error_code EC = sys::fs::openFileForWrite(Name: *TempFileOrErr, ResultFD&: FD))
843 return errorCodeToError(EC);
844 llvm::raw_fd_ostream OS(FD, true);
845 WriteBitcodeToFile(M, Out&: OS);
846 }
847
848 auto FileOrErr = compileModule(M, Kind);
849 if (!FileOrErr)
850 return FileOrErr.takeError();
851 return *FileOrErr;
852}
853
854/// Perform the OpenMP bundling with 'llvm-offload-binary' in verbose mode.
855Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
856bundleOpenMPVerbose(ArrayRef<OffloadingImage> Images) {
857 Expected<std::string> OffloadBinaryPath = findProgram(
858 Name: "llvm-offload-binary", Paths: {getExecutableDir(Name: "llvm-offload-binary")});
859 if (!OffloadBinaryPath)
860 return OffloadBinaryPath.takeError();
861
862 BumpPtrAllocator Alloc;
863 StringSaver Saver(Alloc);
864 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
865 for (const OffloadingImage &Image : Images) {
866 StringRef ImageFile = Image.Image->getBufferIdentifier();
867 auto BinaryOrErr =
868 createOutputFile(Prefix: sys::path::stem(path: ImageFile) + "." +
869 getOffloadKindName(Name: Image.TheOffloadKind),
870 Extension: "offload");
871 if (!BinaryOrErr)
872 return BinaryOrErr.takeError();
873
874 std::string ImageArg = ("--image=file=" + ImageFile +
875 ",kind=" + getOffloadKindName(Name: Image.TheOffloadKind))
876 .str();
877 for (const auto &[Key, Value] : Image.StringData)
878 ImageArg += ("," + Key + "=" + Value).str();
879
880 SmallVector<StringRef> CmdArgs = {*OffloadBinaryPath, "-o", *BinaryOrErr,
881 Saver.save(S: ImageArg)};
882 if (Error Err = executeCommands(ExecutablePath: *OffloadBinaryPath, Args: CmdArgs))
883 return std::move(Err);
884
885 auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename: *BinaryOrErr);
886 if (std::error_code EC = BufferOrErr.getError()) {
887 if (DryRun)
888 BufferOrErr = MemoryBuffer::getMemBuffer(InputData: "", BufferName: *BinaryOrErr);
889 else
890 return createFileError(F: *BinaryOrErr, EC);
891 }
892 Buffers.emplace_back(Args: std::move(*BufferOrErr));
893 }
894
895 return std::move(Buffers);
896}
897
898Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
899bundleOpenMP(ArrayRef<OffloadingImage> Images) {
900 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
901 for (const OffloadingImage &Image : Images)
902 Buffers.emplace_back(
903 Args: MemoryBuffer::getMemBufferCopy(InputData: OffloadBinary::write(OffloadingData: Image)));
904
905 return std::move(Buffers);
906}
907
908Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
909bundleSYCL(ArrayRef<OffloadingImage> Images) {
910 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
911 for (const OffloadingImage &Image : Images) {
912 // clang-sycl-linker packs outputs into one binary blob. Therefore, it is
913 // passed to Offload Wrapper as is.
914 StringRef S(Image.Image->getBufferStart(), Image.Image->getBufferSize());
915 Buffers.emplace_back(
916 Args: MemoryBuffer::getMemBufferCopy(InputData: S, BufferName: Image.Image->getBufferIdentifier()));
917 }
918
919 return std::move(Buffers);
920}
921
922Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
923bundleCuda(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
924 SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles;
925 for (const OffloadingImage &Image : Images)
926 InputFiles.emplace_back(Args: std::make_pair(x: Image.Image->getBufferIdentifier(),
927 y: Image.StringData.lookup(Key: "arch")));
928
929 auto FileOrErr = nvptx::fatbinary(InputFiles, Args);
930 if (!FileOrErr)
931 return FileOrErr.takeError();
932
933 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError =
934 llvm::MemoryBuffer::getFileOrSTDIN(Filename: *FileOrErr);
935
936 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
937 if (std::error_code EC = ImageOrError.getError()) {
938 if (DryRun)
939 ImageOrError = MemoryBuffer::getMemBuffer(InputData: "", BufferName: *FileOrErr);
940 else
941 return createFileError(F: *FileOrErr, EC);
942 }
943 Buffers.emplace_back(Args: std::move(*ImageOrError));
944
945 return std::move(Buffers);
946}
947
948Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
949bundleHIP(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
950 SmallVector<std::tuple<StringRef, StringRef, StringRef>, 4> InputFiles;
951 for (const OffloadingImage &Image : Images)
952 InputFiles.emplace_back(Args: std::make_tuple(args: Image.Image->getBufferIdentifier(),
953 args: Image.StringData.lookup(Key: "triple"),
954 args: Image.StringData.lookup(Key: "arch")));
955
956 auto FileOrErr = amdgcn::fatbinary(InputFiles, Args);
957 if (!FileOrErr)
958 return FileOrErr.takeError();
959
960 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError =
961 llvm::MemoryBuffer::getFileOrSTDIN(Filename: *FileOrErr);
962
963 SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
964 if (std::error_code EC = ImageOrError.getError()) {
965 if (DryRun)
966 ImageOrError = MemoryBuffer::getMemBuffer(InputData: "", BufferName: *FileOrErr);
967 else
968 return createFileError(F: *FileOrErr, EC);
969 }
970 Buffers.emplace_back(Args: std::move(*ImageOrError));
971
972 return std::move(Buffers);
973}
974
975/// Transforms the input \p Images into the binary format the runtime expects
976/// for the given \p Kind.
977Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
978bundleLinkedOutput(ArrayRef<OffloadingImage> Images, const ArgList &Args,
979 OffloadKind Kind) {
980 llvm::TimeTraceScope TimeScope("Bundle linked output");
981 if (usesLLVMOffloadWrapper(Images))
982 return bundleOpenMP(Images);
983
984 switch (Kind) {
985 case OFK_OpenMP:
986 return (Verbose && SaveTemps) ? bundleOpenMPVerbose(Images)
987 : bundleOpenMP(Images);
988 case OFK_SYCL:
989 return bundleSYCL(Images);
990 case OFK_Cuda:
991 return bundleCuda(Images, Args);
992 case OFK_HIP:
993 return bundleHIP(Images, Args);
994 default:
995 return createStringError(S: getOffloadKindName(Name: Kind) +
996 " bundling is not supported");
997 }
998}
999
1000/// Returns a new ArgList containing arguments used for the device linking
1001/// phase.
1002DerivedArgList getLinkerArgs(ArrayRef<OffloadFile> Input,
1003 const InputArgList &Args) {
1004 DerivedArgList DAL(Args);
1005 for (Arg *A : Args)
1006 DAL.append(A);
1007
1008 // Set the subarchitecture and target triple for this compilation.
1009 const OptTable &Tbl = getOptTable();
1010 StringRef Arch = Args.MakeArgString(Str: Input.front().getBinary()->getArch());
1011 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_arch_EQ),
1012 Value: Arch == "generic" ? "" : Arch);
1013 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_triple_EQ),
1014 Value: Args.MakeArgString(Str: Input.front().getBinary()->getTriple()));
1015
1016 // If every input file is bitcode we have whole program visibility as we
1017 // do only support static linking with bitcode.
1018 auto ContainsBitcode = [](const OffloadFile &F) {
1019 return identify_magic(magic: F.getBinary()->getImage()) == file_magic::bitcode;
1020 };
1021 if (llvm::all_of(Range&: Input, P: ContainsBitcode))
1022 DAL.AddFlagArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_whole_program));
1023
1024 llvm::Triple CurrentTT(DAL.getLastArgValue(Id: OPT_triple_EQ));
1025
1026 // Forward '-Xoffload-linker' options to the appropriate backend.
1027 for (StringRef Arg : Args.getAllArgValues(Id: OPT_device_linker_args_EQ)) {
1028 auto [Triple, Value] = Arg.split(Separator: '=');
1029 llvm::Triple TT(Triple);
1030 // If this isn't a recognized triple then it's an `arg=value` option.
1031 if (TT.getArch() == Triple::ArchType::UnknownArch)
1032 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_linker_arg_EQ),
1033 Value: Args.MakeArgString(Str: Arg));
1034 else if (Value.empty())
1035 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_linker_arg_EQ),
1036 Value: Args.MakeArgString(Str: Triple));
1037 else if (TT.isCompatibleWith(Other: CurrentTT))
1038 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_linker_arg_EQ),
1039 Value: Args.MakeArgString(Str: Value));
1040 }
1041
1042 // Forward '-Xoffload-compiler' options to the appropriate backend.
1043 for (StringRef Arg : Args.getAllArgValues(Id: OPT_device_compiler_args_EQ)) {
1044 auto [Triple, Value] = Arg.split(Separator: '=');
1045 llvm::Triple TT(Triple);
1046 // If this isn't a recognized triple then it's an `arg=value` option.
1047 if (TT.getArch() == Triple::ArchType::UnknownArch)
1048 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_compiler_arg_EQ),
1049 Value: Args.MakeArgString(Str: Arg));
1050 else if (Value.empty())
1051 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_compiler_arg_EQ),
1052 Value: Args.MakeArgString(Str: Triple));
1053 else if (TT.isCompatibleWith(Other: CurrentTT))
1054 DAL.AddJoinedArg(BaseArg: nullptr, Opt: Tbl.getOption(Opt: OPT_compiler_arg_EQ),
1055 Value: Args.MakeArgString(Str: Value));
1056 }
1057
1058 return DAL;
1059}
1060
1061Error handleOverrideImages(
1062 const InputArgList &Args,
1063 MapVector<OffloadKind, SmallVector<OffloadingImage, 0>> &Images) {
1064 for (StringRef Arg : Args.getAllArgValues(Id: OPT_override_image)) {
1065 OffloadKind Kind = getOffloadKind(Name: Arg.split(Separator: "=").first);
1066 StringRef Filename = Arg.split(Separator: "=").second;
1067
1068 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
1069 MemoryBuffer::getFileOrSTDIN(Filename);
1070 if (std::error_code EC = BufferOrErr.getError())
1071 return createFileError(F: Filename, EC);
1072
1073 Expected<std::unique_ptr<ObjectFile>> ElfOrErr =
1074 ObjectFile::createELFObjectFile(Object: **BufferOrErr,
1075 /*InitContent=*/false);
1076 if (!ElfOrErr)
1077 return ElfOrErr.takeError();
1078 ObjectFile &Elf = **ElfOrErr;
1079
1080 OffloadingImage TheImage{};
1081 TheImage.TheImageKind = IMG_Object;
1082 TheImage.TheOffloadKind = Kind;
1083 TheImage.StringData["triple"] =
1084 Args.MakeArgString(Str: Elf.makeTriple().getTriple());
1085 if (std::optional<StringRef> CPU = Elf.tryGetCPUName())
1086 TheImage.StringData["arch"] = Args.MakeArgString(Str: *CPU);
1087 TheImage.Image = std::move(*BufferOrErr);
1088
1089 Images[Kind].emplace_back(Args: std::move(TheImage));
1090 }
1091 return Error::success();
1092}
1093
1094/// Transforms all the extracted offloading input files into an image that can
1095/// be registered by the runtime. If NeedsWrapping is false, writes bundled
1096/// output directly without wrapping or host linking.
1097Expected<SmallVector<StringRef>>
1098linkAndWrapDeviceFiles(ArrayRef<SmallVector<OffloadFile>> LinkerInputFiles,
1099 const InputArgList &Args, char **Argv, int Argc,
1100 bool NeedsWrapping) {
1101 llvm::TimeTraceScope TimeScope("Handle all device input");
1102
1103 std::mutex ImageMtx;
1104 MapVector<OffloadKind, SmallVector<OffloadingImage, 0>> Images;
1105
1106 // Initialize the images with any overriding inputs.
1107 if (Args.hasArg(Ids: OPT_override_image))
1108 if (Error Err = handleOverrideImages(Args, Images))
1109 return std::move(Err);
1110
1111 auto Err = parallelForEachError(R&: LinkerInputFiles, Fn: [&](auto &Input) -> Error {
1112 llvm::TimeTraceScope TimeScope("Link device input");
1113
1114 // Each thread needs its own copy of the base arguments to maintain
1115 // per-device argument storage of synthetic strings.
1116 const OptTable &Tbl = getOptTable();
1117 BumpPtrAllocator Alloc;
1118 StringSaver Saver(Alloc);
1119 auto BaseArgs =
1120 Tbl.parseArgs(Argc, Argv, Unknown: OPT_INVALID, Saver, ErrorFn: [](StringRef Err) {
1121 reportError(E: createStringError(S: Err));
1122 });
1123 auto LinkerArgs = getLinkerArgs(Input, BaseArgs);
1124
1125 uint16_t ActiveOffloadKindMask = 0u;
1126 for (const auto &File : Input)
1127 ActiveOffloadKindMask |= File.getBinary()->getOffloadKind();
1128
1129 // Linking images of SYCL offload kind with images of other kind is not
1130 // supported.
1131 // TODO: Remove the above limitation.
1132 if ((ActiveOffloadKindMask & OFK_SYCL) &&
1133 ((ActiveOffloadKindMask ^ OFK_SYCL) != 0))
1134 return createStringError(Fmt: "Linking images of SYCL offload kind with "
1135 "images of any other kind is not supported");
1136
1137 // Write any remaining device inputs to an output file.
1138 SmallVector<StringRef> InputFiles;
1139 for (const OffloadFile &File : Input) {
1140 auto FileNameOrErr = writeOffloadFile(File);
1141 if (!FileNameOrErr)
1142 return FileNameOrErr.takeError();
1143 InputFiles.emplace_back(Args&: *FileNameOrErr);
1144 }
1145
1146 // Link the remaining device files using the device linker.
1147 auto OutputOrErr =
1148 linkDevice(InputFiles, LinkerArgs, ActiveOffloadKindMask);
1149 if (!OutputOrErr)
1150 return OutputOrErr.takeError();
1151
1152 // Store the offloading image for each linked output file.
1153 for (OffloadKind Kind = OFK_OpenMP; Kind != OFK_LAST;
1154 Kind = static_cast<OffloadKind>((uint16_t)(Kind) << 1)) {
1155 if ((ActiveOffloadKindMask & Kind) == 0)
1156 continue;
1157 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
1158 llvm::MemoryBuffer::getFileOrSTDIN(Filename: *OutputOrErr);
1159 if (std::error_code EC = FileOrErr.getError()) {
1160 if (DryRun)
1161 FileOrErr = MemoryBuffer::getMemBuffer("", *OutputOrErr);
1162 else
1163 return createFileError(*OutputOrErr, EC);
1164 }
1165
1166 // Manually containerize offloading images not in ELF format.
1167 if (Error E = containerizeRawImage(*FileOrErr, Kind, LinkerArgs))
1168 return E;
1169
1170 std::scoped_lock<decltype(ImageMtx)> Guard(ImageMtx);
1171 OffloadingImage TheImage{};
1172 TheImage.TheImageKind =
1173 Args.hasArg(Ids: OPT_embed_bitcode) ? IMG_Bitcode : IMG_Object;
1174 TheImage.TheOffloadKind = Kind;
1175 TheImage.StringData["triple"] =
1176 Args.MakeArgString(Str: LinkerArgs.getLastArgValue(OPT_triple_EQ));
1177 TheImage.StringData["arch"] =
1178 Args.MakeArgString(Str: LinkerArgs.getLastArgValue(OPT_arch_EQ));
1179 TheImage.Image = std::move(*FileOrErr);
1180
1181 Images[Kind].emplace_back(Args: std::move(TheImage));
1182 }
1183 return Error::success();
1184 });
1185 if (Err)
1186 return std::move(Err);
1187
1188 // Create a binary image of each offloading image and either embed it into a
1189 // new object file, or if all inputs were direct offload binaries, emit the
1190 // fat binary directly (e.g. .hipfb / .fatbin).
1191 SmallVector<StringRef> WrappedOutput;
1192 for (auto &[Kind, Input] : Images) {
1193 // We sort the entries before bundling so they appear in a deterministic
1194 // order in the final binary.
1195 llvm::sort(C&: Input, Comp: [](OffloadingImage &A, OffloadingImage &B) {
1196 StringRef TripleA = A.StringData.lookup(Key: "triple");
1197 StringRef TripleB = B.StringData.lookup(Key: "triple");
1198 StringRef ArchA = A.StringData.lookup(Key: "arch");
1199 StringRef ArchB = B.StringData.lookup(Key: "arch");
1200 if (TripleA != TripleB)
1201 return TripleA > TripleB;
1202 if (ArchA != ArchB)
1203 return ArchA > ArchB;
1204 return A.TheOffloadKind < B.TheOffloadKind;
1205 });
1206 auto BundledImagesOrErr = bundleLinkedOutput(Images: Input, Args, Kind);
1207 if (!BundledImagesOrErr)
1208 return BundledImagesOrErr.takeError();
1209
1210 if (!NeedsWrapping) {
1211 if (BundledImagesOrErr->size() != 1)
1212 return createStringError(
1213 Fmt: "Expected a single bundled image for direct fat binary output");
1214
1215 Expected<std::unique_ptr<FileOutputBuffer>> FOBOrErr =
1216 FileOutputBuffer::create(
1217 FilePath: ExecutableName, Size: BundledImagesOrErr->front()->getBufferSize());
1218 if (!FOBOrErr)
1219 return FOBOrErr.takeError();
1220 std::unique_ptr<FileOutputBuffer> FOB = std::move(*FOBOrErr);
1221 llvm::copy(Range: BundledImagesOrErr->front()->getBuffer(),
1222 Out: FOB->getBufferStart());
1223 if (Error E = FOB->commit())
1224 return std::move(E);
1225
1226 continue;
1227 }
1228
1229 OffloadKind WrapperKind = usesLLVMOffloadWrapper(Images: Input) ? OFK_OpenMP : Kind;
1230 auto OutputOrErr = wrapDeviceImages(Buffers: *BundledImagesOrErr, Args, Kind: WrapperKind);
1231 if (!OutputOrErr)
1232 return OutputOrErr.takeError();
1233 WrappedOutput.push_back(Elt: *OutputOrErr);
1234 }
1235
1236 return WrappedOutput;
1237}
1238
1239std::optional<std::string> findFile(StringRef Dir, StringRef Root,
1240 const Twine &Name) {
1241 SmallString<128> Path;
1242 if (Dir.starts_with(Prefix: "="))
1243 sys::path::append(path&: Path, a: Root, b: Dir.substr(Start: 1), c: Name);
1244 else
1245 sys::path::append(path&: Path, a: Dir, b: Name);
1246
1247 if (sys::fs::exists(Path))
1248 return static_cast<std::string>(Path);
1249 return std::nullopt;
1250}
1251
1252std::optional<std::string>
1253findFromSearchPaths(StringRef Name, StringRef Root,
1254 ArrayRef<StringRef> SearchPaths) {
1255 for (StringRef Dir : SearchPaths)
1256 if (std::optional<std::string> File = findFile(Dir, Root, Name))
1257 return File;
1258 return std::nullopt;
1259}
1260
1261std::optional<std::string>
1262searchLibraryBaseName(StringRef Name, StringRef Root,
1263 ArrayRef<StringRef> SearchPaths, bool IsWindows) {
1264 SmallVector<std::string> Candidates;
1265 if (IsWindows)
1266 Candidates = {"lib" + Name.str() + ".dll.a", Name.str() + ".dll.a",
1267 "lib" + Name.str() + ".a", Name.str() + ".lib"};
1268 else
1269 Candidates = {"lib" + Name.str() + ".so", "lib" + Name.str() + ".a"};
1270
1271 for (StringRef Dir : SearchPaths)
1272 for (StringRef Candidate : Candidates)
1273 if (std::optional<std::string> File = findFile(Dir, Root, Name: Candidate))
1274 return File;
1275 return std::nullopt;
1276}
1277
1278/// Search for static libraries in the linker's library path given input like
1279/// `-lfoo` or `-l:libfoo.a`.
1280std::optional<std::string> searchLibrary(StringRef Input, StringRef Root,
1281 ArrayRef<StringRef> SearchPaths,
1282 bool IsWindows) {
1283 if (Input.starts_with(Prefix: ":"))
1284 return findFromSearchPaths(Name: Input.drop_front(), Root, SearchPaths);
1285 if (Input.ends_with(Suffix: ".lib"))
1286 return findFromSearchPaths(Name: Input, Root, SearchPaths);
1287 return searchLibraryBaseName(Name: Input, Root, SearchPaths, IsWindows);
1288}
1289
1290/// Search for an input file given by name, e.g. `foo.lib`. COFF linkers use
1291/// this in place of `-lfoo` and look it up in \p SearchPaths.
1292std::optional<std::string> searchInput(StringRef Input, StringRef Root,
1293 ArrayRef<StringRef> SearchPaths) {
1294 if (sys::fs::exists(Path: Input))
1295 return std::string(Input);
1296 return findFromSearchPaths(Name: Input, Root, SearchPaths);
1297}
1298
1299/// In verbose mode we need to replay the extracted files so the user can
1300/// reproduce the generated. This only prints the steps that would result in the
1301/// same output files given the input.
1302Error emitExtractCommands(
1303 ArrayRef<SmallVector<OffloadFile>> InputsForTarget,
1304 const DenseMap<StringRef, StringRef> &SourceForImage) {
1305 Expected<std::string> OffloadBinaryPath = findProgram(
1306 Name: "llvm-offload-binary", Paths: {getExecutableDir(Name: "llvm-offload-binary")});
1307 if (!OffloadBinaryPath)
1308 return OffloadBinaryPath.takeError();
1309
1310 BumpPtrAllocator Alloc;
1311 StringSaver Saver(Alloc);
1312 MapVector<StringRef, SmallVector<StringRef>> Commands;
1313 DenseSet<StringRef> Seen;
1314 for (const auto &Input : InputsForTarget) {
1315 for (const OffloadFile &File : Input) {
1316 const OffloadBinary &Binary = *File.getBinary();
1317 StringRef Identifier = Binary.getMemoryBufferRef().getBufferIdentifier();
1318 StringRef Source = SourceForImage.lookup(Val: Identifier);
1319 if (Source.empty())
1320 Source = Identifier;
1321
1322 auto OutputOrErr =
1323 createOutputFile(Prefix: sys::path::stem(path: Identifier) + "-" +
1324 Binary.getTriple() + "-" + Binary.getArch(),
1325 Extension: "o");
1326 if (!OutputOrErr)
1327 return OutputOrErr.takeError();
1328
1329 std::string ImageArg =
1330 ("--image=kind=" + getOffloadKindName(Name: Binary.getOffloadKind()) +
1331 ",triple=" + Binary.getTriple())
1332 .str();
1333 if (!Binary.getArch().empty())
1334 ImageArg += (",arch=" + Binary.getArch()).str();
1335 file_magic Magic;
1336 if (!identify_magic(path: Source, result&: Magic) && Magic == file_magic::archive)
1337 ImageArg += (",member=" + sys::path::filename(path: Identifier)).str();
1338 ImageArg += (",file=" + *OutputOrErr).str();
1339
1340 // Shared images only need to be extracted once per source.
1341 StringRef SavedImage = Saver.save(S: ImageArg);
1342 if (!Seen.insert(V: Saver.save(S: Source + "\x01" + SavedImage)).second)
1343 continue;
1344 Commands[Source].push_back(Elt: SavedImage);
1345 }
1346 }
1347
1348 for (const auto &[Source, Images] : Commands) {
1349 SmallVector<StringRef> CmdArgs = {*OffloadBinaryPath, Source};
1350 llvm::append_range(C&: CmdArgs, R: Images);
1351 printCommands(CmdArgs);
1352 }
1353 return Error::success();
1354}
1355
1356/// Search the input files and libraries for embedded device offloading code
1357/// and add it to the list of files to be linked. Files coming from static
1358/// libraries are only added to the input if they are used by an existing
1359/// input file. Returns a list of input files intended for a single linking job.
1360Expected<SmallVector<SmallVector<OffloadFile>>>
1361getDeviceInput(const ArgList &Args) {
1362 llvm::TimeTraceScope TimeScope("ExtractDeviceCode");
1363
1364 // Skip all the input if the user is overriding the output.
1365 if (Args.hasArg(Ids: OPT_override_image))
1366 return SmallVector<SmallVector<OffloadFile>>();
1367
1368 const llvm::Triple HostTriple(
1369 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
1370
1371 StringRef Root = Args.getLastArgValue(Id: OPT_sysroot_EQ);
1372 SmallVector<StringRef> LibraryPaths;
1373 for (const opt::Arg *Arg : Args.filtered(Ids: OPT_library_path, Ids: OPT_libpath))
1374 LibraryPaths.push_back(Elt: Arg->getValue());
1375
1376 // Only `link.exe` style linkers search for their input files.
1377 SmallVector<StringRef> InputPaths;
1378 for (const opt::Arg *Arg : Args.filtered(Ids: OPT_libpath))
1379 InputPaths.push_back(Elt: Arg->getValue());
1380
1381 BumpPtrAllocator Alloc;
1382 StringSaver Saver(Alloc);
1383
1384 // Try to extract device code from the linker input files.
1385 bool WholeArchive = Args.hasArg(Ids: OPT_wholearchive_flag);
1386 SmallVector<OffloadFile> ObjectFilesToExtract;
1387 SmallVector<OffloadFile> ArchiveFilesToExtract;
1388 DenseMap<StringRef, StringRef> SourceForImage;
1389 for (const opt::Arg *Arg :
1390 Args.filtered(Ids: OPT_INPUT, Ids: OPT_library, Ids: OPT_wholearchive_file,
1391 Ids: OPT_whole_archive, Ids: OPT_no_whole_archive)) {
1392 if (Arg->getOption().matches(ID: OPT_whole_archive) ||
1393 Arg->getOption().matches(ID: OPT_no_whole_archive)) {
1394 WholeArchive = Arg->getOption().matches(ID: OPT_whole_archive);
1395 continue;
1396 }
1397
1398 std::optional<std::string> Filename =
1399 Arg->getOption().matches(ID: OPT_library)
1400 ? searchLibrary(Input: Arg->getValue(), Root, SearchPaths: LibraryPaths,
1401 IsWindows: HostTriple.isOSWindows())
1402 : searchInput(Input: Arg->getValue(), Root, SearchPaths: InputPaths);
1403
1404 if (!Filename && Arg->getOption().matches(ID: OPT_library))
1405 return createStringError(Fmt: "unable to find library -l%s", Vals: Arg->getValue());
1406
1407 if (!Filename || !sys::fs::exists(Path: *Filename) ||
1408 sys::fs::is_directory(Path: *Filename))
1409 continue;
1410
1411 // Unlike `--whole-archive`, `/wholearchive:` applies to a single library.
1412 bool ExtractWholeArchive =
1413 WholeArchive || Arg->getOption().matches(ID: OPT_wholearchive_file);
1414
1415 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
1416 MemoryBuffer::getFileOrSTDIN(Filename: *Filename);
1417 if (std::error_code EC = BufferOrErr.getError())
1418 return createFileError(F: *Filename, EC);
1419
1420 MemoryBufferRef Buffer = **BufferOrErr;
1421 if (identify_magic(magic: Buffer.getBuffer()) == file_magic::elf_shared_object)
1422 continue;
1423
1424 SmallVector<OffloadFile> Binaries;
1425 if (Error Err = extractOffloadBinaries(Buffer, Binaries))
1426 return std::move(Err);
1427
1428 for (auto &Binary : Binaries) {
1429 if (Verbose && SaveTemps)
1430 SourceForImage.try_emplace(
1431 Key: Binary.getBinary()->getMemoryBufferRef().getBufferIdentifier(),
1432 Args: Saver.save(S: StringRef(*Filename)));
1433 if (identify_magic(magic: Buffer.getBuffer()) == file_magic::archive &&
1434 !ExtractWholeArchive)
1435 ArchiveFilesToExtract.emplace_back(Args: std::move(Binary));
1436 else
1437 ObjectFilesToExtract.emplace_back(Args: std::move(Binary));
1438 }
1439 }
1440
1441 // Handle the most specific target-ids first so a generic input merges last.
1442 llvm::stable_sort(Range&: ObjectFilesToExtract,
1443 C: [](const OffloadFile &A, const OffloadFile &B) {
1444 return A.getBinary()->getArch().count(C: ':') >
1445 B.getBinary()->getArch().count(C: ':');
1446 });
1447
1448 // Link all standard input files and update the list of symbols.
1449 MapVector<OffloadFile::TargetID, SmallVector<OffloadFile, 0>> InputFiles;
1450 for (OffloadFile &Binary : ObjectFilesToExtract) {
1451 if (!Binary.getBinary())
1452 continue;
1453
1454 OffloadFile::TargetID Target = Binary;
1455 SmallVector<OffloadFile::TargetID> CompatibleTargets;
1456 for (const auto &[ID, Input] : InputFiles)
1457 if (object::areTargetsEquivalent(LHS: Target, RHS: ID))
1458 CompatibleTargets.emplace_back(Args: ID);
1459
1460 // Seed a new image when no existing target can provide for this input.
1461 if (CompatibleTargets.empty())
1462 CompatibleTargets.emplace_back(Args&: Target);
1463
1464 for (const auto &[Index, ID] : llvm::enumerate(First&: CompatibleTargets)) {
1465 // If another target needs this binary it must be copied instead.
1466 if (Index == CompatibleTargets.size() - 1)
1467 InputFiles[ID].emplace_back(Args: std::move(Binary));
1468 else
1469 InputFiles[ID].emplace_back(Args: Binary.copy());
1470 }
1471 }
1472
1473 llvm::DenseSet<StringRef> ShouldExtract;
1474 for (StringRef Arg : Args.getAllArgValues(Id: OPT_should_extract))
1475 ShouldExtract.insert(V: Saver.save(S: Arg));
1476
1477 // We only extract archive members from the fat binary if we find a used or
1478 // requested target. Unlike normal static archive handling, we just extract
1479 // every object file contained in the archive.
1480 for (OffloadFile &Binary : ArchiveFilesToExtract) {
1481 if (!Binary.getBinary())
1482 continue;
1483
1484 SmallVector<OffloadFile::TargetID> CompatibleTargets = {Binary};
1485 for (const auto &[ID, Input] : InputFiles)
1486 if (OffloadFile::TargetID(Binary) != ID &&
1487 object::areTargetsCompatible(Provided: Binary, Requested: ID))
1488 CompatibleTargets.emplace_back(Args: ID);
1489
1490 for (const auto &[Index, ID] : llvm::enumerate(First&: CompatibleTargets)) {
1491 // Only extract if we have an object matching this target or it
1492 // was specifically requested.
1493 if (!InputFiles.count(Key: ID) && !ShouldExtract.contains(V: ID.second))
1494 continue;
1495
1496 // If another target needs this binary it must be copied instead.
1497 if (Index == CompatibleTargets.size() - 1)
1498 InputFiles[ID].emplace_back(Args: std::move(Binary));
1499 else
1500 InputFiles[ID].emplace_back(Args: Binary.copy());
1501 }
1502 }
1503
1504 SmallVector<SmallVector<OffloadFile>> InputsForTarget;
1505 for (auto &[ID, Input] : InputFiles)
1506 InputsForTarget.emplace_back(Args: std::move(Input));
1507
1508 if (Verbose && SaveTemps)
1509 if (Error Err = emitExtractCommands(InputsForTarget, SourceForImage))
1510 return std::move(Err);
1511
1512 return std::move(InputsForTarget);
1513}
1514
1515} // namespace
1516
1517int main(int Argc, char **Argv) {
1518 InitLLVM X(Argc, Argv);
1519 InitializeAllTargetInfos();
1520 InitializeAllTargets();
1521 InitializeAllTargetMCs();
1522 InitializeAllAsmParsers();
1523 InitializeAllAsmPrinters();
1524
1525 LinkerExecutable = Argv[0];
1526 sys::PrintStackTraceOnErrorSignal(Argv0: Argv[0]);
1527
1528 const OptTable &Tbl = getOptTable();
1529 BumpPtrAllocator Alloc;
1530 StringSaver Saver(Alloc);
1531 auto Args = Tbl.parseArgs(Argc, Argv, Unknown: OPT_INVALID, Saver, ErrorFn: [&](StringRef Err) {
1532 reportError(E: createStringError(S: Err));
1533 });
1534
1535 if (Args.hasArg(Ids: OPT_help) || Args.hasArg(Ids: OPT_help_hidden)) {
1536 Tbl.printHelp(
1537 OS&: outs(),
1538 Usage: "clang-linker-wrapper [options] -- <options to pass to the linker>",
1539 Title: "\nA wrapper utility over the host linker. It scans the input files\n"
1540 "for sections that require additional processing prior to linking.\n"
1541 "It will then transparently pass all arguments and input to the\n"
1542 "specified host linker to create the final binary.\n",
1543 ShowHidden: Args.hasArg(Ids: OPT_help_hidden), ShowAllAliases: Args.hasArg(Ids: OPT_help_hidden));
1544 return EXIT_SUCCESS;
1545 }
1546 if (Args.hasArg(Ids: OPT_version)) {
1547 printVersion(OS&: outs());
1548 return EXIT_SUCCESS;
1549 }
1550
1551 // This forwards '-mllvm' arguments to LLVM if present.
1552 SmallVector<const char *> NewArgv = {Argv[0]};
1553 for (const opt::Arg *Arg : Args.filtered(Ids: OPT_mllvm))
1554 NewArgv.push_back(Elt: Arg->getValue());
1555 for (const opt::Arg *Arg : Args.filtered(Ids: OPT_offload_opt_eq_minus))
1556 NewArgv.push_back(Elt: Arg->getValue());
1557 SmallVector<PassPlugin, 1> PluginList;
1558 PassPlugins.setCallback([&](const std::string &PluginPath) {
1559 auto Plugin = PassPlugin::Load(Filename: PluginPath);
1560 if (!Plugin)
1561 reportFatalUsageError(Err: Plugin.takeError());
1562 PluginList.emplace_back(Args&: Plugin.get());
1563 });
1564 cl::ParseCommandLineOptions(argc: NewArgv.size(), argv: &NewArgv[0]);
1565
1566 Verbose = Args.hasArg(Ids: OPT_verbose);
1567 DryRun = Args.hasArg(Ids: OPT_dry_run);
1568 SaveTemps = Args.hasArg(Ids: OPT_save_temps);
1569 CudaBinaryPath = Args.getLastArgValue(Id: OPT_cuda_path_EQ).str();
1570 CanonicalPrefixes = !Args.hasArg(Ids: OPT_no_canonical_prefixes);
1571
1572 llvm::Triple Triple(
1573 Args.getLastArgValue(Id: OPT_host_triple_EQ, Default: sys::getDefaultTargetTriple()));
1574 if (Args.hasArg(Ids: OPT_o))
1575 ExecutableName = Args.getLastArgValue(Id: OPT_o, Default: "a.out");
1576 else if (Args.hasArg(Ids: OPT_out))
1577 ExecutableName = Args.getLastArgValue(Id: OPT_out, Default: "a.exe");
1578 else
1579 ExecutableName = Triple.isOSWindows() ? "a.exe" : "a.out";
1580
1581 parallel::strategy = hardware_concurrency(ThreadCount: 1);
1582 if (auto *Arg = Args.getLastArg(Ids: OPT_wrapper_jobs)) {
1583 StringRef Val = Arg->getValue();
1584 if (Val.equals_insensitive(RHS: "jobserver"))
1585 parallel::strategy = jobserver_concurrency();
1586 else {
1587 unsigned Threads = 0;
1588 if (!llvm::to_integer(S: Val, Num&: Threads) || Threads == 0)
1589 reportError(E: createStringError(
1590 Fmt: "%s: expected a positive integer or 'jobserver', got '%s'",
1591 Vals: Arg->getSpelling().data(), Vals: Val.data()));
1592 else
1593 parallel::strategy = hardware_concurrency(ThreadCount: Threads);
1594 }
1595 }
1596
1597 if (Args.hasArg(Ids: OPT_wrapper_time_trace_eq)) {
1598 unsigned Granularity;
1599 if (Args.getLastArgValue(Id: OPT_wrapper_time_trace_granularity, Default: "500")
1600 .getAsInteger(Radix: 10, Result&: Granularity))
1601 reportError(
1602 E: createStringError(Fmt: "invalid value for time trace granularity"));
1603 timeTraceProfilerInitialize(TimeTraceGranularity: Granularity, ProcName: Argv[0]);
1604 }
1605
1606 {
1607 llvm::TimeTraceScope TimeScope("Execute linker wrapper");
1608
1609 // Extract the device input files stored in the host fat binary.
1610 auto DeviceInputFiles = getDeviceInput(Args);
1611 if (!DeviceInputFiles)
1612 reportError(E: DeviceInputFiles.takeError());
1613
1614 // Check if we should emit fat binary directly without wrapping or host
1615 // linking.
1616 bool EmitFatbinOnly = Args.hasArg(Ids: OPT_emit_fatbin_only);
1617
1618 // Link and process the device images. The function may emit a direct fat
1619 // binary if --emit-fatbin-only is specified.
1620 auto FilesOrErr = linkAndWrapDeviceFiles(LinkerInputFiles: *DeviceInputFiles, Args, Argv,
1621 Argc, NeedsWrapping: !EmitFatbinOnly);
1622 if (!FilesOrErr)
1623 reportError(E: FilesOrErr.takeError());
1624
1625 // Run the host linking job with the rendered arguments.
1626 if (!EmitFatbinOnly) {
1627 if (Error Err = runLinker(Files: *FilesOrErr, Args))
1628 reportError(E: std::move(Err));
1629 }
1630 }
1631
1632 if (const opt::Arg *Arg = Args.getLastArg(Ids: OPT_wrapper_time_trace_eq)) {
1633 if (Error Err = timeTraceProfilerWrite(PreferredFileName: Arg->getValue(), FallbackFileName: ExecutableName))
1634 reportError(E: std::move(Err));
1635 timeTraceProfilerCleanup();
1636 }
1637
1638 // Remove the temporary files created.
1639 if (!SaveTemps)
1640 for (const auto &TempFile : TempFiles)
1641 if (std::error_code EC = sys::fs::remove(path: TempFile))
1642 reportError(E: createFileError(F: TempFile, EC));
1643
1644 return EXIT_SUCCESS;
1645}
1646