Coverage Report

Created: 2022-01-18 06:27

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