Coverage Report

Created: 2021-01-19 06:58

/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/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 <forward_list>
45
#include <memory>
46
#include <set>
47
#include <string>
48
#include <system_error>
49
#include <utility>
50
51
using namespace llvm;
52
using namespace llvm::object;
53
54
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
55
56
// Mark all our options with this category, everything else (except for -version
57
// and -help) will be hidden.
58
static cl::OptionCategory
59
    ClangOffloadBundlerCategory("clang-offload-bundler options");
60
61
static cl::list<std::string>
62
    InputFileNames("inputs", cl::CommaSeparated, cl::OneOrMore,
63
                   cl::desc("[<input file>,...]"),
64
                   cl::cat(ClangOffloadBundlerCategory));
65
static cl::list<std::string>
66
    OutputFileNames("outputs", cl::CommaSeparated,
67
                    cl::desc("[<output file>,...]"),
68
                    cl::cat(ClangOffloadBundlerCategory));
69
static cl::list<std::string>
70
    TargetNames("targets", cl::CommaSeparated,
71
                cl::desc("[<offload kind>-<target triple>,...]"),
72
                cl::cat(ClangOffloadBundlerCategory));
73
static cl::opt<std::string>
74
    FilesType("type", cl::Required,
75
              cl::desc("Type of the files to be bundled/unbundled.\n"
76
                       "Current supported types are:\n"
77
                       "  i   - cpp-output\n"
78
                       "  ii  - c++-cpp-output\n"
79
                       "  cui - cuda/hip-output\n"
80
                       "  d   - dependency\n"
81
                       "  ll  - llvm\n"
82
                       "  bc  - llvm-bc\n"
83
                       "  s   - assembler\n"
84
                       "  o   - object\n"
85
                       "  gch - precompiled-header\n"
86
                       "  ast - clang AST file"),
87
              cl::cat(ClangOffloadBundlerCategory));
88
static cl::opt<bool>
89
    Unbundle("unbundle",
90
             cl::desc("Unbundle bundled file into several output files.\n"),
91
             cl::init(false), cl::cat(ClangOffloadBundlerCategory));
92
93
static cl::opt<bool>
94
    ListBundleIDs("list", cl::desc("List bundle IDs in the bundled file.\n"),
95
                  cl::init(false), cl::cat(ClangOffloadBundlerCategory));
96
97
static cl::opt<bool> PrintExternalCommands(
98
    "###",
99
    cl::desc("Print any external commands that are to be executed "
100
             "instead of actually executing them - for testing purposes.\n"),
101
    cl::init(false), cl::cat(ClangOffloadBundlerCategory));
102
103
static cl::opt<bool>
104
    AllowMissingBundles("allow-missing-bundles",
105
                        cl::desc("Create empty files if bundles are missing "
106
                                 "when unbundling.\n"),
107
                        cl::init(false), cl::cat(ClangOffloadBundlerCategory));
108
109
static cl::opt<unsigned>
110
    BundleAlignment("bundle-align",
111
                    cl::desc("Alignment of bundle for binary files"),
112
                    cl::init(1), cl::cat(ClangOffloadBundlerCategory));
113
114
/// Magic string that marks the existence of offloading data.
115
0
#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
116
117
/// The index of the host input in the list of inputs.
118
static unsigned HostInputIndex = ~0u;
119
120
/// Path to the current binary.
121
static std::string BundlerExecutable;
122
123
/// Obtain the offload kind and real machine triple out of the target
124
/// information specified by the user.
125
static void getOffloadKindAndTriple(StringRef Target, StringRef &OffloadKind,
126
4
                                    StringRef &Triple) {
127
4
  auto KindTriplePair = Target.split('-');
128
4
  OffloadKind = KindTriplePair.first;
129
4
  Triple = KindTriplePair.second;
130
4
}
131
0
static bool hasHostKind(StringRef Target) {
132
0
  StringRef OffloadKind;
133
0
  StringRef Triple;
134
0
  getOffloadKindAndTriple(Target, OffloadKind, Triple);
135
0
  return OffloadKind == "host";
136
0
}
137
138
/// Generic file handler interface.
139
class FileHandler {
140
public:
141
  struct BundleInfo {
142
    StringRef BundleID;
143
  };
144
145
2
  FileHandler() {}
146
147
2
  virtual ~FileHandler() {}
148
149
  /// Update the file handler with information from the header of the bundled
150
  /// file.
151
  virtual Error ReadHeader(MemoryBuffer &Input) = 0;
152
153
  /// Read the marker of the next bundled to be read in the file. The bundle
154
  /// name is returned if there is one in the file, or `None` if there are no
155
  /// more bundles to be read.
156
  virtual Expected<Optional<StringRef>>
157
  ReadBundleStart(MemoryBuffer &Input) = 0;
158
159
  /// Read the marker that closes the current bundle.
160
  virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
161
162
  /// Read the current bundle and write the result into the stream \a OS.
163
  virtual Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
164
165
  /// Write the header of the bundled file to \a OS based on the information
166
  /// gathered from \a Inputs.
167
  virtual Error WriteHeader(raw_fd_ostream &OS,
168
                            ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
169
170
  /// Write the marker that initiates a bundle for the triple \a TargetTriple to
171
  /// \a OS.
172
  virtual Error WriteBundleStart(raw_fd_ostream &OS,
173
                                 StringRef TargetTriple) = 0;
174
175
  /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
176
  /// OS.
177
  virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
178
179
  /// Write the bundle from \a Input into \a OS.
180
  virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
181
182
  /// List bundle IDs in \a Input.
183
0
  virtual Error listBundleIDs(MemoryBuffer &Input) {
184
0
    if (Error Err = ReadHeader(Input))
185
0
      return Err;
186
187
0
    return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
188
0
      llvm::outs() << Info.BundleID << '\n';
189
0
      Error Err = listBundleIDsCallback(Input, Info);
190
0
      if (Err)
191
0
        return Err;
192
0
      return Error::success();
193
0
    });
194
0
  }
195
196
  /// For each bundle in \a Input, do \a Func.
197
  Error forEachBundle(MemoryBuffer &Input,
198
0
                      std::function<Error(const BundleInfo &)> Func) {
199
0
    while (true) {
200
0
      Expected<Optional<StringRef>> CurTripleOrErr = ReadBundleStart(Input);
201
0
      if (!CurTripleOrErr)
202
0
        return CurTripleOrErr.takeError();
203
204
      // No more bundles.
205
0
      if (!*CurTripleOrErr)
206
0
        break;
207
208
0
      StringRef CurTriple = **CurTripleOrErr;
209
0
      assert(!CurTriple.empty());
210
211
0
      BundleInfo Info{CurTriple};
212
0
      if (Error Err = Func(Info))
213
0
        return Err;
214
0
    }
215
0
    return Error::success();
216
0
  }
217
218
protected:
219
  virtual Error listBundleIDsCallback(MemoryBuffer &Input,
220
0
                                      const BundleInfo &Info) {
221
0
    return Error::success();
222
0
  }
223
};
224
225
/// Handler for binary files. The bundled file will have the following format
226
/// (all integers are stored in little-endian format):
227
///
228
/// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
229
///
230
/// NumberOfOffloadBundles (8-byte integer)
231
///
232
/// OffsetOfBundle1 (8-byte integer)
233
/// SizeOfBundle1 (8-byte integer)
234
/// NumberOfBytesInTripleOfBundle1 (8-byte integer)
235
/// TripleOfBundle1 (byte length defined before)
236
///
237
/// ...
238
///
239
/// OffsetOfBundleN (8-byte integer)
240
/// SizeOfBundleN (8-byte integer)
241
/// NumberOfBytesInTripleOfBundleN (8-byte integer)
242
/// TripleOfBundleN (byte length defined before)
243
///
244
/// Bundle1
245
/// ...
246
/// BundleN
247
248
/// Read 8-byte integers from a buffer in little-endian format.
249
0
static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
250
0
  uint64_t Res = 0;
251
0
  const char *Data = Buffer.data();
252
253
0
  for (unsigned i = 0; i < 8; ++i) {
254
0
    Res <<= 8;
255
0
    uint64_t Char = (uint64_t)Data[pos + 7 - i];
256
0
    Res |= 0xffu & Char;
257
0
  }
258
0
  return Res;
259
0
}
260
261
/// Write 8-byte integers to a buffer in little-endian format.
262
0
static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
263
0
  for (unsigned i = 0; i < 8; ++i) {
264
0
    char Char = (char)(Val & 0xffu);
265
0
    OS.write(&Char, 1);
266
0
    Val >>= 8;
267
0
  }
268
0
}
269
270
class BinaryFileHandler final : public FileHandler {
271
  /// Information about the bundles extracted from the header.
272
  struct BinaryBundleInfo final : public BundleInfo {
273
    /// Size of the bundle.
274
    uint64_t Size = 0u;
275
    /// Offset at which the bundle starts in the bundled file.
276
    uint64_t Offset = 0u;
277
278
0
    BinaryBundleInfo() {}
279
    BinaryBundleInfo(uint64_t Size, uint64_t Offset)
280
0
        : Size(Size), Offset(Offset) {}
281
  };
282
283
  /// Map between a triple and the corresponding bundle information.
284
  StringMap<BinaryBundleInfo> BundlesInfo;
285
286
  /// Iterator for the bundle information that is being read.
287
  StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
288
  StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
289
290
  /// Current bundle target to be written.
291
  std::string CurWriteBundleTarget;
292
293
public:
294
0
  BinaryFileHandler() : FileHandler() {}
295
296
0
  ~BinaryFileHandler() final {}
297
298
0
  Error ReadHeader(MemoryBuffer &Input) final {
299
0
    StringRef FC = Input.getBuffer();
300
301
    // Initialize the current bundle with the end of the container.
302
0
    CurBundleInfo = BundlesInfo.end();
303
304
    // Check if buffer is smaller than magic string.
305
0
    size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
306
0
    if (ReadChars > FC.size())
307
0
      return Error::success();
308
309
    // Check if no magic was found.
310
0
    StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
311
0
    if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
312
0
      return Error::success();
313
314
    // Read number of bundles.
315
0
    if (ReadChars + 8 > FC.size())
316
0
      return Error::success();
317
318
0
    uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
319
0
    ReadChars += 8;
320
321
    // Read bundle offsets, sizes and triples.
322
0
    for (uint64_t i = 0; i < NumberOfBundles; ++i) {
323
324
      // Read offset.
325
0
      if (ReadChars + 8 > FC.size())
326
0
        return Error::success();
327
328
0
      uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
329
0
      ReadChars += 8;
330
331
      // Read size.
332
0
      if (ReadChars + 8 > FC.size())
333
0
        return Error::success();
334
335
0
      uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
336
0
      ReadChars += 8;
337
338
      // Read triple size.
339
0
      if (ReadChars + 8 > FC.size())
340
0
        return Error::success();
341
342
0
      uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
343
0
      ReadChars += 8;
344
345
      // Read triple.
346
0
      if (ReadChars + TripleSize > FC.size())
347
0
        return Error::success();
348
349
0
      StringRef Triple(&FC.data()[ReadChars], TripleSize);
350
0
      ReadChars += TripleSize;
351
352
      // Check if the offset and size make sense.
353
0
      if (!Offset || Offset + Size > FC.size())
354
0
        return Error::success();
355
356
0
      assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
357
0
             "Triple is duplicated??");
358
0
      BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
359
0
    }
360
    // Set the iterator to where we will start to read.
361
0
    CurBundleInfo = BundlesInfo.end();
362
0
    NextBundleInfo = BundlesInfo.begin();
363
0
    return Error::success();
364
0
  }
365
366
0
  Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
367
0
    if (NextBundleInfo == BundlesInfo.end())
368
0
      return None;
369
0
    CurBundleInfo = NextBundleInfo++;
370
0
    return CurBundleInfo->first();
371
0
  }
372
373
0
  Error ReadBundleEnd(MemoryBuffer &Input) final {
374
0
    assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
375
0
    return Error::success();
376
0
  }
377
378
0
  Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
379
0
    assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
380
0
    StringRef FC = Input.getBuffer();
381
0
    OS.write(FC.data() + CurBundleInfo->second.Offset,
382
0
             CurBundleInfo->second.Size);
383
0
    return Error::success();
384
0
  }
385
386
  Error WriteHeader(raw_fd_ostream &OS,
387
0
                    ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
388
    // Compute size of the header.
389
0
    uint64_t HeaderSize = 0;
390
391
0
    HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
392
0
    HeaderSize += 8; // Number of Bundles
393
394
0
    for (auto &T : TargetNames) {
395
0
      HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
396
0
      HeaderSize += T.size(); // The triple.
397
0
    }
398
399
    // Write to the buffer the header.
400
0
    OS << OFFLOAD_BUNDLER_MAGIC_STR;
401
402
0
    Write8byteIntegerToBuffer(OS, TargetNames.size());
403
404
0
    unsigned Idx = 0;
405
0
    for (auto &T : TargetNames) {
406
0
      MemoryBuffer &MB = *Inputs[Idx++];
407
0
      HeaderSize = alignTo(HeaderSize, BundleAlignment);
408
      // Bundle offset.
409
0
      Write8byteIntegerToBuffer(OS, HeaderSize);
410
      // Size of the bundle (adds to the next bundle's offset)
411
0
      Write8byteIntegerToBuffer(OS, MB.getBufferSize());
412
0
      BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
413
0
      HeaderSize += MB.getBufferSize();
414
      // Size of the triple
415
0
      Write8byteIntegerToBuffer(OS, T.size());
416
      // Triple
417
0
      OS << T;
418
0
    }
419
0
    return Error::success();
420
0
  }
421
422
0
  Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
423
0
    CurWriteBundleTarget = TargetTriple.str();
424
0
    return Error::success();
425
0
  }
426
427
0
  Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
428
0
    return Error::success();
429
0
  }
430
431
0
  Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
432
0
    auto BI = BundlesInfo[CurWriteBundleTarget];
433
0
    OS.seek(BI.Offset);
434
0
    OS.write(Input.getBufferStart(), Input.getBufferSize());
435
0
    return Error::success();
436
0
  }
437
};
438
439
namespace {
440
441
// This class implements a list of temporary files that are removed upon
442
// object destruction.
443
class TempFileHandlerRAII {
444
public:
445
0
  ~TempFileHandlerRAII() {
446
0
    for (const auto &File : Files)
447
0
      sys::fs::remove(File);
448
0
  }
449
450
  // Creates temporary file with given contents.
451
0
  Expected<StringRef> Create(Optional<ArrayRef<char>> Contents) {
452
0
    SmallString<128u> File;
453
0
    if (std::error_code EC =
454
0
            sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))
455
0
      return createFileError(File, EC);
456
0
    Files.push_front(File);
457
458
0
    if (Contents) {
459
0
      std::error_code EC;
460
0
      raw_fd_ostream OS(File, EC);
461
0
      if (EC)
462
0
        return createFileError(File, EC);
463
0
      OS.write(Contents->data(), Contents->size());
464
0
    }
465
0
    return Files.front();
466
0
  }
467
468
private:
469
  std::forward_list<SmallString<128u>> Files;
470
};
471
472
} // end anonymous namespace
473
474
/// Handler for object files. The bundles are organized by sections with a
475
/// designated name.
476
///
477
/// To unbundle, we just copy the contents of the designated section.
478
class ObjectFileHandler final : public FileHandler {
479
480
  /// The object file we are currently dealing with.
481
  std::unique_ptr<ObjectFile> Obj;
482
483
  /// Return the input file contents.
484
0
  StringRef getInputFileContents() const { return Obj->getData(); }
485
486
  /// Return bundle name (<kind>-<triple>) if the provided section is an offload
487
  /// section.
488
0
  static Expected<Optional<StringRef>> IsOffloadSection(SectionRef CurSection) {
489
0
    Expected<StringRef> NameOrErr = CurSection.getName();
490
0
    if (!NameOrErr)
491
0
      return NameOrErr.takeError();
492
493
    // If it does not start with the reserved suffix, just skip this section.
494
0
    if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
495
0
      return None;
496
497
    // Return the triple that is right after the reserved prefix.
498
0
    return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
499
0
  }
500
501
  /// Total number of inputs.
502
  unsigned NumberOfInputs = 0;
503
504
  /// Total number of processed inputs, i.e, inputs that were already
505
  /// read from the buffers.
506
  unsigned NumberOfProcessedInputs = 0;
507
508
  /// Iterator of the current and next section.
509
  section_iterator CurrentSection;
510
  section_iterator NextSection;
511
512
public:
513
  ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn)
514
      : FileHandler(), Obj(std::move(ObjIn)),
515
        CurrentSection(Obj->section_begin()),
516
0
        NextSection(Obj->section_begin()) {}
517
518
0
  ~ObjectFileHandler() final {}
519
520
0
  Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
521
522
0
  Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
523
0
    while (NextSection != Obj->section_end()) {
524
0
      CurrentSection = NextSection;
525
0
      ++NextSection;
526
527
      // Check if the current section name starts with the reserved prefix. If
528
      // so, return the triple.
529
0
      Expected<Optional<StringRef>> TripleOrErr =
530
0
          IsOffloadSection(*CurrentSection);
531
0
      if (!TripleOrErr)
532
0
        return TripleOrErr.takeError();
533
0
      if (*TripleOrErr)
534
0
        return **TripleOrErr;
535
0
    }
536
0
    return None;
537
0
  }
538
539
0
  Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
540
541
0
  Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
542
0
    Expected<StringRef> ContentOrErr = CurrentSection->getContents();
543
0
    if (!ContentOrErr)
544
0
      return ContentOrErr.takeError();
545
0
    StringRef Content = *ContentOrErr;
546
547
    // Copy fat object contents to the output when extracting host bundle.
548
0
    if (Content.size() == 1u && Content.front() == 0)
549
0
      Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
550
551
0
    OS.write(Content.data(), Content.size());
552
0
    return Error::success();
553
0
  }
554
555
  Error WriteHeader(raw_fd_ostream &OS,
556
0
                    ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
557
0
    assert(HostInputIndex != ~0u && "Host input index not defined.");
558
559
    // Record number of inputs.
560
0
    NumberOfInputs = Inputs.size();
561
0
    return Error::success();
562
0
  }
563
564
0
  Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
565
0
    ++NumberOfProcessedInputs;
566
0
    return Error::success();
567
0
  }
568
569
0
  Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
570
0
    assert(NumberOfProcessedInputs <= NumberOfInputs &&
571
0
           "Processing more inputs that actually exist!");
572
0
    assert(HostInputIndex != ~0u && "Host input index not defined.");
573
574
    // If this is not the last output, we don't have to do anything.
575
0
    if (NumberOfProcessedInputs != NumberOfInputs)
576
0
      return Error::success();
577
578
    // We will use llvm-objcopy to add target objects sections to the output
579
    // fat object. These sections should have 'exclude' flag set which tells
580
    // link editor to remove them from linker inputs when linking executable or
581
    // shared library. llvm-objcopy currently does not support adding new
582
    // section and changing flags for the added section in one invocation, and
583
    // because of that we have to run it two times. First run adds sections and
584
    // the second changes flags.
585
    // TODO: change it to one run once llvm-objcopy starts supporting that.
586
587
    // Find llvm-objcopy in order to create the bundle binary.
588
0
    ErrorOr<std::string> Objcopy = sys::findProgramByName(
589
0
        "llvm-objcopy", sys::path::parent_path(BundlerExecutable));
590
0
    if (!Objcopy)
591
0
      Objcopy = sys::findProgramByName("llvm-objcopy");
592
0
    if (!Objcopy)
593
0
      return createStringError(Objcopy.getError(),
594
0
                               "unable to find 'llvm-objcopy' in path");
595
596
    // We write to the output file directly. So, we close it and use the name
597
    // to pass down to llvm-objcopy.
598
0
    OS.close();
599
600
    // Temporary files that need to be removed.
601
0
    TempFileHandlerRAII TempFiles;
602
603
    // Create an intermediate temporary file to save object after the first
604
    // llvm-objcopy run.
605
0
    Expected<StringRef> IntermediateObjOrErr = TempFiles.Create(None);
606
0
    if (!IntermediateObjOrErr)
607
0
      return IntermediateObjOrErr.takeError();
608
0
    StringRef IntermediateObj = *IntermediateObjOrErr;
609
610
    // Compose llvm-objcopy command line for add target objects' sections.
611
0
    BumpPtrAllocator Alloc;
612
0
    StringSaver SS{Alloc};
613
0
    SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
614
0
    for (unsigned I = 0; I < NumberOfInputs; ++I) {
615
0
      StringRef InputFile = InputFileNames[I];
616
0
      if (I == HostInputIndex) {
617
        // Special handling for the host bundle. We do not need to add a
618
        // standard bundle for the host object since we are going to use fat
619
        // object as a host object. Therefore use dummy contents (one zero byte)
620
        // when creating section for the host bundle.
621
0
        Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
622
0
        if (!TempFileOrErr)
623
0
          return TempFileOrErr.takeError();
624
0
        InputFile = *TempFileOrErr;
625
0
      }
626
627
0
      ObjcopyArgs.push_back(SS.save(Twine("--add-section=") +
628
0
                                    OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] +
629
0
                                    "=" + InputFile));
630
0
    }
631
0
    ObjcopyArgs.push_back(InputFileNames[HostInputIndex]);
632
0
    ObjcopyArgs.push_back(IntermediateObj);
633
634
0
    if (Error Err = executeObjcopy(*Objcopy, ObjcopyArgs))
635
0
      return Err;
636
637
    // And run llvm-objcopy for the second time to update section flags.
638
0
    ObjcopyArgs.resize(1);
639
0
    for (unsigned I = 0; I < NumberOfInputs; ++I)
640
0
      ObjcopyArgs.push_back(SS.save(Twine("--set-section-flags=") +
641
0
                                    OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] +
642
0
                                    "=readonly,exclude"));
643
0
    ObjcopyArgs.push_back(IntermediateObj);
644
0
    ObjcopyArgs.push_back(OutputFileNames.front());
645
646
0
    if (Error Err = executeObjcopy(*Objcopy, ObjcopyArgs))
647
0
      return Err;
648
649
0
    return Error::success();
650
0
  }
651
652
0
  Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
653
0
    return Error::success();
654
0
  }
655
656
private:
657
0
  static Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
658
    // If the user asked for the commands to be printed out, we do that
659
    // instead of executing it.
660
0
    if (PrintExternalCommands) {
661
0
      errs() << "\"" << Objcopy << "\"";
662
0
      for (StringRef Arg : drop_begin(Args, 1))
663
0
        errs() << " \"" << Arg << "\"";
664
0
      errs() << "\n";
665
0
    } else {
666
0
      if (sys::ExecuteAndWait(Objcopy, Args))
667
0
        return createStringError(inconvertibleErrorCode(),
668
0
                                 "'llvm-objcopy' tool failed");
669
0
    }
670
0
    return Error::success();
671
0
  }
672
};
673
674
/// Handler for text files. The bundled file will have the following format.
675
///
676
/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
677
/// Bundle 1
678
/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
679
/// ...
680
/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
681
/// Bundle N
682
/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
683
class TextFileHandler final : public FileHandler {
684
  /// String that begins a line comment.
685
  StringRef Comment;
686
687
  /// String that initiates a bundle.
688
  std::string BundleStartString;
689
690
  /// String that closes a bundle.
691
  std::string BundleEndString;
692
693
  /// Number of chars read from input.
694
  size_t ReadChars = 0u;
695
696
protected:
697
0
  Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
698
699
0
  Expected<Optional<StringRef>> ReadBundleStart(MemoryBuffer &Input) final {
700
0
    StringRef FC = Input.getBuffer();
701
702
    // Find start of the bundle.
703
0
    ReadChars = FC.find(BundleStartString, ReadChars);
704
0
    if (ReadChars == FC.npos)
705
0
      return None;
706
707
    // Get position of the triple.
708
0
    size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
709
710
    // Get position that closes the triple.
711
0
    size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
712
0
    if (TripleEnd == FC.npos)
713
0
      return None;
714
715
    // Next time we read after the new line.
716
0
    ++ReadChars;
717
718
0
    return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
719
0
  }
720
721
0
  Error ReadBundleEnd(MemoryBuffer &Input) final {
722
0
    StringRef FC = Input.getBuffer();
723
724
    // Read up to the next new line.
725
0
    assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
726
727
0
    size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
728
0
    if (TripleEnd != FC.npos)
729
      // Next time we read after the new line.
730
0
      ++ReadChars;
731
732
0
    return Error::success();
733
0
  }
734
735
0
  Error ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
736
0
    StringRef FC = Input.getBuffer();
737
0
    size_t BundleStart = ReadChars;
738
739
    // Find end of the bundle.
740
0
    size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
741
742
0
    StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
743
0
    OS << Bundle;
744
745
0
    return Error::success();
746
0
  }
747
748
  Error WriteHeader(raw_fd_ostream &OS,
749
2
                    ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
750
2
    return Error::success();
751
2
  }
752
753
4
  Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
754
4
    OS << BundleStartString << TargetTriple << "\n";
755
4
    return Error::success();
756
4
  }
757
758
4
  Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
759
4
    OS << BundleEndString << TargetTriple << "\n";
760
4
    return Error::success();
761
4
  }
762
763
4
  Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
764
4
    OS << Input.getBuffer();
765
4
    return Error::success();
766
4
  }
767
768
public:
769
  TextFileHandler(StringRef Comment)
770
2
      : FileHandler(), Comment(Comment), ReadChars(0) {
771
2
    BundleStartString =
772
2
        "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
773
2
    BundleEndString =
774
2
        "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
775
2
  }
776
777
  Error listBundleIDsCallback(MemoryBuffer &Input,
778
0
                              const BundleInfo &Info) final {
779
    // TODO: To list bundle IDs in a bundled text file we need to go through
780
    // all bundles. The format of bundled text file may need to include a
781
    // header if the performance of listing bundle IDs of bundled text file is
782
    // important.
783
0
    ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
784
0
    if (Error Err = ReadBundleEnd(Input))
785
0
      return Err;
786
0
    return Error::success();
787
0
  }
788
};
789
790
/// Return an appropriate object file handler. We use the specific object
791
/// handler if we know how to deal with that format, otherwise we use a default
792
/// binary file handler.
793
static std::unique_ptr<FileHandler>
794
0
CreateObjectFileHandler(MemoryBuffer &FirstInput) {
795
  // Check if the input file format is one that we know how to deal with.
796
0
  Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
797
798
  // We only support regular object files. If failed to open the input as a
799
  // known binary or this is not an object file use the default binary handler.
800
0
  if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
801
0
    return std::make_unique<BinaryFileHandler>();
802
803
  // Otherwise create an object file handler. The handler will be owned by the
804
  // client of this function.
805
0
  return std::make_unique<ObjectFileHandler>(
806
0
      std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())));
807
0
}
808
809
/// Return an appropriate handler given the input files and options.
810
static Expected<std::unique_ptr<FileHandler>>
811
2
CreateFileHandler(MemoryBuffer &FirstInput) {
812
2
  if (FilesType == "i")
813
1
    return std::make_unique<TextFileHandler>(/*Comment=*/"//");
814
1
  if (FilesType == "ii")
815
0
    return std::make_unique<TextFileHandler>(/*Comment=*/"//");
816
1
  if (FilesType == "cui")
817
1
    return std::make_unique<TextFileHandler>(/*Comment=*/"//");
818
  // TODO: `.d` should be eventually removed once `-M` and its variants are
819
  // handled properly in offload compilation.
820
0
  if (FilesType == "d")
821
0
    return std::make_unique<TextFileHandler>(/*Comment=*/"#");
822
0
  if (FilesType == "ll")
823
0
    return std::make_unique<TextFileHandler>(/*Comment=*/";");
824
0
  if (FilesType == "bc")
825
0
    return std::make_unique<BinaryFileHandler>();
826
0
  if (FilesType == "s")
827
0
    return std::make_unique<TextFileHandler>(/*Comment=*/"#");
828
0
  if (FilesType == "o")
829
0
    return CreateObjectFileHandler(FirstInput);
830
0
  if (FilesType == "gch")
831
0
    return std::make_unique<BinaryFileHandler>();
832
0
  if (FilesType == "ast")
833
0
    return std::make_unique<BinaryFileHandler>();
834
835
0
  return createStringError(errc::invalid_argument,
836
0
                           "'" + FilesType + "': invalid file type specified");
837
0
}
838
839
/// Bundle the files. Return true if an error was found.
840
2
static Error BundleFiles() {
841
2
  std::error_code EC;
842
843
  // Create output file.
844
2
  raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::OF_None);
845
2
  if (EC)
846
0
    return createFileError(OutputFileNames.front(), EC);
847
848
  // Open input files.
849
2
  SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
850
2
  InputBuffers.reserve(InputFileNames.size());
851
4
  for (auto &I : InputFileNames) {
852
4
    ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
853
4
        MemoryBuffer::getFileOrSTDIN(I);
854
4
    if (std::error_code EC = CodeOrErr.getError())
855
0
      return createFileError(I, EC);
856
4
    InputBuffers.emplace_back(std::move(*CodeOrErr));
857
4
  }
858
859
  // Get the file handler. We use the host buffer as reference.
860
2
  assert(HostInputIndex != ~0u && "Host input index undefined??");
861
2
  Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
862
2
      CreateFileHandler(*InputBuffers[HostInputIndex]);
863
2
  if (!FileHandlerOrErr)
864
0
    return FileHandlerOrErr.takeError();
865
866
2
  std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
867
2
  assert(FH);
868
869
  // Write header.
870
2
  if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
871
0
    return Err;
872
873
  // Write all bundles along with the start/end markers. If an error was found
874
  // writing the end of the bundle component, abort the bundle writing.
875
2
  auto Input = InputBuffers.begin();
876
4
  for (auto &Triple : TargetNames) {
877
4
    if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
878
0
      return Err;
879
4
    if (Error Err = FH->WriteBundle(OutputFile, **Input))
880
0
      return Err;
881
4
    if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
882
0
      return Err;
883
4
    ++Input;
884
4
  }
885
2
  return Error::success();
886
2
}
887
888
// List bundle IDs. Return true if an error was found.
889
0
static Error ListBundleIDsInFile(StringRef InputFileName) {
890
  // Open Input file.
891
0
  ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
892
0
      MemoryBuffer::getFileOrSTDIN(InputFileName);
893
0
  if (std::error_code EC = CodeOrErr.getError())
894
0
    return createFileError(InputFileName, EC);
895
896
0
  MemoryBuffer &Input = **CodeOrErr;
897
898
  // Select the right files handler.
899
0
  Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
900
0
      CreateFileHandler(Input);
901
0
  if (!FileHandlerOrErr)
902
0
    return FileHandlerOrErr.takeError();
903
904
0
  std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
905
0
  assert(FH);
906
0
  return FH->listBundleIDs(Input);
907
0
}
908
909
// Unbundle the files. Return true if an error was found.
910
0
static Error UnbundleFiles() {
911
  // Open Input file.
912
0
  ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
913
0
      MemoryBuffer::getFileOrSTDIN(InputFileNames.front());
914
0
  if (std::error_code EC = CodeOrErr.getError())
915
0
    return createFileError(InputFileNames.front(), EC);
916
917
0
  MemoryBuffer &Input = **CodeOrErr;
918
919
  // Select the right files handler.
920
0
  Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
921
0
      CreateFileHandler(Input);
922
0
  if (!FileHandlerOrErr)
923
0
    return FileHandlerOrErr.takeError();
924
925
0
  std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
926
0
  assert(FH);
927
928
  // Read the header of the bundled file.
929
0
  if (Error Err = FH->ReadHeader(Input))
930
0
    return Err;
931
932
  // Create a work list that consist of the map triple/output file.
933
0
  StringMap<StringRef> Worklist;
934
0
  auto Output = OutputFileNames.begin();
935
0
  for (auto &Triple : TargetNames) {
936
0
    Worklist[Triple] = *Output;
937
0
    ++Output;
938
0
  }
939
940
  // Read all the bundles that are in the work list. If we find no bundles we
941
  // assume the file is meant for the host target.
942
0
  bool FoundHostBundle = false;
943
0
  while (!Worklist.empty()) {
944
0
    Expected<Optional<StringRef>> CurTripleOrErr = FH->ReadBundleStart(Input);
945
0
    if (!CurTripleOrErr)
946
0
      return CurTripleOrErr.takeError();
947
948
    // We don't have more bundles.
949
0
    if (!*CurTripleOrErr)
950
0
      break;
951
952
0
    StringRef CurTriple = **CurTripleOrErr;
953
0
    assert(!CurTriple.empty());
954
955
0
    auto Output = Worklist.find(CurTriple);
956
    // The file may have more bundles for other targets, that we don't care
957
    // about. Therefore, move on to the next triple
958
0
    if (Output == Worklist.end())
959
0
      continue;
960
961
    // Check if the output file can be opened and copy the bundle to it.
962
0
    std::error_code EC;
963
0
    raw_fd_ostream OutputFile(Output->second, EC, sys::fs::OF_None);
964
0
    if (EC)
965
0
      return createFileError(Output->second, EC);
966
0
    if (Error Err = FH->ReadBundle(OutputFile, Input))
967
0
      return Err;
968
0
    if (Error Err = FH->ReadBundleEnd(Input))
969
0
      return Err;
970
0
    Worklist.erase(Output);
971
972
    // Record if we found the host bundle.
973
0
    if (hasHostKind(CurTriple))
974
0
      FoundHostBundle = true;
975
0
  }
976
977
0
  if (!AllowMissingBundles && !Worklist.empty()) {
978
0
    std::string ErrMsg = "Can't find bundles for";
979
0
    std::set<StringRef> Sorted;
980
0
    for (auto &E : Worklist)
981
0
      Sorted.insert(E.first());
982
0
    unsigned I = 0;
983
0
    unsigned Last = Sorted.size() - 1;
984
0
    for (auto &E : Sorted) {
985
0
      if (I != 0 && Last > 1)
986
0
        ErrMsg += ",";
987
0
      ErrMsg += " ";
988
0
      if (I == Last && I != 0)
989
0
        ErrMsg += "and ";
990
0
      ErrMsg += E.str();
991
0
      ++I;
992
0
    }
993
0
    return createStringError(inconvertibleErrorCode(), ErrMsg);
994
0
  }
995
996
  // If no bundles were found, assume the input file is the host bundle and
997
  // create empty files for the remaining targets.
998
0
  if (Worklist.size() == TargetNames.size()) {
999
0
    for (auto &E : Worklist) {
1000
0
      std::error_code EC;
1001
0
      raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1002
0
      if (EC)
1003
0
        return createFileError(E.second, EC);
1004
1005
      // If this entry has a host kind, copy the input file to the output file.
1006
0
      if (hasHostKind(E.first()))
1007
0
        OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
1008
0
    }
1009
0
    return Error::success();
1010
0
  }
1011
1012
  // If we found elements, we emit an error if none of those were for the host
1013
  // in case host bundle name was provided in command line.
1014
0
  if (!FoundHostBundle && HostInputIndex != ~0u)
1015
0
    return createStringError(inconvertibleErrorCode(),
1016
0
                             "Can't find bundle for the host target");
1017
1018
  // If we still have any elements in the worklist, create empty files for them.
1019
0
  for (auto &E : Worklist) {
1020
0
    std::error_code EC;
1021
0
    raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1022
0
    if (EC)
1023
0
      return createFileError(E.second, EC);
1024
0
  }
1025
1026
0
  return Error::success();
1027
0
}
1028
1029
0
static void PrintVersion(raw_ostream &OS) {
1030
0
  OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
1031
0
}
1032
1033
2
int main(int argc, const char **argv) {
1034
2
  sys::PrintStackTraceOnErrorSignal(argv[0]);
1035
1036
2
  cl::HideUnrelatedOptions(ClangOffloadBundlerCategory);
1037
2
  cl::SetVersionPrinter(PrintVersion);
1038
2
  cl::ParseCommandLineOptions(
1039
2
      argc, argv,
1040
2
      "A tool to bundle several input files of the specified type <type> \n"
1041
2
      "referring to the same source file but different targets into a single \n"
1042
2
      "one. The resulting file can also be unbundled into different files by \n"
1043
2
      "this tool if -unbundle is provided.\n");
1044
1045
2
  if (Help) {
1046
0
    cl::PrintHelpMessage();
1047
0
    return 0;
1048
0
  }
1049
1050
2
  auto reportError = [argv](Error E) {
1051
0
    logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
1052
0
    exit(1);
1053
0
  };
1054
1055
2
  auto doWork = [&](std::function<llvm::Error()> Work) {
1056
    // Save the current executable directory as it will be useful to find other
1057
    // tools.
1058
2
    BundlerExecutable = argv[0];
1059
2
    if (!llvm::sys::fs::exists(BundlerExecutable))
1060
0
      BundlerExecutable =
1061
0
          sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
1062
1063
2
    if (llvm::Error Err = Work()) {
1064
0
      reportError(std::move(Err));
1065
0
    }
1066
2
  };
1067
1068
2
  if (ListBundleIDs) {
1069
0
    if (Unbundle) {
1070
0
      reportError(
1071
0
          createStringError(errc::invalid_argument,
1072
0
                            "-unbundle and -list cannot be used together"));
1073
0
    }
1074
0
    if (InputFileNames.size() != 1) {
1075
0
      reportError(createStringError(errc::invalid_argument,
1076
0
                                    "only one input file supported for -list"));
1077
0
    }
1078
0
    if (OutputFileNames.size()) {
1079
0
      reportError(createStringError(errc::invalid_argument,
1080
0
                                    "-outputs option is invalid for -list"));
1081
0
    }
1082
0
    if (TargetNames.size()) {
1083
0
      reportError(createStringError(errc::invalid_argument,
1084
0
                                    "-targets option is invalid for -list"));
1085
0
    }
1086
1087
0
    doWork([]() { return ListBundleIDsInFile(InputFileNames.front()); });
1088
0
    return 0;
1089
0
  }
1090
1091
2
  if (OutputFileNames.getNumOccurrences() == 0) {
1092
0
    reportError(createStringError(
1093
0
        errc::invalid_argument,
1094
0
        "for the --outputs option: must be specified at least once!"));
1095
0
  }
1096
2
  if (TargetNames.getNumOccurrences() == 0) {
1097
0
    reportError(createStringError(
1098
0
        errc::invalid_argument,
1099
0
        "for the --targets option: must be specified at least once!"));
1100
0
  }
1101
2
  if (Unbundle) {
1102
0
    if (InputFileNames.size() != 1) {
1103
0
      reportError(createStringError(
1104
0
          errc::invalid_argument,
1105
0
          "only one input file supported in unbundling mode"));
1106
0
    }
1107
0
    if (OutputFileNames.size() != TargetNames.size()) {
1108
0
      reportError(createStringError(errc::invalid_argument,
1109
0
                                    "number of output files and targets should "
1110
0
                                    "match in unbundling mode"));
1111
0
    }
1112
2
  } else {
1113
2
    if (OutputFileNames.size() != 1) {
1114
0
      reportError(createStringError(
1115
0
          errc::invalid_argument,
1116
0
          "only one output file supported in bundling mode"));
1117
0
    }
1118
2
    if (InputFileNames.size() != TargetNames.size()) {
1119
0
      reportError(createStringError(
1120
0
          errc::invalid_argument,
1121
0
          "number of input files and targets should match in bundling mode"));
1122
0
    }
1123
2
  }
1124
1125
  // Verify that the offload kinds and triples are known. We also check that we
1126
  // have exactly one host target.
1127
2
  unsigned Index = 0u;
1128
2
  unsigned HostTargetNum = 0u;
1129
2
  llvm::DenseSet<StringRef> ParsedTargets;
1130
4
  for (StringRef Target : TargetNames) {
1131
4
    if (ParsedTargets.contains(Target)) {
1132
0
      reportError(createStringError(errc::invalid_argument,
1133
0
                                    "Duplicate targets are not allowed"));
1134
0
    }
1135
4
    ParsedTargets.insert(Target);
1136
1137
4
    StringRef Kind;
1138
4
    StringRef Triple;
1139
4
    getOffloadKindAndTriple(Target, Kind, Triple);
1140
1141
4
    bool KindIsValid = !Kind.empty();
1142
4
    KindIsValid = KindIsValid && StringSwitch<bool>(Kind)
1143
4
                                     .Case("host", true)
1144
4
                                     .Case("openmp", true)
1145
4
                                     .Case("hip", true)
1146
4
                                     .Default(false);
1147
1148
4
    bool TripleIsValid = !Triple.empty();
1149
4
    llvm::Triple T(Triple);
1150
4
    TripleIsValid &= T.getArch() != Triple::UnknownArch;
1151
1152
4
    if (!KindIsValid || !TripleIsValid) {
1153
0
      SmallVector<char, 128u> Buf;
1154
0
      raw_svector_ostream Msg(Buf);
1155
0
      Msg << "invalid target '" << Target << "'";
1156
0
      if (!KindIsValid)
1157
0
        Msg << ", unknown offloading kind '" << Kind << "'";
1158
0
      if (!TripleIsValid)
1159
0
        Msg << ", unknown target triple '" << Triple << "'";
1160
0
      reportError(createStringError(errc::invalid_argument, Msg.str()));
1161
0
    }
1162
1163
4
    if (KindIsValid && Kind == "host") {
1164
2
      ++HostTargetNum;
1165
      // Save the index of the input that refers to the host.
1166
2
      HostInputIndex = Index;
1167
2
    }
1168
1169
4
    ++Index;
1170
4
  }
1171
1172
  // Host triple is not really needed for unbundling operation, so do not
1173
  // treat missing host triple as error if we do unbundling.
1174
2
  if ((Unbundle && 
HostTargetNum > 10
) || (!Unbundle && HostTargetNum != 1)) {
1175
0
    reportError(createStringError(errc::invalid_argument,
1176
0
                                  "expecting exactly one host target but got " +
1177
0
                                      Twine(HostTargetNum)));
1178
0
  }
1179
1180
2
  doWork([]() { return Unbundle ? 
UnbundleFiles()0
: BundleFiles(); });
1181
2
  return 0;
1182
2
}