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(MemoryBuffer &Input) = 0;
201 ReadBundleStart(MemoryBuffer &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 if (Error Err = ReadHeader(Input))
232 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
233 llvm::outs() << Info.BundleID <<
'\n';
234 Error Err = listBundleIDsCallback(Input, Info);
237 return Error::success();
242 virtual Error getBundleIDs(MemoryBuffer &Input,
243 std::set<StringRef> &BundleIds) {
244 if (Error Err = ReadHeader(Input))
246 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
247 BundleIds.insert(Info.BundleID);
248 Error Err = listBundleIDsCallback(Input, Info);
251 return Error::success();
256 Error forEachBundle(MemoryBuffer &Input,
260 ReadBundleStart(Input);
262 return CurTripleOrErr.takeError();
265 if (!*CurTripleOrErr)
268 StringRef CurTriple = **CurTripleOrErr;
269 assert(!CurTriple.empty());
271 BundleInfo Info{CurTriple};
272 if (Error Err =
Func(Info))
275 return Error::success();
279 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
280 const BundleInfo &Info) {
281 return Error::success();
309static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
310 return llvm::support::endian::read64le(Buffer.data() + pos);
314static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
315 llvm::support::endian::write(OS, Val, llvm::endianness::little);
318class BinaryFileHandler final :
public FileHandler {
320 struct BinaryBundleInfo final :
public BundleInfo {
326 BinaryBundleInfo() {}
327 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
332 StringMap<BinaryBundleInfo> BundlesInfo;
335 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
336 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
339 std::string CurWriteBundleTarget;
348 ~BinaryFileHandler() final {}
350 Error ReadHeader(MemoryBuffer &Input)
final {
351 StringRef FC = Input.getBuffer();
354 CurBundleInfo = BundlesInfo.end();
358 if (ReadChars > FC.size())
359 return Error::success();
362 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
363 return Error::success();
366 if (ReadChars + 8 > FC.size())
367 return Error::success();
369 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
373 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
376 if (ReadChars + 8 > FC.size())
377 return Error::success();
379 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
383 if (ReadChars + 8 > FC.size())
384 return Error::success();
386 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
390 if (ReadChars + 8 > FC.size())
391 return Error::success();
393 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
397 if (ReadChars + TripleSize > FC.size())
398 return Error::success();
400 StringRef Triple(&FC.data()[ReadChars], TripleSize);
401 ReadChars += TripleSize;
404 if (!Offset || Offset + Size > FC.size())
405 return Error::success();
407 assert(!BundlesInfo.contains(Triple) &&
"Triple is duplicated??");
408 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
411 CurBundleInfo = BundlesInfo.end();
412 NextBundleInfo = BundlesInfo.begin();
413 return Error::success();
417 ReadBundleStart(MemoryBuffer &Input)
final {
418 if (NextBundleInfo == BundlesInfo.end())
420 CurBundleInfo = NextBundleInfo++;
421 return CurBundleInfo->first();
424 Error ReadBundleEnd(MemoryBuffer &Input)
final {
425 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
426 return Error::success();
429 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
430 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
431 StringRef FC = Input.getBuffer();
432 OS.write(FC.data() + CurBundleInfo->second.Offset,
433 CurBundleInfo->second.Size);
434 return Error::success();
437 Error WriteHeader(raw_ostream &OS,
438 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
448 HeaderSize +=
T.size();
454 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
458 MemoryBuffer &MB = *Inputs[Idx++];
461 Write8byteIntegerToBuffer(OS, HeaderSize);
463 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
464 BundlesInfo[
T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
465 HeaderSize += MB.getBufferSize();
467 Write8byteIntegerToBuffer(OS,
T.size());
471 return Error::success();
474 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
475 CurWriteBundleTarget = TargetTriple.str();
476 return Error::success();
479 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
480 return Error::success();
483 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
484 auto BI = BundlesInfo[CurWriteBundleTarget];
487 size_t CurrentPos = OS.tell();
488 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
489 for (
size_t I = 0; I < PaddingSize; ++I)
491 assert(OS.tell() == BI.Offset);
493 OS.write(Input.getBufferStart(), Input.getBufferSize());
495 return Error::success();
501class TempFileHandlerRAII {
503 ~TempFileHandlerRAII() {
504 for (
const auto &
File : Files)
505 sys::fs::remove(
File);
511 if (std::error_code EC =
512 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
513 return createFileError(
File, EC);
514 Files.push_front(
File);
518 raw_fd_ostream OS(
File, EC);
520 return createFileError(
File, EC);
521 OS.write(Contents->data(), Contents->size());
523 return Files.front().str();
527 std::forward_list<SmallString<128u>> Files;
534class ObjectFileHandler final :
public FileHandler {
537 std::unique_ptr<ObjectFile> Obj;
540 StringRef getInputFileContents()
const {
return Obj->getData(); }
545 IsOffloadSection(SectionRef CurSection) {
548 return NameOrErr.takeError();
551 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
559 unsigned NumberOfInputs = 0;
563 unsigned NumberOfProcessedInputs = 0;
566 section_iterator CurrentSection;
567 section_iterator NextSection;
574 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
576 : Obj(
std::move(ObjIn)), CurrentSection(Obj->section_begin()),
577 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
579 ~ObjectFileHandler() final {}
581 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
584 ReadBundleStart(MemoryBuffer &Input)
final {
585 while (NextSection != Obj->section_end()) {
586 CurrentSection = NextSection;
592 IsOffloadSection(*CurrentSection);
594 return TripleOrErr.takeError();
596 return **TripleOrErr;
601 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
603 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
606 return ContentOrErr.takeError();
607 StringRef Content = *ContentOrErr;
610 std::string ModifiedContent;
611 if (Content.size() == 1u && Content.front() == 0) {
612 auto HostBundleOrErr = getHostBundle(
613 StringRef(Input.getBufferStart(), Input.getBufferSize()));
614 if (!HostBundleOrErr)
615 return HostBundleOrErr.takeError();
617 ModifiedContent = std::move(*HostBundleOrErr);
618 Content = ModifiedContent;
621 OS.write(Content.data(), Content.size());
622 return Error::success();
625 Error WriteHeader(raw_ostream &OS,
626 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
628 "Host input index not defined.");
631 NumberOfInputs = Inputs.size();
632 return Error::success();
635 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
636 ++NumberOfProcessedInputs;
637 return Error::success();
640 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
641 return Error::success();
644 Error finalizeOutputFile() final {
645 assert(NumberOfProcessedInputs <= NumberOfInputs &&
646 "Processing more inputs that actually exist!");
648 "Host input index not defined.");
651 if (NumberOfProcessedInputs != NumberOfInputs)
652 return Error::success();
660 "llvm-objcopy path not specified");
663 TempFileHandlerRAII TempFiles;
667 BumpPtrAllocator
Alloc;
668 StringSaver SS{
Alloc};
671 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
680 return TempFileOrErr.takeError();
681 InputFile = *TempFileOrErr;
684 ObjcopyArgs.push_back(
687 ObjcopyArgs.push_back(
689 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
691 ObjcopyArgs.push_back(
"--");
692 ObjcopyArgs.push_back(
696 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
699 return Error::success();
702 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
703 return Error::success();
711 errs() <<
"\"" << Objcopy <<
"\"";
712 for (StringRef Arg : drop_begin(Args, 1))
713 errs() <<
" \"" << Arg <<
"\"";
716 if (sys::ExecuteAndWait(Objcopy, Args))
717 return createStringError(inconvertibleErrorCode(),
718 "'llvm-objcopy' tool failed");
720 return Error::success();
724 TempFileHandlerRAII TempFiles;
726 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
727 if (!ModifiedObjPathOrErr)
728 return ModifiedObjPathOrErr.takeError();
729 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
731 BumpPtrAllocator
Alloc;
732 StringSaver SS{
Alloc};
735 ObjcopyArgs.push_back(
"--regex");
736 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
737 ObjcopyArgs.push_back(
"--");
739 StringRef ObjcopyInputFileName;
746 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
749 return InputFileOrErr.takeError();
750 ObjcopyInputFileName = *InputFileOrErr;
754 ObjcopyArgs.push_back(ObjcopyInputFileName);
755 ObjcopyArgs.push_back(ModifiedObjPath);
757 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
758 return std::move(Err);
760 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
762 return createStringError(BufOrErr.getError(),
763 "Failed to read back the modified object file");
765 return BufOrErr->get()->getBuffer().str();
778class TextFileHandler final :
public FileHandler {
783 std::string BundleStartString;
786 std::string BundleEndString;
789 size_t ReadChars = 0u;
792 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
795 ReadBundleStart(MemoryBuffer &Input)
final {
796 StringRef FC = Input.getBuffer();
799 ReadChars = FC.find(BundleStartString, ReadChars);
800 if (ReadChars == FC.npos)
804 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
807 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
808 if (TripleEnd == FC.npos)
814 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
817 Error ReadBundleEnd(MemoryBuffer &Input)
final {
818 StringRef FC = Input.getBuffer();
821 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
823 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
824 if (TripleEnd != FC.npos)
828 return Error::success();
831 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
832 StringRef FC = Input.getBuffer();
833 size_t BundleStart = ReadChars;
836 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
838 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
841 return Error::success();
844 Error WriteHeader(raw_ostream &OS,
845 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
846 return Error::success();
849 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
850 OS << BundleStartString << TargetTriple <<
"\n";
851 return Error::success();
854 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
855 OS << BundleEndString << TargetTriple <<
"\n";
856 return Error::success();
859 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
860 OS << Input.getBuffer();
861 return Error::success();
865 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
872 Error listBundleIDsCallback(MemoryBuffer &Input,
873 const BundleInfo &Info)
final {
878 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
879 if (Error Err = ReadBundleEnd(Input))
881 return Error::success();
889static std::unique_ptr<FileHandler>
897 if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
898 return std::make_unique<BinaryFileHandler>(BundlerConfig);
902 return std::make_unique<ObjectFileHandler>(
903 std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
911 std::string FilesType = BundlerConfig.
FilesType;
913 if (FilesType ==
"i")
914 return std::make_unique<TextFileHandler>(
"//");
915 if (FilesType ==
"ii")
916 return std::make_unique<TextFileHandler>(
"//");
917 if (FilesType ==
"cui")
918 return std::make_unique<TextFileHandler>(
"//");
919 if (FilesType ==
"hipi")
920 return std::make_unique<TextFileHandler>(
"//");
923 if (FilesType ==
"d")
924 return std::make_unique<TextFileHandler>(
"#");
925 if (FilesType ==
"ll")
926 return std::make_unique<TextFileHandler>(
";");
927 if (FilesType ==
"bc")
928 return std::make_unique<BinaryFileHandler>(BundlerConfig);
929 if (FilesType ==
"s")
930 return std::make_unique<TextFileHandler>(
"#");
931 if (FilesType ==
"o")
933 if (FilesType ==
"a")
935 if (FilesType ==
"gch")
936 return std::make_unique<BinaryFileHandler>(BundlerConfig);
937 if (FilesType ==
"ast")
938 return std::make_unique<BinaryFileHandler>(BundlerConfig);
940 return createStringError(errc::invalid_argument,
941 "'" + FilesType +
"': invalid file type specified");
946 if (llvm::compression::zstd::isAvailable()) {
951 }
else if (llvm::compression::zlib::isAvailable()) {
957 auto IgnoreEnvVarOpt =
958 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
959 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
961 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
962 if (VerboseEnvVarOpt.has_value())
963 Verbose = VerboseEnvVarOpt.value() ==
"1";
964 auto CompressEnvVarOpt =
965 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
966 if (CompressEnvVarOpt.has_value())
967 Compress = CompressEnvVarOpt.value() ==
"1";
968 auto CompressionLevelEnvVarOpt =
969 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
970 if (CompressionLevelEnvVarOpt.has_value()) {
971 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
973 if (!CompressionLevelStr.getAsInteger(10, Level))
977 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
978 << CompressionLevelStr.str() <<
". Ignoring it.\n";
980 auto CompressedBundleFormatVersionOpt =
981 llvm::sys::Process::GetEnv(
"COMPRESSED_BUNDLE_FORMAT_VERSION");
982 if (CompressedBundleFormatVersionOpt.has_value()) {
983 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();
985 if (!VersionStr.getAsInteger(10, Version)) {
986 if (Version >= 2 && Version <= 3)
990 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
992 <<
". Valid values are 2 or 3. Using default version "
996 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
997 << VersionStr.str() <<
". Using default version "
1004 std::string
Num = std::to_string(
Value);
1005 int InsertPosition =
Num.length() - 3;
1006 while (InsertPosition > 0) {
1007 Num.insert(InsertPosition,
",");
1008 InsertPosition -= 3;
1015 const llvm::MemoryBuffer &Input,
1016 uint16_t Version,
bool Verbose) {
1017 if (!llvm::compression::zstd::isAvailable() &&
1018 !llvm::compression::zlib::isAvailable())
1019 return createStringError(llvm::inconvertibleErrorCode(),
1020 "Compression not supported");
1021 llvm::Timer HashTimer(
"Hash Calculation Timer",
"Hash calculation time",
1024 HashTimer.startTimer();
1026 llvm::MD5::MD5Result
Result;
1027 Hash.update(Input.getBuffer());
1029 uint64_t TruncatedHash =
Result.low();
1031 HashTimer.stopTimer();
1035 reinterpret_cast<const uint8_t *
>(Input.getBuffer().data()),
1036 Input.getBuffer().size());
1037 llvm::Timer CompressTimer(
"Compression Timer",
"Compression time",
1040 CompressTimer.startTimer();
1041 llvm::compression::compress(
P, BufferUint8, CompressedBuffer);
1043 CompressTimer.stopTimer();
1045 uint16_t CompressionMethod =
static_cast<uint16_t
>(
P.format);
1048 uint64_t UncompressedSize64 = Input.getBuffer().size();
1049 uint64_t TotalFileSize64;
1054 if (UncompressedSize64 > std::numeric_limits<uint32_t>::max())
1055 return createStringError(llvm::inconvertibleErrorCode(),
1056 "Uncompressed size exceeds version 2 limit");
1057 if ((MagicNumber.size() +
sizeof(uint32_t) +
sizeof(Version) +
1058 sizeof(CompressionMethod) +
sizeof(uint32_t) +
sizeof(TruncatedHash) +
1059 CompressedBuffer.size()) > std::numeric_limits<uint32_t>::max())
1060 return createStringError(llvm::inconvertibleErrorCode(),
1061 "Total file size exceeds version 2 limit");
1063 TotalFileSize64 = MagicNumber.size() +
sizeof(uint32_t) +
sizeof(Version) +
1064 sizeof(CompressionMethod) +
sizeof(uint32_t) +
1065 sizeof(TruncatedHash) + CompressedBuffer.size();
1067 TotalFileSize64 = MagicNumber.size() +
sizeof(uint64_t) +
sizeof(Version) +
1068 sizeof(CompressionMethod) +
sizeof(uint64_t) +
1069 sizeof(TruncatedHash) + CompressedBuffer.size();
1073 llvm::raw_svector_ostream OS(FinalBuffer);
1075 OS.write(
reinterpret_cast<const char *
>(&Version),
sizeof(Version));
1076 OS.write(
reinterpret_cast<const char *
>(&CompressionMethod),
1077 sizeof(CompressionMethod));
1081 uint32_t TotalFileSize32 =
static_cast<uint32_t
>(TotalFileSize64);
1082 uint32_t UncompressedSize32 =
static_cast<uint32_t
>(UncompressedSize64);
1083 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize32),
1084 sizeof(TotalFileSize32));
1085 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize32),
1086 sizeof(UncompressedSize32));
1088 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize64),
1089 sizeof(TotalFileSize64));
1090 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize64),
1091 sizeof(UncompressedSize64));
1094 OS.write(
reinterpret_cast<const char *
>(&TruncatedHash),
1095 sizeof(TruncatedHash));
1096 OS.write(
reinterpret_cast<const char *
>(CompressedBuffer.data()),
1097 CompressedBuffer.size());
1101 P.format == llvm::compression::Format::Zstd ?
"zstd" :
"zlib";
1102 double CompressionRate =
1103 static_cast<double>(UncompressedSize64) / CompressedBuffer.size();
1104 double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
1105 double CompressionSpeedMBs =
1106 (UncompressedSize64 / (1024.0 * 1024.0)) / CompressionTimeSeconds;
1107 llvm::errs() <<
"Compressed bundle format version: " << Version <<
"\n"
1108 <<
"Total file size (including headers): "
1110 <<
"Compression method used: " << MethodUsed <<
"\n"
1111 <<
"Compression level: " <<
P.level <<
"\n"
1112 <<
"Binary size before compression: "
1114 <<
"Binary size after compression: "
1116 <<
"Compression rate: "
1117 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1118 <<
"Compression ratio: "
1119 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1120 <<
"Compression speed: "
1121 << llvm::format(
"%.2lf MB/s", CompressionSpeedMBs) <<
"\n"
1122 <<
"Truncated MD5 hash: "
1123 << llvm::format_hex(TruncatedHash, 16) <<
"\n";
1126 return llvm::MemoryBuffer::getMemBufferCopy(
1127 llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
1177 llvm_unreachable(
"Unsupported version");
1184 assert(llvm::identify_magic(Blob) ==
1185 llvm::file_magic::offload_bundle_compressed);
1188 memcpy(&Header, Blob.data(), std::min(Blob.size(),
sizeof(Header)));
1194 if (Blob.size() < RequiredSize)
1195 return createStringError(inconvertibleErrorCode(),
1196 "Compressed bundle header size too small");
1214 return createStringError(inconvertibleErrorCode(),
1215 "Unknown compressed bundle version");
1220 case static_cast<uint16_t
>(compression::Format::Zlib):
1221 case static_cast<uint16_t
>(compression::Format::Zstd):
1223 static_cast<compression::Format
>(Header.
Common.
Method);
1226 return createStringError(inconvertibleErrorCode(),
1227 "Unknown compressing method");
1236 StringRef Blob = Input.getBuffer();
1240 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1242 if (llvm::identify_magic(Blob) !=
1243 llvm::file_magic::offload_bundle_compressed) {
1245 llvm::errs() <<
"Uncompressed bundle.\n";
1246 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1252 return HeaderOrErr.takeError();
1255 unsigned ThisVersion = Normalized.
Version;
1260 size_t TotalFileSize = Normalized.
FileSize.value_or(0);
1262 auto StoredHash = Normalized.
Hash;
1264 llvm::Timer DecompressTimer(
"Decompression Timer",
"Decompression time",
1267 DecompressTimer.startTimer();
1270 StringRef CompressedData = Blob.substr(HeaderSize);
1271 if (llvm::Error DecompressionError = llvm::compression::decompress(
1272 CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
1273 DecompressedData, UncompressedSize))
1274 return createStringError(inconvertibleErrorCode(),
1275 "Could not decompress embedded file contents: " +
1276 llvm::toString(std::move(DecompressionError)));
1279 DecompressTimer.stopTimer();
1281 double DecompressionTimeSeconds =
1282 DecompressTimer.getTotalTime().getWallTime();
1285 llvm::Timer HashRecalcTimer(
"Hash Recalculation Timer",
1286 "Hash recalculation time",
1288 HashRecalcTimer.startTimer();
1290 llvm::MD5::MD5Result
Result;
1293 uint64_t RecalculatedHash =
Result.low();
1294 HashRecalcTimer.stopTimer();
1295 bool HashMatch = (StoredHash == RecalculatedHash);
1297 double CompressionRate =
1298 static_cast<double>(UncompressedSize) / CompressedData.size();
1299 double DecompressionSpeedMBs =
1300 (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
1302 llvm::errs() <<
"Compressed bundle format version: " << ThisVersion <<
"\n";
1303 if (ThisVersion >= 2)
1304 llvm::errs() <<
"Total file size (from header): "
1306 llvm::errs() <<
"Decompression method: "
1307 << (CompressionFormat == llvm::compression::Format::Zlib
1311 <<
"Size before decompression: "
1313 <<
"Size after decompression: "
1315 <<
"Compression rate: "
1316 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1317 <<
"Compression ratio: "
1318 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1319 <<
"Decompression speed: "
1320 << llvm::format(
"%.2lf MB/s", DecompressionSpeedMBs) <<
"\n"
1321 <<
"Stored hash: " << llvm::format_hex(StoredHash, 16) <<
"\n"
1322 <<
"Recalculated hash: "
1323 << llvm::format_hex(RecalculatedHash, 16) <<
"\n"
1324 <<
"Hashes match: " << (HashMatch ?
"Yes" :
"No") <<
"\n";
1327 return llvm::MemoryBuffer::getMemBufferCopy(
1328 llvm::toStringRef(DecompressedData));
1335 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1336 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1337 if (std::error_code EC = CodeOrErr.getError())
1338 return createFileError(InputFileName, EC);
1343 if (!DecompressedBufferOrErr)
1344 return createStringError(
1345 inconvertibleErrorCode(),
1346 "Failed to decompress input: " +
1347 llvm::toString(DecompressedBufferOrErr.takeError()));
1349 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1354 if (!FileHandlerOrErr)
1355 return FileHandlerOrErr.takeError();
1357 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1359 return FH->listBundleIDs(DecompressedInput);
1370 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1371 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1372 << CodeObjectInfo.
str()
1373 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1381 "CodeObjectCompatibility",
1382 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1383 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1389 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1391 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1396 if (!TargetProc || !CodeObjectProc ||
1397 CodeObjectProc.value() != TargetProc.value()) {
1398 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1399 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1400 << CodeObjectInfo.
str()
1401 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1407 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1408 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1409 dbgs() <<
"Incompatible: CodeObject has more features "
1410 "than target \t[CodeObject: "
1411 << CodeObjectInfo.
str()
1412 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1420 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1421 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1422 if (TargetFeature == TargetFeatureMap.end()) {
1424 "CodeObjectCompatibility",
1426 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1427 "not matching with Target feature's ANY value \t[CodeObject: "
1428 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1431 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1433 "CodeObjectCompatibility",
1434 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1435 "not matching with Target feature's non-ANY value "
1437 << CodeObjectInfo.
str()
1438 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1448 "CodeObjectCompatibility",
1449 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1450 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1461 llvm::raw_svector_ostream BufferStream(Buffer);
1467 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1468 MemoryBuffer::getFileOrSTDIN(I,
true);
1469 if (std::error_code EC = CodeOrErr.getError())
1470 return createFileError(I, EC);
1471 InputBuffers.emplace_back(std::move(*CodeOrErr));
1476 "Host input index undefined??");
1481 if (!FileHandlerOrErr)
1482 return FileHandlerOrErr.takeError();
1484 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1488 if (Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1493 auto Input = InputBuffers.begin();
1495 if (Error Err = FH->WriteBundleStart(BufferStream, Triple))
1497 if (Error Err = FH->WriteBundle(BufferStream, **Input))
1499 if (Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1511 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1512 llvm::MemoryBuffer::getMemBufferCopy(
1513 llvm::StringRef(Buffer.data(), Buffer.size()));
1519 if (
auto Error = CompressionResult.takeError())
1522 auto CompressedMemBuffer = std::move(CompressionResult.get());
1523 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1524 CompressedMemBuffer->getBufferEnd());
1526 CompressedBuffer = Buffer;
1528 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1530 return FH->finalizeOutputFile();
1536 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1537 MemoryBuffer::getFileOrSTDIN(BundlerConfig.
InputFileNames.front(),
1539 if (std::error_code EC = CodeOrErr.getError())
1540 return createFileError(BundlerConfig.
InputFileNames.front(), EC);
1545 if (!DecompressedBufferOrErr)
1546 return createStringError(
1547 inconvertibleErrorCode(),
1548 "Failed to decompress input: " +
1549 llvm::toString(DecompressedBufferOrErr.takeError()));
1551 MemoryBuffer &Input = **DecompressedBufferOrErr;
1556 if (!FileHandlerOrErr)
1557 return FileHandlerOrErr.takeError();
1559 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1563 if (Error Err = FH->ReadHeader(Input))
1567 StringMap<StringRef> Worklist;
1571 return createStringError(errc::invalid_argument,
1572 "invalid bundle id from bundle config");
1573 Worklist[Triple] = *Output;
1579 bool FoundHostBundle =
false;
1580 while (!Worklist.empty()) {
1582 FH->ReadBundleStart(Input);
1583 if (!CurTripleOrErr)
1584 return CurTripleOrErr.takeError();
1587 if (!*CurTripleOrErr)
1590 StringRef CurTriple = **CurTripleOrErr;
1591 assert(!CurTriple.empty());
1593 return createStringError(errc::invalid_argument,
1594 "invalid bundle id read from the bundle");
1596 auto Output = Worklist.begin();
1597 for (
auto E = Worklist.end(); Output !=
E; Output++) {
1605 if (Output == Worklist.end())
1609 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1611 return createFileError((*Output).second, EC);
1612 if (Error Err = FH->ReadBundle(OutputFile, Input))
1614 if (Error Err = FH->ReadBundleEnd(Input))
1616 Worklist.erase(Output);
1620 if (OffloadInfo.hasHostKind())
1621 FoundHostBundle =
true;
1625 std::string ErrMsg =
"Can't find bundles for";
1626 std::set<StringRef> Sorted;
1627 for (
auto &
E : Worklist)
1628 Sorted.insert(
E.first());
1630 unsigned Last = Sorted.size() - 1;
1631 for (
auto &
E : Sorted) {
1632 if (I != 0 &&
Last > 1)
1635 if (I ==
Last && I != 0)
1640 return createStringError(inconvertibleErrorCode(), ErrMsg);
1645 if (Worklist.size() == BundlerConfig.
TargetNames.size()) {
1646 for (
auto &
E : Worklist) {
1648 raw_fd_ostream OutputFile(
E.second, EC, sys::fs::OF_None);
1650 return createFileError(
E.second, EC);
1656 if (OffloadInfo.hasHostKind())
1657 OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
1659 return Error::success();
1666 return createStringError(inconvertibleErrorCode(),
1667 "Can't find bundle for the host target");
1670 for (
auto &
E : Worklist) {
1672 raw_fd_ostream OutputFile(
E.second, EC, sys::fs::OF_None);
1674 return createFileError(
E.second, EC);
1677 return Error::success();
1681 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1695 if (!CompatibleTargets.empty()) {
1696 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1697 dbgs() <<
"CompatibleTargets list should be empty\n");
1703 CompatibleTargets.push_back(
Target);
1705 return !CompatibleTargets.empty();
1715 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1716 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1717 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1718 if (std::error_code EC = BufOrErr.getError())
1719 return createFileError(ArchiveName, EC);
1721 ArchiveBuffers.push_back(std::move(*BufOrErr));
1723 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1725 return LibOrErr.takeError();
1727 auto Archive = std::move(*LibOrErr);
1729 Error ArchiveErr = Error::success();
1730 auto ChildEnd = Archive->child_end();
1733 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1734 ArchiveIter != ChildEnd; ++ArchiveIter) {
1737 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1738 if (!ArchiveChildNameOrErr)
1739 return ArchiveChildNameOrErr.takeError();
1741 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1742 if (!CodeObjectBufferRefOrErr)
1743 return CodeObjectBufferRefOrErr.takeError();
1745 auto CodeObjectBuffer =
1746 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1750 if (!FileHandlerOrErr)
1751 return FileHandlerOrErr.takeError();
1753 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1754 assert(FileHandler);
1756 std::set<StringRef> BundleIds;
1757 auto CodeObjectFileError =
1758 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1759 if (CodeObjectFileError)
1760 return CodeObjectFileError;
1763 if (ConflictingArchs) {
1764 std::string ErrMsg =
1765 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1766 ", " + ConflictingArchs.value().second +
"] found in " +
1767 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1769 return createStringError(inconvertibleErrorCode(), ErrMsg);
1784 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1788 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1791 StringMap<StringRef> TargetOutputFileNameMap;
1795 TargetOutputFileNameMap[
Target] = *Output;
1807 return ArchiveError;
1811 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1812 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1813 if (std::error_code EC = BufOrErr.getError())
1814 return createFileError(BundlerConfig.
InputFileNames.front(), EC);
1816 ArchiveBuffers.push_back(std::move(*BufOrErr));
1818 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1820 return LibOrErr.takeError();
1822 auto Archive = std::move(*LibOrErr);
1824 Error ArchiveErr = Error::success();
1825 auto ChildEnd = Archive->child_end();
1828 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1829 ArchiveIter != ChildEnd; ++ArchiveIter) {
1832 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1833 if (!ArchiveChildNameOrErr)
1834 return ArchiveChildNameOrErr.takeError();
1836 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1838 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1839 if (!CodeObjectBufferRefOrErr)
1840 return CodeObjectBufferRefOrErr.takeError();
1842 auto TempCodeObjectBuffer =
1843 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1849 if (!DecompressedBufferOrErr)
1850 return createStringError(
1851 inconvertibleErrorCode(),
1852 "Failed to decompress code object: " +
1853 llvm::toString(DecompressedBufferOrErr.takeError()));
1855 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1859 if (!FileHandlerOrErr)
1860 return FileHandlerOrErr.takeError();
1862 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1863 assert(FileHandler &&
1864 "FileHandle creation failed for file in the archive!");
1866 if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer))
1870 FileHandler->ReadBundleStart(CodeObjectBuffer);
1871 if (!CurBundleIDOrErr)
1872 return CurBundleIDOrErr.takeError();
1874 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1876 if (!OptionalCurBundleID)
1878 StringRef CodeObject = *OptionalCurBundleID;
1882 while (!CodeObject.empty()) {
1885 return createStringError(errc::invalid_argument,
1886 "Invalid bundle id read from code object");
1891 std::string BundleData;
1892 raw_string_ostream DataStream(BundleData);
1893 if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1896 for (
auto &CompatibleTarget : CompatibleTargets) {
1898 BundledObjectFileName.assign(BundledObjectFile);
1899 auto OutputBundleName =
1900 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1903 CodeObjectInfo.TargetID))
1907 llvm::replace(OutputBundleName,
':',
'_');
1909 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1910 DataStream.str(), OutputBundleName);
1911 ArchiveBuffers.push_back(std::move(MemBuf));
1912 llvm::MemoryBufferRef MemBufRef =
1913 MemoryBufferRef(*(ArchiveBuffers.back()));
1917 OutputArchivesMap[CompatibleTarget].push_back(
1918 NewArchiveMember(MemBufRef));
1922 if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1926 FileHandler->ReadBundleStart(CodeObjectBuffer);
1927 if (!NextTripleOrErr)
1928 return NextTripleOrErr.takeError();
1930 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1934 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1939 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
1940 if (CurArchiveMembers != OutputArchivesMap.end()) {
1941 if (Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1942 SymtabWritingMode::NormalSymtab,
1947 std::string ErrMsg =
1948 Twine(
"no compatible code object found for the target '" +
Target +
1949 "' in heterogeneous archive library: " + IFName)
1951 return createStringError(inconvertibleErrorCode(), ErrMsg);
1956 std::vector<llvm::NewArchiveMember> EmptyArchive;
1957 EmptyArchive.clear();
1958 if (Error WriteErr = writeArchive(
1959 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1965 return Error::success();
1972 Str.split(Components,
'-', 5);
1973 return Components.size() == 5 || Components.size() == 6;
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)
Exposes information about the current target.
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
The JSON file list parser is used to communicate input to InstallAPI.
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)
const FunctionProtoType * T
bool checkOffloadBundleID(const llvm::StringRef Str)
Check whether the bundle id is in the following format: <kind>-<triple>[-<target id>[:target features...
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