Home | History | Annotate | Line # | Download | only in clang-offload-bundler
ClangOffloadBundler.cpp revision 1.1.1.1
      1 //===-- clang-offload-bundler/ClangOffloadBundler.cpp ---------------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 ///
      9 /// \file
     10 /// This file implements a clang-offload-bundler that bundles different
     11 /// files that relate with the same source code but different targets into a
     12 /// single one. Also the implements the opposite functionality, i.e. unbundle
     13 /// files previous created by this tool.
     14 ///
     15 //===----------------------------------------------------------------------===//
     16 
     17 #include "clang/Basic/Version.h"
     18 #include "llvm/ADT/ArrayRef.h"
     19 #include "llvm/ADT/SmallString.h"
     20 #include "llvm/ADT/SmallVector.h"
     21 #include "llvm/ADT/StringMap.h"
     22 #include "llvm/ADT/StringRef.h"
     23 #include "llvm/ADT/StringSwitch.h"
     24 #include "llvm/ADT/Triple.h"
     25 #include "llvm/Object/Binary.h"
     26 #include "llvm/Object/ObjectFile.h"
     27 #include "llvm/Support/Casting.h"
     28 #include "llvm/Support/CommandLine.h"
     29 #include "llvm/Support/Errc.h"
     30 #include "llvm/Support/Error.h"
     31 #include "llvm/Support/ErrorOr.h"
     32 #include "llvm/Support/FileSystem.h"
     33 #include "llvm/Support/MemoryBuffer.h"
     34 #include "llvm/Support/Path.h"
     35 #include "llvm/Support/Program.h"
     36 #include "llvm/Support/Signals.h"
     37 #include "llvm/Support/StringSaver.h"
     38 #include "llvm/Support/WithColor.h"
     39 #include "llvm/Support/raw_ostream.h"
     40 #include <algorithm>
     41 #include <cassert>
     42 #include <cstddef>
     43 #include <cstdint>
     44 #include <memory>
     45 #include <string>
     46 #include <system_error>
     47 #include <utility>
     48 
     49 using namespace llvm;
     50 using namespace llvm::object;
     51 
     52 static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
     53 
     54 // Mark all our options with this category, everything else (except for -version
     55 // and -help) will be hidden.
     56 static cl::OptionCategory
     57     ClangOffloadBundlerCategory("clang-offload-bundler options");
     58 
     59 static cl::list<std::string>
     60     InputFileNames("inputs", cl::CommaSeparated, cl::OneOrMore,
     61                    cl::desc("[<input file>,...]"),
     62                    cl::cat(ClangOffloadBundlerCategory));
     63 static cl::list<std::string>
     64     OutputFileNames("outputs", cl::CommaSeparated, cl::OneOrMore,
     65                     cl::desc("[<output file>,...]"),
     66                     cl::cat(ClangOffloadBundlerCategory));
     67 static cl::list<std::string>
     68     TargetNames("targets", cl::CommaSeparated, cl::OneOrMore,
     69                 cl::desc("[<offload kind>-<target triple>,...]"),
     70                 cl::cat(ClangOffloadBundlerCategory));
     71 static cl::opt<std::string>
     72     FilesType("type", cl::Required,
     73               cl::desc("Type of the files to be bundled/unbundled.\n"
     74                        "Current supported types are:\n"
     75                        "  i   - cpp-output\n"
     76                        "  ii  - c++-cpp-output\n"
     77                        "  cui - cuda/hip-output\n"
     78                        "  d   - dependency\n"
     79                        "  ll  - llvm\n"
     80                        "  bc  - llvm-bc\n"
     81                        "  s   - assembler\n"
     82                        "  o   - object\n"
     83                        "  gch - precompiled-header\n"
     84                        "  ast - clang AST file"),
     85               cl::cat(ClangOffloadBundlerCategory));
     86 static cl::opt<bool>
     87     Unbundle("unbundle",
     88              cl::desc("Unbundle bundled file into several output files.\n"),
     89              cl::init(false), cl::cat(ClangOffloadBundlerCategory));
     90 
     91 static cl::opt<bool> PrintExternalCommands(
     92     "###",
     93     cl::desc("Print any external commands that are to be executed "
     94              "instead of actually executing them - for testing purposes.\n"),
     95     cl::init(false), cl::cat(ClangOffloadBundlerCategory));
     96 
     97 /// Magic string that marks the existence of offloading data.
     98 #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
     99 
    100 /// The index of the host input in the list of inputs.
    101 static unsigned HostInputIndex = ~0u;
    102 
    103 /// Path to the current binary.
    104 static std::string BundlerExecutable;
    105 
    106 /// Obtain the offload kind and real machine triple out of the target
    107 /// information specified by the user.
    108 static void getOffloadKindAndTriple(StringRef Target, StringRef &OffloadKind,
    109                                     StringRef &Triple) {
    110   auto KindTriplePair = Target.split('-');
    111   OffloadKind = KindTriplePair.first;
    112   Triple = KindTriplePair.second;
    113 }
    114 static bool hasHostKind(StringRef Target) {
    115   StringRef OffloadKind;
    116   StringRef Triple;
    117   getOffloadKindAndTriple(Target, OffloadKind, Triple);
    118   return OffloadKind == "host";
    119 }
    120 
    121 /// Generic file handler interface.
    122 class FileHandler {
    123 public:
    124   FileHandler() {}
    125 
    126   virtual ~FileHandler() {}
    127 
    128   /// Update the file handler with information from the header of the bundled
    129   /// file.
    130   virtual Error ReadHeader(MemoryBuffer &Input) = 0;
    131 
    132   /// Read the marker of the next bundled to be read in the file. The bundle
    133   /// name is returned if there is one in the file, or `None` if there are no
    134   /// more bundles to be read.
    135   virtual Expected<Optional<StringRef>>
    136   ReadBundleStart(MemoryBuffer &Input) = 0;
    137 
    138   /// Read the marker that closes the current bundle.
    139   virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
    140 
    141   /// Read the current bundle and write the result into the stream \a OS.
    142   virtual Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
    143 
    144   /// Write the header of the bundled file to \a OS based on the information
    145   /// gathered from \a Inputs.
    146   virtual Error WriteHeader(raw_fd_ostream &OS,
    147                             ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
    148 
    149   /// Write the marker that initiates a bundle for the triple \a TargetTriple to
    150   /// \a OS.
    151   virtual Error WriteBundleStart(raw_fd_ostream &OS,
    152                                  StringRef TargetTriple) = 0;
    153 
    154   /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
    155   /// OS.
    156   virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
    157 
    158   /// Write the bundle from \a Input into \a OS.
    159   virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
    160 };
    161 
    162 /// Handler for binary files. The bundled file will have the following format
    163 /// (all integers are stored in little-endian format):
    164 ///
    165 /// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
    166 ///
    167 /// NumberOfOffloadBundles (8-byte integer)
    168 ///
    169 /// OffsetOfBundle1 (8-byte integer)
    170 /// SizeOfBundle1 (8-byte integer)
    171 /// NumberOfBytesInTripleOfBundle1 (8-byte integer)
    172 /// TripleOfBundle1 (byte length defined before)
    173 ///
    174 /// ...
    175 ///
    176 /// OffsetOfBundleN (8-byte integer)
    177 /// SizeOfBundleN (8-byte integer)
    178 /// NumberOfBytesInTripleOfBundleN (8-byte integer)
    179 /// TripleOfBundleN (byte length defined before)
    180 ///
    181 /// Bundle1
    182 /// ...
    183 /// BundleN
    184 
    185 /// Read 8-byte integers from a buffer in little-endian format.
    186 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
    187   uint64_t Res = 0;
    188   const char *Data = Buffer.data();
    189 
    190   for (unsigned i = 0; i < 8; ++i) {
    191     Res <<= 8;
    192     uint64_t Char = (uint64_t)Data[pos + 7 - i];
    193     Res |= 0xffu & Char;
    194   }
    195   return Res;
    196 }
    197 
    198 /// Write 8-byte integers to a buffer in little-endian format.
    199 static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
    200   for (unsigned i = 0; i < 8; ++i) {
    201     char Char = (char)(Val & 0xffu);
    202     OS.write(&Char, 1);
    203     Val >>= 8;
    204   }
    205 }
    206 
    207 class BinaryFileHandler final : public FileHandler {
    208   /// Information about the bundles extracted from the header.
    209   struct BundleInfo final {
    210     /// Size of the bundle.
    211     uint64_t Size = 0u;
    212     /// Offset at which the bundle starts in the bundled file.
    213     uint64_t Offset = 0u;
    214 
    215     BundleInfo() {}
    216     BundleInfo(uint64_t Size, uint64_t Offset) : Size(Size), Offset(Offset) {}
    217   };
    218 
    219   /// Map between a triple and the corresponding bundle information.
    220   StringMap<BundleInfo> BundlesInfo;
    221 
    222   /// Iterator for the bundle information that is being read.
    223   StringMap<BundleInfo>::iterator CurBundleInfo;
    224   StringMap<BundleInfo>::iterator NextBundleInfo;
    225 
    226 public:
    227   BinaryFileHandler() : FileHandler() {}
    228 
    229   ~BinaryFileHandler() final {}
    230 
    231   Error ReadHeader(MemoryBuffer &Input) final {
    232     StringRef FC = Input.getBuffer();
    233 
    234     // Initialize the current bundle with the end of the container.
    235     CurBundleInfo = BundlesInfo.end();
    236 
    237     // Check if buffer is smaller than magic string.
    238     size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
    239     if (ReadChars > FC.size())
    240       return Error::success();
    241 
    242     // Check if no magic was found.
    243     StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
    244     if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
    245       return Error::success();
    246 
    247     // Read number of bundles.
    248     if (ReadChars + 8 > FC.size())
    249       return Error::success();
    250 
    251     uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
    252     ReadChars += 8;
    253 
    254     // Read bundle offsets, sizes and triples.
    255     for (uint64_t i = 0; i < NumberOfBundles; ++i) {
    256 
    257       // Read offset.
    258       if (ReadChars + 8 > FC.size())
    259         return Error::success();
    260 
    261       uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
    262       ReadChars += 8;
    263 
    264       // Read size.
    265       if (ReadChars + 8 > FC.size())
    266         return Error::success();
    267 
    268       uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
    269       ReadChars += 8;
    270 
    271       // Read triple size.
    272       if (ReadChars + 8 > FC.size())
    273         return Error::success();
    274 
    275       uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
    276       ReadChars += 8;
    277 
    278       // Read triple.
    279       if (ReadChars + TripleSize > FC.size())
    280         return Error::success();
    281 
    282       StringRef Triple(&FC.data()[ReadChars], TripleSize);
    283       ReadChars += TripleSize;
    284 
    285       // Check if the offset and size make sense.
    286       if (!Offset || Offset + Size > FC.size())
    287         return Error::success();
    288 
    289       assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
    290              "Triple is duplicated??");
    291       BundlesInfo[Triple] = BundleInfo(Size, Offset);
    292     }
    293     // Set the iterator to where we will start to read.
    294     CurBundleInfo = BundlesInfo.end();
    295     NextBundleInfo = BundlesInfo.begin();
    296     return Error::success();
    297   }
    298 
    299   Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
    300     if (NextBundleInfo == BundlesInfo.end())
    301       return None;
    302     CurBundleInfo = NextBundleInfo++;
    303     return CurBundleInfo->first();
    304   }
    305 
    306   Error ReadBundleEnd(MemoryBuffer &Input) final {
    307     assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
    308     return Error::success();
    309   }
    310 
    311   Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
    312     assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
    313     StringRef FC = Input.getBuffer();
    314     OS.write(FC.data() + CurBundleInfo->second.Offset,
    315              CurBundleInfo->second.Size);
    316     return Error::success();
    317   }
    318 
    319   Error WriteHeader(raw_fd_ostream &OS,
    320                     ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
    321     // Compute size of the header.
    322     uint64_t HeaderSize = 0;
    323 
    324     HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
    325     HeaderSize += 8; // Number of Bundles
    326 
    327     for (auto &T : TargetNames) {
    328       HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
    329       HeaderSize += T.size(); // The triple.
    330     }
    331 
    332     // Write to the buffer the header.
    333     OS << OFFLOAD_BUNDLER_MAGIC_STR;
    334 
    335     Write8byteIntegerToBuffer(OS, TargetNames.size());
    336 
    337     unsigned Idx = 0;
    338     for (auto &T : TargetNames) {
    339       MemoryBuffer &MB = *Inputs[Idx++];
    340       // Bundle offset.
    341       Write8byteIntegerToBuffer(OS, HeaderSize);
    342       // Size of the bundle (adds to the next bundle's offset)
    343       Write8byteIntegerToBuffer(OS, MB.getBufferSize());
    344       HeaderSize += MB.getBufferSize();
    345       // Size of the triple
    346       Write8byteIntegerToBuffer(OS, T.size());
    347       // Triple
    348       OS << T;
    349     }
    350     return Error::success();
    351   }
    352 
    353   Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
    354     return Error::success();
    355   }
    356 
    357   Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
    358     return Error::success();
    359   }
    360 
    361   Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
    362     OS.write(Input.getBufferStart(), Input.getBufferSize());
    363     return Error::success();
    364   }
    365 };
    366 
    367 /// Handler for object files. The bundles are organized by sections with a
    368 /// designated name.
    369 ///
    370 /// To unbundle, we just copy the contents of the designated section.
    371 class ObjectFileHandler final : public FileHandler {
    372 
    373   /// The object file we are currently dealing with.
    374   std::unique_ptr<ObjectFile> Obj;
    375 
    376   /// Return the input file contents.
    377   StringRef getInputFileContents() const { return Obj->getData(); }
    378 
    379   /// Return bundle name (<kind>-<triple>) if the provided section is an offload
    380   /// section.
    381   static Expected<Optional<StringRef>> IsOffloadSection(SectionRef CurSection) {
    382     Expected<StringRef> NameOrErr = CurSection.getName();
    383     if (!NameOrErr)
    384       return NameOrErr.takeError();
    385 
    386     // If it does not start with the reserved suffix, just skip this section.
    387     if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
    388       return None;
    389 
    390     // Return the triple that is right after the reserved prefix.
    391     return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
    392   }
    393 
    394   /// Total number of inputs.
    395   unsigned NumberOfInputs = 0;
    396 
    397   /// Total number of processed inputs, i.e, inputs that were already
    398   /// read from the buffers.
    399   unsigned NumberOfProcessedInputs = 0;
    400 
    401   /// Iterator of the current and next section.
    402   section_iterator CurrentSection;
    403   section_iterator NextSection;
    404 
    405 public:
    406   ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn)
    407       : FileHandler(), Obj(std::move(ObjIn)),
    408         CurrentSection(Obj->section_begin()),
    409         NextSection(Obj->section_begin()) {}
    410 
    411   ~ObjectFileHandler() final {}
    412 
    413   Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
    414 
    415   Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
    416     while (NextSection != Obj->section_end()) {
    417       CurrentSection = NextSection;
    418       ++NextSection;
    419 
    420       // Check if the current section name starts with the reserved prefix. If
    421       // so, return the triple.
    422       Expected<Optional<StringRef>> TripleOrErr =
    423           IsOffloadSection(*CurrentSection);
    424       if (!TripleOrErr)
    425         return TripleOrErr.takeError();
    426       if (*TripleOrErr)
    427         return **TripleOrErr;
    428     }
    429     return None;
    430   }
    431 
    432   Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
    433 
    434   Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
    435     Expected<StringRef> Content = CurrentSection->getContents();
    436     if (!Content)
    437       return Content.takeError();
    438 
    439     OS.write(Content->data(), Content->size());
    440     return Error::success();
    441   }
    442 
    443   Error WriteHeader(raw_fd_ostream &OS,
    444                     ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
    445     assert(HostInputIndex != ~0u && "Host input index not defined.");
    446 
    447     // Record number of inputs.
    448     NumberOfInputs = Inputs.size();
    449     return Error::success();
    450   }
    451 
    452   Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
    453     ++NumberOfProcessedInputs;
    454     return Error::success();
    455   }
    456 
    457   Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
    458     assert(NumberOfProcessedInputs <= NumberOfInputs &&
    459            "Processing more inputs that actually exist!");
    460     assert(HostInputIndex != ~0u && "Host input index not defined.");
    461 
    462     // If this is not the last output, we don't have to do anything.
    463     if (NumberOfProcessedInputs != NumberOfInputs)
    464       return Error::success();
    465 
    466     // Find llvm-objcopy in order to create the bundle binary.
    467     ErrorOr<std::string> Objcopy = sys::findProgramByName(
    468         "llvm-objcopy", sys::path::parent_path(BundlerExecutable));
    469     if (!Objcopy)
    470       Objcopy = sys::findProgramByName("llvm-objcopy");
    471     if (!Objcopy)
    472       return createStringError(Objcopy.getError(),
    473                                "unable to find 'llvm-objcopy' in path");
    474 
    475     // We write to the output file directly. So, we close it and use the name
    476     // to pass down to llvm-objcopy.
    477     OS.close();
    478 
    479     // Compose command line for the objcopy tool.
    480     BumpPtrAllocator Alloc;
    481     StringSaver SS{Alloc};
    482     SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
    483     for (unsigned I = 0; I < NumberOfInputs; ++I)
    484       ObjcopyArgs.push_back(SS.save(Twine("--add-section=") +
    485                                     OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] +
    486                                     "=" + InputFileNames[I]));
    487     ObjcopyArgs.push_back(InputFileNames[HostInputIndex]);
    488     ObjcopyArgs.push_back(OutputFileNames.front());
    489 
    490     // If the user asked for the commands to be printed out, we do that instead
    491     // of executing it.
    492     if (PrintExternalCommands) {
    493       errs() << "\"" << *Objcopy << "\"";
    494       for (StringRef Arg : drop_begin(ObjcopyArgs, 1))
    495         errs() << " \"" << Arg << "\"";
    496       errs() << "\n";
    497     } else {
    498       if (sys::ExecuteAndWait(*Objcopy, ObjcopyArgs))
    499         return createStringError(inconvertibleErrorCode(),
    500                                  "'llvm-objcopy' tool failed");
    501     }
    502 
    503     return Error::success();
    504   }
    505 
    506   Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
    507     return Error::success();
    508   }
    509 };
    510 
    511 /// Handler for text files. The bundled file will have the following format.
    512 ///
    513 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
    514 /// Bundle 1
    515 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
    516 /// ...
    517 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
    518 /// Bundle N
    519 /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
    520 class TextFileHandler final : public FileHandler {
    521   /// String that begins a line comment.
    522   StringRef Comment;
    523 
    524   /// String that initiates a bundle.
    525   std::string BundleStartString;
    526 
    527   /// String that closes a bundle.
    528   std::string BundleEndString;
    529 
    530   /// Number of chars read from input.
    531   size_t ReadChars = 0u;
    532 
    533 protected:
    534   Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
    535 
    536   Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
    537     StringRef FC = Input.getBuffer();
    538 
    539     // Find start of the bundle.
    540     ReadChars = FC.find(BundleStartString, ReadChars);
    541     if (ReadChars == FC.npos)
    542       return None;
    543 
    544     // Get position of the triple.
    545     size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
    546 
    547     // Get position that closes the triple.
    548     size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
    549     if (TripleEnd == FC.npos)
    550       return None;
    551 
    552     // Next time we read after the new line.
    553     ++ReadChars;
    554 
    555     return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
    556   }
    557 
    558   Error ReadBundleEnd(MemoryBuffer &Input) final {
    559     StringRef FC = Input.getBuffer();
    560 
    561     // Read up to the next new line.
    562     assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
    563 
    564     size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
    565     if (TripleEnd != FC.npos)
    566       // Next time we read after the new line.
    567       ++ReadChars;
    568 
    569     return Error::success();
    570   }
    571 
    572   Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
    573     StringRef FC = Input.getBuffer();
    574     size_t BundleStart = ReadChars;
    575 
    576     // Find end of the bundle.
    577     size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
    578 
    579     StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
    580     OS << Bundle;
    581 
    582     return Error::success();
    583   }
    584 
    585   Error WriteHeader(raw_fd_ostream &OS,
    586                     ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
    587     return Error::success();
    588   }
    589 
    590   Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
    591     OS << BundleStartString << TargetTriple << "\n";
    592     return Error::success();
    593   }
    594 
    595   Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
    596     OS << BundleEndString << TargetTriple << "\n";
    597     return Error::success();
    598   }
    599 
    600   Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
    601     OS << Input.getBuffer();
    602     return Error::success();
    603   }
    604 
    605 public:
    606   TextFileHandler(StringRef Comment)
    607       : FileHandler(), Comment(Comment), ReadChars(0) {
    608     BundleStartString =
    609         "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
    610     BundleEndString =
    611         "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
    612   }
    613 };
    614 
    615 /// Return an appropriate object file handler. We use the specific object
    616 /// handler if we know how to deal with that format, otherwise we use a default
    617 /// binary file handler.
    618 static std::unique_ptr<FileHandler>
    619 CreateObjectFileHandler(MemoryBuffer &FirstInput) {
    620   // Check if the input file format is one that we know how to deal with.
    621   Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
    622 
    623   // We only support regular object files. If failed to open the input as a
    624   // known binary or this is not an object file use the default binary handler.
    625   if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
    626     return std::make_unique<BinaryFileHandler>();
    627 
    628   // Otherwise create an object file handler. The handler will be owned by the
    629   // client of this function.
    630   return std::make_unique<ObjectFileHandler>(
    631       std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())));
    632 }
    633 
    634 /// Return an appropriate handler given the input files and options.
    635 static Expected<std::unique_ptr<FileHandler>>
    636 CreateFileHandler(MemoryBuffer &FirstInput) {
    637   if (FilesType == "i")
    638     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
    639   if (FilesType == "ii")
    640     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
    641   if (FilesType == "cui")
    642     return std::make_unique<TextFileHandler>(/*Comment=*/"//");
    643   // TODO: `.d` should be eventually removed once `-M` and its variants are
    644   // handled properly in offload compilation.
    645   if (FilesType == "d")
    646     return std::make_unique<TextFileHandler>(/*Comment=*/"#");
    647   if (FilesType == "ll")
    648     return std::make_unique<TextFileHandler>(/*Comment=*/";");
    649   if (FilesType == "bc")
    650     return std::make_unique<BinaryFileHandler>();
    651   if (FilesType == "s")
    652     return std::make_unique<TextFileHandler>(/*Comment=*/"#");
    653   if (FilesType == "o")
    654     return CreateObjectFileHandler(FirstInput);
    655   if (FilesType == "gch")
    656     return std::make_unique<BinaryFileHandler>();
    657   if (FilesType == "ast")
    658     return std::make_unique<BinaryFileHandler>();
    659 
    660   return createStringError(errc::invalid_argument,
    661                            "'" + FilesType + "': invalid file type specified");
    662 }
    663 
    664 /// Bundle the files. Return true if an error was found.
    665 static Error BundleFiles() {
    666   std::error_code EC;
    667 
    668   // Create output file.
    669   raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::OF_None);
    670   if (EC)
    671     return createFileError(OutputFileNames.front(), EC);
    672 
    673   // Open input files.
    674   SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
    675   InputBuffers.reserve(InputFileNames.size());
    676   for (auto &I : InputFileNames) {
    677     ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
    678         MemoryBuffer::getFileOrSTDIN(I);
    679     if (std::error_code EC = CodeOrErr.getError())
    680       return createFileError(I, EC);
    681     InputBuffers.emplace_back(std::move(*CodeOrErr));
    682   }
    683 
    684   // Get the file handler. We use the host buffer as reference.
    685   assert(HostInputIndex != ~0u && "Host input index undefined??");
    686   Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
    687       CreateFileHandler(*InputBuffers[HostInputIndex]);
    688   if (!FileHandlerOrErr)
    689     return FileHandlerOrErr.takeError();
    690 
    691   std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
    692   assert(FH);
    693 
    694   // Write header.
    695   if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
    696     return Err;
    697 
    698   // Write all bundles along with the start/end markers. If an error was found
    699   // writing the end of the bundle component, abort the bundle writing.
    700   auto Input = InputBuffers.begin();
    701   for (auto &Triple : TargetNames) {
    702     if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
    703       return Err;
    704     if (Error Err = FH->WriteBundle(OutputFile, **Input))
    705       return Err;
    706     if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
    707       return Err;
    708     ++Input;
    709   }
    710   return Error::success();
    711 }
    712 
    713 // Unbundle the files. Return true if an error was found.
    714 static Error UnbundleFiles() {
    715   // Open Input file.
    716   ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
    717       MemoryBuffer::getFileOrSTDIN(InputFileNames.front());
    718   if (std::error_code EC = CodeOrErr.getError())
    719     return createFileError(InputFileNames.front(), EC);
    720 
    721   MemoryBuffer &Input = **CodeOrErr;
    722 
    723   // Select the right files handler.
    724   Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
    725       CreateFileHandler(Input);
    726   if (!FileHandlerOrErr)
    727     return FileHandlerOrErr.takeError();
    728 
    729   std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
    730   assert(FH);
    731 
    732   // Read the header of the bundled file.
    733   if (Error Err = FH->ReadHeader(Input))
    734     return Err;
    735 
    736   // Create a work list that consist of the map triple/output file.
    737   StringMap<StringRef> Worklist;
    738   auto Output = OutputFileNames.begin();
    739   for (auto &Triple : TargetNames) {
    740     Worklist[Triple] = *Output;
    741     ++Output;
    742   }
    743 
    744   // Read all the bundles that are in the work list. If we find no bundles we
    745   // assume the file is meant for the host target.
    746   bool FoundHostBundle = false;
    747   while (!Worklist.empty()) {
    748     Expected<Optional<StringRef>> CurTripleOrErr = FH->ReadBundleStart(Input);
    749     if (!CurTripleOrErr)
    750       return CurTripleOrErr.takeError();
    751 
    752     // We don't have more bundles.
    753     if (!*CurTripleOrErr)
    754       break;
    755 
    756     StringRef CurTriple = **CurTripleOrErr;
    757     assert(!CurTriple.empty());
    758 
    759     auto Output = Worklist.find(CurTriple);
    760     // The file may have more bundles for other targets, that we don't care
    761     // about. Therefore, move on to the next triple
    762     if (Output == Worklist.end())
    763       continue;
    764 
    765     // Check if the output file can be opened and copy the bundle to it.
    766     std::error_code EC;
    767     raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None);
    768     if (EC)
    769       return createFileError(Output->second, EC);
    770     if (Error Err = FH->ReadBundle(OutputFile, Input))
    771       return Err;
    772     if (Error Err = FH->ReadBundleEnd(Input))
    773       return Err;
    774     Worklist.erase(Output);
    775 
    776     // Record if we found the host bundle.
    777     if (hasHostKind(CurTriple))
    778       FoundHostBundle = true;
    779   }
    780 
    781   // If no bundles were found, assume the input file is the host bundle and
    782   // create empty files for the remaining targets.
    783   if (Worklist.size() == TargetNames.size()) {
    784     for (auto &E : Worklist) {
    785       std::error_code EC;
    786       raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
    787       if (EC)
    788         return createFileError(E.second, EC);
    789 
    790       // If this entry has a host kind, copy the input file to the output file.
    791       if (hasHostKind(E.first()))
    792         OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
    793     }
    794     return Error::success();
    795   }
    796 
    797   // If we found elements, we emit an error if none of those were for the host
    798   // in case host bundle name was provided in command line.
    799   if (!FoundHostBundle && HostInputIndex != ~0u)
    800     return createStringError(inconvertibleErrorCode(),
    801                              "Can't find bundle for the host target");
    802 
    803   // If we still have any elements in the worklist, create empty files for them.
    804   for (auto &E : Worklist) {
    805     std::error_code EC;
    806     raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
    807     if (EC)
    808       return createFileError(E.second, EC);
    809   }
    810 
    811   return Error::success();
    812 }
    813 
    814 static void PrintVersion(raw_ostream &OS) {
    815   OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
    816 }
    817 
    818 int main(int argc, const char **argv) {
    819   sys::PrintStackTraceOnErrorSignal(argv[0]);
    820 
    821   cl::HideUnrelatedOptions(ClangOffloadBundlerCategory);
    822   cl::SetVersionPrinter(PrintVersion);
    823   cl::ParseCommandLineOptions(
    824       argc, argv,
    825       "A tool to bundle several input files of the specified type <type> \n"
    826       "referring to the same source file but different targets into a single \n"
    827       "one. The resulting file can also be unbundled into different files by \n"
    828       "this tool if -unbundle is provided.\n");
    829 
    830   if (Help) {
    831     cl::PrintHelpMessage();
    832     return 0;
    833   }
    834 
    835   auto reportError = [argv](Error E) {
    836     logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
    837   };
    838 
    839   bool Error = false;
    840   if (Unbundle) {
    841     if (InputFileNames.size() != 1) {
    842       Error = true;
    843       reportError(createStringError(
    844           errc::invalid_argument,
    845           "only one input file supported in unbundling mode"));
    846     }
    847     if (OutputFileNames.size() != TargetNames.size()) {
    848       Error = true;
    849       reportError(createStringError(errc::invalid_argument,
    850                                     "number of output files and targets should "
    851                                     "match in unbundling mode"));
    852     }
    853   } else {
    854     if (OutputFileNames.size() != 1) {
    855       Error = true;
    856       reportError(createStringError(
    857           errc::invalid_argument,
    858           "only one output file supported in bundling mode"));
    859     }
    860     if (InputFileNames.size() != TargetNames.size()) {
    861       Error = true;
    862       reportError(createStringError(
    863           errc::invalid_argument,
    864           "number of input files and targets should match in bundling mode"));
    865     }
    866   }
    867 
    868   // Verify that the offload kinds and triples are known. We also check that we
    869   // have exactly one host target.
    870   unsigned Index = 0u;
    871   unsigned HostTargetNum = 0u;
    872   for (StringRef Target : TargetNames) {
    873     StringRef Kind;
    874     StringRef Triple;
    875     getOffloadKindAndTriple(Target, Kind, Triple);
    876 
    877     bool KindIsValid = !Kind.empty();
    878     KindIsValid = KindIsValid && StringSwitch<bool>(Kind)
    879                                      .Case("host", true)
    880                                      .Case("openmp", true)
    881                                      .Case("hip", true)
    882                                      .Default(false);
    883 
    884     bool TripleIsValid = !Triple.empty();
    885     llvm::Triple T(Triple);
    886     TripleIsValid &= T.getArch() != Triple::UnknownArch;
    887 
    888     if (!KindIsValid || !TripleIsValid) {
    889       Error = true;
    890 
    891       SmallVector<char, 128u> Buf;
    892       raw_svector_ostream Msg(Buf);
    893       Msg << "invalid target '" << Target << "'";
    894       if (!KindIsValid)
    895         Msg << ", unknown offloading kind '" << Kind << "'";
    896       if (!TripleIsValid)
    897         Msg << ", unknown target triple '" << Triple << "'";
    898       reportError(createStringError(errc::invalid_argument, Msg.str()));
    899     }
    900 
    901     if (KindIsValid && Kind == "host") {
    902       ++HostTargetNum;
    903       // Save the index of the input that refers to the host.
    904       HostInputIndex = Index;
    905     }
    906 
    907     ++Index;
    908   }
    909 
    910   // Host triple is not really needed for unbundling operation, so do not
    911   // treat missing host triple as error if we do unbundling.
    912   if ((Unbundle && HostTargetNum > 1) || (!Unbundle && HostTargetNum != 1)) {
    913     Error = true;
    914     reportError(createStringError(errc::invalid_argument,
    915                                   "expecting exactly one host target but got " +
    916                                       Twine(HostTargetNum)));
    917   }
    918 
    919   if (Error)
    920     return 1;
    921 
    922   // Save the current executable directory as it will be useful to find other
    923   // tools.
    924   BundlerExecutable = sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
    925 
    926   if (llvm::Error Err = Unbundle ? UnbundleFiles() : BundleFiles()) {
    927     reportError(std::move(Err));
    928     return 1;
    929   }
    930   return 0;
    931 }
    932