20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/StringMap.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/BinaryFormat/Magic.h"
27#include "llvm/Object/Archive.h"
28#include "llvm/Object/ArchiveWriter.h"
29#include "llvm/Object/Binary.h"
30#include "llvm/Object/ObjectFile.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/Compiler.h"
33#include "llvm/Support/Compression.h"
34#include "llvm/Support/Debug.h"
35#include "llvm/Support/EndianStream.h"
36#include "llvm/Support/Errc.h"
37#include "llvm/Support/Error.h"
38#include "llvm/Support/ErrorOr.h"
39#include "llvm/Support/FileSystem.h"
40#include "llvm/Support/MD5.h"
41#include "llvm/Support/ManagedStatic.h"
42#include "llvm/Support/MemoryBuffer.h"
43#include "llvm/Support/Path.h"
44#include "llvm/Support/Program.h"
45#include "llvm/Support/Signals.h"
46#include "llvm/Support/StringSaver.h"
47#include "llvm/Support/Timer.h"
48#include "llvm/Support/WithColor.h"
49#include "llvm/Support/raw_ostream.h"
50#include "llvm/TargetParser/Host.h"
51#include "llvm/TargetParser/Triple.h"
56#include <forward_list>
57#include <llvm/Support/Process.h>
61#include <system_error>
65using namespace llvm::object;
69struct CreateClangOffloadBundlerTimerGroup {
71 return new TimerGroup(
"Clang Offload Bundler Timer Group",
72 "Timer group for clang offload bundler");
76static llvm::ManagedStatic<llvm::TimerGroup,
77 CreateClangOffloadBundlerTimerGroup>
81#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
90 Target.split(Components,
'-', 5);
91 assert((Components.size() == 5 || Components.size() == 6) &&
92 "malformed target string");
94 StringRef TargetIdWithFeature =
95 Components.size() == 6 ? Components.back() :
"";
96 StringRef TargetId = TargetIdWithFeature.split(
':').first;
97 if (!TargetId.empty() &&
99 this->
TargetID = TargetIdWithFeature;
105 llvm::Triple T = llvm::Triple(llvm::join(TripleSlice,
"-"));
106 this->
Triple = llvm::Triple(T.getArchName(), T.getVendorName(), T.getOSName(),
107 T.getEnvironmentName());
120 const StringRef TargetOffloadKind)
const {
122 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
123 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
127 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
128 TargetOffloadKind ==
"openmp";
129 bool OpenMPCompatibleWithHIP =
131 TargetOffloadKind.starts_with_insensitive(
"hip");
132 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
138 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
147 std::string NormalizedTriple;
152 if (
Triple.getOS() == Triple::OSType::AMDHSA) {
153 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::THREE_IDENT);
154 NormalizedTriple.push_back(
'-');
156 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::FOUR_IDENT);
162 StringRef BundleFileName) {
163 if (
Device.contains(
"gfx"))
165 if (
Device.contains(
"sm_"))
167 return sys::path::extension(BundleFileName);
172 StringRef LibName = sys::path::stem(BundleFileName);
191 virtual ~FileHandler() {}
195 virtual Error ReadHeader(StringRef FC) = 0;
200 virtual Expected<std::optional<StringRef>>
201 ReadBundleStart(StringRef Input) = 0;
204 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
207 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
211 virtual Error WriteHeader(raw_ostream &OS,
212 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
216 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
220 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
223 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
226 virtual Error finalizeOutputFile() {
return Error::success(); }
229 virtual Error listBundleIDs(MemoryBuffer &Input) {
230 size_t NextBundleStart = 0;
231 StringRef BufferString = Input.getBuffer();
232 while (NextBundleStart != StringRef::npos) {
235 BufferString = BufferString.drop_front(NextBundleStart);
238 Error Err = ReadHeader(BufferString);
242 Err = forEachBundle(BufferString, [&](
const BundleInfo &Info) ->
Error {
243 llvm::outs() << Info.BundleID <<
'\n';
244 Error Err = listBundleIDsCallback(Input, Info);
247 return Error::success();
257 return Error::success();
261 virtual Error getBundleIDs(MemoryBuffer &Input,
262 std::set<StringRef> &BundleIds) {
264 if (
Error Err = ReadHeader(Input.getBuffer()))
266 return forEachBundle(Input.getBuffer(),
267 [&](
const BundleInfo &Info) ->
Error {
268 BundleIds.insert(Info.BundleID);
269 Error Err = listBundleIDsCallback(Input, Info);
272 return Error::success();
277 Error forEachBundle(StringRef Input,
280 Expected<std::optional<StringRef>> CurTripleOrErr =
281 ReadBundleStart(Input);
283 return CurTripleOrErr.takeError();
286 if (!*CurTripleOrErr)
289 StringRef CurTriple = **CurTripleOrErr;
290 assert(!CurTriple.empty());
292 BundleInfo Info{CurTriple};
296 return Error::success();
300 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
301 const BundleInfo &Info) {
302 return Error::success();
330static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
331 return llvm::support::endian::read64le(Buffer.data() + pos);
335static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
336 llvm::support::endian::write(OS, Val, llvm::endianness::little);
339class BinaryFileHandler final :
public FileHandler {
341 struct BinaryBundleInfo final :
public BundleInfo {
347 BinaryBundleInfo() {}
348 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
353 StringMap<BinaryBundleInfo> BundlesInfo;
356 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
357 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
360 std::string CurWriteBundleTarget;
363 const OffloadBundlerConfig &BundlerConfig;
367 BinaryFileHandler(
const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
369 ~BinaryFileHandler() final {}
371 Error ReadHeader(StringRef FC)
final {
373 CurBundleInfo = BundlesInfo.end();
377 if (ReadChars > FC.size())
378 return Error::success();
381 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
382 return Error::success();
385 if (ReadChars + 8 > FC.size())
386 return Error::success();
388 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
392 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
395 if (ReadChars + 8 > FC.size())
396 return Error::success();
398 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
402 if (ReadChars + 8 > FC.size())
403 return Error::success();
405 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
409 if (ReadChars + 8 > FC.size())
410 return Error::success();
412 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
416 if (ReadChars + TripleSize > FC.size())
417 return Error::success();
419 StringRef Triple(&FC.data()[ReadChars], TripleSize);
420 ReadChars += TripleSize;
423 if (!Offset || Offset + Size > FC.size())
424 return Error::success();
426 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
429 CurBundleInfo = BundlesInfo.end();
430 NextBundleInfo = BundlesInfo.begin();
431 return Error::success();
434 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
435 if (NextBundleInfo == BundlesInfo.end())
437 CurBundleInfo = NextBundleInfo++;
438 return CurBundleInfo->first();
441 Error ReadBundleEnd(MemoryBuffer &Input)
final {
442 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
443 return Error::success();
446 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
447 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
448 StringRef FC = Input.getBuffer();
449 OS.write(FC.data() + CurBundleInfo->second.Offset,
450 CurBundleInfo->second.Size);
451 return Error::success();
454 Error WriteHeader(raw_ostream &OS,
455 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
465 HeaderSize += T.size();
471 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
475 MemoryBuffer &MB = *Inputs[Idx++];
478 Write8byteIntegerToBuffer(OS, HeaderSize);
480 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
481 BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
482 HeaderSize += MB.getBufferSize();
484 Write8byteIntegerToBuffer(OS, T.size());
488 return Error::success();
491 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
492 CurWriteBundleTarget = TargetTriple.str();
493 return Error::success();
496 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
497 return Error::success();
500 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
501 auto BI = BundlesInfo[CurWriteBundleTarget];
504 size_t CurrentPos =
OS.tell();
505 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
506 for (
size_t I = 0; I < PaddingSize; ++I)
508 assert(
OS.tell() == BI.Offset);
510 OS.write(Input.getBufferStart(), Input.getBufferSize());
512 return Error::success();
518class TempFileHandlerRAII {
520 ~TempFileHandlerRAII() {
521 for (
const auto &
File : Files)
522 sys::fs::remove(
File);
526 Expected<StringRef>
Create(std::optional<ArrayRef<char>> Contents) {
527 SmallString<128u>
File;
528 if (std::error_code EC =
529 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
530 return createFileError(
File, EC);
531 Files.push_front(
File);
535 raw_fd_ostream
OS(
File, EC);
537 return createFileError(
File, EC);
538 OS.write(Contents->data(), Contents->size());
540 return Files.front().str();
544 std::forward_list<SmallString<128u>> Files;
551class ObjectFileHandler final :
public FileHandler {
554 std::unique_ptr<ObjectFile> Obj;
557 StringRef getInputFileContents()
const {
return Obj->getData(); }
561 static Expected<std::optional<StringRef>>
562 IsOffloadSection(SectionRef CurSection) {
563 Expected<StringRef> NameOrErr = CurSection.getName();
565 return NameOrErr.takeError();
568 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
576 unsigned NumberOfInputs = 0;
580 unsigned NumberOfProcessedInputs = 0;
583 section_iterator CurrentSection;
584 section_iterator NextSection;
587 const OffloadBundlerConfig &BundlerConfig;
591 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
592 const OffloadBundlerConfig &BC)
593 : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
594 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
596 ~ObjectFileHandler() final {}
598 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
600 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
601 while (NextSection != Obj->section_end()) {
602 CurrentSection = NextSection;
607 Expected<std::optional<StringRef>> TripleOrErr =
608 IsOffloadSection(*CurrentSection);
610 return TripleOrErr.takeError();
612 return **TripleOrErr;
617 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
619 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
620 Expected<StringRef> ContentOrErr = CurrentSection->getContents();
622 return ContentOrErr.takeError();
623 StringRef Content = *ContentOrErr;
626 std::string ModifiedContent;
627 if (Content.size() == 1u && Content.front() == 0) {
628 auto HostBundleOrErr = getHostBundle(
629 StringRef(Input.getBufferStart(), Input.getBufferSize()));
630 if (!HostBundleOrErr)
631 return HostBundleOrErr.takeError();
633 ModifiedContent = std::move(*HostBundleOrErr);
634 Content = ModifiedContent;
637 OS.write(Content.data(), Content.size());
638 return Error::success();
641 Error WriteHeader(raw_ostream &OS,
642 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
644 "Host input index not defined.");
647 NumberOfInputs = Inputs.size();
648 return Error::success();
651 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
652 ++NumberOfProcessedInputs;
653 return Error::success();
656 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
657 return Error::success();
660 Error finalizeOutputFile() final {
661 assert(NumberOfProcessedInputs <= NumberOfInputs &&
662 "Processing more inputs that actually exist!");
664 "Host input index not defined.");
667 if (NumberOfProcessedInputs != NumberOfInputs)
668 return Error::success();
676 "llvm-objcopy path not specified");
679 TempFileHandlerRAII TempFiles;
683 BumpPtrAllocator
Alloc;
684 StringSaver SS{
Alloc};
685 SmallVector<StringRef, 8u> ObjcopyArgs{
"llvm-objcopy"};
687 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
694 Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
696 return TempFileOrErr.takeError();
697 InputFile = *TempFileOrErr;
700 ObjcopyArgs.push_back(
703 ObjcopyArgs.push_back(
705 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
707 ObjcopyArgs.push_back(
"--");
708 ObjcopyArgs.push_back(
715 return Error::success();
718 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
719 return Error::success();
723 Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
727 errs() <<
"\"" << Objcopy <<
"\"";
728 for (StringRef Arg : drop_begin(Args, 1))
729 errs() <<
" \"" << Arg <<
"\"";
732 if (sys::ExecuteAndWait(Objcopy, Args))
733 return createStringError(inconvertibleErrorCode(),
734 "'llvm-objcopy' tool failed");
736 return Error::success();
739 Expected<std::string> getHostBundle(StringRef Input) {
740 TempFileHandlerRAII TempFiles;
742 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
743 if (!ModifiedObjPathOrErr)
744 return ModifiedObjPathOrErr.takeError();
745 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
747 BumpPtrAllocator
Alloc;
748 StringSaver SS{
Alloc};
749 SmallVector<StringRef, 16> ObjcopyArgs{
"llvm-objcopy"};
751 ObjcopyArgs.push_back(
"--regex");
752 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
753 ObjcopyArgs.push_back(
"--");
755 StringRef ObjcopyInputFileName;
762 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
763 auto InputFileOrErr = TempFiles.Create(ArrayRef<char>(Input));
765 return InputFileOrErr.takeError();
766 ObjcopyInputFileName = *InputFileOrErr;
770 ObjcopyArgs.push_back(ObjcopyInputFileName);
771 ObjcopyArgs.push_back(ModifiedObjPath);
774 return std::move(Err);
776 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
778 return createStringError(BufOrErr.getError(),
779 "Failed to read back the modified object file");
781 return BufOrErr->get()->getBuffer().str();
794class TextFileHandler final :
public FileHandler {
799 std::string BundleStartString;
802 std::string BundleEndString;
805 size_t ReadChars = 0u;
808 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
810 Expected<std::optional<StringRef>> ReadBundleStart(StringRef FC)
final {
813 ReadChars = FC.find(BundleStartString, ReadChars);
814 if (ReadChars == FC.npos)
818 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
821 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
822 if (TripleEnd == FC.npos)
828 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
831 Error ReadBundleEnd(MemoryBuffer &Input)
final {
832 StringRef FC = Input.getBuffer();
835 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
837 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
838 if (TripleEnd != FC.npos)
842 return Error::success();
845 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
846 StringRef FC = Input.getBuffer();
847 size_t BundleStart = ReadChars;
850 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
852 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
855 return Error::success();
858 Error WriteHeader(raw_ostream &OS,
859 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
860 return Error::success();
863 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
864 OS << BundleStartString << TargetTriple <<
"\n";
865 return Error::success();
868 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
869 OS << BundleEndString << TargetTriple <<
"\n";
870 return Error::success();
873 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
874 OS << Input.getBuffer();
875 return Error::success();
879 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
886 Error listBundleIDsCallback(MemoryBuffer &Input,
887 const BundleInfo &Info)
final {
892 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
893 if (
Error Err = ReadBundleEnd(Input))
895 return Error::success();
903static std::unique_ptr<FileHandler>
911 if (errorToBool(BinaryOrErr.takeError()) || !
isa<ObjectFile>(*BinaryOrErr))
912 return std::make_unique<BinaryFileHandler>(BundlerConfig);
916 return std::make_unique<ObjectFileHandler>(
925 std::string FilesType = BundlerConfig.
FilesType;
927 if (FilesType ==
"i")
928 return std::make_unique<TextFileHandler>(
"//");
929 if (FilesType ==
"ii")
930 return std::make_unique<TextFileHandler>(
"//");
931 if (FilesType ==
"cui")
932 return std::make_unique<TextFileHandler>(
"//");
933 if (FilesType ==
"hipi")
934 return std::make_unique<TextFileHandler>(
"//");
937 if (FilesType ==
"d")
938 return std::make_unique<TextFileHandler>(
"#");
939 if (FilesType ==
"ll")
940 return std::make_unique<TextFileHandler>(
";");
941 if (FilesType ==
"bc")
942 return std::make_unique<BinaryFileHandler>(BundlerConfig);
943 if (FilesType ==
"s")
944 return std::make_unique<TextFileHandler>(
"#");
945 if (FilesType ==
"o")
947 if (FilesType ==
"a")
949 if (FilesType ==
"gch")
950 return std::make_unique<BinaryFileHandler>(BundlerConfig);
951 if (FilesType ==
"ast")
952 return std::make_unique<BinaryFileHandler>(BundlerConfig);
954 return createStringError(errc::invalid_argument,
955 "'" + FilesType +
"': invalid file type specified");
960 if (llvm::compression::zstd::isAvailable()) {
965 }
else if (llvm::compression::zlib::isAvailable()) {
971 auto IgnoreEnvVarOpt =
972 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
973 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
975 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
976 if (VerboseEnvVarOpt.has_value())
977 Verbose = VerboseEnvVarOpt.value() ==
"1";
978 auto CompressEnvVarOpt =
979 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
980 if (CompressEnvVarOpt.has_value())
981 Compress = CompressEnvVarOpt.value() ==
"1";
982 auto CompressionLevelEnvVarOpt =
983 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
984 if (CompressionLevelEnvVarOpt.has_value()) {
985 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
987 if (!CompressionLevelStr.getAsInteger(10, Level))
991 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
992 << CompressionLevelStr.str() <<
". Ignoring it.\n";
994 auto CompressedBundleFormatVersionOpt =
995 llvm::sys::Process::GetEnv(
"COMPRESSED_BUNDLE_FORMAT_VERSION");
996 if (CompressedBundleFormatVersionOpt.has_value()) {
997 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();
999 if (!VersionStr.getAsInteger(10, Version)) {
1000 if (Version >= 2 && Version <= 3)
1004 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
1006 <<
". Valid values are 2 or 3. Using default version "
1010 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
1011 << VersionStr.str() <<
". Using default version "
1018 std::string
Num = std::to_string(
Value);
1019 int InsertPosition =
Num.length() - 3;
1020 while (InsertPosition > 0) {
1021 Num.insert(InsertPosition,
",");
1022 InsertPosition -= 3;
1029 const llvm::MemoryBuffer &Input,
1030 uint16_t Version,
bool Verbose) {
1031 if (!llvm::compression::zstd::isAvailable() &&
1032 !llvm::compression::zlib::isAvailable())
1033 return createStringError(llvm::inconvertibleErrorCode(),
1034 "Compression not supported");
1035 llvm::Timer HashTimer(
"Hash Calculation Timer",
"Hash calculation time",
1038 HashTimer.startTimer();
1040 llvm::MD5::MD5Result
Result;
1041 Hash.update(Input.getBuffer());
1043 uint64_t TruncatedHash =
Result.low();
1045 HashTimer.stopTimer();
1049 reinterpret_cast<const uint8_t *
>(Input.getBuffer().data()),
1050 Input.getBuffer().size());
1051 llvm::Timer CompressTimer(
"Compression Timer",
"Compression time",
1054 CompressTimer.startTimer();
1055 llvm::compression::compress(P, BufferUint8, CompressedBuffer);
1057 CompressTimer.stopTimer();
1059 uint16_t CompressionMethod =
static_cast<uint16_t
>(P.format);
1062 uint64_t UncompressedSize64 = Input.getBuffer().size();
1063 uint64_t TotalFileSize64;
1068 if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
1069 return createStringError(llvm::inconvertibleErrorCode(),
1070 "Uncompressed size exceeds version 2 limit");
1071 if ((MagicNumber.size() +
sizeof(uint32_t) +
sizeof(Version) +
1072 sizeof(CompressionMethod) +
sizeof(uint32_t) +
sizeof(TruncatedHash) +
1073 CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
1074 return createStringError(llvm::inconvertibleErrorCode(),
1075 "Total file size exceeds version 2 limit");
1077 TotalFileSize64 = MagicNumber.size() +
sizeof(uint32_t) +
sizeof(Version) +
1078 sizeof(CompressionMethod) +
sizeof(uint32_t) +
1079 sizeof(TruncatedHash) + CompressedBuffer.size();
1081 TotalFileSize64 = MagicNumber.size() +
sizeof(uint64_t) +
sizeof(Version) +
1082 sizeof(CompressionMethod) +
sizeof(uint64_t) +
1083 sizeof(TruncatedHash) + CompressedBuffer.size();
1087 llvm::raw_svector_ostream OS(FinalBuffer);
1089 OS.write(
reinterpret_cast<const char *
>(&Version),
sizeof(Version));
1090 OS.write(
reinterpret_cast<const char *
>(&CompressionMethod),
1091 sizeof(CompressionMethod));
1095 uint32_t TotalFileSize32 =
static_cast<uint32_t
>(TotalFileSize64);
1096 uint32_t UncompressedSize32 =
static_cast<uint32_t
>(UncompressedSize64);
1097 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize32),
1098 sizeof(TotalFileSize32));
1099 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize32),
1100 sizeof(UncompressedSize32));
1102 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize64),
1103 sizeof(TotalFileSize64));
1104 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize64),
1105 sizeof(UncompressedSize64));
1108 OS.write(
reinterpret_cast<const char *
>(&TruncatedHash),
1109 sizeof(TruncatedHash));
1110 OS.write(
reinterpret_cast<const char *
>(CompressedBuffer.data()),
1111 CompressedBuffer.size());
1115 P.format == llvm::compression::Format::Zstd ?
"zstd" :
"zlib";
1116 double CompressionRate =
1117 static_cast<double>(UncompressedSize64) / CompressedBuffer.size();
1118 double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
1119 double CompressionSpeedMBs =
1120 (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
1121 llvm::errs() <<
"Compressed bundle format version: " << Version <<
"\n"
1122 <<
"Total file size (including headers): "
1124 <<
"Compression method used: " << MethodUsed <<
"\n"
1125 <<
"Compression level: " << P.level <<
"\n"
1126 <<
"Binary size before compression: "
1128 <<
"Binary size after compression: "
1130 <<
"Compression rate: "
1131 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1132 <<
"Compression ratio: "
1133 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1134 <<
"Compression speed: "
1135 << llvm::format(
"%.2lf MB/s", CompressionSpeedMBs) <<
"\n"
1136 <<
"Truncated MD5 hash: "
1137 << llvm::format_hex(TruncatedHash, 16) <<
"\n";
1140 return llvm::MemoryBuffer::getMemBufferCopy(
1141 llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
1191 llvm_unreachable(
"Unsupported version");
1198 assert(llvm::identify_magic(Blob) ==
1199 llvm::file_magic::offload_bundle_compressed);
1202 memcpy(&Header, Blob.data(), std::min(Blob.size(),
sizeof(Header)));
1208 if (Blob.size() < RequiredSize)
1209 return createStringError(inconvertibleErrorCode(),
1210 "Compressed bundle header size too small");
1228 return createStringError(inconvertibleErrorCode(),
1229 "Unknown compressed bundle version");
1234 case static_cast<uint16_t
>(compression::Format::Zlib):
1235 case static_cast<uint16_t
>(compression::Format::Zstd):
1237 static_cast<compression::Format
>(Header.
Common.
Method);
1240 return createStringError(inconvertibleErrorCode(),
1241 "Unknown compressing method");
1250 StringRef Blob = Input.getBuffer();
1254 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1256 if (llvm::identify_magic(Blob) !=
1257 llvm::file_magic::offload_bundle_compressed) {
1259 llvm::errs() <<
"Uncompressed bundle.\n";
1260 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1266 return HeaderOrErr.takeError();
1269 unsigned ThisVersion = Normalized.
Version;
1274 size_t TotalFileSize = Normalized.
FileSize.value_or(0);
1276 auto StoredHash = Normalized.
Hash;
1278 llvm::Timer DecompressTimer(
"Decompression Timer",
"Decompression time",
1281 DecompressTimer.startTimer();
1284 StringRef CompressedData =
1285 Blob.substr(HeaderSize, TotalFileSize - HeaderSize);
1286 if (llvm::Error DecompressionError = llvm::compression::decompress(
1287 CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
1288 DecompressedData, UncompressedSize))
1289 return createStringError(inconvertibleErrorCode(),
1290 "Could not decompress embedded file contents: " +
1291 llvm::toString(std::move(DecompressionError)));
1294 DecompressTimer.stopTimer();
1296 double DecompressionTimeSeconds =
1297 DecompressTimer.getTotalTime().getWallTime();
1300 llvm::Timer HashRecalcTimer(
"Hash Recalculation Timer",
1301 "Hash recalculation time",
1303 HashRecalcTimer.startTimer();
1305 llvm::MD5::MD5Result
Result;
1308 uint64_t RecalculatedHash =
Result.low();
1309 HashRecalcTimer.stopTimer();
1310 bool HashMatch = (StoredHash == RecalculatedHash);
1312 double CompressionRate =
1313 static_cast<double>(UncompressedSize) / CompressedData.size();
1314 double DecompressionSpeedMBs =
1315 (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
1317 llvm::errs() <<
"Compressed bundle format version: " << ThisVersion <<
"\n";
1318 if (ThisVersion >= 2)
1319 llvm::errs() <<
"Total file size (from header): "
1321 llvm::errs() <<
"Decompression method: "
1322 << (CompressionFormat == llvm::compression::Format::Zlib
1326 <<
"Size before decompression: "
1328 <<
"Size after decompression: "
1330 <<
"Compression rate: "
1331 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1332 <<
"Compression ratio: "
1333 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1334 <<
"Decompression speed: "
1335 << llvm::format(
"%.2lf MB/s", DecompressionSpeedMBs) <<
"\n"
1336 <<
"Stored hash: " << llvm::format_hex(StoredHash, 16) <<
"\n"
1337 <<
"Recalculated hash: "
1338 << llvm::format_hex(RecalculatedHash, 16) <<
"\n"
1339 <<
"Hashes match: " << (HashMatch ?
"Yes" :
"No") <<
"\n";
1342 return llvm::MemoryBuffer::getMemBufferCopy(
1343 llvm::toStringRef(DecompressedData));
1351 size_t NextBundleStart = 0;
1352 std::unique_ptr<MemoryBuffer> Buffer;
1355 ErrorOr<std::unique_ptr<MemoryBuffer>> Contents =
1356 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1357 if (std::error_code EC = Contents.getError())
1358 return createFileError(InputFileName, EC);
1361 while ((NextBundleStart != StringRef::npos) &&
1362 (Offset < (**Contents).getBufferSize())) {
1363 Buffer = MemoryBuffer::getMemBuffer(
1364 (**Contents).getBuffer().drop_front(Offset),
"",
1367 if (identify_magic((*Buffer).getBuffer()) ==
1368 file_magic::offload_bundle_compressed) {
1369 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1371 NextBundleStart = StringRef::npos;
1373 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1374 MemoryBuffer::getMemBuffer(
1375 (*Buffer).getBuffer().take_front(NextBundleStart),
1378 if (std::error_code EC = CodeOrErr.getError())
1379 return createFileError(InputFileName, EC);
1384 if (!DecompressedBufferOrErr)
1385 return createStringError(
1386 inconvertibleErrorCode(),
1387 "Failed to decompress input: " +
1388 llvm::toString(DecompressedBufferOrErr.takeError()));
1390 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1395 if (!FileHandlerOrErr)
1396 return FileHandlerOrErr.takeError();
1397 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1399 Error E = FH->listBundleIDs(DecompressedInput);
1403 if (NextBundleStart != StringRef::npos)
1404 Offset += NextBundleStart;
1406 return Error::success();
1417 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1418 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1419 << CodeObjectInfo.
str()
1420 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1428 "CodeObjectCompatibility",
1429 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1430 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1436 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1438 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1443 if (!TargetProc || !CodeObjectProc ||
1444 CodeObjectProc.value() != TargetProc.value()) {
1445 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1446 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1447 << CodeObjectInfo.
str()
1448 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1454 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1455 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1456 dbgs() <<
"Incompatible: CodeObject has more features "
1457 "than target \t[CodeObject: "
1458 << CodeObjectInfo.
str()
1459 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1467 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1468 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1469 if (TargetFeature == TargetFeatureMap.end()) {
1471 "CodeObjectCompatibility",
1473 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1474 "not matching with Target feature's ANY value \t[CodeObject: "
1475 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1478 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1480 "CodeObjectCompatibility",
1481 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1482 "not matching with Target feature's non-ANY value "
1484 << CodeObjectInfo.
str()
1485 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1495 "CodeObjectCompatibility",
1496 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1497 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1508 llvm::raw_svector_ostream BufferStream(Buffer);
1514 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1515 MemoryBuffer::getFileOrSTDIN(I,
true);
1516 if (std::error_code EC = CodeOrErr.getError())
1517 return createFileError(I, EC);
1518 InputBuffers.emplace_back(std::move(*CodeOrErr));
1523 "Host input index undefined??");
1528 if (!FileHandlerOrErr)
1529 return FileHandlerOrErr.takeError();
1531 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1535 if (
Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1540 auto Input = InputBuffers.begin();
1542 if (
Error Err = FH->WriteBundleStart(BufferStream, Triple))
1544 if (
Error Err = FH->WriteBundle(BufferStream, **Input))
1546 if (
Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1551 raw_fd_ostream OutputFile(
BundlerConfig.OutputFileNames.front(), EC,
1554 return createFileError(
BundlerConfig.OutputFileNames.front(), EC);
1558 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1559 llvm::MemoryBuffer::getMemBufferCopy(
1560 llvm::StringRef(Buffer.data(), Buffer.size()));
1566 if (
auto Error = CompressionResult.takeError())
1569 auto CompressedMemBuffer = std::move(CompressionResult.get());
1570 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1571 CompressedMemBuffer->getBufferEnd());
1573 CompressedBuffer = std::move(Buffer);
1575 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1577 return FH->finalizeOutputFile();
1583 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1584 MemoryBuffer::getFileOrSTDIN(
BundlerConfig.InputFileNames.front(),
1586 if (std::error_code EC = CodeOrErr.getError())
1587 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1590 StringMap<StringRef> Worklist;
1594 return createStringError(errc::invalid_argument,
1595 "invalid bundle id from bundle config");
1596 Worklist[Triple] = *Output;
1604 bool FoundHostBundle =
false;
1606 size_t NextBundleStart = 0;
1607 std::unique_ptr<MemoryBuffer> Buffer;
1609 while ((NextBundleStart != StringRef::npos) &&
1610 (Offset < (**CodeOrErr).getBufferSize())) {
1612 Buffer = MemoryBuffer::getMemBuffer(
1613 (**CodeOrErr).getBuffer().drop_front(Offset),
"",
1616 if (identify_magic((*Buffer).getBuffer()) ==
1617 file_magic::offload_bundle_compressed) {
1618 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1619 }
else if (identify_magic((*Buffer).getBuffer()) ==
1620 file_magic::offload_bundle) {
1621 NextBundleStart = (*Buffer).getBuffer().find(
1624 NextBundleStart = StringRef::npos;
1626 ErrorOr<std::unique_ptr<MemoryBuffer>> BlobOrErr =
1627 MemoryBuffer::getMemBuffer(
1628 (*Buffer).getBuffer().take_front(NextBundleStart),
1631 if (std::error_code EC = BlobOrErr.getError())
1632 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1637 if (!DecompressedBufferOrErr)
1638 return createStringError(
1639 inconvertibleErrorCode(),
1640 "Failed to decompress input: " +
1641 llvm::toString(DecompressedBufferOrErr.takeError()));
1643 MemoryBuffer &Input = **DecompressedBufferOrErr;
1648 if (!FileHandlerOrErr)
1649 return FileHandlerOrErr.takeError();
1651 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1655 if (
Error Err = FH->ReadHeader(Input.getBuffer()))
1659 while (!Worklist.empty()) {
1661 FH->ReadBundleStart(Input.getBuffer());
1662 if (!CurTripleOrErr)
1663 return CurTripleOrErr.takeError();
1666 if (!*CurTripleOrErr)
1669 StringRef CurTriple = **CurTripleOrErr;
1670 assert(!CurTriple.empty());
1672 return createStringError(errc::invalid_argument,
1673 "invalid bundle id read from the bundle");
1675 auto Output = Worklist.begin();
1676 for (
auto E = Worklist.end(); Output != E; Output++) {
1683 if (Output == Worklist.end())
1688 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1690 return createFileError((*Output).second, EC);
1691 if (
Error Err = FH->ReadBundle(OutputFile, Input))
1693 if (
Error Err = FH->ReadBundleEnd(Input))
1695 Worklist.erase(Output);
1699 if (OffloadInfo.hasHostKind())
1700 FoundHostBundle =
true;
1703 if (NextBundleStart != StringRef::npos)
1704 Offset += NextBundleStart;
1707 if (!
BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1708 std::string ErrMsg =
"Can't find bundles for";
1709 std::set<StringRef> Sorted;
1710 for (
auto &E : Worklist)
1711 Sorted.insert(E.first());
1713 unsigned Last = Sorted.size() - 1;
1714 for (
auto &E : Sorted) {
1715 if (I != 0 &&
Last > 1)
1718 if (I ==
Last && I != 0)
1723 return createStringError(inconvertibleErrorCode(), ErrMsg);
1729 for (
auto &E : Worklist) {
1731 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1733 return createFileError(E.second, EC);
1739 if (OffloadInfo.hasHostKind())
1740 OutputFile.write((**CodeOrErr).getBufferStart(),
1741 (**CodeOrErr).getBufferSize());
1743 return Error::success();
1748 if (!(FoundHostBundle ||
BundlerConfig.HostInputIndex == ~0u ||
1750 return createStringError(inconvertibleErrorCode(),
1751 "Can't find bundle for the host target");
1754 for (
auto &E : Worklist) {
1756 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1758 return createFileError(E.second, EC);
1761 return Error::success();
1765 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1779 if (!CompatibleTargets.empty()) {
1780 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1781 dbgs() <<
"CompatibleTargets list should be empty\n");
1787 CompatibleTargets.push_back(
Target);
1789 return !CompatibleTargets.empty();
1799 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1800 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1801 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1802 if (std::error_code EC = BufOrErr.getError())
1803 return createFileError(ArchiveName, EC);
1805 ArchiveBuffers.push_back(std::move(*BufOrErr));
1807 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1809 return LibOrErr.takeError();
1811 auto Archive = std::move(*LibOrErr);
1813 Error ArchiveErr = Error::success();
1814 auto ChildEnd = Archive->child_end();
1817 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1818 ArchiveIter != ChildEnd; ++ArchiveIter) {
1821 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1822 if (!ArchiveChildNameOrErr)
1823 return ArchiveChildNameOrErr.takeError();
1825 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1826 if (!CodeObjectBufferRefOrErr)
1827 return CodeObjectBufferRefOrErr.takeError();
1829 auto CodeObjectBuffer =
1830 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1834 if (!FileHandlerOrErr)
1835 return FileHandlerOrErr.takeError();
1837 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1838 assert(FileHandler);
1840 std::set<StringRef> BundleIds;
1841 auto CodeObjectFileError =
1842 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1843 if (CodeObjectFileError)
1844 return CodeObjectFileError;
1847 if (ConflictingArchs) {
1848 std::string ErrMsg =
1849 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1850 ", " + ConflictingArchs.value().second +
"] found in " +
1851 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1853 return createStringError(inconvertibleErrorCode(), ErrMsg);
1868 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1872 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1875 StringMap<StringRef> TargetOutputFileNameMap;
1879 TargetOutputFileNameMap[
Target] = *Output;
1891 return ArchiveError;
1895 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1896 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1897 if (std::error_code EC = BufOrErr.getError())
1898 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1900 ArchiveBuffers.push_back(std::move(*BufOrErr));
1902 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1904 return LibOrErr.takeError();
1906 auto Archive = std::move(*LibOrErr);
1908 Error ArchiveErr = Error::success();
1909 auto ChildEnd = Archive->child_end();
1912 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1913 ArchiveIter != ChildEnd; ++ArchiveIter) {
1916 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1917 if (!ArchiveChildNameOrErr)
1918 return ArchiveChildNameOrErr.takeError();
1920 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1922 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1923 if (!CodeObjectBufferRefOrErr)
1924 return CodeObjectBufferRefOrErr.takeError();
1926 auto TempCodeObjectBuffer =
1927 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1933 if (!DecompressedBufferOrErr)
1934 return createStringError(
1935 inconvertibleErrorCode(),
1936 "Failed to decompress code object: " +
1937 llvm::toString(DecompressedBufferOrErr.takeError()));
1939 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1943 if (!FileHandlerOrErr)
1944 return FileHandlerOrErr.takeError();
1946 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1947 assert(FileHandler &&
1948 "FileHandle creation failed for file in the archive!");
1950 if (
Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer.getBuffer()))
1954 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1955 if (!CurBundleIDOrErr)
1956 return CurBundleIDOrErr.takeError();
1958 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1960 if (!OptionalCurBundleID)
1962 StringRef CodeObject = *OptionalCurBundleID;
1966 while (!CodeObject.empty()) {
1969 return createStringError(errc::invalid_argument,
1970 "Invalid bundle id read from code object");
1975 std::string BundleData;
1976 raw_string_ostream DataStream(BundleData);
1977 if (
Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1980 for (
auto &CompatibleTarget : CompatibleTargets) {
1982 BundledObjectFileName.assign(BundledObjectFile);
1983 auto OutputBundleName =
1984 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1987 CodeObjectInfo.TargetID))
1991 llvm::replace(OutputBundleName,
':',
'_');
1993 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1994 DataStream.str(), OutputBundleName);
1995 ArchiveBuffers.push_back(std::move(MemBuf));
1996 llvm::MemoryBufferRef MemBufRef =
1997 MemoryBufferRef(*(ArchiveBuffers.back()));
2001 OutputArchivesMap[CompatibleTarget].push_back(
2002 NewArchiveMember(MemBufRef));
2006 if (
Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
2010 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
2011 if (!NextTripleOrErr)
2012 return NextTripleOrErr.takeError();
2014 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
2018 assert(!ArchiveErr &&
"Error occurred while reading archive!");
2023 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
2024 if (CurArchiveMembers != OutputArchivesMap.end()) {
2025 if (
Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
2026 SymtabWritingMode::NormalSymtab,
2031 std::string ErrMsg =
2032 Twine(
"no compatible code object found for the target '" +
Target +
2033 "' in heterogeneous archive library: " + IFName)
2035 return createStringError(inconvertibleErrorCode(), ErrMsg);
2040 std::vector<llvm::NewArchiveMember> EmptyArchive;
2041 EmptyArchive.clear();
2042 if (
Error WriteErr = writeArchive(
2043 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
2049 return Error::success();
2056 Str.split(Components,
'-', 5);
2057 return Components.size() == 5 || Components.size() == 6;
Result
Implement __builtin_bit_cast and related operations.
llvm::MachO::Target Target
static LLVM_PACKED_END size_t getHeaderSize(uint16_t Version)
static std::string getDeviceLibraryFileName(StringRef BundleFileName, StringRef Device)
static llvm::ManagedStatic< llvm::TimerGroup, CreateClangOffloadBundlerTimerGroup > ClangOffloadBundlerTimerGroup
static StringRef getDeviceFileExtension(StringRef Device, StringRef BundleFileName)
static Expected< std::unique_ptr< FileHandler > > CreateFileHandler(MemoryBuffer &FirstInput, const OffloadBundlerConfig &BundlerConfig)
Return an appropriate handler given the input files and options.
#define OFFLOAD_BUNDLER_MAGIC_STR
Magic string that marks the existence of offloading data.
bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo, const OffloadTargetInfo &TargetInfo)
Checks if a code object CodeObjectInfo is compatible with a given target TargetInfo.
static Error CheckHeterogeneousArchive(StringRef ArchiveName, const OffloadBundlerConfig &BundlerConfig)
static std::unique_ptr< FileHandler > CreateObjectFileHandler(MemoryBuffer &FirstInput, const OffloadBundlerConfig &BundlerConfig)
Return an appropriate object file handler.
static Archive::Kind getDefaultArchiveKindForHost()
static std::string formatWithCommas(unsigned long long Value)
static bool getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo, SmallVectorImpl< StringRef > &CompatibleTargets, const OffloadBundlerConfig &BundlerConfig)
Computes a list of targets among all given targets which are compatible with this code object.
This file defines an offload bundling API that bundles different files that relate with the same sour...
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > decompress(const llvm::MemoryBuffer &Input, bool Verbose=false)
static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, uint16_t Version, bool Verbose=false)
llvm::compression::Format CompressionFormat
std::vector< std::string > OutputFileNames
std::vector< std::string > TargetNames
uint16_t CompressedBundleVersion
std::vector< std::string > InputFileNames
bool PrintExternalCommands
llvm::Error BundleFiles()
Bundle the files. Return true if an error was found.
llvm::Error UnbundleFiles()
llvm::Error UnbundleArchive()
UnbundleArchive takes an archive file (".a") as input containing bundled code object files,...
static llvm::Error ListBundleIDsInFile(llvm::StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig)
const OffloadBundlerConfig & BundlerConfig
Exposes information about the current target.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
std::optional< llvm::StringRef > parseTargetID(const llvm::Triple &T, llvm::StringRef OffloadArch, llvm::StringMap< bool > *FeatureMap)
Parse a target ID to get processor and feature map.
@ Create
'create' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...
std::optional< std::pair< llvm::StringRef, llvm::StringRef > > getConflictTargetIDCombination(const std::set< llvm::StringRef > &TargetIDs)
Get the conflicted pair of target IDs for a compilation or a bundled code object, assuming TargetIDs ...
@ Result
The result type of a method or function.
OffloadArch StringToOffloadArch(llvm::StringRef S)
bool checkOffloadBundleID(const llvm::StringRef Str)
Check whether the bundle id is in the following format: <kind>-<triple>[-<target id>[:target features...
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.
int const char * function
Obtain the offload kind, real machine triple, and an optional TargetID out of the target information ...
bool operator==(const OffloadTargetInfo &Target) const
bool isOffloadKindCompatible(const llvm::StringRef TargetOffloadKind) const
bool isTripleValid() const
OffloadTargetInfo(const llvm::StringRef Target, const OffloadBundlerConfig &BC)
llvm::StringRef OffloadKind
bool isOffloadKindValid() const
const OffloadBundlerConfig & BundlerConfig