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