21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/ADT/StringMap.h"
26#include "llvm/ADT/StringRef.h"
27#include "llvm/BinaryFormat/Magic.h"
28#include "llvm/Object/Archive.h"
29#include "llvm/Object/ArchiveWriter.h"
30#include "llvm/Object/Binary.h"
31#include "llvm/Object/ObjectFile.h"
32#include "llvm/Support/Casting.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/MemoryBuffer.h"
42#include "llvm/Support/Path.h"
43#include "llvm/Support/Program.h"
44#include "llvm/Support/Signals.h"
45#include "llvm/Support/StringSaver.h"
46#include "llvm/Support/Timer.h"
47#include "llvm/Support/WithColor.h"
48#include "llvm/Support/raw_ostream.h"
49#include "llvm/TargetParser/Host.h"
50#include "llvm/TargetParser/Triple.h"
55#include <forward_list>
56#include <llvm/Support/Process.h>
60#include <system_error>
64using namespace llvm::object;
67static llvm::TimerGroup
69 "Timer group for clang offload bundler");
72#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
79 auto TargetFeatures =
Target.split(
':');
80 auto TripleOrGPU = TargetFeatures.first.rsplit(
'-');
84 auto KindTriple = TripleOrGPU.first.split(
'-');
88 llvm::Triple t = llvm::Triple(KindTriple.second);
89 this->
Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
90 t.getOSName(), t.getEnvironmentName());
94 auto KindTriple = TargetFeatures.first.split(
'-');
98 llvm::Triple t = llvm::Triple(KindTriple.second);
99 this->
Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
100 t.getOSName(), t.getEnvironmentName());
116 const StringRef TargetOffloadKind)
const {
118 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
119 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
123 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
124 TargetOffloadKind ==
"openmp";
125 bool OpenMPCompatibleWithHIP =
127 TargetOffloadKind.starts_with_insensitive(
"hip");
128 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
134 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
147 StringRef BundleFileName) {
148 if (
Device.contains(
"gfx"))
150 if (
Device.contains(
"sm_"))
152 return sys::path::extension(BundleFileName);
157 StringRef LibName = sys::path::stem(BundleFileName);
176 virtual ~FileHandler() {}
180 virtual Error ReadHeader(MemoryBuffer &Input) = 0;
186 ReadBundleStart(MemoryBuffer &Input) = 0;
189 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
192 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
196 virtual Error WriteHeader(raw_ostream &OS,
197 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
201 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
205 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
208 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
211 virtual Error finalizeOutputFile() {
return Error::success(); }
214 virtual Error listBundleIDs(MemoryBuffer &Input) {
215 if (Error Err = ReadHeader(Input))
217 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
218 llvm::outs() << Info.BundleID <<
'\n';
219 Error Err = listBundleIDsCallback(Input, Info);
222 return Error::success();
227 virtual Error getBundleIDs(MemoryBuffer &Input,
228 std::set<StringRef> &BundleIds) {
229 if (Error Err = ReadHeader(Input))
231 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
232 BundleIds.insert(Info.BundleID);
233 Error Err = listBundleIDsCallback(Input, Info);
236 return Error::success();
241 Error forEachBundle(MemoryBuffer &Input,
242 std::function<
Error(
const BundleInfo &)>
Func) {
245 ReadBundleStart(Input);
247 return CurTripleOrErr.takeError();
250 if (!*CurTripleOrErr)
253 StringRef CurTriple = **CurTripleOrErr;
254 assert(!CurTriple.empty());
256 BundleInfo Info{CurTriple};
257 if (Error Err =
Func(Info))
260 return Error::success();
264 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
265 const BundleInfo &Info) {
266 return Error::success();
294static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
295 return llvm::support::endian::read64le(Buffer.data() + pos);
299static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
300 llvm::support::endian::write(OS, Val, llvm::endianness::little);
303class BinaryFileHandler final :
public FileHandler {
305 struct BinaryBundleInfo final :
public BundleInfo {
311 BinaryBundleInfo() {}
312 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
317 StringMap<BinaryBundleInfo> BundlesInfo;
320 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
321 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
324 std::string CurWriteBundleTarget;
333 ~BinaryFileHandler() final {}
335 Error ReadHeader(MemoryBuffer &Input)
final {
336 StringRef FC = Input.getBuffer();
339 CurBundleInfo = BundlesInfo.end();
343 if (ReadChars > FC.size())
344 return Error::success();
347 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
348 return Error::success();
351 if (ReadChars + 8 > FC.size())
352 return Error::success();
354 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
358 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
361 if (ReadChars + 8 > FC.size())
362 return Error::success();
364 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
368 if (ReadChars + 8 > FC.size())
369 return Error::success();
371 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
375 if (ReadChars + 8 > FC.size())
376 return Error::success();
378 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
382 if (ReadChars + TripleSize > FC.size())
383 return Error::success();
385 StringRef Triple(&FC.data()[ReadChars], TripleSize);
386 ReadChars += TripleSize;
389 if (!Offset || Offset + Size > FC.size())
390 return Error::success();
392 assert(!BundlesInfo.contains(Triple) &&
"Triple is duplicated??");
393 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
396 CurBundleInfo = BundlesInfo.end();
397 NextBundleInfo = BundlesInfo.begin();
398 return Error::success();
402 ReadBundleStart(MemoryBuffer &Input)
final {
403 if (NextBundleInfo == BundlesInfo.end())
405 CurBundleInfo = NextBundleInfo++;
406 return CurBundleInfo->first();
409 Error ReadBundleEnd(MemoryBuffer &Input)
final {
410 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
411 return Error::success();
414 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
415 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
416 StringRef FC = Input.getBuffer();
417 OS.write(FC.data() + CurBundleInfo->second.Offset,
418 CurBundleInfo->second.Size);
419 return Error::success();
422 Error WriteHeader(raw_ostream &OS,
423 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
433 HeaderSize +=
T.size();
439 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
443 MemoryBuffer &MB = *Inputs[Idx++];
446 Write8byteIntegerToBuffer(OS, HeaderSize);
448 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
449 BundlesInfo[
T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
450 HeaderSize += MB.getBufferSize();
452 Write8byteIntegerToBuffer(OS,
T.size());
456 return Error::success();
459 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
460 CurWriteBundleTarget = TargetTriple.str();
461 return Error::success();
464 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
465 return Error::success();
468 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
469 auto BI = BundlesInfo[CurWriteBundleTarget];
472 size_t CurrentPos = OS.tell();
473 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
474 for (
size_t I = 0;
I < PaddingSize; ++
I)
476 assert(OS.tell() == BI.Offset);
478 OS.write(Input.getBufferStart(), Input.getBufferSize());
480 return Error::success();
486class TempFileHandlerRAII {
488 ~TempFileHandlerRAII() {
489 for (
const auto &
File : Files)
490 sys::fs::remove(
File);
496 if (std::error_code EC =
497 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
498 return createFileError(
File, EC);
499 Files.push_front(
File);
503 raw_fd_ostream OS(
File, EC);
505 return createFileError(
File, EC);
506 OS.write(Contents->data(), Contents->size());
508 return Files.front().str();
512 std::forward_list<SmallString<128u>> Files;
519class ObjectFileHandler final :
public FileHandler {
522 std::unique_ptr<ObjectFile> Obj;
525 StringRef getInputFileContents()
const {
return Obj->getData(); }
530 IsOffloadSection(SectionRef CurSection) {
533 return NameOrErr.takeError();
536 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
544 unsigned NumberOfInputs = 0;
548 unsigned NumberOfProcessedInputs = 0;
551 section_iterator CurrentSection;
552 section_iterator NextSection;
559 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
561 : Obj(
std::move(ObjIn)), CurrentSection(Obj->section_begin()),
562 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
564 ~ObjectFileHandler() final {}
566 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
569 ReadBundleStart(MemoryBuffer &Input)
final {
570 while (NextSection != Obj->section_end()) {
571 CurrentSection = NextSection;
577 IsOffloadSection(*CurrentSection);
579 return TripleOrErr.takeError();
581 return **TripleOrErr;
586 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
588 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
591 return ContentOrErr.takeError();
592 StringRef Content = *ContentOrErr;
595 std::string ModifiedContent;
596 if (Content.size() == 1u && Content.front() == 0) {
597 auto HostBundleOrErr = getHostBundle(
598 StringRef(Input.getBufferStart(), Input.getBufferSize()));
599 if (!HostBundleOrErr)
600 return HostBundleOrErr.takeError();
602 ModifiedContent = std::move(*HostBundleOrErr);
603 Content = ModifiedContent;
606 OS.write(Content.data(), Content.size());
607 return Error::success();
610 Error WriteHeader(raw_ostream &OS,
611 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
613 "Host input index not defined.");
616 NumberOfInputs = Inputs.size();
617 return Error::success();
620 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
621 ++NumberOfProcessedInputs;
622 return Error::success();
625 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
626 return Error::success();
629 Error finalizeOutputFile() final {
630 assert(NumberOfProcessedInputs <= NumberOfInputs &&
631 "Processing more inputs that actually exist!");
633 "Host input index not defined.");
636 if (NumberOfProcessedInputs != NumberOfInputs)
637 return Error::success();
645 "llvm-objcopy path not specified");
648 TempFileHandlerRAII TempFiles;
652 BumpPtrAllocator
Alloc;
653 StringSaver SS{
Alloc};
656 for (
unsigned I = 0;
I < NumberOfInputs; ++
I) {
665 return TempFileOrErr.takeError();
666 InputFile = *TempFileOrErr;
669 ObjcopyArgs.push_back(
672 ObjcopyArgs.push_back(
676 ObjcopyArgs.push_back(
"--");
677 ObjcopyArgs.push_back(
681 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
684 return Error::success();
687 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
688 return Error::success();
696 errs() <<
"\"" << Objcopy <<
"\"";
697 for (StringRef Arg : drop_begin(Args, 1))
698 errs() <<
" \"" << Arg <<
"\"";
701 if (sys::ExecuteAndWait(Objcopy, Args))
702 return createStringError(inconvertibleErrorCode(),
703 "'llvm-objcopy' tool failed");
705 return Error::success();
709 TempFileHandlerRAII TempFiles;
711 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
712 if (!ModifiedObjPathOrErr)
713 return ModifiedObjPathOrErr.takeError();
714 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
716 BumpPtrAllocator
Alloc;
717 StringSaver SS{
Alloc};
720 ObjcopyArgs.push_back(
"--regex");
721 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
722 ObjcopyArgs.push_back(
"--");
724 StringRef ObjcopyInputFileName;
731 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
732 auto InputFileOrErr =
735 return InputFileOrErr.takeError();
736 ObjcopyInputFileName = *InputFileOrErr;
740 ObjcopyArgs.push_back(ObjcopyInputFileName);
741 ObjcopyArgs.push_back(ModifiedObjPath);
743 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
744 return std::move(Err);
746 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
748 return createStringError(BufOrErr.getError(),
749 "Failed to read back the modified object file");
751 return BufOrErr->get()->getBuffer().str();
764class TextFileHandler final :
public FileHandler {
769 std::string BundleStartString;
772 std::string BundleEndString;
775 size_t ReadChars = 0u;
778 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
781 ReadBundleStart(MemoryBuffer &Input)
final {
782 StringRef FC = Input.getBuffer();
785 ReadChars = FC.find(BundleStartString, ReadChars);
786 if (ReadChars == FC.npos)
790 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
793 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
794 if (TripleEnd == FC.npos)
800 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
803 Error ReadBundleEnd(MemoryBuffer &Input)
final {
804 StringRef FC = Input.getBuffer();
807 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
809 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
810 if (TripleEnd != FC.npos)
814 return Error::success();
817 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
818 StringRef FC = Input.getBuffer();
819 size_t BundleStart = ReadChars;
822 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
824 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
827 return Error::success();
830 Error WriteHeader(raw_ostream &OS,
831 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
832 return Error::success();
835 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
836 OS << BundleStartString << TargetTriple <<
"\n";
837 return Error::success();
840 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
841 OS << BundleEndString << TargetTriple <<
"\n";
842 return Error::success();
845 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
846 OS << Input.getBuffer();
847 return Error::success();
851 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
858 Error listBundleIDsCallback(MemoryBuffer &Input,
859 const BundleInfo &Info)
final {
864 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
865 if (Error Err = ReadBundleEnd(Input))
867 return Error::success();
875static std::unique_ptr<FileHandler>
883 if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
884 return std::make_unique<BinaryFileHandler>(BundlerConfig);
888 return std::make_unique<ObjectFileHandler>(
889 std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
897 std::string FilesType = BundlerConfig.
FilesType;
899 if (FilesType ==
"i")
900 return std::make_unique<TextFileHandler>(
"//");
901 if (FilesType ==
"ii")
902 return std::make_unique<TextFileHandler>(
"//");
903 if (FilesType ==
"cui")
904 return std::make_unique<TextFileHandler>(
"//");
905 if (FilesType ==
"hipi")
906 return std::make_unique<TextFileHandler>(
"//");
909 if (FilesType ==
"d")
910 return std::make_unique<TextFileHandler>(
"#");
911 if (FilesType ==
"ll")
912 return std::make_unique<TextFileHandler>(
";");
913 if (FilesType ==
"bc")
914 return std::make_unique<BinaryFileHandler>(BundlerConfig);
915 if (FilesType ==
"s")
916 return std::make_unique<TextFileHandler>(
"#");
917 if (FilesType ==
"o")
919 if (FilesType ==
"a")
921 if (FilesType ==
"gch")
922 return std::make_unique<BinaryFileHandler>(BundlerConfig);
923 if (FilesType ==
"ast")
924 return std::make_unique<BinaryFileHandler>(BundlerConfig);
926 return createStringError(errc::invalid_argument,
927 "'" + FilesType +
"': invalid file type specified");
931 if (llvm::compression::zstd::isAvailable()) {
936 }
else if (llvm::compression::zlib::isAvailable()) {
942 auto IgnoreEnvVarOpt =
943 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
944 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
947 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
948 if (VerboseEnvVarOpt.has_value())
949 Verbose = VerboseEnvVarOpt.value() ==
"1";
951 auto CompressEnvVarOpt =
952 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
953 if (CompressEnvVarOpt.has_value())
954 Compress = CompressEnvVarOpt.value() ==
"1";
956 auto CompressionLevelEnvVarOpt =
957 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
958 if (CompressionLevelEnvVarOpt.has_value()) {
959 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
961 if (!CompressionLevelStr.getAsInteger(10, Level))
965 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
966 << CompressionLevelStr.str() <<
". Ignoring it.\n";
972 std::string Num = std::to_string(
Value);
973 int InsertPosition = Num.length() - 3;
974 while (InsertPosition > 0) {
975 Num.insert(InsertPosition,
",");
983 const llvm::MemoryBuffer &Input,
985 if (!llvm::compression::zstd::isAvailable() &&
986 !llvm::compression::zlib::isAvailable())
987 return createStringError(llvm::inconvertibleErrorCode(),
988 "Compression not supported");
990 llvm::Timer HashTimer(
"Hash Calculation Timer",
"Hash calculation time",
993 HashTimer.startTimer();
995 llvm::MD5::MD5Result
Result;
996 Hash.update(Input.getBuffer());
998 uint64_t TruncatedHash =
Result.low();
1000 HashTimer.stopTimer();
1004 reinterpret_cast<const uint8_t *
>(Input.getBuffer().data()),
1005 Input.getBuffer().size());
1007 llvm::Timer CompressTimer(
"Compression Timer",
"Compression time",
1010 CompressTimer.startTimer();
1011 llvm::compression::compress(
P, BufferUint8, CompressedBuffer);
1013 CompressTimer.stopTimer();
1015 uint16_t CompressionMethod =
static_cast<uint16_t
>(
P.format);
1016 uint32_t UncompressedSize = Input.getBuffer().size();
1017 uint32_t TotalFileSize = MagicNumber.size() +
sizeof(TotalFileSize) +
1018 sizeof(Version) +
sizeof(CompressionMethod) +
1019 sizeof(UncompressedSize) +
sizeof(TruncatedHash) +
1020 CompressedBuffer.size();
1023 llvm::raw_svector_ostream OS(FinalBuffer);
1025 OS.write(
reinterpret_cast<const char *
>(&Version),
sizeof(Version));
1026 OS.write(
reinterpret_cast<const char *
>(&CompressionMethod),
1027 sizeof(CompressionMethod));
1028 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize),
1029 sizeof(TotalFileSize));
1030 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize),
1031 sizeof(UncompressedSize));
1032 OS.write(
reinterpret_cast<const char *
>(&TruncatedHash),
1033 sizeof(TruncatedHash));
1034 OS.write(
reinterpret_cast<const char *
>(CompressedBuffer.data()),
1035 CompressedBuffer.size());
1039 P.format == llvm::compression::Format::Zstd ?
"zstd" :
"zlib";
1040 double CompressionRate =
1041 static_cast<double>(UncompressedSize) / CompressedBuffer.size();
1042 double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
1043 double CompressionSpeedMBs =
1044 (UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;
1046 llvm::errs() <<
"Compressed bundle format version: " << Version <<
"\n"
1047 <<
"Total file size (including headers): "
1049 <<
"Compression method used: " << MethodUsed <<
"\n"
1050 <<
"Compression level: " <<
P.level <<
"\n"
1051 <<
"Binary size before compression: "
1053 <<
"Binary size after compression: "
1055 <<
"Compression rate: "
1056 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1057 <<
"Compression ratio: "
1058 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1059 <<
"Compression speed: "
1060 << llvm::format(
"%.2lf MB/s", CompressionSpeedMBs) <<
"\n"
1061 <<
"Truncated MD5 hash: "
1062 << llvm::format_hex(TruncatedHash, 16) <<
"\n";
1064 return llvm::MemoryBuffer::getMemBufferCopy(
1065 llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
1072 StringRef Blob = Input.getBuffer();
1074 if (Blob.size() < V1HeaderSize)
1075 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1077 if (llvm::identify_magic(Blob) !=
1078 llvm::file_magic::offload_bundle_compressed) {
1080 llvm::errs() <<
"Uncompressed bundle.\n";
1081 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1084 size_t CurrentOffset = MagicSize;
1086 uint16_t ThisVersion;
1087 memcpy(&ThisVersion, Blob.data() + CurrentOffset,
sizeof(uint16_t));
1088 CurrentOffset += VersionFieldSize;
1090 uint16_t CompressionMethod;
1091 memcpy(&CompressionMethod, Blob.data() + CurrentOffset,
sizeof(uint16_t));
1092 CurrentOffset += MethodFieldSize;
1094 uint32_t TotalFileSize;
1095 if (ThisVersion >= 2) {
1096 if (Blob.size() < V2HeaderSize)
1097 return createStringError(inconvertibleErrorCode(),
1098 "Compressed bundle header size too small");
1099 memcpy(&TotalFileSize, Blob.data() + CurrentOffset,
sizeof(uint32_t));
1100 CurrentOffset += FileSizeFieldSize;
1103 uint32_t UncompressedSize;
1104 memcpy(&UncompressedSize, Blob.data() + CurrentOffset,
sizeof(uint32_t));
1105 CurrentOffset += UncompressedSizeFieldSize;
1107 uint64_t StoredHash;
1108 memcpy(&StoredHash, Blob.data() + CurrentOffset,
sizeof(uint64_t));
1109 CurrentOffset += HashFieldSize;
1111 llvm::compression::Format CompressionFormat;
1112 if (CompressionMethod ==
1113 static_cast<uint16_t
>(llvm::compression::Format::Zlib))
1114 CompressionFormat = llvm::compression::Format::Zlib;
1115 else if (CompressionMethod ==
1116 static_cast<uint16_t
>(llvm::compression::Format::Zstd))
1117 CompressionFormat = llvm::compression::Format::Zstd;
1119 return createStringError(inconvertibleErrorCode(),
1120 "Unknown compressing method");
1122 llvm::Timer DecompressTimer(
"Decompression Timer",
"Decompression time",
1125 DecompressTimer.startTimer();
1128 StringRef CompressedData = Blob.substr(CurrentOffset);
1129 if (llvm::Error DecompressionError = llvm::compression::decompress(
1130 CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
1131 DecompressedData, UncompressedSize))
1132 return createStringError(inconvertibleErrorCode(),
1133 "Could not decompress embedded file contents: " +
1134 llvm::toString(std::move(DecompressionError)));
1137 DecompressTimer.stopTimer();
1139 double DecompressionTimeSeconds =
1140 DecompressTimer.getTotalTime().getWallTime();
1143 llvm::Timer HashRecalcTimer(
"Hash Recalculation Timer",
1144 "Hash recalculation time",
1146 HashRecalcTimer.startTimer();
1148 llvm::MD5::MD5Result
Result;
1150 DecompressedData.size()));
1152 uint64_t RecalculatedHash =
Result.low();
1153 HashRecalcTimer.stopTimer();
1154 bool HashMatch = (StoredHash == RecalculatedHash);
1156 double CompressionRate =
1157 static_cast<double>(UncompressedSize) / CompressedData.size();
1158 double DecompressionSpeedMBs =
1159 (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
1161 llvm::errs() <<
"Compressed bundle format version: " << ThisVersion <<
"\n";
1162 if (ThisVersion >= 2)
1163 llvm::errs() <<
"Total file size (from header): "
1165 llvm::errs() <<
"Decompression method: "
1166 << (CompressionFormat == llvm::compression::Format::Zlib
1170 <<
"Size before decompression: "
1172 <<
"Size after decompression: "
1174 <<
"Compression rate: "
1175 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1176 <<
"Compression ratio: "
1177 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1178 <<
"Decompression speed: "
1179 << llvm::format(
"%.2lf MB/s", DecompressionSpeedMBs) <<
"\n"
1180 <<
"Stored hash: " << llvm::format_hex(StoredHash, 16) <<
"\n"
1181 <<
"Recalculated hash: "
1182 << llvm::format_hex(RecalculatedHash, 16) <<
"\n"
1183 <<
"Hashes match: " << (HashMatch ?
"Yes" :
"No") <<
"\n";
1186 return llvm::MemoryBuffer::getMemBufferCopy(
1187 llvm::toStringRef(DecompressedData));
1194 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1195 MemoryBuffer::getFileOrSTDIN(InputFileName);
1196 if (std::error_code EC = CodeOrErr.getError())
1197 return createFileError(InputFileName, EC);
1202 if (!DecompressedBufferOrErr)
1203 return createStringError(
1204 inconvertibleErrorCode(),
1205 "Failed to decompress input: " +
1206 llvm::toString(DecompressedBufferOrErr.takeError()));
1208 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1213 if (!FileHandlerOrErr)
1214 return FileHandlerOrErr.takeError();
1216 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1218 return FH->listBundleIDs(DecompressedInput);
1229 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1230 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1231 << CodeObjectInfo.
str()
1232 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1240 "CodeObjectCompatibility",
1241 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1242 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1248 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1250 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1255 if (!TargetProc || !CodeObjectProc ||
1256 CodeObjectProc.value() != TargetProc.value()) {
1257 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1258 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1259 << CodeObjectInfo.
str()
1260 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1266 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1267 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1268 dbgs() <<
"Incompatible: CodeObject has more features "
1269 "than target \t[CodeObject: "
1270 << CodeObjectInfo.
str()
1271 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1279 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1280 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1281 if (TargetFeature == TargetFeatureMap.end()) {
1283 "CodeObjectCompatibility",
1285 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1286 "not matching with Target feature's ANY value \t[CodeObject: "
1287 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1290 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1292 "CodeObjectCompatibility",
1293 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1294 "not matching with Target feature's non-ANY value "
1296 << CodeObjectInfo.
str()
1297 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1307 "CodeObjectCompatibility",
1308 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1309 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1320 llvm::raw_svector_ostream BufferStream(Buffer);
1326 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1327 MemoryBuffer::getFileOrSTDIN(
I);
1328 if (std::error_code EC = CodeOrErr.getError())
1329 return createFileError(
I, EC);
1330 InputBuffers.emplace_back(std::move(*CodeOrErr));
1335 "Host input index undefined??");
1340 if (!FileHandlerOrErr)
1341 return FileHandlerOrErr.takeError();
1343 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1347 if (Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1352 auto Input = InputBuffers.begin();
1354 if (Error Err = FH->WriteBundleStart(BufferStream, Triple))
1356 if (Error Err = FH->WriteBundle(BufferStream, **Input))
1358 if (Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1370 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1371 llvm::MemoryBuffer::getMemBufferCopy(
1372 llvm::StringRef(Buffer.data(), Buffer.size()));
1377 if (
auto Error = CompressionResult.takeError())
1380 auto CompressedMemBuffer = std::move(CompressionResult.get());
1381 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1382 CompressedMemBuffer->getBufferEnd());
1384 CompressedBuffer = Buffer;
1386 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1388 return FH->finalizeOutputFile();
1394 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1396 if (std::error_code EC = CodeOrErr.getError())
1402 if (!DecompressedBufferOrErr)
1403 return createStringError(
1404 inconvertibleErrorCode(),
1405 "Failed to decompress input: " +
1406 llvm::toString(DecompressedBufferOrErr.takeError()));
1408 MemoryBuffer &Input = **DecompressedBufferOrErr;
1413 if (!FileHandlerOrErr)
1414 return FileHandlerOrErr.takeError();
1416 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1420 if (Error Err = FH->ReadHeader(Input))
1424 StringMap<StringRef> Worklist;
1427 Worklist[Triple] = *Output;
1433 bool FoundHostBundle =
false;
1434 while (!Worklist.empty()) {
1436 FH->ReadBundleStart(Input);
1437 if (!CurTripleOrErr)
1438 return CurTripleOrErr.takeError();
1441 if (!*CurTripleOrErr)
1444 StringRef CurTriple = **CurTripleOrErr;
1445 assert(!CurTriple.empty());
1447 auto Output = Worklist.begin();
1448 for (
auto E = Worklist.end(); Output !=
E; Output++) {
1456 if (Output == Worklist.end())
1460 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1462 return createFileError((*Output).second, EC);
1463 if (Error Err = FH->ReadBundle(OutputFile, Input))
1465 if (Error Err = FH->ReadBundleEnd(Input))
1467 Worklist.erase(Output);
1471 if (OffloadInfo.hasHostKind())
1472 FoundHostBundle =
true;
1476 std::string ErrMsg =
"Can't find bundles for";
1477 std::set<StringRef> Sorted;
1478 for (
auto &
E : Worklist)
1479 Sorted.insert(
E.first());
1481 unsigned Last = Sorted.size() - 1;
1482 for (
auto &
E : Sorted) {
1483 if (
I != 0 &&
Last > 1)
1491 return createStringError(inconvertibleErrorCode(), ErrMsg);
1497 for (
auto &
E : Worklist) {
1499 raw_fd_ostream OutputFile(
E.second, EC, sys::fs::OF_None);
1501 return createFileError(
E.second, EC);
1505 if (OffloadInfo.hasHostKind())
1506 OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
1508 return Error::success();
1515 return createStringError(inconvertibleErrorCode(),
1516 "Can't find bundle for the host target");
1519 for (
auto &
E : Worklist) {
1521 raw_fd_ostream OutputFile(
E.second, EC, sys::fs::OF_None);
1523 return createFileError(
E.second, EC);
1526 return Error::success();
1530 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1544 if (!CompatibleTargets.empty()) {
1545 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1546 dbgs() <<
"CompatibleTargets list should be empty\n");
1552 CompatibleTargets.push_back(
Target);
1554 return !CompatibleTargets.empty();
1564 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1565 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1566 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1567 if (std::error_code EC = BufOrErr.getError())
1568 return createFileError(ArchiveName, EC);
1570 ArchiveBuffers.push_back(std::move(*BufOrErr));
1572 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1574 return LibOrErr.takeError();
1576 auto Archive = std::move(*LibOrErr);
1578 Error ArchiveErr = Error::success();
1579 auto ChildEnd = Archive->child_end();
1582 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1583 ArchiveIter != ChildEnd; ++ArchiveIter) {
1586 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1587 if (!ArchiveChildNameOrErr)
1588 return ArchiveChildNameOrErr.takeError();
1590 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1591 if (!CodeObjectBufferRefOrErr)
1592 return CodeObjectBufferRefOrErr.takeError();
1594 auto CodeObjectBuffer =
1595 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1599 if (!FileHandlerOrErr)
1600 return FileHandlerOrErr.takeError();
1602 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1603 assert(FileHandler);
1605 std::set<StringRef> BundleIds;
1606 auto CodeObjectFileError =
1607 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1608 if (CodeObjectFileError)
1609 return CodeObjectFileError;
1612 if (ConflictingArchs) {
1613 std::string ErrMsg =
1614 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1615 ", " + ConflictingArchs.value().second +
"] found in " +
1616 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1618 return createStringError(inconvertibleErrorCode(), ErrMsg);
1633 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1637 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1640 StringMap<StringRef> TargetOutputFileNameMap;
1644 TargetOutputFileNameMap[
Target] = *Output;
1656 return ArchiveError;
1660 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1661 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1662 if (std::error_code EC = BufOrErr.getError())
1665 ArchiveBuffers.push_back(std::move(*BufOrErr));
1667 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1669 return LibOrErr.takeError();
1671 auto Archive = std::move(*LibOrErr);
1673 Error ArchiveErr = Error::success();
1674 auto ChildEnd = Archive->child_end();
1677 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1678 ArchiveIter != ChildEnd; ++ArchiveIter) {
1681 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1682 if (!ArchiveChildNameOrErr)
1683 return ArchiveChildNameOrErr.takeError();
1685 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1687 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1688 if (!CodeObjectBufferRefOrErr)
1689 return CodeObjectBufferRefOrErr.takeError();
1691 auto TempCodeObjectBuffer =
1692 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1698 if (!DecompressedBufferOrErr)
1699 return createStringError(
1700 inconvertibleErrorCode(),
1701 "Failed to decompress code object: " +
1702 llvm::toString(DecompressedBufferOrErr.takeError()));
1704 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1708 if (!FileHandlerOrErr)
1709 return FileHandlerOrErr.takeError();
1711 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1712 assert(FileHandler &&
1713 "FileHandle creation failed for file in the archive!");
1715 if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer))
1719 FileHandler->ReadBundleStart(CodeObjectBuffer);
1720 if (!CurBundleIDOrErr)
1721 return CurBundleIDOrErr.takeError();
1723 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1725 if (!OptionalCurBundleID)
1727 StringRef CodeObject = *OptionalCurBundleID;
1731 while (!CodeObject.empty()) {
1736 std::string BundleData;
1737 raw_string_ostream DataStream(BundleData);
1738 if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1741 for (
auto &CompatibleTarget : CompatibleTargets) {
1743 BundledObjectFileName.assign(BundledObjectFile);
1744 auto OutputBundleName =
1745 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1748 CodeObjectInfo.TargetID))
1752 std::replace(OutputBundleName.begin(), OutputBundleName.end(),
':',
1755 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1756 DataStream.str(), OutputBundleName);
1757 ArchiveBuffers.push_back(std::move(MemBuf));
1758 llvm::MemoryBufferRef MemBufRef =
1759 MemoryBufferRef(*(ArchiveBuffers.back()));
1763 if (!OutputArchivesMap.contains(CompatibleTarget)) {
1765 std::vector<NewArchiveMember> ArchiveMembers;
1766 ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
1767 OutputArchivesMap.insert_or_assign(CompatibleTarget,
1768 std::move(ArchiveMembers));
1770 OutputArchivesMap[CompatibleTarget].push_back(
1771 NewArchiveMember(MemBufRef));
1776 if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1780 FileHandler->ReadBundleStart(CodeObjectBuffer);
1781 if (!NextTripleOrErr)
1782 return NextTripleOrErr.takeError();
1784 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1788 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1793 StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
1794 OutputArchivesMap.find(
Target);
1795 if (CurArchiveMembers != OutputArchivesMap.end()) {
1796 if (Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1797 SymtabWritingMode::NormalSymtab,
1802 std::string ErrMsg =
1803 Twine(
"no compatible code object found for the target '" +
Target +
1804 "' in heterogeneous archive library: " + IFName)
1806 return createStringError(inconvertibleErrorCode(), ErrMsg);
1811 std::vector<llvm::NewArchiveMember> EmptyArchive;
1812 EmptyArchive.clear();
1813 if (Error WriteErr = writeArchive(
1814 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1820 return Error::success();
llvm::MachO::Target Target
static std::string getDeviceLibraryFileName(StringRef BundleFileName, StringRef Device)
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 llvm::TimerGroup ClangOffloadBundlerTimerGroup("Clang Offload Bundler Timer Group", "Timer group for clang offload bundler")
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...
Defines version macros and version-related utility functions for Clang.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, bool Verbose=false)
static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > decompress(const llvm::MemoryBuffer &Input, bool Verbose=false)
llvm::compression::Format CompressionFormat
std::vector< std::string > OutputFileNames
std::vector< std::string > TargetNames
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.
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
The JSON file list parser is used to communicate input to InstallAPI.
@ Create
'create' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...
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.
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
Diagnostic wrappers for TextAPI types for error reporting.
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