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