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