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