1 //===-- clang-linker-wrapper/ClangLinkerWrapper.cpp - wrapper over linker-===//
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 "OffloadWrapper.h"
18 #include "clang/Basic/Version.h"
19 #include "llvm/BinaryFormat/Magic.h"
20 #include "llvm/Bitcode/BitcodeWriter.h"
21 #include "llvm/CodeGen/CommandFlags.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/DiagnosticPrinter.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/IRReader/IRReader.h"
26 #include "llvm/LTO/LTO.h"
27 #include "llvm/MC/TargetRegistry.h"
28 #include "llvm/Object/Archive.h"
29 #include "llvm/Object/ArchiveWriter.h"
30 #include "llvm/Object/Binary.h"
31 #include "llvm/Object/ELFObjectFile.h"
32 #include "llvm/Object/IRObjectFile.h"
33 #include "llvm/Object/ObjectFile.h"
34 #include "llvm/Object/OffloadBinary.h"
35 #include "llvm/Option/ArgList.h"
36 #include "llvm/Option/OptTable.h"
37 #include "llvm/Option/Option.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/Errc.h"
40 #include "llvm/Support/FileOutputBuffer.h"
41 #include "llvm/Support/FileSystem.h"
42 #include "llvm/Support/Host.h"
43 #include "llvm/Support/InitLLVM.h"
44 #include "llvm/Support/MemoryBuffer.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/WithColor.h"
52 #include "llvm/Support/raw_ostream.h"
53 #include "llvm/Target/TargetMachine.h"
54 
55 using namespace llvm;
56 using namespace llvm::opt;
57 using namespace llvm::object;
58 
59 /// Path of the current binary.
60 static const char *LinkerExecutable;
61 
62 /// Ssave intermediary results.
63 static bool SaveTemps = false;
64 
65 /// Print arguments without executing.
66 static bool DryRun = false;
67 
68 /// Print verbose output.
69 static bool Verbose = false;
70 
71 /// Filename of the executable being created.
72 static StringRef ExecutableName;
73 
74 /// Binary path for the CUDA installation.
75 static std::string CudaBinaryPath;
76 
77 /// Temporary files created by the linker wrapper.
78 static std::list<SmallString<128>> TempFiles;
79 
80 /// Codegen flags for LTO backend.
81 static codegen::RegisterCodeGenFlags CodeGenFlags;
82 
83 /// Global flag to indicate that the LTO pipeline threw an error.
84 static std::atomic<bool> LTOError;
85 
86 using OffloadingImage = OffloadBinary::OffloadingImage;
87 
88 /// A class to contain the binary information for a single OffloadBinary.
89 class OffloadFile : public OwningBinary<OffloadBinary> {
90 public:
91   using TargetID = std::pair<StringRef, StringRef>;
92 
OffloadFile(std::unique_ptr<OffloadBinary> Binary,std::unique_ptr<MemoryBuffer> Buffer)93   OffloadFile(std::unique_ptr<OffloadBinary> Binary,
94               std::unique_ptr<MemoryBuffer> Buffer)
95       : OwningBinary<OffloadBinary>(std::move(Binary), std::move(Buffer)) {}
96 
97   /// We use the Triple and Architecture pair to group linker inputs together.
98   /// This conversion function lets us use these files in a hash-map.
operator TargetID() const99   operator TargetID() const {
100     return std::make_pair(getBinary()->getTriple(), getBinary()->getArch());
101   }
102 };
103 
104 namespace llvm {
105 // Provide DenseMapInfo so that OffloadKind can be used in a DenseMap.
106 template <> struct DenseMapInfo<OffloadKind> {
getEmptyKeyllvm::DenseMapInfo107   static inline OffloadKind getEmptyKey() { return OFK_LAST; }
getTombstoneKeyllvm::DenseMapInfo108   static inline OffloadKind getTombstoneKey() {
109     return static_cast<OffloadKind>(OFK_LAST + 1);
110   }
getHashValuellvm::DenseMapInfo111   static unsigned getHashValue(const OffloadKind &Val) { return Val; }
112 
isEqualllvm::DenseMapInfo113   static bool isEqual(const OffloadKind &LHS, const OffloadKind &RHS) {
114     return LHS == RHS;
115   }
116 };
117 } // namespace llvm
118 
119 namespace {
120 using std::error_code;
121 
122 /// Must not overlap with llvm::opt::DriverFlag.
123 enum WrapperFlags {
124   WrapperOnlyOption = (1 << 4), // Options only used by the linker wrapper.
125   DeviceOnlyOption = (1 << 5),  // Options only used for device linking.
126 };
127 
128 enum ID {
129   OPT_INVALID = 0, // This is not an option ID.
130 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
131                HELPTEXT, METAVAR, VALUES)                                      \
132   OPT_##ID,
133 #include "LinkerWrapperOpts.inc"
134   LastOption
135 #undef OPTION
136 };
137 
138 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
139 #include "LinkerWrapperOpts.inc"
140 #undef PREFIX
141 
142 static const OptTable::Info InfoTable[] = {
143 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
144                HELPTEXT, METAVAR, VALUES)                                      \
145   {PREFIX, NAME,  HELPTEXT,    METAVAR,     OPT_##ID,  Option::KIND##Class,    \
146    PARAM,  FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
147 #include "LinkerWrapperOpts.inc"
148 #undef OPTION
149 };
150 
151 class WrapperOptTable : public opt::OptTable {
152 public:
WrapperOptTable()153   WrapperOptTable() : OptTable(InfoTable) {}
154 };
155 
getOptTable()156 const OptTable &getOptTable() {
157   static const WrapperOptTable *Table = []() {
158     auto Result = std::make_unique<WrapperOptTable>();
159     return Result.release();
160   }();
161   return *Table;
162 }
163 
164 Error extractFromBuffer(std::unique_ptr<MemoryBuffer> Buffer,
165                         SmallVectorImpl<OffloadFile> &DeviceFiles);
166 
printCommands(ArrayRef<StringRef> CmdArgs)167 void printCommands(ArrayRef<StringRef> CmdArgs) {
168   if (CmdArgs.empty())
169     return;
170 
171   llvm::errs() << " \"" << CmdArgs.front() << "\" ";
172   for (auto IC = std::next(CmdArgs.begin()), IE = CmdArgs.end(); IC != IE; ++IC)
173     llvm::errs() << *IC << (std::next(IC) != IE ? " " : "\n");
174 }
175 
reportError(Error E)176 [[noreturn]] void reportError(Error E) {
177   outs().flush();
178   logAllUnhandledErrors(std::move(E),
179                         WithColor::error(errs(), LinkerExecutable));
180   exit(EXIT_FAILURE);
181 }
182 
183 /// Create an extra user-specified \p OffloadFile.
184 /// TODO: We should find a way to wrap these as libraries instead.
getInputBitcodeLibrary(StringRef Input)185 Expected<OffloadFile> getInputBitcodeLibrary(StringRef Input) {
186   auto DeviceAndPath = StringRef(Input).split('=');
187   auto StringAndArch = DeviceAndPath.first.rsplit('-');
188   auto KindAndTriple = StringAndArch.first.split('-');
189 
190   llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> ImageOrError =
191       llvm::MemoryBuffer::getFileOrSTDIN(DeviceAndPath.second);
192   if (std::error_code EC = ImageOrError.getError())
193     return createFileError(DeviceAndPath.second, EC);
194 
195   OffloadingImage Image{};
196   Image.TheImageKind = IMG_Bitcode;
197   Image.TheOffloadKind = getOffloadKind(KindAndTriple.first);
198   Image.StringData = {{"triple", KindAndTriple.second},
199                       {"arch", StringAndArch.second}};
200   Image.Image = std::move(*ImageOrError);
201 
202   std::unique_ptr<MemoryBuffer> Binary = OffloadBinary::write(Image);
203   auto NewBinaryOrErr = OffloadBinary::create(*Binary);
204   if (!NewBinaryOrErr)
205     return NewBinaryOrErr.takeError();
206   return OffloadFile(std::move(*NewBinaryOrErr), std::move(Binary));
207 }
208 
getMainExecutable(const char * Name)209 std::string getMainExecutable(const char *Name) {
210   void *Ptr = (void *)(intptr_t)&getMainExecutable;
211   auto COWPath = sys::fs::getMainExecutable(Name, Ptr);
212   return sys::path::parent_path(COWPath).str();
213 }
214 
215 /// Get a temporary filename suitable for output.
createOutputFile(const Twine & Prefix,StringRef Extension)216 Expected<StringRef> createOutputFile(const Twine &Prefix, StringRef Extension) {
217   SmallString<128> OutputFile;
218   if (SaveTemps) {
219     (Prefix + "." + Extension).toNullTerminatedStringRef(OutputFile);
220   } else {
221     if (std::error_code EC =
222             sys::fs::createTemporaryFile(Prefix, Extension, OutputFile))
223       return createFileError(OutputFile, EC);
224   }
225 
226   TempFiles.emplace_back(std::move(OutputFile));
227   return TempFiles.back();
228 }
229 
230 /// Execute the command \p ExecutablePath with the arguments \p Args.
executeCommands(StringRef ExecutablePath,ArrayRef<StringRef> Args)231 Error executeCommands(StringRef ExecutablePath, ArrayRef<StringRef> Args) {
232   if (Verbose || DryRun)
233     printCommands(Args);
234 
235   if (!DryRun)
236     if (sys::ExecuteAndWait(ExecutablePath, Args))
237       return createStringError(inconvertibleErrorCode(),
238                                "'" + sys::path::filename(ExecutablePath) + "'" +
239                                    " failed");
240   return Error::success();
241 }
242 
findProgram(StringRef Name,ArrayRef<StringRef> Paths)243 Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) {
244 
245   ErrorOr<std::string> Path = sys::findProgramByName(Name, Paths);
246   if (!Path)
247     Path = sys::findProgramByName(Name);
248   if (!Path && DryRun)
249     return Name.str();
250   if (!Path)
251     return createStringError(Path.getError(),
252                              "Unable to find '" + Name + "' in path");
253   return *Path;
254 }
255 
256 /// Runs the wrapped linker job with the newly created input.
runLinker(ArrayRef<StringRef> Files,const ArgList & Args)257 Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
258   llvm::TimeTraceScope TimeScope("Execute host linker");
259 
260   // Render the linker arguments and add the newly created image. We add it
261   // after the output file to ensure it is linked with the correct libraries.
262   StringRef LinkerPath = Args.getLastArgValue(OPT_linker_path_EQ);
263   ArgStringList NewLinkerArgs;
264   for (const opt::Arg *Arg : Args) {
265     // Do not forward arguments only intended for the linker wrapper.
266     if (Arg->getOption().hasFlag(WrapperOnlyOption))
267       continue;
268 
269     Arg->render(Args, NewLinkerArgs);
270     if (Arg->getOption().matches(OPT_o))
271       llvm::transform(Files, std::back_inserter(NewLinkerArgs),
272                       [&](StringRef Arg) { return Args.MakeArgString(Arg); });
273   }
274 
275   SmallVector<StringRef> LinkerArgs({LinkerPath});
276   for (StringRef Arg : NewLinkerArgs)
277     LinkerArgs.push_back(Arg);
278   if (Error Err = executeCommands(LinkerPath, LinkerArgs))
279     return Err;
280   return Error::success();
281 }
282 
printVersion(raw_ostream & OS)283 void printVersion(raw_ostream &OS) {
284   OS << clang::getClangToolFullVersion("clang-linker-wrapper") << '\n';
285 }
286 
287 /// Attempts to extract all the embedded device images contained inside the
288 /// buffer \p Contents. The buffer is expected to contain a valid offloading
289 /// binary format.
extractOffloadFiles(MemoryBufferRef Contents,SmallVectorImpl<OffloadFile> & DeviceFiles)290 Error extractOffloadFiles(MemoryBufferRef Contents,
291                           SmallVectorImpl<OffloadFile> &DeviceFiles) {
292   uint64_t Offset = 0;
293   // There could be multiple offloading binaries stored at this section.
294   while (Offset < Contents.getBuffer().size()) {
295     std::unique_ptr<MemoryBuffer> Buffer =
296         MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "",
297                                    /*RequiresNullTerminator*/ false);
298     auto BinaryOrErr = OffloadBinary::create(*Buffer);
299     if (!BinaryOrErr)
300       return BinaryOrErr.takeError();
301     OffloadBinary &Binary = **BinaryOrErr;
302 
303     // Create a new owned binary with a copy of the original memory.
304     std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy(
305         Binary.getData().take_front(Binary.getSize()),
306         Contents.getBufferIdentifier());
307     auto NewBinaryOrErr = OffloadBinary::create(*BufferCopy);
308     if (!NewBinaryOrErr)
309       return NewBinaryOrErr.takeError();
310     DeviceFiles.emplace_back(std::move(*NewBinaryOrErr), std::move(BufferCopy));
311 
312     Offset += Binary.getSize();
313   }
314 
315   return Error::success();
316 }
317 
318 // Extract offloading binaries from an Object file \p Obj.
extractFromBinary(const ObjectFile & Obj,SmallVectorImpl<OffloadFile> & DeviceFiles)319 Error extractFromBinary(const ObjectFile &Obj,
320                         SmallVectorImpl<OffloadFile> &DeviceFiles) {
321   for (ELFSectionRef Sec : Obj.sections()) {
322     if (Sec.getType() != ELF::SHT_LLVM_OFFLOADING)
323       continue;
324 
325     Expected<StringRef> Buffer = Sec.getContents();
326     if (!Buffer)
327       return Buffer.takeError();
328 
329     MemoryBufferRef Contents(*Buffer, Obj.getFileName());
330     if (Error Err = extractOffloadFiles(Contents, DeviceFiles))
331       return Err;
332   }
333 
334   return Error::success();
335 }
336 
extractFromBitcode(std::unique_ptr<MemoryBuffer> Buffer,SmallVectorImpl<OffloadFile> & DeviceFiles)337 Error extractFromBitcode(std::unique_ptr<MemoryBuffer> Buffer,
338                          SmallVectorImpl<OffloadFile> &DeviceFiles) {
339   LLVMContext Context;
340   SMDiagnostic Err;
341   std::unique_ptr<Module> M = getLazyIRModule(std::move(Buffer), Err, Context);
342   if (!M)
343     return createStringError(inconvertibleErrorCode(),
344                              "Failed to create module");
345 
346   // Extract offloading data from globals referenced by the
347   // `llvm.embedded.object` metadata with the `.llvm.offloading` section.
348   auto *MD = M->getNamedMetadata("llvm.embedded.objects");
349   if (!MD)
350     return Error::success();
351 
352   for (const MDNode *Op : MD->operands()) {
353     if (Op->getNumOperands() < 2)
354       continue;
355 
356     MDString *SectionID = dyn_cast<MDString>(Op->getOperand(1));
357     if (!SectionID || SectionID->getString() != ".llvm.offloading")
358       continue;
359 
360     GlobalVariable *GV =
361         mdconst::dyn_extract_or_null<GlobalVariable>(Op->getOperand(0));
362     if (!GV)
363       continue;
364 
365     auto *CDS = dyn_cast<ConstantDataSequential>(GV->getInitializer());
366     if (!CDS)
367       continue;
368 
369     MemoryBufferRef Contents(CDS->getAsString(), M->getName());
370     if (Error Err = extractOffloadFiles(Contents, DeviceFiles))
371       return Err;
372   }
373 
374   return Error::success();
375 }
376 
extractFromArchive(const Archive & Library,SmallVectorImpl<OffloadFile> & DeviceFiles)377 Error extractFromArchive(const Archive &Library,
378                          SmallVectorImpl<OffloadFile> &DeviceFiles) {
379   // Try to extract device code from each file stored in the static archive.
380   Error Err = Error::success();
381   for (auto Child : Library.children(Err)) {
382     auto ChildBufferOrErr = Child.getMemoryBufferRef();
383     if (!ChildBufferOrErr)
384       return ChildBufferOrErr.takeError();
385     std::unique_ptr<MemoryBuffer> ChildBuffer =
386         MemoryBuffer::getMemBuffer(*ChildBufferOrErr, false);
387 
388     // Check if the buffer has the required alignment.
389     if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
390                        ChildBuffer->getBufferStart()))
391       ChildBuffer = MemoryBuffer::getMemBufferCopy(
392           ChildBufferOrErr->getBuffer(),
393           ChildBufferOrErr->getBufferIdentifier());
394 
395     if (Error Err = extractFromBuffer(std::move(ChildBuffer), DeviceFiles))
396       return Err;
397   }
398 
399   if (Err)
400     return Err;
401   return Error::success();
402 }
403 
404 /// Extracts embedded device offloading code from a memory \p Buffer to a list
405 /// of \p DeviceFiles.
extractFromBuffer(std::unique_ptr<MemoryBuffer> Buffer,SmallVectorImpl<OffloadFile> & DeviceFiles)406 Error extractFromBuffer(std::unique_ptr<MemoryBuffer> Buffer,
407                         SmallVectorImpl<OffloadFile> &DeviceFiles) {
408   file_magic Type = identify_magic(Buffer->getBuffer());
409   switch (Type) {
410   case file_magic::bitcode:
411     return extractFromBitcode(std::move(Buffer), DeviceFiles);
412   case file_magic::elf_relocatable: {
413     Expected<std::unique_ptr<ObjectFile>> ObjFile =
414         ObjectFile::createObjectFile(*Buffer, Type);
415     if (!ObjFile)
416       return ObjFile.takeError();
417     return extractFromBinary(*ObjFile->get(), DeviceFiles);
418   }
419   case file_magic::archive: {
420     Expected<std::unique_ptr<llvm::object::Archive>> LibFile =
421         object::Archive::create(*Buffer);
422     if (!LibFile)
423       return LibFile.takeError();
424     return extractFromArchive(*LibFile->get(), DeviceFiles);
425   }
426   default:
427     return Error::success();
428   }
429 }
430 
431 namespace nvptx {
assemble(StringRef InputFile,const ArgList & Args,bool RDC=true)432 Expected<StringRef> assemble(StringRef InputFile, const ArgList &Args,
433                              bool RDC = true) {
434   llvm::TimeTraceScope TimeScope("NVPTX Assembler");
435   // NVPTX uses the ptxas binary to create device object files.
436   Expected<std::string> PtxasPath = findProgram("ptxas", {CudaBinaryPath});
437   if (!PtxasPath)
438     return PtxasPath.takeError();
439 
440   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
441   StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
442   // Create a new file to write the linked device image to. Assume that the
443   // input filename already has the device and architecture.
444   auto TempFileOrErr = createOutputFile(sys::path::stem(InputFile), "cubin");
445   if (!TempFileOrErr)
446     return TempFileOrErr.takeError();
447 
448   SmallVector<StringRef, 16> CmdArgs;
449   StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2");
450   CmdArgs.push_back(*PtxasPath);
451   CmdArgs.push_back(Triple.isArch64Bit() ? "-m64" : "-m32");
452   if (Verbose)
453     CmdArgs.push_back("-v");
454   for (StringRef Arg : Args.getAllArgValues(OPT_ptxas_arg))
455     CmdArgs.push_back(Args.MakeArgString(Arg));
456   CmdArgs.push_back("-o");
457   CmdArgs.push_back(*TempFileOrErr);
458   CmdArgs.push_back(Args.MakeArgString("-" + OptLevel));
459   CmdArgs.push_back("--gpu-name");
460   CmdArgs.push_back(Arch);
461   if (Args.hasArg(OPT_debug))
462     CmdArgs.push_back("-g");
463   if (RDC)
464     CmdArgs.push_back("-c");
465 
466   CmdArgs.push_back(InputFile);
467 
468   if (Error Err = executeCommands(*PtxasPath, CmdArgs))
469     return std::move(Err);
470 
471   return *TempFileOrErr;
472 }
473 
link(ArrayRef<StringRef> InputFiles,const ArgList & Args)474 Expected<StringRef> link(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
475   llvm::TimeTraceScope TimeScope("NVPTX linker");
476   // NVPTX uses the nvlink binary to link device object files.
477   Expected<std::string> NvlinkPath = findProgram("nvlink", {CudaBinaryPath});
478   if (!NvlinkPath)
479     return NvlinkPath.takeError();
480 
481   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
482   StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
483 
484   // Create a new file to write the linked device image to.
485   auto TempFileOrErr =
486       createOutputFile(sys::path::filename(ExecutableName) + "-device-" +
487                            Triple.getArchName() + "-" + Arch,
488                        "out");
489   if (!TempFileOrErr)
490     return TempFileOrErr.takeError();
491 
492   SmallVector<StringRef, 16> CmdArgs;
493   CmdArgs.push_back(*NvlinkPath);
494   CmdArgs.push_back(Triple.isArch64Bit() ? "-m64" : "-m32");
495   if (Args.hasArg(OPT_debug))
496     CmdArgs.push_back("-g");
497   if (Verbose)
498     CmdArgs.push_back("-v");
499   CmdArgs.push_back("-o");
500   CmdArgs.push_back(*TempFileOrErr);
501   CmdArgs.push_back("-arch");
502   CmdArgs.push_back(Arch);
503 
504   // Add extracted input files.
505   for (StringRef Input : InputFiles)
506     CmdArgs.push_back(Input);
507 
508   for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ))
509     CmdArgs.push_back(Args.MakeArgString(Arg));
510   if (Error Err = executeCommands(*NvlinkPath, CmdArgs))
511     return std::move(Err);
512 
513   return *TempFileOrErr;
514 }
515 
516 Expected<StringRef>
fatbinary(ArrayRef<std::pair<StringRef,StringRef>> InputFiles,const ArgList & Args)517 fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,
518           const ArgList &Args) {
519   llvm::TimeTraceScope TimeScope("NVPTX fatbinary");
520   // NVPTX uses the fatbinary program to bundle the linked images.
521   Expected<std::string> FatBinaryPath =
522       findProgram("fatbinary", {CudaBinaryPath});
523   if (!FatBinaryPath)
524     return FatBinaryPath.takeError();
525 
526   llvm::Triple Triple(
527       Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
528 
529   // Create a new file to write the linked device image to.
530   auto TempFileOrErr = createOutputFile(
531       sys::path::filename(ExecutableName) + "-device", "fatbin");
532   if (!TempFileOrErr)
533     return TempFileOrErr.takeError();
534 
535   SmallVector<StringRef, 16> CmdArgs;
536   CmdArgs.push_back(*FatBinaryPath);
537   CmdArgs.push_back(Triple.isArch64Bit() ? "-64" : "-32");
538   CmdArgs.push_back("--create");
539   CmdArgs.push_back(*TempFileOrErr);
540   for (const auto &FileAndArch : InputFiles)
541     CmdArgs.push_back(
542         Args.MakeArgString("--image=profile=" + std::get<1>(FileAndArch) +
543                            ",file=" + std::get<0>(FileAndArch)));
544 
545   if (Error Err = executeCommands(*FatBinaryPath, CmdArgs))
546     return std::move(Err);
547 
548   return *TempFileOrErr;
549 }
550 } // namespace nvptx
551 
552 namespace amdgcn {
link(ArrayRef<StringRef> InputFiles,const ArgList & Args)553 Expected<StringRef> link(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
554   llvm::TimeTraceScope TimeScope("AMDGPU linker");
555   // AMDGPU uses lld to link device object files.
556   Expected<std::string> LLDPath =
557       findProgram("lld", {getMainExecutable("lld")});
558   if (!LLDPath)
559     return LLDPath.takeError();
560 
561   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
562   StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
563 
564   // Create a new file to write the linked device image to.
565   auto TempFileOrErr =
566       createOutputFile(sys::path::filename(ExecutableName) + "-" +
567                            Triple.getArchName() + "-" + Arch,
568                        "out");
569   if (!TempFileOrErr)
570     return TempFileOrErr.takeError();
571   std::string ArchArg = ("-plugin-opt=mcpu=" + Arch).str();
572 
573   SmallVector<StringRef, 16> CmdArgs;
574   CmdArgs.push_back(*LLDPath);
575   CmdArgs.push_back("-flavor");
576   CmdArgs.push_back("gnu");
577   CmdArgs.push_back("--no-undefined");
578   CmdArgs.push_back("-shared");
579   CmdArgs.push_back("-plugin-opt=-amdgpu-internalize-symbols");
580   CmdArgs.push_back(ArchArg);
581   CmdArgs.push_back("-o");
582   CmdArgs.push_back(*TempFileOrErr);
583 
584   // Add extracted input files.
585   for (StringRef Input : InputFiles)
586     CmdArgs.push_back(Input);
587 
588   for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ))
589     CmdArgs.push_back(Args.MakeArgString(Arg));
590   if (Error Err = executeCommands(*LLDPath, CmdArgs))
591     return std::move(Err);
592 
593   return *TempFileOrErr;
594 }
595 
596 Expected<StringRef>
fatbinary(ArrayRef<std::pair<StringRef,StringRef>> InputFiles,const ArgList & Args)597 fatbinary(ArrayRef<std::pair<StringRef, StringRef>> InputFiles,
598           const ArgList &Args) {
599   llvm::TimeTraceScope TimeScope("AMDGPU Fatbinary");
600 
601   // AMDGPU uses the clang-offload-bundler to bundle the linked images.
602   Expected<std::string> OffloadBundlerPath = findProgram(
603       "clang-offload-bundler", {getMainExecutable("clang-offload-bundler")});
604   if (!OffloadBundlerPath)
605     return OffloadBundlerPath.takeError();
606 
607   llvm::Triple Triple(
608       Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
609 
610   // Create a new file to write the linked device image to.
611   auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) +
612                                             "-device-" + Triple.getArchName(),
613                                         "hipfb");
614   if (!TempFileOrErr)
615     return TempFileOrErr.takeError();
616 
617   BumpPtrAllocator Alloc;
618   StringSaver Saver(Alloc);
619 
620   SmallVector<StringRef, 16> CmdArgs;
621   CmdArgs.push_back(*OffloadBundlerPath);
622   CmdArgs.push_back("-type=o");
623   CmdArgs.push_back("-bundle-align=4096");
624 
625   SmallVector<StringRef> Targets = {"-targets=host-x86_64-unknown-linux"};
626   for (const auto &FileAndArch : InputFiles)
627     Targets.push_back(
628         Saver.save("hipv4-amdgcn-amd-amdhsa--" + std::get<1>(FileAndArch)));
629   CmdArgs.push_back(Saver.save(llvm::join(Targets, ",")));
630 
631   CmdArgs.push_back("-input=/dev/null");
632   for (const auto &FileAndArch : InputFiles)
633     CmdArgs.push_back(Saver.save("-input=" + std::get<0>(FileAndArch)));
634 
635   CmdArgs.push_back(Saver.save("-output=" + *TempFileOrErr));
636 
637   if (Error Err = executeCommands(*OffloadBundlerPath, CmdArgs))
638     return std::move(Err);
639 
640   return *TempFileOrErr;
641 }
642 } // namespace amdgcn
643 
644 namespace generic {
645 
getLDMOption(const llvm::Triple & T)646 const char *getLDMOption(const llvm::Triple &T) {
647   switch (T.getArch()) {
648   case llvm::Triple::x86:
649     if (T.isOSIAMCU())
650       return "elf_iamcu";
651     return "elf_i386";
652   case llvm::Triple::aarch64:
653     return "aarch64linux";
654   case llvm::Triple::aarch64_be:
655     return "aarch64linuxb";
656   case llvm::Triple::ppc64:
657     return "elf64ppc";
658   case llvm::Triple::ppc64le:
659     return "elf64lppc";
660   case llvm::Triple::x86_64:
661     if (T.isX32())
662       return "elf32_x86_64";
663     return "elf_x86_64";
664   case llvm::Triple::ve:
665     return "elf64ve";
666   default:
667     return nullptr;
668   }
669 }
670 
link(ArrayRef<StringRef> InputFiles,const ArgList & Args)671 Expected<StringRef> link(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
672   llvm::TimeTraceScope TimeScope("Generic linker");
673   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
674   StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
675 
676   // Create a new file to write the linked device image to.
677   auto TempFileOrErr =
678       createOutputFile(sys::path::filename(ExecutableName) + "-" +
679                            Triple.getArchName() + "-" + Arch,
680                        "out");
681   if (!TempFileOrErr)
682     return TempFileOrErr.takeError();
683 
684   // Use the host linker to perform generic offloading. Use the same libraries
685   // and paths as the host application does.
686   SmallVector<StringRef, 16> CmdArgs;
687   CmdArgs.push_back(Args.getLastArgValue(OPT_linker_path_EQ));
688   CmdArgs.push_back("-m");
689   CmdArgs.push_back(getLDMOption(Triple));
690   CmdArgs.push_back("-shared");
691 
692   ArgStringList LinkerArgs;
693   for (const opt::Arg *Arg : Args) {
694     auto Op = Arg->getOption();
695     if (Op.matches(OPT_library) || Op.matches(OPT_library_path) ||
696         Op.matches(OPT_as_needed) || Op.matches(OPT_no_as_needed) ||
697         Op.matches(OPT_rpath) || Op.matches(OPT_dynamic_linker))
698       Arg->render(Args, LinkerArgs);
699   }
700   for (StringRef Arg : LinkerArgs)
701     CmdArgs.push_back(Arg);
702 
703   CmdArgs.push_back("-Bsymbolic");
704   CmdArgs.push_back("-o");
705   CmdArgs.push_back(*TempFileOrErr);
706 
707   // Add extracted input files.
708   for (StringRef Input : InputFiles)
709     CmdArgs.push_back(Input);
710 
711   for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ))
712     CmdArgs.push_back(Args.MakeArgString(Arg));
713   if (Error Err =
714           executeCommands(Args.getLastArgValue(OPT_linker_path_EQ), CmdArgs))
715     return std::move(Err);
716 
717   return *TempFileOrErr;
718 }
719 } // namespace generic
720 
linkDevice(ArrayRef<StringRef> InputFiles,const ArgList & Args)721 Expected<StringRef> linkDevice(ArrayRef<StringRef> InputFiles,
722                                const ArgList &Args) {
723   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
724   switch (Triple.getArch()) {
725   case Triple::nvptx:
726   case Triple::nvptx64:
727     return nvptx::link(InputFiles, Args);
728   case Triple::amdgcn:
729     return amdgcn::link(InputFiles, Args);
730   case Triple::x86:
731   case Triple::x86_64:
732   case Triple::aarch64:
733   case Triple::aarch64_be:
734   case Triple::ppc64:
735   case Triple::ppc64le:
736     return generic::link(InputFiles, Args);
737   default:
738     return createStringError(inconvertibleErrorCode(),
739                              Triple.getArchName() +
740                                  " linking is not supported");
741   }
742 }
743 
diagnosticHandler(const DiagnosticInfo & DI)744 void diagnosticHandler(const DiagnosticInfo &DI) {
745   std::string ErrStorage;
746   raw_string_ostream OS(ErrStorage);
747   DiagnosticPrinterRawOStream DP(OS);
748   DI.print(DP);
749 
750   switch (DI.getSeverity()) {
751   case DS_Error:
752     WithColor::error(errs(), LinkerExecutable) << ErrStorage << "\n";
753     LTOError = true;
754     break;
755   case DS_Warning:
756     WithColor::warning(errs(), LinkerExecutable) << ErrStorage << "\n";
757     break;
758   case DS_Note:
759     WithColor::note(errs(), LinkerExecutable) << ErrStorage << "\n";
760     break;
761   case DS_Remark:
762     WithColor::remark(errs()) << ErrStorage << "\n";
763     break;
764   }
765 }
766 
767 // Get the list of target features from the input file and unify them such that
768 // if there are multiple +xxx or -xxx features we only keep the last one.
getTargetFeatures(ArrayRef<OffloadFile> InputFiles)769 std::vector<std::string> getTargetFeatures(ArrayRef<OffloadFile> InputFiles) {
770   SmallVector<StringRef> Features;
771   for (const OffloadFile &File : InputFiles) {
772     for (auto Arg : llvm::split(File.getBinary()->getString("feature"), ","))
773       Features.emplace_back(Arg);
774   }
775 
776   // Only add a feature if it hasn't been seen before starting from the end.
777   std::vector<std::string> UnifiedFeatures;
778   DenseSet<StringRef> UsedFeatures;
779   for (StringRef Feature : llvm::reverse(Features)) {
780     if (UsedFeatures.insert(Feature.drop_front()).second)
781       UnifiedFeatures.push_back(Feature.str());
782   }
783 
784   return UnifiedFeatures;
785 }
786 
getCGOptLevel(unsigned OptLevel)787 CodeGenOpt::Level getCGOptLevel(unsigned OptLevel) {
788   switch (OptLevel) {
789   case 0:
790     return CodeGenOpt::None;
791   case 1:
792     return CodeGenOpt::Less;
793   case 2:
794     return CodeGenOpt::Default;
795   case 3:
796     return CodeGenOpt::Aggressive;
797   }
798   llvm_unreachable("Invalid optimization level");
799 }
800 
801 template <typename ModuleHook = function_ref<bool(size_t, const Module &)>>
createLTO(const ArgList & Args,const std::vector<std::string> & Features,ModuleHook Hook=[](size_t,const Module &){})802 std::unique_ptr<lto::LTO> createLTO(
803     const ArgList &Args, const std::vector<std::string> &Features,
804     ModuleHook Hook = [](size_t, const Module &) { return true; }) {
805   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
806   StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
807   lto::Config Conf;
808   lto::ThinBackend Backend;
809   // TODO: Handle index-only thin-LTO
810   Backend =
811       lto::createInProcessThinBackend(llvm::heavyweight_hardware_concurrency());
812 
813   Conf.CPU = Arch.str();
814   Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple);
815 
816   StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2");
817   Conf.MAttrs = Features;
818   Conf.CGOptLevel = getCGOptLevel(OptLevel[1] - '0');
819   Conf.OptLevel = OptLevel[1] - '0';
820   if (Conf.OptLevel > 0)
821     Conf.UseDefaultPipeline = true;
822   Conf.DefaultTriple = Triple.getTriple();
823 
824   LTOError = false;
825   Conf.DiagHandler = diagnosticHandler;
826 
827   Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
828   Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
829 
830   if (SaveTemps) {
831     std::string TempName = (sys::path::filename(ExecutableName) + "-device-" +
832                             Triple.getTriple() + "-" + Arch)
833                                .str();
__anon18832d830502(size_t Task, const Module &M) 834     Conf.PostInternalizeModuleHook = [=](size_t Task, const Module &M) {
835       std::string File = !Task ? TempName + ".bc"
836                                : TempName + "." + std::to_string(Task) + ".bc";
837       error_code EC;
838       raw_fd_ostream LinkedBitcode(File, EC, sys::fs::OF_None);
839       if (EC)
840         reportError(errorCodeToError(EC));
841       WriteBitcodeToFile(M, LinkedBitcode);
842       return true;
843     };
844   }
845   Conf.PostOptModuleHook = Hook;
846   Conf.CGFileType = Triple.isNVPTX() ? CGFT_AssemblyFile : CGFT_ObjectFile;
847 
848   // TODO: Handle remark files
849   Conf.HasWholeProgramVisibility = Args.hasArg(OPT_whole_program);
850 
851   return std::make_unique<lto::LTO>(std::move(Conf), Backend);
852 }
853 
854 // Returns true if \p S is valid as a C language identifier and will be given
855 // `__start_` and `__stop_` symbols.
isValidCIdentifier(StringRef S)856 bool isValidCIdentifier(StringRef S) {
857   return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
858          std::all_of(S.begin() + 1, S.end(),
859                      [](char C) { return C == '_' || isAlnum(C); });
860 }
861 
linkBitcodeFiles(SmallVectorImpl<OffloadFile> & InputFiles,SmallVectorImpl<StringRef> & OutputFiles,const ArgList & Args)862 Error linkBitcodeFiles(SmallVectorImpl<OffloadFile> &InputFiles,
863                        SmallVectorImpl<StringRef> &OutputFiles,
864                        const ArgList &Args) {
865   llvm::TimeTraceScope TimeScope("Link bitcode files");
866   const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
867 
868   SmallVector<OffloadFile, 4> BitcodeInputFiles;
869   DenseSet<StringRef> UsedInRegularObj;
870   DenseSet<StringRef> UsedInSharedLib;
871   BumpPtrAllocator Alloc;
872   StringSaver Saver(Alloc);
873 
874   // Search for bitcode files in the input and create an LTO input file. If it
875   // is not a bitcode file, scan its symbol table for symbols we need to save.
876   for (OffloadFile &File : InputFiles) {
877     MemoryBufferRef Buffer = MemoryBufferRef(File.getBinary()->getImage(), "");
878 
879     file_magic Type = identify_magic(Buffer.getBuffer());
880     switch (Type) {
881     case file_magic::bitcode: {
882       BitcodeInputFiles.emplace_back(std::move(File));
883       continue;
884     }
885     case file_magic::elf_relocatable:
886     case file_magic::elf_shared_object: {
887       Expected<std::unique_ptr<ObjectFile>> ObjFile =
888           ObjectFile::createObjectFile(Buffer);
889       if (!ObjFile)
890         continue;
891 
892       for (SymbolRef Sym : (*ObjFile)->symbols()) {
893         Expected<StringRef> Name = Sym.getName();
894         if (!Name)
895           return Name.takeError();
896 
897         // Record if we've seen these symbols in any object or shared libraries.
898         if ((*ObjFile)->isRelocatableObject())
899           UsedInRegularObj.insert(Saver.save(*Name));
900         else
901           UsedInSharedLib.insert(Saver.save(*Name));
902       }
903       continue;
904     }
905     default:
906       continue;
907     }
908   }
909 
910   if (BitcodeInputFiles.empty())
911     return Error::success();
912 
913   // Remove all the bitcode files that we moved from the original input.
914   llvm::erase_if(InputFiles, [](OffloadFile &F) { return !F.getBinary(); });
915 
916   // LTO Module hook to output bitcode without running the backend.
917   SmallVector<StringRef, 4> BitcodeOutput;
918   auto OutputBitcode = [&](size_t, const Module &M) {
919     auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) +
920                                               "-jit-" + Triple.getTriple(),
921                                           "bc");
922     if (!TempFileOrErr)
923       reportError(TempFileOrErr.takeError());
924 
925     std::error_code EC;
926     raw_fd_ostream LinkedBitcode(*TempFileOrErr, EC, sys::fs::OF_None);
927     if (EC)
928       reportError(errorCodeToError(EC));
929     WriteBitcodeToFile(M, LinkedBitcode);
930     BitcodeOutput.push_back(*TempFileOrErr);
931     return false;
932   };
933 
934   // We assume visibility of the whole program if every input file was bitcode.
935   auto Features = getTargetFeatures(BitcodeInputFiles);
936   auto LTOBackend = Args.hasArg(OPT_embed_bitcode)
937                         ? createLTO(Args, Features, OutputBitcode)
938                         : createLTO(Args, Features);
939 
940   // We need to resolve the symbols so the LTO backend knows which symbols need
941   // to be kept or can be internalized. This is a simplified symbol resolution
942   // scheme to approximate the full resolution a linker would do.
943   uint64_t Idx = 0;
944   DenseSet<StringRef> PrevailingSymbols;
945   for (auto &BitcodeInput : BitcodeInputFiles) {
946     // Get a semi-unique buffer identifier for Thin-LTO.
947     StringRef Identifier = Saver.save(
948         std::to_string(Idx++) + "." +
949         BitcodeInput.getBinary()->getMemoryBufferRef().getBufferIdentifier());
950     MemoryBufferRef Buffer =
951         MemoryBufferRef(BitcodeInput.getBinary()->getImage(), Identifier);
952     Expected<std::unique_ptr<lto::InputFile>> BitcodeFileOrErr =
953         llvm::lto::InputFile::create(Buffer);
954     if (!BitcodeFileOrErr)
955       return BitcodeFileOrErr.takeError();
956 
957     // Save the input file and the buffer associated with its memory.
958     const auto Symbols = (*BitcodeFileOrErr)->symbols();
959     SmallVector<lto::SymbolResolution, 16> Resolutions(Symbols.size());
960     size_t Idx = 0;
961     for (auto &Sym : Symbols) {
962       lto::SymbolResolution &Res = Resolutions[Idx++];
963 
964       // We will use this as the prevailing symbol definition in LTO unless
965       // it is undefined or another definition has already been used.
966       Res.Prevailing =
967           !Sym.isUndefined() &&
968           PrevailingSymbols.insert(Saver.save(Sym.getName())).second;
969 
970       // We need LTO to preseve the following global symbols:
971       // 1) Symbols used in regular objects.
972       // 2) Sections that will be given a __start/__stop symbol.
973       // 3) Prevailing symbols that are needed visible to external libraries.
974       Res.VisibleToRegularObj =
975           UsedInRegularObj.contains(Sym.getName()) ||
976           isValidCIdentifier(Sym.getSectionName()) ||
977           (Res.Prevailing &&
978            (Sym.getVisibility() != GlobalValue::HiddenVisibility &&
979             !Sym.canBeOmittedFromSymbolTable()));
980 
981       // Identify symbols that must be exported dynamically and can be
982       // referenced by other files.
983       Res.ExportDynamic =
984           Sym.getVisibility() != GlobalValue::HiddenVisibility &&
985           (UsedInSharedLib.contains(Sym.getName()) ||
986            !Sym.canBeOmittedFromSymbolTable());
987 
988       // The final definition will reside in this linkage unit if the symbol is
989       // defined and local to the module. This only checks for bitcode files,
990       // full assertion will require complete symbol resolution.
991       Res.FinalDefinitionInLinkageUnit =
992           Sym.getVisibility() != GlobalValue::DefaultVisibility &&
993           (!Sym.isUndefined() && !Sym.isCommon());
994 
995       // We do not support linker redefined symbols (e.g. --wrap) for device
996       // image linking, so the symbols will not be changed after LTO.
997       Res.LinkerRedefined = false;
998     }
999 
1000     // Add the bitcode file with its resolved symbols to the LTO job.
1001     if (Error Err = LTOBackend->add(std::move(*BitcodeFileOrErr), Resolutions))
1002       return Err;
1003   }
1004 
1005   // Run the LTO job to compile the bitcode.
1006   size_t MaxTasks = LTOBackend->getMaxTasks();
1007   SmallVector<StringRef> Files(MaxTasks);
1008   auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
1009     int FD = -1;
1010     auto &TempFile = Files[Task];
1011     StringRef Extension = (Triple.isNVPTX()) ? "s" : "o";
1012     std::string TaskStr = Task ? "." + std::to_string(Task) : "";
1013     auto TempFileOrErr =
1014         createOutputFile(sys::path::filename(ExecutableName) + "-device-" +
1015                              Triple.getTriple() + TaskStr,
1016                          Extension);
1017     if (!TempFileOrErr)
1018       reportError(TempFileOrErr.takeError());
1019     TempFile = *TempFileOrErr;
1020     if (std::error_code EC = sys::fs::openFileForWrite(TempFile, FD))
1021       reportError(errorCodeToError(EC));
1022     return std::make_unique<CachedFileStream>(
1023         std::make_unique<llvm::raw_fd_ostream>(FD, true));
1024   };
1025 
1026   if (Error Err = LTOBackend->run(AddStream))
1027     return Err;
1028 
1029   if (LTOError)
1030     return createStringError(inconvertibleErrorCode(),
1031                              "Errors encountered inside the LTO pipeline.");
1032 
1033   // If we are embedding bitcode we only need the intermediate output.
1034   bool SingleOutput = Files.size() == 1;
1035   if (Args.hasArg(OPT_embed_bitcode)) {
1036     if (BitcodeOutput.size() != 1 || !SingleOutput)
1037       return createStringError(inconvertibleErrorCode(),
1038                                "Cannot embed bitcode with multiple files.");
1039     OutputFiles.push_back(static_cast<std::string>(BitcodeOutput.front()));
1040     return Error::success();
1041   }
1042 
1043   // Is we are compiling for NVPTX we need to run the assembler first.
1044   if (Triple.isNVPTX()) {
1045     for (StringRef &File : Files) {
1046       auto FileOrErr = nvptx::assemble(File, Args, !SingleOutput);
1047       if (!FileOrErr)
1048         return FileOrErr.takeError();
1049       File = *FileOrErr;
1050     }
1051   }
1052 
1053   // Append the new inputs to the device linker input.
1054   for (StringRef File : Files)
1055     OutputFiles.push_back(File);
1056 
1057   return Error::success();
1058 }
1059 
writeOffloadFile(const OffloadFile & File)1060 Expected<StringRef> writeOffloadFile(const OffloadFile &File) {
1061   const OffloadBinary &Binary = *File.getBinary();
1062 
1063   StringRef Prefix =
1064       sys::path::stem(Binary.getMemoryBufferRef().getBufferIdentifier());
1065   StringRef Suffix = getImageKindName(Binary.getImageKind());
1066 
1067   auto TempFileOrErr = createOutputFile(
1068       Prefix + "-" + Binary.getTriple() + "-" + Binary.getArch(), Suffix);
1069   if (!TempFileOrErr)
1070     return TempFileOrErr.takeError();
1071 
1072   Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
1073       FileOutputBuffer::create(*TempFileOrErr, Binary.getImage().size());
1074   if (!OutputOrErr)
1075     return OutputOrErr.takeError();
1076   std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr);
1077   std::copy(Binary.getImage().bytes_begin(), Binary.getImage().bytes_end(),
1078             Output->getBufferStart());
1079   if (Error E = Output->commit())
1080     return std::move(E);
1081 
1082   return *TempFileOrErr;
1083 }
1084 
1085 // Compile the module to an object file using the appropriate target machine for
1086 // the host triple.
compileModule(Module & M)1087 Expected<StringRef> compileModule(Module &M) {
1088   llvm::TimeTraceScope TimeScope("Compile module");
1089   std::string Msg;
1090   const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
1091   if (!T)
1092     return createStringError(inconvertibleErrorCode(), Msg);
1093 
1094   auto Options =
1095       codegen::InitTargetOptionsFromCodeGenFlags(Triple(M.getTargetTriple()));
1096   StringRef CPU = "";
1097   StringRef Features = "";
1098   std::unique_ptr<TargetMachine> TM(
1099       T->createTargetMachine(M.getTargetTriple(), CPU, Features, Options,
1100                              Reloc::PIC_, M.getCodeModel()));
1101 
1102   if (M.getDataLayout().isDefault())
1103     M.setDataLayout(TM->createDataLayout());
1104 
1105   int FD = -1;
1106   auto TempFileOrErr =
1107       createOutputFile(sys::path::filename(ExecutableName) + "-wrapper", "o");
1108   if (!TempFileOrErr)
1109     return TempFileOrErr.takeError();
1110   if (std::error_code EC = sys::fs::openFileForWrite(*TempFileOrErr, FD))
1111     return errorCodeToError(EC);
1112 
1113   auto OS = std::make_unique<llvm::raw_fd_ostream>(FD, true);
1114 
1115   legacy::PassManager CodeGenPasses;
1116   TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple()));
1117   CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
1118   if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr, CGFT_ObjectFile))
1119     return createStringError(inconvertibleErrorCode(),
1120                              "Failed to execute host backend");
1121   CodeGenPasses.run(M);
1122 
1123   return *TempFileOrErr;
1124 }
1125 
1126 /// Creates the object file containing the device image and runtime
1127 /// registration code from the device images stored in \p Images.
1128 Expected<StringRef>
wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,const ArgList & Args,OffloadKind Kind)1129 wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
1130                  const ArgList &Args, OffloadKind Kind) {
1131   llvm::TimeTraceScope TimeScope("Wrap bundled images");
1132 
1133   SmallVector<ArrayRef<char>, 4> BuffersToWrap;
1134   for (const auto &Buffer : Buffers)
1135     BuffersToWrap.emplace_back(
1136         ArrayRef<char>(Buffer->getBufferStart(), Buffer->getBufferSize()));
1137 
1138   LLVMContext Context;
1139   Module M("offload.wrapper.module", Context);
1140   M.setTargetTriple(
1141       Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
1142 
1143   switch (Kind) {
1144   case OFK_OpenMP:
1145     if (Error Err = wrapOpenMPBinaries(M, BuffersToWrap))
1146       return std::move(Err);
1147     break;
1148   case OFK_Cuda:
1149     if (Error Err = wrapCudaBinary(M, BuffersToWrap.front()))
1150       return std::move(Err);
1151     break;
1152   case OFK_HIP:
1153     if (Error Err = wrapHIPBinary(M, BuffersToWrap.front()))
1154       return std::move(Err);
1155     break;
1156   default:
1157     return createStringError(inconvertibleErrorCode(),
1158                              getOffloadKindName(Kind) +
1159                                  " wrapping is not supported");
1160   }
1161 
1162   if (Args.hasArg(OPT_print_wrapped_module))
1163     errs() << M;
1164 
1165   auto FileOrErr = compileModule(M);
1166   if (!FileOrErr)
1167     return FileOrErr.takeError();
1168   return *FileOrErr;
1169 }
1170 
1171 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
bundleOpenMP(ArrayRef<OffloadingImage> Images)1172 bundleOpenMP(ArrayRef<OffloadingImage> Images) {
1173   SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
1174   for (const OffloadingImage &Image : Images)
1175     Buffers.emplace_back(OffloadBinary::write(Image));
1176 
1177   return std::move(Buffers);
1178 }
1179 
1180 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
bundleCuda(ArrayRef<OffloadingImage> Images,const ArgList & Args)1181 bundleCuda(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
1182   SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles;
1183   for (const OffloadingImage &Image : Images)
1184     InputFiles.emplace_back(std::make_pair(Image.Image->getBufferIdentifier(),
1185                                            Image.StringData.lookup("arch")));
1186 
1187   Triple TheTriple = Triple(Images.front().StringData.lookup("triple"));
1188   auto FileOrErr = nvptx::fatbinary(InputFiles, Args);
1189   if (!FileOrErr)
1190     return FileOrErr.takeError();
1191 
1192   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError =
1193       llvm::MemoryBuffer::getFileOrSTDIN(*FileOrErr);
1194 
1195   SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
1196   if (std::error_code EC = ImageOrError.getError())
1197     return createFileError(*FileOrErr, EC);
1198   Buffers.emplace_back(std::move(*ImageOrError));
1199 
1200   return std::move(Buffers);
1201 }
1202 
1203 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
bundleHIP(ArrayRef<OffloadingImage> Images,const ArgList & Args)1204 bundleHIP(ArrayRef<OffloadingImage> Images, const ArgList &Args) {
1205   SmallVector<std::pair<StringRef, StringRef>, 4> InputFiles;
1206   for (const OffloadingImage &Image : Images)
1207     InputFiles.emplace_back(std::make_pair(Image.Image->getBufferIdentifier(),
1208                                            Image.StringData.lookup("arch")));
1209 
1210   Triple TheTriple = Triple(Images.front().StringData.lookup("triple"));
1211   auto FileOrErr = amdgcn::fatbinary(InputFiles, Args);
1212   if (!FileOrErr)
1213     return FileOrErr.takeError();
1214 
1215   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ImageOrError =
1216       llvm::MemoryBuffer::getFileOrSTDIN(*FileOrErr);
1217 
1218   SmallVector<std::unique_ptr<MemoryBuffer>> Buffers;
1219   if (std::error_code EC = ImageOrError.getError())
1220     return createFileError(*FileOrErr, EC);
1221   Buffers.emplace_back(std::move(*ImageOrError));
1222 
1223   return std::move(Buffers);
1224 }
1225 
1226 /// Transforms the input \p Images into the binary format the runtime expects
1227 /// for the given \p Kind.
1228 Expected<SmallVector<std::unique_ptr<MemoryBuffer>>>
bundleLinkedOutput(ArrayRef<OffloadingImage> Images,const ArgList & Args,OffloadKind Kind)1229 bundleLinkedOutput(ArrayRef<OffloadingImage> Images, const ArgList &Args,
1230                    OffloadKind Kind) {
1231   llvm::TimeTraceScope TimeScope("Bundle linked output");
1232   switch (Kind) {
1233   case OFK_OpenMP:
1234     return bundleOpenMP(Images);
1235   case OFK_Cuda:
1236     return bundleCuda(Images, Args);
1237   case OFK_HIP:
1238     return bundleHIP(Images, Args);
1239   default:
1240     return createStringError(inconvertibleErrorCode(),
1241                              getOffloadKindName(Kind) +
1242                                  " bundling is not supported");
1243   }
1244 }
1245 
1246 /// Returns a new ArgList containg arguments used for the device linking phase.
getLinkerArgs(ArrayRef<OffloadFile> Input,const InputArgList & Args)1247 DerivedArgList getLinkerArgs(ArrayRef<OffloadFile> Input,
1248                              const InputArgList &Args) {
1249   DerivedArgList DAL = DerivedArgList(DerivedArgList(Args));
1250   for (Arg *A : Args)
1251     DAL.append(A);
1252 
1253   // Set the subarchitecture and target triple for this compilation.
1254   const OptTable &Tbl = getOptTable();
1255   DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_arch_EQ),
1256                    Args.MakeArgString(Input.front().getBinary()->getArch()));
1257   DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_triple_EQ),
1258                    Args.MakeArgString(Input.front().getBinary()->getTriple()));
1259 
1260   // If every input file is bitcode we have whole program visibility as we do
1261   // only support static linking with bitcode.
1262   auto ContainsBitcode = [](const OffloadFile &F) {
1263     return identify_magic(F.getBinary()->getImage()) == file_magic::bitcode;
1264   };
1265   if (llvm::all_of(Input, ContainsBitcode))
1266     DAL.AddFlagArg(nullptr, Tbl.getOption(OPT_whole_program));
1267 
1268   // Forward '-Xoffload-linker' options to the appropriate backend.
1269   for (StringRef Arg : Args.getAllArgValues(OPT_device_linker_args_EQ)) {
1270     auto TripleAndValue = Arg.split('=');
1271     if (TripleAndValue.second.empty())
1272       DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ),
1273                        Args.MakeArgString(TripleAndValue.first));
1274     else if (TripleAndValue.first == DAL.getLastArgValue(OPT_triple_EQ))
1275       DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ),
1276                        Args.MakeArgString(TripleAndValue.second));
1277   }
1278 
1279   return DAL;
1280 }
1281 
1282 /// Transforms all the extracted offloading input files into an image that can
1283 /// be registered by the runtime.
1284 Expected<SmallVector<StringRef>>
linkAndWrapDeviceFiles(SmallVectorImpl<OffloadFile> & LinkerInputFiles,const InputArgList & Args)1285 linkAndWrapDeviceFiles(SmallVectorImpl<OffloadFile> &LinkerInputFiles,
1286                        const InputArgList &Args) {
1287   llvm::TimeTraceScope TimeScope("Handle all device input");
1288 
1289   DenseMap<OffloadFile::TargetID, SmallVector<OffloadFile, 4>> InputsForTarget;
1290   for (auto &File : LinkerInputFiles)
1291     InputsForTarget[File].emplace_back(std::move(File));
1292   LinkerInputFiles.clear();
1293 
1294   DenseMap<OffloadKind, SmallVector<OffloadingImage, 2>> Images;
1295   for (auto &InputForTarget : InputsForTarget) {
1296     llvm::TimeTraceScope TimeScope("Link device input");
1297 
1298     SmallVector<OffloadFile, 4> &Input = InputForTarget.getSecond();
1299     auto LinkerArgs = getLinkerArgs(Input, Args);
1300 
1301     DenseSet<OffloadKind> ActiveOffloadKinds;
1302     for (const auto &File : Input)
1303       ActiveOffloadKinds.insert(File.getBinary()->getOffloadKind());
1304 
1305     // First link and remove all the input files containing bitcode.
1306     SmallVector<StringRef> InputFiles;
1307     if (Error Err = linkBitcodeFiles(Input, InputFiles, LinkerArgs))
1308       return std::move(Err);
1309 
1310     // Write any remaining device inputs to an output file for the linker job.
1311     for (const OffloadFile &File : Input) {
1312       auto FileNameOrErr = writeOffloadFile(File);
1313       if (!FileNameOrErr)
1314         return FileNameOrErr.takeError();
1315       InputFiles.emplace_back(*FileNameOrErr);
1316     }
1317 
1318     // Link the remaining device files, if necessary, using the device linker.
1319     llvm::Triple Triple(LinkerArgs.getLastArgValue(OPT_triple_EQ));
1320     bool RequiresLinking =
1321         !Args.hasArg(OPT_embed_bitcode) &&
1322         !(Input.empty() && InputFiles.size() == 1 && Triple.isNVPTX());
1323     auto OutputOrErr = RequiresLinking ? linkDevice(InputFiles, LinkerArgs)
1324                                        : InputFiles.front();
1325     if (!OutputOrErr)
1326       return OutputOrErr.takeError();
1327 
1328     // Store the offloading image for each linked output file.
1329     for (OffloadKind Kind : ActiveOffloadKinds) {
1330       llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
1331           llvm::MemoryBuffer::getFileOrSTDIN(*OutputOrErr);
1332       if (std::error_code EC = FileOrErr.getError())
1333         return createFileError(*OutputOrErr, EC);
1334 
1335       OffloadingImage TheImage{};
1336       TheImage.TheImageKind = IMG_Object;
1337       TheImage.TheOffloadKind = Kind;
1338       TheImage.StringData = {
1339           {"triple", LinkerArgs.getLastArgValue(OPT_triple_EQ)},
1340           {"arch", LinkerArgs.getLastArgValue(OPT_arch_EQ)}};
1341       TheImage.Image = std::move(*FileOrErr);
1342       Images[Kind].emplace_back(std::move(TheImage));
1343     }
1344   }
1345 
1346   // Create a binary image of each offloading image and embed it into a new
1347   // object file.
1348   SmallVector<StringRef> WrappedOutput;
1349   for (const auto &KindAndImages : Images) {
1350     OffloadKind Kind = KindAndImages.first;
1351     auto BundledImagesOrErr =
1352         bundleLinkedOutput(KindAndImages.second, Args, Kind);
1353     if (!BundledImagesOrErr)
1354       return BundledImagesOrErr.takeError();
1355     auto OutputOrErr = wrapDeviceImages(*BundledImagesOrErr, Args, Kind);
1356     if (!OutputOrErr)
1357       return OutputOrErr.takeError();
1358     WrappedOutput.push_back(*OutputOrErr);
1359   }
1360 
1361   return WrappedOutput;
1362 }
1363 
findFile(StringRef Dir,StringRef Root,const Twine & Name)1364 Optional<std::string> findFile(StringRef Dir, StringRef Root,
1365                                const Twine &Name) {
1366   SmallString<128> Path;
1367   if (Dir.startswith("="))
1368     sys::path::append(Path, Root, Dir.substr(1), Name);
1369   else
1370     sys::path::append(Path, Dir, Name);
1371 
1372   if (sys::fs::exists(Path))
1373     return static_cast<std::string>(Path);
1374   return None;
1375 }
1376 
findFromSearchPaths(StringRef Name,StringRef Root,ArrayRef<StringRef> SearchPaths)1377 Optional<std::string> findFromSearchPaths(StringRef Name, StringRef Root,
1378                                           ArrayRef<StringRef> SearchPaths) {
1379   for (StringRef Dir : SearchPaths)
1380     if (Optional<std::string> File = findFile(Dir, Root, Name))
1381       return File;
1382   return None;
1383 }
1384 
searchLibraryBaseName(StringRef Name,StringRef Root,ArrayRef<StringRef> SearchPaths)1385 Optional<std::string> searchLibraryBaseName(StringRef Name, StringRef Root,
1386                                             ArrayRef<StringRef> SearchPaths) {
1387   for (StringRef Dir : SearchPaths) {
1388     if (Optional<std::string> File = findFile(Dir, Root, "lib" + Name + ".so"))
1389       return None;
1390     if (Optional<std::string> File = findFile(Dir, Root, "lib" + Name + ".a"))
1391       return File;
1392   }
1393   return None;
1394 }
1395 
1396 /// Search for static libraries in the linker's library path given input like
1397 /// `-lfoo` or `-l:libfoo.a`.
searchLibrary(StringRef Input,StringRef Root,ArrayRef<StringRef> SearchPaths)1398 Optional<std::string> searchLibrary(StringRef Input, StringRef Root,
1399                                     ArrayRef<StringRef> SearchPaths) {
1400   if (Input.startswith(":"))
1401     return findFromSearchPaths(Input.drop_front(), Root, SearchPaths);
1402   return searchLibraryBaseName(Input, Root, SearchPaths);
1403 }
1404 
1405 /// Search the input files and libraries for embedded device offloading code and
1406 /// add it to the list of files to be linked. Files coming from static libraries
1407 /// are only added to the input if they are used by an existing input file.
getDeviceInput(const ArgList & Args)1408 Expected<SmallVector<OffloadFile>> getDeviceInput(const ArgList &Args) {
1409   llvm::TimeTraceScope TimeScope("ExtractDeviceCode");
1410 
1411   StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ);
1412   SmallVector<StringRef> LibraryPaths;
1413   for (const opt::Arg *Arg : Args.filtered(OPT_library_path))
1414     LibraryPaths.push_back(Arg->getValue());
1415 
1416   // Try to extract device code from the linker input files.
1417   SmallVector<OffloadFile> InputFiles;
1418   SmallVector<OffloadFile> LazyInputFiles;
1419   for (const opt::Arg *Arg : Args.filtered(OPT_INPUT)) {
1420     StringRef Filename = Arg->getValue();
1421     if (!sys::fs::exists(Filename) || sys::fs::is_directory(Filename))
1422       continue;
1423 
1424     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
1425         MemoryBuffer::getFileOrSTDIN(Filename);
1426     if (std::error_code EC = BufferOrErr.getError())
1427       reportError(createFileError(Filename, EC));
1428 
1429     bool IsLazy =
1430         identify_magic((*BufferOrErr)->getBuffer()) == file_magic::archive;
1431     if (Error Err = extractFromBuffer(std::move(*BufferOrErr),
1432                                       IsLazy ? LazyInputFiles : InputFiles))
1433       reportError(std::move(Err));
1434   }
1435 
1436   // Try to extract input from input libraries.
1437   for (const opt::Arg *Arg : Args.filtered(OPT_library)) {
1438     if (auto Library = searchLibrary(Arg->getValue(), Root, LibraryPaths)) {
1439       ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
1440           MemoryBuffer::getFileOrSTDIN(*Library);
1441       if (std::error_code EC = BufferOrErr.getError())
1442         reportError(createFileError(*Library, EC));
1443 
1444       if (Error Err =
1445               extractFromBuffer(std::move(*BufferOrErr), LazyInputFiles))
1446         reportError(std::move(Err));
1447     }
1448   }
1449 
1450   for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
1451     auto FileOrErr = getInputBitcodeLibrary(Library);
1452     if (!FileOrErr)
1453       reportError(FileOrErr.takeError());
1454     InputFiles.push_back(std::move(*FileOrErr));
1455   }
1456 
1457   DenseSet<OffloadFile::TargetID> IsTargetUsed;
1458   for (const auto &File : InputFiles)
1459     IsTargetUsed.insert(File);
1460 
1461   // We should only include input files that are used.
1462   // TODO: Only load a library if it defined undefined symbols in the input.
1463   for (auto &LazyFile : LazyInputFiles)
1464     if (IsTargetUsed.contains(LazyFile))
1465       InputFiles.emplace_back(std::move(LazyFile));
1466 
1467   return std::move(InputFiles);
1468 }
1469 
1470 } // namespace
1471 
main(int Argc,char ** Argv)1472 int main(int Argc, char **Argv) {
1473   InitLLVM X(Argc, Argv);
1474   InitializeAllTargetInfos();
1475   InitializeAllTargets();
1476   InitializeAllTargetMCs();
1477   InitializeAllAsmParsers();
1478   InitializeAllAsmPrinters();
1479 
1480   LinkerExecutable = Argv[0];
1481   sys::PrintStackTraceOnErrorSignal(Argv[0]);
1482 
1483   const OptTable &Tbl = getOptTable();
1484   BumpPtrAllocator Alloc;
1485   StringSaver Saver(Alloc);
1486   auto Args = Tbl.parseArgs(Argc, Argv, OPT_INVALID, Saver, [&](StringRef Err) {
1487     reportError(createStringError(inconvertibleErrorCode(), Err));
1488   });
1489 
1490   if (Args.hasArg(OPT_help) || Args.hasArg(OPT_help_hidden)) {
1491     Tbl.printHelp(
1492         outs(),
1493         "clang-linker-wrapper [options] -- <options to passed to the linker>",
1494         "\nA wrapper utility over the host linker. It scans the input files\n"
1495         "for sections that require additional processing prior to linking.\n"
1496         "The will then transparently pass all arguments and input to the\n"
1497         "specified host linker to create the final binary.\n",
1498         Args.hasArg(OPT_help_hidden), Args.hasArg(OPT_help_hidden));
1499     return EXIT_SUCCESS;
1500   }
1501   if (Args.hasArg(OPT_v)) {
1502     printVersion(outs());
1503     return EXIT_SUCCESS;
1504   }
1505 
1506   // This forwards '-mllvm' arguments to LLVM if present.
1507   SmallVector<const char *> NewArgv = {Argv[0]};
1508   for (const opt::Arg *Arg : Args.filtered(OPT_mllvm))
1509     NewArgv.push_back(Arg->getValue());
1510   for (const opt::Arg *Arg : Args.filtered(OPT_offload_opt_eq_minus))
1511     NewArgv.push_back(Args.MakeArgString(StringRef("-") + Arg->getValue()));
1512   cl::ParseCommandLineOptions(NewArgv.size(), &NewArgv[0]);
1513 
1514   Verbose = Args.hasArg(OPT_verbose);
1515   DryRun = Args.hasArg(OPT_dry_run);
1516   SaveTemps = Args.hasArg(OPT_save_temps);
1517   ExecutableName = Args.getLastArgValue(OPT_o, "a.out");
1518   CudaBinaryPath = Args.getLastArgValue(OPT_cuda_path_EQ).str();
1519   if (!CudaBinaryPath.empty())
1520     CudaBinaryPath = CudaBinaryPath + "/bin";
1521 
1522   if (Args.hasArg(OPT_wrapper_time_trace_eq)) {
1523     unsigned Granularity;
1524     Args.getLastArgValue(OPT_wrapper_time_trace_granularity, "500")
1525         .getAsInteger(10, Granularity);
1526     timeTraceProfilerInitialize(Granularity, Argv[0]);
1527   }
1528 
1529   {
1530     llvm::TimeTraceScope TimeScope("Execute linker wrapper");
1531 
1532     // Extract the device input files stored in the host fat binary.
1533     auto DeviceInputFiles = getDeviceInput(Args);
1534     if (!DeviceInputFiles)
1535       reportError(DeviceInputFiles.takeError());
1536 
1537     // Link and wrap the device images extracted from the linker input.
1538     auto FilesOrErr = linkAndWrapDeviceFiles(*DeviceInputFiles, Args);
1539     if (!FilesOrErr)
1540       reportError(FilesOrErr.takeError());
1541 
1542     // Run the host linking job with the rendered arguments.
1543     if (Error Err = runLinker(*FilesOrErr, Args))
1544       reportError(std::move(Err));
1545   }
1546 
1547   if (const opt::Arg *Arg = Args.getLastArg(OPT_wrapper_time_trace_eq)) {
1548     if (Error Err = timeTraceProfilerWrite(Arg->getValue(), ExecutableName))
1549       reportError(std::move(Err));
1550     timeTraceProfilerCleanup();
1551   }
1552 
1553   // Remove the temporary files created.
1554   if (!SaveTemps)
1555     for (const auto &TempFile : TempFiles)
1556       if (std::error_code EC = sys::fs::remove(TempFile))
1557         reportError(createFileError(TempFile, EC));
1558 
1559   return EXIT_SUCCESS;
1560 }
1561