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