1 //===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===//
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 /// \file
10 /// This file implements an offload bundling API that bundles different files
11 /// that relate with the same source code but different targets into a single
12 /// one. Also the implements the opposite functionality, i.e. unbundle files
13 /// previous created by this API.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "clang/Driver/OffloadBundler.h"
18 #include "clang/Basic/Cuda.h"
19 #include "clang/Basic/TargetID.h"
20 #include "clang/Basic/Version.h"
21 #include "llvm/ADT/ArrayRef.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringMap.h"
25 #include "llvm/ADT/StringRef.h"
26 #include "llvm/ADT/Triple.h"
27 #include "llvm/Object/Archive.h"
28 #include "llvm/Object/ArchiveWriter.h"
29 #include "llvm/Object/Binary.h"
30 #include "llvm/Object/ObjectFile.h"
31 #include "llvm/Support/Casting.h"
32 #include "llvm/Support/Debug.h"
33 #include "llvm/Support/EndianStream.h"
34 #include "llvm/Support/Errc.h"
35 #include "llvm/Support/Error.h"
36 #include "llvm/Support/ErrorOr.h"
37 #include "llvm/Support/FileSystem.h"
38 #include "llvm/Support/Host.h"
39 #include "llvm/Support/MemoryBuffer.h"
40 #include "llvm/Support/Path.h"
41 #include "llvm/Support/Program.h"
42 #include "llvm/Support/Signals.h"
43 #include "llvm/Support/StringSaver.h"
44 #include "llvm/Support/WithColor.h"
45 #include "llvm/Support/raw_ostream.h"
46 #include <algorithm>
47 #include <cassert>
48 #include <cstddef>
49 #include <cstdint>
50 #include <forward_list>
51 #include <memory>
52 #include <set>
53 #include <string>
54 #include <system_error>
55 #include <utility>
56 
57 using namespace llvm;
58 using namespace llvm::object;
59 using namespace clang;
60 
61 /// Magic string that marks the existence of offloading data.
62 #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
63 
64 OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
65                                      const OffloadBundlerConfig &BC)
66     : BundlerConfig(BC) {
67 
68   // TODO: Add error checking from ClangOffloadBundler.cpp
69   auto TargetFeatures = Target.split(':');
70   auto TripleOrGPU = TargetFeatures.first.rsplit('-');
71 
72   if (clang::StringToCudaArch(TripleOrGPU.second) != clang::CudaArch::UNKNOWN) {
73     auto KindTriple = TripleOrGPU.first.split('-');
74     this->OffloadKind = KindTriple.first;
75     this->Triple = llvm::Triple(KindTriple.second);
76     this->TargetID = Target.substr(Target.find(TripleOrGPU.second));
77   } else {
78     auto KindTriple = TargetFeatures.first.split('-');
79     this->OffloadKind = KindTriple.first;
80     this->Triple = llvm::Triple(KindTriple.second);
81     this->TargetID = "";
82   }
83 }
84 
85 bool OffloadTargetInfo::hasHostKind() const {
86   return this->OffloadKind == "host";
87 }
88 
89 bool OffloadTargetInfo::isOffloadKindValid() const {
90   return OffloadKind == "host" || OffloadKind == "openmp" ||
91          OffloadKind == "hip" || OffloadKind == "hipv4";
92 }
93 
94 bool OffloadTargetInfo::isOffloadKindCompatible(
95     const StringRef TargetOffloadKind) const {
96   if (OffloadKind == TargetOffloadKind)
97     return true;
98   if (BundlerConfig.HipOpenmpCompatible) {
99     bool HIPCompatibleWithOpenMP = OffloadKind.startswith_insensitive("hip") &&
100                                    TargetOffloadKind == "openmp";
101     bool OpenMPCompatibleWithHIP =
102         OffloadKind == "openmp" &&
103         TargetOffloadKind.startswith_insensitive("hip");
104     return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
105   }
106   return false;
107 }
108 
109 bool OffloadTargetInfo::isTripleValid() const {
110   return !Triple.str().empty() && Triple.getArch() != Triple::UnknownArch;
111 }
112 
113 bool OffloadTargetInfo::operator==(const OffloadTargetInfo &Target) const {
114   return OffloadKind == Target.OffloadKind &&
115          Triple.isCompatibleWith(Target.Triple) && TargetID == Target.TargetID;
116 }
117 
118 std::string OffloadTargetInfo::str() const {
119   return Twine(OffloadKind + "-" + Triple.str() + "-" + TargetID).str();
120 }
121 
122 static StringRef getDeviceFileExtension(StringRef Device,
123                                         StringRef BundleFileName) {
124   if (Device.contains("gfx"))
125     return ".bc";
126   if (Device.contains("sm_"))
127     return ".cubin";
128   return sys::path::extension(BundleFileName);
129 }
130 
131 static std::string getDeviceLibraryFileName(StringRef BundleFileName,
132                                             StringRef Device) {
133   StringRef LibName = sys::path::stem(BundleFileName);
134   StringRef Extension = getDeviceFileExtension(Device, BundleFileName);
135 
136   std::string Result;
137   Result += LibName;
138   Result += Extension;
139   return Result;
140 }
141 
142 /// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
143 /// target \p TargetInfo.
144 /// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
145 bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
146                             const OffloadTargetInfo &TargetInfo) {
147 
148   // Compatible in case of exact match.
149   if (CodeObjectInfo == TargetInfo) {
150     DEBUG_WITH_TYPE("CodeObjectCompatibility",
151                     dbgs() << "Compatible: Exact match: \t[CodeObject: "
152                            << CodeObjectInfo.str()
153                            << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
154     return true;
155   }
156 
157   // Incompatible if Kinds or Triples mismatch.
158   if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
159       !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
160     DEBUG_WITH_TYPE(
161         "CodeObjectCompatibility",
162         dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
163                << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
164                << "]\n");
165     return false;
166   }
167 
168   // Incompatible if target IDs are incompatible.
169   if (!clang::isCompatibleTargetID(CodeObjectInfo.TargetID,
170                                    TargetInfo.TargetID)) {
171     DEBUG_WITH_TYPE(
172         "CodeObjectCompatibility",
173         dbgs() << "Incompatible: target IDs are incompatible \t[CodeObject: "
174                << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
175                << "]\n");
176     return false;
177   }
178 
179   DEBUG_WITH_TYPE(
180       "CodeObjectCompatibility",
181       dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
182              << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
183              << "]\n");
184   return true;
185 }
186 
187 namespace {
188 /// Generic file handler interface.
189 class FileHandler {
190 public:
191   struct BundleInfo {
192     StringRef BundleID;
193   };
194 
195   FileHandler() {}
196 
197   virtual ~FileHandler() {}
198 
199   /// Update the file handler with information from the header of the bundled
200   /// file.
201   virtual Error ReadHeader(MemoryBuffer &Input) = 0;
202 
203   /// Read the marker of the next bundled to be read in the file. The bundle
204   /// name is returned if there is one in the file, or `std::nullopt` if there
205   /// are no more bundles to be read.
206   virtual Expected<std::optional<StringRef>>
207   ReadBundleStart(MemoryBuffer &Input) = 0;
208 
209   /// Read the marker that closes the current bundle.
210   virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
211 
212   /// Read the current bundle and write the result into the stream \a OS.
213   virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
214 
215   /// Write the header of the bundled file to \a OS based on the information
216   /// gathered from \a Inputs.
217   virtual Error WriteHeader(raw_fd_ostream &OS,
218                             ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
219 
220   /// Write the marker that initiates a bundle for the triple \a TargetTriple to
221   /// \a OS.
222   virtual Error WriteBundleStart(raw_fd_ostream &OS,
223                                  StringRef TargetTriple) = 0;
224 
225   /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
226   /// OS.
227   virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
228 
229   /// Write the bundle from \a Input into \a OS.
230   virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
231 
232   /// List bundle IDs in \a Input.
233   virtual Error listBundleIDs(MemoryBuffer &Input) {
234     if (Error Err = ReadHeader(Input))
235       return Err;
236     return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
237       llvm::outs() << Info.BundleID << '\n';
238       Error Err = listBundleIDsCallback(Input, Info);
239       if (Err)
240         return Err;
241       return Error::success();
242     });
243   }
244 
245   /// For each bundle in \a Input, do \a Func.
246   Error forEachBundle(MemoryBuffer &Input,
247                       std::function<Error(const BundleInfo &)> Func) {
248     while (true) {
249       Expected<std::optional<StringRef>> CurTripleOrErr =
250           ReadBundleStart(Input);
251       if (!CurTripleOrErr)
252         return CurTripleOrErr.takeError();
253 
254       // No more bundles.
255       if (!*CurTripleOrErr)
256         break;
257 
258       StringRef CurTriple = **CurTripleOrErr;
259       assert(!CurTriple.empty());
260 
261       BundleInfo Info{CurTriple};
262       if (Error Err = Func(Info))
263         return Err;
264     }
265     return Error::success();
266   }
267 
268 protected:
269   virtual Error listBundleIDsCallback(MemoryBuffer &Input,
270                                       const BundleInfo &Info) {
271     return Error::success();
272   }
273 };
274 
275 /// Handler for binary files. The bundled file will have the following format
276 /// (all integers are stored in little-endian format):
277 ///
278 /// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
279 ///
280 /// NumberOfOffloadBundles (8-byte integer)
281 ///
282 /// OffsetOfBundle1 (8-byte integer)
283 /// SizeOfBundle1 (8-byte integer)
284 /// NumberOfBytesInTripleOfBundle1 (8-byte integer)
285 /// TripleOfBundle1 (byte length defined before)
286 ///
287 /// ...
288 ///
289 /// OffsetOfBundleN (8-byte integer)
290 /// SizeOfBundleN (8-byte integer)
291 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
292 /// TripleOfBundleN (byte length defined before)
293 ///
294 /// Bundle1
295 /// ...
296 /// BundleN
297 
298 /// Read 8-byte integers from a buffer in little-endian format.
299 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
300   return llvm::support::endian::read64le(Buffer.data() + pos);
301 }
302 
303 /// Write 8-byte integers to a buffer in little-endian format.
304 static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
305   llvm::support::endian::write(OS, Val, llvm::support::little);
306 }
307 
308 class BinaryFileHandler final : public FileHandler {
309   /// Information about the bundles extracted from the header.
310   struct BinaryBundleInfo final : public BundleInfo {
311     /// Size of the bundle.
312     uint64_t Size = 0u;
313     /// Offset at which the bundle starts in the bundled file.
314     uint64_t Offset = 0u;
315 
316     BinaryBundleInfo() {}
317     BinaryBundleInfo(uint64_t Size, uint64_t Offset)
318         : Size(Size), Offset(Offset) {}
319   };
320 
321   /// Map between a triple and the corresponding bundle information.
322   StringMap<BinaryBundleInfo> BundlesInfo;
323 
324   /// Iterator for the bundle information that is being read.
325   StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
326   StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
327 
328   /// Current bundle target to be written.
329   std::string CurWriteBundleTarget;
330 
331   /// Configuration options and arrays for this bundler job
332   const OffloadBundlerConfig &BundlerConfig;
333 
334 public:
335   // TODO: Add error checking from ClangOffloadBundler.cpp
336   BinaryFileHandler(const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
337 
338   ~BinaryFileHandler() final {}
339 
340   Error ReadHeader(MemoryBuffer &Input) final {
341     StringRef FC = Input.getBuffer();
342 
343     // Initialize the current bundle with the end of the container.
344     CurBundleInfo = BundlesInfo.end();
345 
346     // Check if buffer is smaller than magic string.
347     size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
348     if (ReadChars > FC.size())
349       return Error::success();
350 
351     // Check if no magic was found.
352     StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
353     if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
354       return Error::success();
355 
356     // Read number of bundles.
357     if (ReadChars + 8 > FC.size())
358       return Error::success();
359 
360     uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
361     ReadChars += 8;
362 
363     // Read bundle offsets, sizes and triples.
364     for (uint64_t i = 0; i < NumberOfBundles; ++i) {
365 
366       // Read offset.
367       if (ReadChars + 8 > FC.size())
368         return Error::success();
369 
370       uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
371       ReadChars += 8;
372 
373       // Read size.
374       if (ReadChars + 8 > FC.size())
375         return Error::success();
376 
377       uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
378       ReadChars += 8;
379 
380       // Read triple size.
381       if (ReadChars + 8 > FC.size())
382         return Error::success();
383 
384       uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
385       ReadChars += 8;
386 
387       // Read triple.
388       if (ReadChars + TripleSize > FC.size())
389         return Error::success();
390 
391       StringRef Triple(&FC.data()[ReadChars], TripleSize);
392       ReadChars += TripleSize;
393 
394       // Check if the offset and size make sense.
395       if (!Offset || Offset + Size > FC.size())
396         return Error::success();
397 
398       assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
399              "Triple is duplicated??");
400       BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
401     }
402     // Set the iterator to where we will start to read.
403     CurBundleInfo = BundlesInfo.end();
404     NextBundleInfo = BundlesInfo.begin();
405     return Error::success();
406   }
407 
408   Expected<std::optional<StringRef>>
409   ReadBundleStart(MemoryBuffer &Input) final {
410     if (NextBundleInfo == BundlesInfo.end())
411       return std::nullopt;
412     CurBundleInfo = NextBundleInfo++;
413     return CurBundleInfo->first();
414   }
415 
416   Error ReadBundleEnd(MemoryBuffer &Input) final {
417     assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
418     return Error::success();
419   }
420 
421   Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
422     assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
423     StringRef FC = Input.getBuffer();
424     OS.write(FC.data() + CurBundleInfo->second.Offset,
425              CurBundleInfo->second.Size);
426     return Error::success();
427   }
428 
429   Error WriteHeader(raw_fd_ostream &OS,
430                     ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
431 
432     // Compute size of the header.
433     uint64_t HeaderSize = 0;
434 
435     HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
436     HeaderSize += 8; // Number of Bundles
437 
438     for (auto &T : BundlerConfig.TargetNames) {
439       HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
440       HeaderSize += T.size(); // The triple.
441     }
442 
443     // Write to the buffer the header.
444     OS << OFFLOAD_BUNDLER_MAGIC_STR;
445 
446     Write8byteIntegerToBuffer(OS, BundlerConfig.TargetNames.size());
447 
448     unsigned Idx = 0;
449     for (auto &T : BundlerConfig.TargetNames) {
450       MemoryBuffer &MB = *Inputs[Idx++];
451       HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);
452       // Bundle offset.
453       Write8byteIntegerToBuffer(OS, HeaderSize);
454       // Size of the bundle (adds to the next bundle's offset)
455       Write8byteIntegerToBuffer(OS, MB.getBufferSize());
456       BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
457       HeaderSize += MB.getBufferSize();
458       // Size of the triple
459       Write8byteIntegerToBuffer(OS, T.size());
460       // Triple
461       OS << T;
462     }
463     return Error::success();
464   }
465 
466   Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
467     CurWriteBundleTarget = TargetTriple.str();
468     return Error::success();
469   }
470 
471   Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
472     return Error::success();
473   }
474 
475   Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
476     auto BI = BundlesInfo[CurWriteBundleTarget];
477     OS.seek(BI.Offset);
478     OS.write(Input.getBufferStart(), Input.getBufferSize());
479     return Error::success();
480   }
481 };
482 
483 // This class implements a list of temporary files that are removed upon
484 // object destruction.
485 class TempFileHandlerRAII {
486 public:
487   ~TempFileHandlerRAII() {
488     for (const auto &File : Files)
489       sys::fs::remove(File);
490   }
491 
492   // Creates temporary file with given contents.
493   Expected<StringRef> Create(std::optional<ArrayRef<char>> Contents) {
494     SmallString<128u> File;
495     if (std::error_code EC =
496             sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))
497       return createFileError(File, EC);
498     Files.push_front(File);
499 
500     if (Contents) {
501       std::error_code EC;
502       raw_fd_ostream OS(File, EC);
503       if (EC)
504         return createFileError(File, EC);
505       OS.write(Contents->data(), Contents->size());
506     }
507     return Files.front().str();
508   }
509 
510 private:
511   std::forward_list<SmallString<128u>> Files;
512 };
513 
514 /// Handler for object files. The bundles are organized by sections with a
515 /// designated name.
516 ///
517 /// To unbundle, we just copy the contents of the designated section.
518 class ObjectFileHandler final : public FileHandler {
519 
520   /// The object file we are currently dealing with.
521   std::unique_ptr<ObjectFile> Obj;
522 
523   /// Return the input file contents.
524   StringRef getInputFileContents() const { return Obj->getData(); }
525 
526   /// Return bundle name (<kind>-<triple>) if the provided section is an offload
527   /// section.
528   static Expected<std::optional<StringRef>>
529   IsOffloadSection(SectionRef CurSection) {
530     Expected<StringRef> NameOrErr = CurSection.getName();
531     if (!NameOrErr)
532       return NameOrErr.takeError();
533 
534     // If it does not start with the reserved suffix, just skip this section.
535     if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
536       return std::nullopt;
537 
538     // Return the triple that is right after the reserved prefix.
539     return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
540   }
541 
542   /// Total number of inputs.
543   unsigned NumberOfInputs = 0;
544 
545   /// Total number of processed inputs, i.e, inputs that were already
546   /// read from the buffers.
547   unsigned NumberOfProcessedInputs = 0;
548 
549   /// Iterator of the current and next section.
550   section_iterator CurrentSection;
551   section_iterator NextSection;
552 
553   /// Configuration options and arrays for this bundler job
554   const OffloadBundlerConfig &BundlerConfig;
555 
556 public:
557   // TODO: Add error checking from ClangOffloadBundler.cpp
558   ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
559                     const OffloadBundlerConfig &BC)
560       : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
561         NextSection(Obj->section_begin()), BundlerConfig(BC) {}
562 
563   ~ObjectFileHandler() final {}
564 
565   Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
566 
567   Expected<std::optional<StringRef>>
568   ReadBundleStart(MemoryBuffer &Input) final {
569     while (NextSection != Obj->section_end()) {
570       CurrentSection = NextSection;
571       ++NextSection;
572 
573       // Check if the current section name starts with the reserved prefix. If
574       // so, return the triple.
575       Expected<std::optional<StringRef>> TripleOrErr =
576           IsOffloadSection(*CurrentSection);
577       if (!TripleOrErr)
578         return TripleOrErr.takeError();
579       if (*TripleOrErr)
580         return **TripleOrErr;
581     }
582     return std::nullopt;
583   }
584 
585   Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
586 
587   Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
588     Expected<StringRef> ContentOrErr = CurrentSection->getContents();
589     if (!ContentOrErr)
590       return ContentOrErr.takeError();
591     StringRef Content = *ContentOrErr;
592 
593     // Copy fat object contents to the output when extracting host bundle.
594     if (Content.size() == 1u && Content.front() == 0)
595       Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
596 
597     OS.write(Content.data(), Content.size());
598     return Error::success();
599   }
600 
601   Error WriteHeader(raw_fd_ostream &OS,
602                     ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
603     assert(BundlerConfig.HostInputIndex != ~0u &&
604            "Host input index not defined.");
605 
606     // Record number of inputs.
607     NumberOfInputs = Inputs.size();
608     return Error::success();
609   }
610 
611   Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
612     ++NumberOfProcessedInputs;
613     return Error::success();
614   }
615 
616   Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
617     assert(NumberOfProcessedInputs <= NumberOfInputs &&
618            "Processing more inputs that actually exist!");
619     assert(BundlerConfig.HostInputIndex != ~0u &&
620            "Host input index not defined.");
621 
622     // If this is not the last output, we don't have to do anything.
623     if (NumberOfProcessedInputs != NumberOfInputs)
624       return Error::success();
625 
626     // We will use llvm-objcopy to add target objects sections to the output
627     // fat object. These sections should have 'exclude' flag set which tells
628     // link editor to remove them from linker inputs when linking executable or
629     // shared library.
630 
631     assert(BundlerConfig.ObjcopyPath != "" &&
632            "llvm-objcopy path not specified");
633 
634     // We write to the output file directly. So, we close it and use the name
635     // to pass down to llvm-objcopy.
636     OS.close();
637 
638     // Temporary files that need to be removed.
639     TempFileHandlerRAII TempFiles;
640 
641     // Compose llvm-objcopy command line for add target objects' sections with
642     // appropriate flags.
643     BumpPtrAllocator Alloc;
644     StringSaver SS{Alloc};
645     SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
646 
647     for (unsigned I = 0; I < NumberOfInputs; ++I) {
648       StringRef InputFile = BundlerConfig.InputFileNames[I];
649       if (I == BundlerConfig.HostInputIndex) {
650         // Special handling for the host bundle. We do not need to add a
651         // standard bundle for the host object since we are going to use fat
652         // object as a host object. Therefore use dummy contents (one zero byte)
653         // when creating section for the host bundle.
654         Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
655         if (!TempFileOrErr)
656           return TempFileOrErr.takeError();
657         InputFile = *TempFileOrErr;
658       }
659 
660       ObjcopyArgs.push_back(
661           SS.save(Twine("--add-section=") + OFFLOAD_BUNDLER_MAGIC_STR +
662                   BundlerConfig.TargetNames[I] + "=" + InputFile));
663       ObjcopyArgs.push_back(
664           SS.save(Twine("--set-section-flags=") + OFFLOAD_BUNDLER_MAGIC_STR +
665                   BundlerConfig.TargetNames[I] + "=readonly,exclude"));
666     }
667     ObjcopyArgs.push_back("--");
668     ObjcopyArgs.push_back(
669         BundlerConfig.InputFileNames[BundlerConfig.HostInputIndex]);
670     ObjcopyArgs.push_back(BundlerConfig.OutputFileNames.front());
671 
672     if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
673       return Err;
674 
675     return Error::success();
676   }
677 
678   Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
679     return Error::success();
680   }
681 
682 private:
683   Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
684     // If the user asked for the commands to be printed out, we do that
685     // instead of executing it.
686     if (BundlerConfig.PrintExternalCommands) {
687       errs() << "\"" << Objcopy << "\"";
688       for (StringRef Arg : drop_begin(Args, 1))
689         errs() << " \"" << Arg << "\"";
690       errs() << "\n";
691     } else {
692       if (sys::ExecuteAndWait(Objcopy, Args))
693         return createStringError(inconvertibleErrorCode(),
694                                  "'llvm-objcopy' tool failed");
695     }
696     return Error::success();
697   }
698 };
699 
700 /// Handler for text files. The bundled file will have the following format.
701 ///
702 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
703 /// Bundle 1
704 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
705 /// ...
706 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
707 /// Bundle N
708 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
709 class TextFileHandler final : public FileHandler {
710   /// String that begins a line comment.
711   StringRef Comment;
712 
713   /// String that initiates a bundle.
714   std::string BundleStartString;
715 
716   /// String that closes a bundle.
717   std::string BundleEndString;
718 
719   /// Number of chars read from input.
720   size_t ReadChars = 0u;
721 
722 protected:
723   Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
724 
725   Expected<std::optional<StringRef>>
726   ReadBundleStart(MemoryBuffer &Input) final {
727     StringRef FC = Input.getBuffer();
728 
729     // Find start of the bundle.
730     ReadChars = FC.find(BundleStartString, ReadChars);
731     if (ReadChars == FC.npos)
732       return std::nullopt;
733 
734     // Get position of the triple.
735     size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
736 
737     // Get position that closes the triple.
738     size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
739     if (TripleEnd == FC.npos)
740       return std::nullopt;
741 
742     // Next time we read after the new line.
743     ++ReadChars;
744 
745     return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
746   }
747 
748   Error ReadBundleEnd(MemoryBuffer &Input) final {
749     StringRef FC = Input.getBuffer();
750 
751     // Read up to the next new line.
752     assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
753 
754     size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
755     if (TripleEnd != FC.npos)
756       // Next time we read after the new line.
757       ++ReadChars;
758 
759     return Error::success();
760   }
761 
762   Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
763     StringRef FC = Input.getBuffer();
764     size_t BundleStart = ReadChars;
765 
766     // Find end of the bundle.
767     size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
768 
769     StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
770     OS << Bundle;
771 
772     return Error::success();
773   }
774 
775   Error WriteHeader(raw_fd_ostream &OS,
776                     ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
777     return Error::success();
778   }
779 
780   Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
781     OS << BundleStartString << TargetTriple << "\n";
782     return Error::success();
783   }
784 
785   Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
786     OS << BundleEndString << TargetTriple << "\n";
787     return Error::success();
788   }
789 
790   Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
791     OS << Input.getBuffer();
792     return Error::success();
793   }
794 
795 public:
796   TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
797     BundleStartString =
798         "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
799     BundleEndString =
800         "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
801   }
802 
803   Error listBundleIDsCallback(MemoryBuffer &Input,
804                               const BundleInfo &Info) final {
805     // TODO: To list bundle IDs in a bundled text file we need to go through
806     // all bundles. The format of bundled text file may need to include a
807     // header if the performance of listing bundle IDs of bundled text file is
808     // important.
809     ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
810     if (Error Err = ReadBundleEnd(Input))
811       return Err;
812     return Error::success();
813   }
814 };
815 } // namespace
816 
817 /// Return an appropriate object file handler. We use the specific object
818 /// handler if we know how to deal with that format, otherwise we use a default
819 /// binary file handler.
820 static std::unique_ptr<FileHandler>
821 CreateObjectFileHandler(MemoryBuffer &FirstInput,
822                         const OffloadBundlerConfig &BundlerConfig) {
823   // Check if the input file format is one that we know how to deal with.
824   Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
825 
826   // We only support regular object files. If failed to open the input as a
827   // known binary or this is not an object file use the default binary handler.
828   if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
829     return std::make_unique<BinaryFileHandler>(BundlerConfig);
830 
831   // Otherwise create an object file handler. The handler will be owned by the
832   // client of this function.
833   return std::make_unique<ObjectFileHandler>(
834       std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
835       BundlerConfig);
836 }
837 
838 /// Return an appropriate handler given the input files and options.
839 static Expected<std::unique_ptr<FileHandler>>
840 CreateFileHandler(MemoryBuffer &FirstInput,
841                   const OffloadBundlerConfig &BundlerConfig) {
842   std::string FilesType = BundlerConfig.FilesType;
843 
844   if (FilesType == "i")
845     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
846   if (FilesType == "ii")
847     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
848   if (FilesType == "cui")
849     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
850   if (FilesType == "hipi")
851     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
852   // TODO: `.d` should be eventually removed once `-M` and its variants are
853   // handled properly in offload compilation.
854   if (FilesType == "d")
855     return std::make_unique<TextFileHandler>(/*Comment=*/"#");
856   if (FilesType == "ll")
857     return std::make_unique<TextFileHandler>(/*Comment=*/";");
858   if (FilesType == "bc")
859     return std::make_unique<BinaryFileHandler>(BundlerConfig);
860   if (FilesType == "s")
861     return std::make_unique<TextFileHandler>(/*Comment=*/"#");
862   if (FilesType == "o")
863     return CreateObjectFileHandler(FirstInput, BundlerConfig);
864   if (FilesType == "a")
865     return CreateObjectFileHandler(FirstInput, BundlerConfig);
866   if (FilesType == "gch")
867     return std::make_unique<BinaryFileHandler>(BundlerConfig);
868   if (FilesType == "ast")
869     return std::make_unique<BinaryFileHandler>(BundlerConfig);
870 
871   return createStringError(errc::invalid_argument,
872                            "'" + FilesType + "': invalid file type specified");
873 }
874 
875 // List bundle IDs. Return true if an error was found.
876 Error OffloadBundler::ListBundleIDsInFile(
877     StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig) {
878   // Open Input file.
879   ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
880       MemoryBuffer::getFileOrSTDIN(InputFileName);
881   if (std::error_code EC = CodeOrErr.getError())
882     return createFileError(InputFileName, EC);
883 
884   MemoryBuffer &Input = **CodeOrErr;
885 
886   // Select the right files handler.
887   Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
888       CreateFileHandler(Input, BundlerConfig);
889   if (!FileHandlerOrErr)
890     return FileHandlerOrErr.takeError();
891 
892   std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
893   assert(FH);
894   return FH->listBundleIDs(Input);
895 }
896 
897 /// Bundle the files. Return true if an error was found.
898 Error OffloadBundler::BundleFiles() {
899   std::error_code EC;
900 
901   // Create output file.
902   raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC,
903                             sys::fs::OF_None);
904   if (EC)
905     return createFileError(BundlerConfig.OutputFileNames.front(), EC);
906 
907   // Open input files.
908   SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
909   InputBuffers.reserve(BundlerConfig.InputFileNames.size());
910   for (auto &I : BundlerConfig.InputFileNames) {
911     ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
912         MemoryBuffer::getFileOrSTDIN(I);
913     if (std::error_code EC = CodeOrErr.getError())
914       return createFileError(I, EC);
915     InputBuffers.emplace_back(std::move(*CodeOrErr));
916   }
917 
918   // Get the file handler. We use the host buffer as reference.
919   assert((BundlerConfig.HostInputIndex != ~0u || BundlerConfig.AllowNoHost) &&
920          "Host input index undefined??");
921   Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = CreateFileHandler(
922       *InputBuffers[BundlerConfig.AllowNoHost ? 0
923                                               : BundlerConfig.HostInputIndex],
924       BundlerConfig);
925   if (!FileHandlerOrErr)
926     return FileHandlerOrErr.takeError();
927 
928   std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
929   assert(FH);
930 
931   // Write header.
932   if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
933     return Err;
934 
935   // Write all bundles along with the start/end markers. If an error was found
936   // writing the end of the bundle component, abort the bundle writing.
937   auto Input = InputBuffers.begin();
938   for (auto &Triple : BundlerConfig.TargetNames) {
939     if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
940       return Err;
941     if (Error Err = FH->WriteBundle(OutputFile, **Input))
942       return Err;
943     if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
944       return Err;
945     ++Input;
946   }
947   return Error::success();
948 }
949 
950 // Unbundle the files. Return true if an error was found.
951 Error OffloadBundler::UnbundleFiles() {
952   // Open Input file.
953   ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
954       MemoryBuffer::getFileOrSTDIN(BundlerConfig.InputFileNames.front());
955   if (std::error_code EC = CodeOrErr.getError())
956     return createFileError(BundlerConfig.InputFileNames.front(), EC);
957 
958   MemoryBuffer &Input = **CodeOrErr;
959 
960   // Select the right files handler.
961   Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
962       CreateFileHandler(Input, BundlerConfig);
963   if (!FileHandlerOrErr)
964     return FileHandlerOrErr.takeError();
965 
966   std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
967   assert(FH);
968 
969   // Read the header of the bundled file.
970   if (Error Err = FH->ReadHeader(Input))
971     return Err;
972 
973   // Create a work list that consist of the map triple/output file.
974   StringMap<StringRef> Worklist;
975   auto Output = BundlerConfig.OutputFileNames.begin();
976   for (auto &Triple : BundlerConfig.TargetNames) {
977     Worklist[Triple] = *Output;
978     ++Output;
979   }
980 
981   // Read all the bundles that are in the work list. If we find no bundles we
982   // assume the file is meant for the host target.
983   bool FoundHostBundle = false;
984   while (!Worklist.empty()) {
985     Expected<std::optional<StringRef>> CurTripleOrErr =
986         FH->ReadBundleStart(Input);
987     if (!CurTripleOrErr)
988       return CurTripleOrErr.takeError();
989 
990     // We don't have more bundles.
991     if (!*CurTripleOrErr)
992       break;
993 
994     StringRef CurTriple = **CurTripleOrErr;
995     assert(!CurTriple.empty());
996 
997     auto Output = Worklist.begin();
998     for (auto E = Worklist.end(); Output != E; Output++) {
999       if (isCodeObjectCompatible(
1000               OffloadTargetInfo(CurTriple, BundlerConfig),
1001               OffloadTargetInfo((*Output).first(), BundlerConfig))) {
1002         break;
1003       }
1004     }
1005 
1006     if (Output == Worklist.end())
1007       continue;
1008     // Check if the output file can be opened and copy the bundle to it.
1009     std::error_code EC;
1010     raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1011     if (EC)
1012       return createFileError((*Output).second, EC);
1013     if (Error Err = FH->ReadBundle(OutputFile, Input))
1014       return Err;
1015     if (Error Err = FH->ReadBundleEnd(Input))
1016       return Err;
1017     Worklist.erase(Output);
1018 
1019     // Record if we found the host bundle.
1020     auto OffloadInfo = OffloadTargetInfo(CurTriple, BundlerConfig);
1021     if (OffloadInfo.hasHostKind())
1022       FoundHostBundle = true;
1023   }
1024 
1025   if (!BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1026     std::string ErrMsg = "Can't find bundles for";
1027     std::set<StringRef> Sorted;
1028     for (auto &E : Worklist)
1029       Sorted.insert(E.first());
1030     unsigned I = 0;
1031     unsigned Last = Sorted.size() - 1;
1032     for (auto &E : Sorted) {
1033       if (I != 0 && Last > 1)
1034         ErrMsg += ",";
1035       ErrMsg += " ";
1036       if (I == Last && I != 0)
1037         ErrMsg += "and ";
1038       ErrMsg += E.str();
1039       ++I;
1040     }
1041     return createStringError(inconvertibleErrorCode(), ErrMsg);
1042   }
1043 
1044   // If no bundles were found, assume the input file is the host bundle and
1045   // create empty files for the remaining targets.
1046   if (Worklist.size() == BundlerConfig.TargetNames.size()) {
1047     for (auto &E : Worklist) {
1048       std::error_code EC;
1049       raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1050       if (EC)
1051         return createFileError(E.second, EC);
1052 
1053       // If this entry has a host kind, copy the input file to the output file.
1054       auto OffloadInfo = OffloadTargetInfo(E.getKey(), BundlerConfig);
1055       if (OffloadInfo.hasHostKind())
1056         OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
1057     }
1058     return Error::success();
1059   }
1060 
1061   // If we found elements, we emit an error if none of those were for the host
1062   // in case host bundle name was provided in command line.
1063   if (!(FoundHostBundle || BundlerConfig.HostInputIndex == ~0u ||
1064         BundlerConfig.AllowMissingBundles))
1065     return createStringError(inconvertibleErrorCode(),
1066                              "Can't find bundle for the host target");
1067 
1068   // If we still have any elements in the worklist, create empty files for them.
1069   for (auto &E : Worklist) {
1070     std::error_code EC;
1071     raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1072     if (EC)
1073       return createFileError(E.second, EC);
1074   }
1075 
1076   return Error::success();
1077 }
1078 
1079 static Archive::Kind getDefaultArchiveKindForHost() {
1080   return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1081                                                             : Archive::K_GNU;
1082 }
1083 
1084 /// @brief Computes a list of targets among all given targets which are
1085 /// compatible with this code object
1086 /// @param [in] CodeObjectInfo Code Object
1087 /// @param [out] CompatibleTargets List of all compatible targets among all
1088 /// given targets
1089 /// @return false, if no compatible target is found.
1090 static bool
1091 getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
1092                             SmallVectorImpl<StringRef> &CompatibleTargets,
1093                             const OffloadBundlerConfig &BundlerConfig) {
1094   if (!CompatibleTargets.empty()) {
1095     DEBUG_WITH_TYPE("CodeObjectCompatibility",
1096                     dbgs() << "CompatibleTargets list should be empty\n");
1097     return false;
1098   }
1099   for (auto &Target : BundlerConfig.TargetNames) {
1100     auto TargetInfo = OffloadTargetInfo(Target, BundlerConfig);
1101     if (isCodeObjectCompatible(CodeObjectInfo, TargetInfo))
1102       CompatibleTargets.push_back(Target);
1103   }
1104   return !CompatibleTargets.empty();
1105 }
1106 
1107 /// UnbundleArchive takes an archive file (".a") as input containing bundled
1108 /// code object files, and a list of offload targets (not host), and extracts
1109 /// the code objects into a new archive file for each offload target. Each
1110 /// resulting archive file contains all code object files corresponding to that
1111 /// particular offload target. The created archive file does not
1112 /// contain an index of the symbols and code object files are named as
1113 /// <<Parent Bundle Name>-<CodeObject's GPUArch>>, with ':' replaced with '_'.
1114 Error OffloadBundler::UnbundleArchive() {
1115   std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1116 
1117   /// Map of target names with list of object files that will form the device
1118   /// specific archive for that target
1119   StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1120 
1121   // Map of target names and output archive filenames
1122   StringMap<StringRef> TargetOutputFileNameMap;
1123 
1124   auto Output = BundlerConfig.OutputFileNames.begin();
1125   for (auto &Target : BundlerConfig.TargetNames) {
1126     TargetOutputFileNameMap[Target] = *Output;
1127     ++Output;
1128   }
1129 
1130   StringRef IFName = BundlerConfig.InputFileNames.front();
1131 
1132   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1133       MemoryBuffer::getFileOrSTDIN(IFName, true, false);
1134   if (std::error_code EC = BufOrErr.getError())
1135     return createFileError(BundlerConfig.InputFileNames.front(), EC);
1136 
1137   ArchiveBuffers.push_back(std::move(*BufOrErr));
1138   Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
1139       Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1140   if (!LibOrErr)
1141     return LibOrErr.takeError();
1142 
1143   auto Archive = std::move(*LibOrErr);
1144 
1145   Error ArchiveErr = Error::success();
1146   auto ChildEnd = Archive->child_end();
1147 
1148   /// Iterate over all bundled code object files in the input archive.
1149   for (auto ArchiveIter = Archive->child_begin(ArchiveErr);
1150        ArchiveIter != ChildEnd; ++ArchiveIter) {
1151     if (ArchiveErr)
1152       return ArchiveErr;
1153     auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1154     if (!ArchiveChildNameOrErr)
1155       return ArchiveChildNameOrErr.takeError();
1156 
1157     StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1158 
1159     auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1160     if (!CodeObjectBufferRefOrErr)
1161       return CodeObjectBufferRefOrErr.takeError();
1162 
1163     auto CodeObjectBuffer =
1164         MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);
1165 
1166     Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
1167         CreateFileHandler(*CodeObjectBuffer, BundlerConfig);
1168     if (!FileHandlerOrErr)
1169       return FileHandlerOrErr.takeError();
1170 
1171     std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1172     assert(FileHandler &&
1173            "FileHandle creation failed for file in the archive!");
1174 
1175     if (Error ReadErr = FileHandler->ReadHeader(*CodeObjectBuffer))
1176       return ReadErr;
1177 
1178     Expected<std::optional<StringRef>> CurBundleIDOrErr =
1179         FileHandler->ReadBundleStart(*CodeObjectBuffer);
1180     if (!CurBundleIDOrErr)
1181       return CurBundleIDOrErr.takeError();
1182 
1183     std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1184     // No device code in this child, skip.
1185     if (!OptionalCurBundleID)
1186       continue;
1187     StringRef CodeObject = *OptionalCurBundleID;
1188 
1189     // Process all bundle entries (CodeObjects) found in this child of input
1190     // archive.
1191     while (!CodeObject.empty()) {
1192       SmallVector<StringRef> CompatibleTargets;
1193       auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig);
1194       if (CodeObjectInfo.hasHostKind()) {
1195         // Do nothing, we don't extract host code yet.
1196       } else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
1197                                              BundlerConfig)) {
1198         std::string BundleData;
1199         raw_string_ostream DataStream(BundleData);
1200         if (Error Err = FileHandler->ReadBundle(DataStream, *CodeObjectBuffer))
1201           return Err;
1202 
1203         for (auto &CompatibleTarget : CompatibleTargets) {
1204           SmallString<128> BundledObjectFileName;
1205           BundledObjectFileName.assign(BundledObjectFile);
1206           auto OutputBundleName =
1207               Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
1208                     CodeObject +
1209                     getDeviceLibraryFileName(BundledObjectFileName,
1210                                              CodeObjectInfo.TargetID))
1211                   .str();
1212           // Replace ':' in optional target feature list with '_' to ensure
1213           // cross-platform validity.
1214           std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
1215                        '_');
1216 
1217           std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1218               DataStream.str(), OutputBundleName);
1219           ArchiveBuffers.push_back(std::move(MemBuf));
1220           llvm::MemoryBufferRef MemBufRef =
1221               MemoryBufferRef(*(ArchiveBuffers.back()));
1222 
1223           // For inserting <CompatibleTarget, list<CodeObject>> entry in
1224           // OutputArchivesMap.
1225           if (OutputArchivesMap.find(CompatibleTarget) ==
1226               OutputArchivesMap.end()) {
1227 
1228             std::vector<NewArchiveMember> ArchiveMembers;
1229             ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
1230             OutputArchivesMap.insert_or_assign(CompatibleTarget,
1231                                                std::move(ArchiveMembers));
1232           } else {
1233             OutputArchivesMap[CompatibleTarget].push_back(
1234                 NewArchiveMember(MemBufRef));
1235           }
1236         }
1237       }
1238 
1239       if (Error Err = FileHandler->ReadBundleEnd(*CodeObjectBuffer))
1240         return Err;
1241 
1242       Expected<std::optional<StringRef>> NextTripleOrErr =
1243           FileHandler->ReadBundleStart(*CodeObjectBuffer);
1244       if (!NextTripleOrErr)
1245         return NextTripleOrErr.takeError();
1246 
1247       CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr : "";
1248     } // End of processing of all bundle entries of this child of input archive.
1249   }   // End of while over children of input archive.
1250 
1251   assert(!ArchiveErr && "Error occurred while reading archive!");
1252 
1253   /// Write out an archive for each target
1254   for (auto &Target : BundlerConfig.TargetNames) {
1255     StringRef FileName = TargetOutputFileNameMap[Target];
1256     StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
1257         OutputArchivesMap.find(Target);
1258     if (CurArchiveMembers != OutputArchivesMap.end()) {
1259       if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
1260                                         true, getDefaultArchiveKindForHost(),
1261                                         true, false, nullptr))
1262         return WriteErr;
1263     } else if (!BundlerConfig.AllowMissingBundles) {
1264       std::string ErrMsg =
1265           Twine("no compatible code object found for the target '" + Target +
1266                 "' in heterogeneous archive library: " + IFName)
1267               .str();
1268       return createStringError(inconvertibleErrorCode(), ErrMsg);
1269     } else { // Create an empty archive file if no compatible code object is
1270              // found and "allow-missing-bundles" is enabled. It ensures that
1271              // the linker using output of this step doesn't complain about
1272              // the missing input file.
1273       std::vector<llvm::NewArchiveMember> EmptyArchive;
1274       EmptyArchive.clear();
1275       if (Error WriteErr = writeArchive(FileName, EmptyArchive, true,
1276                                         getDefaultArchiveKindForHost(), true,
1277                                         false, nullptr))
1278         return WriteErr;
1279     }
1280   }
1281 
1282   return Error::success();
1283 }
1284