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/Compression.h"
33#include "llvm/Support/Debug.h"
34#include "llvm/Support/EndianStream.h"
35#include "llvm/Support/Errc.h"
36#include "llvm/Support/Error.h"
37#include "llvm/Support/ErrorOr.h"
38#include "llvm/Support/FileSystem.h"
39#include "llvm/Support/MD5.h"
40#include "llvm/Support/ManagedStatic.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;
68struct CreateClangOffloadBundlerTimerGroup {
70 return new TimerGroup(
"Clang Offload Bundler Timer Group",
71 "Timer group for clang offload bundler");
75static llvm::ManagedStatic<llvm::TimerGroup,
76 CreateClangOffloadBundlerTimerGroup>
80#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
87 auto TargetFeatures =
Target.split(
':');
88 auto TripleOrGPU = TargetFeatures.first.rsplit(
'-');
92 auto KindTriple = TripleOrGPU.first.split(
'-');
96 llvm::Triple t = llvm::Triple(KindTriple.second);
97 this->
Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
98 t.getOSName(), t.getEnvironmentName());
102 auto KindTriple = TargetFeatures.first.split(
'-');
106 llvm::Triple t = llvm::Triple(KindTriple.second);
107 this->
Triple = llvm::Triple(t.getArchName(), t.getVendorName(),
108 t.getOSName(), t.getEnvironmentName());
124 const StringRef TargetOffloadKind)
const {
126 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
127 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
131 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
132 TargetOffloadKind ==
"openmp";
133 bool OpenMPCompatibleWithHIP =
135 TargetOffloadKind.starts_with_insensitive(
"hip");
136 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
142 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
155 StringRef BundleFileName) {
156 if (
Device.contains(
"gfx"))
158 if (
Device.contains(
"sm_"))
160 return sys::path::extension(BundleFileName);
165 StringRef LibName = sys::path::stem(BundleFileName);
184 virtual ~FileHandler() {}
188 virtual Error ReadHeader(MemoryBuffer &Input) = 0;
194 ReadBundleStart(MemoryBuffer &Input) = 0;
197 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
200 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
204 virtual Error WriteHeader(raw_ostream &OS,
205 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
209 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
213 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
216 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
219 virtual Error finalizeOutputFile() {
return Error::success(); }
222 virtual Error listBundleIDs(MemoryBuffer &Input) {
223 if (Error Err = ReadHeader(Input))
225 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
226 llvm::outs() << Info.BundleID <<
'\n';
227 Error Err = listBundleIDsCallback(Input, Info);
230 return Error::success();
235 virtual Error getBundleIDs(MemoryBuffer &Input,
236 std::set<StringRef> &BundleIds) {
237 if (Error Err = ReadHeader(Input))
239 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
240 BundleIds.insert(Info.BundleID);
241 Error Err = listBundleIDsCallback(Input, Info);
244 return Error::success();
249 Error forEachBundle(MemoryBuffer &Input,
250 std::function<
Error(
const BundleInfo &)>
Func) {
253 ReadBundleStart(Input);
255 return CurTripleOrErr.takeError();
258 if (!*CurTripleOrErr)
261 StringRef CurTriple = **CurTripleOrErr;
262 assert(!CurTriple.empty());
264 BundleInfo Info{CurTriple};
265 if (Error Err =
Func(Info))
268 return Error::success();
272 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
273 const BundleInfo &Info) {
274 return Error::success();
302static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
303 return llvm::support::endian::read64le(Buffer.data() + pos);
307static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
308 llvm::support::endian::write(OS, Val, llvm::endianness::little);
311class BinaryFileHandler final :
public FileHandler {
313 struct BinaryBundleInfo final :
public BundleInfo {
319 BinaryBundleInfo() {}
320 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
325 StringMap<BinaryBundleInfo> BundlesInfo;
328 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
329 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
332 std::string CurWriteBundleTarget;
341 ~BinaryFileHandler() final {}
343 Error ReadHeader(MemoryBuffer &Input)
final {
344 StringRef FC = Input.getBuffer();
347 CurBundleInfo = BundlesInfo.end();
351 if (ReadChars > FC.size())
352 return Error::success();
355 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
356 return Error::success();
359 if (ReadChars + 8 > FC.size())
360 return Error::success();
362 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
366 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
369 if (ReadChars + 8 > FC.size())
370 return Error::success();
372 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
376 if (ReadChars + 8 > FC.size())
377 return Error::success();
379 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
383 if (ReadChars + 8 > FC.size())
384 return Error::success();
386 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
390 if (ReadChars + TripleSize > FC.size())
391 return Error::success();
393 StringRef Triple(&FC.data()[ReadChars], TripleSize);
394 ReadChars += TripleSize;
397 if (!Offset || Offset + Size > FC.size())
398 return Error::success();
400 assert(!BundlesInfo.contains(Triple) &&
"Triple is duplicated??");
401 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
404 CurBundleInfo = BundlesInfo.end();
405 NextBundleInfo = BundlesInfo.begin();
406 return Error::success();
410 ReadBundleStart(MemoryBuffer &Input)
final {
411 if (NextBundleInfo == BundlesInfo.end())
413 CurBundleInfo = NextBundleInfo++;
414 return CurBundleInfo->first();
417 Error ReadBundleEnd(MemoryBuffer &Input)
final {
418 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
419 return Error::success();
422 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
423 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
424 StringRef FC = Input.getBuffer();
425 OS.write(FC.data() + CurBundleInfo->second.Offset,
426 CurBundleInfo->second.Size);
427 return Error::success();
430 Error WriteHeader(raw_ostream &OS,
431 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
441 HeaderSize +=
T.size();
447 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
451 MemoryBuffer &MB = *Inputs[Idx++];
454 Write8byteIntegerToBuffer(OS, HeaderSize);
456 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
457 BundlesInfo[
T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
458 HeaderSize += MB.getBufferSize();
460 Write8byteIntegerToBuffer(OS,
T.size());
464 return Error::success();
467 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
468 CurWriteBundleTarget = TargetTriple.str();
469 return Error::success();
472 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
473 return Error::success();
476 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
477 auto BI = BundlesInfo[CurWriteBundleTarget];
480 size_t CurrentPos = OS.tell();
481 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
482 for (
size_t I = 0; I < PaddingSize; ++I)
484 assert(OS.tell() == BI.Offset);
486 OS.write(Input.getBufferStart(), Input.getBufferSize());
488 return Error::success();
494class TempFileHandlerRAII {
496 ~TempFileHandlerRAII() {
497 for (
const auto &
File : Files)
498 sys::fs::remove(
File);
504 if (std::error_code EC =
505 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
506 return createFileError(
File, EC);
507 Files.push_front(
File);
511 raw_fd_ostream OS(
File, EC);
513 return createFileError(
File, EC);
514 OS.write(Contents->data(), Contents->size());
516 return Files.front().str();
520 std::forward_list<SmallString<128u>> Files;
527class ObjectFileHandler final :
public FileHandler {
530 std::unique_ptr<ObjectFile> Obj;
533 StringRef getInputFileContents()
const {
return Obj->getData(); }
538 IsOffloadSection(SectionRef CurSection) {
541 return NameOrErr.takeError();
544 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
552 unsigned NumberOfInputs = 0;
556 unsigned NumberOfProcessedInputs = 0;
559 section_iterator CurrentSection;
560 section_iterator NextSection;
567 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
569 : Obj(
std::move(ObjIn)), CurrentSection(Obj->section_begin()),
570 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
572 ~ObjectFileHandler() final {}
574 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
577 ReadBundleStart(MemoryBuffer &Input)
final {
578 while (NextSection != Obj->section_end()) {
579 CurrentSection = NextSection;
585 IsOffloadSection(*CurrentSection);
587 return TripleOrErr.takeError();
589 return **TripleOrErr;
594 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
596 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
599 return ContentOrErr.takeError();
600 StringRef Content = *ContentOrErr;
603 std::string ModifiedContent;
604 if (Content.size() == 1u && Content.front() == 0) {
605 auto HostBundleOrErr = getHostBundle(
606 StringRef(Input.getBufferStart(), Input.getBufferSize()));
607 if (!HostBundleOrErr)
608 return HostBundleOrErr.takeError();
610 ModifiedContent = std::move(*HostBundleOrErr);
611 Content = ModifiedContent;
614 OS.write(Content.data(), Content.size());
615 return Error::success();
618 Error WriteHeader(raw_ostream &OS,
619 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
621 "Host input index not defined.");
624 NumberOfInputs = Inputs.size();
625 return Error::success();
628 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
629 ++NumberOfProcessedInputs;
630 return Error::success();
633 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
634 return Error::success();
637 Error finalizeOutputFile() final {
638 assert(NumberOfProcessedInputs <= NumberOfInputs &&
639 "Processing more inputs that actually exist!");
641 "Host input index not defined.");
644 if (NumberOfProcessedInputs != NumberOfInputs)
645 return Error::success();
653 "llvm-objcopy path not specified");
656 TempFileHandlerRAII TempFiles;
660 BumpPtrAllocator
Alloc;
661 StringSaver SS{
Alloc};
664 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
673 return TempFileOrErr.takeError();
674 InputFile = *TempFileOrErr;
677 ObjcopyArgs.push_back(
680 ObjcopyArgs.push_back(
682 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
684 ObjcopyArgs.push_back(
"--");
685 ObjcopyArgs.push_back(
689 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
692 return Error::success();
695 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
696 return Error::success();
704 errs() <<
"\"" << Objcopy <<
"\"";
705 for (StringRef Arg : drop_begin(Args, 1))
706 errs() <<
" \"" << Arg <<
"\"";
709 if (sys::ExecuteAndWait(Objcopy, Args))
710 return createStringError(inconvertibleErrorCode(),
711 "'llvm-objcopy' tool failed");
713 return Error::success();
717 TempFileHandlerRAII TempFiles;
719 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
720 if (!ModifiedObjPathOrErr)
721 return ModifiedObjPathOrErr.takeError();
722 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
724 BumpPtrAllocator
Alloc;
725 StringSaver SS{
Alloc};
728 ObjcopyArgs.push_back(
"--regex");
729 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
730 ObjcopyArgs.push_back(
"--");
732 StringRef ObjcopyInputFileName;
739 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
740 auto InputFileOrErr =
743 return InputFileOrErr.takeError();
744 ObjcopyInputFileName = *InputFileOrErr;
748 ObjcopyArgs.push_back(ObjcopyInputFileName);
749 ObjcopyArgs.push_back(ModifiedObjPath);
751 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
752 return std::move(Err);
754 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
756 return createStringError(BufOrErr.getError(),
757 "Failed to read back the modified object file");
759 return BufOrErr->get()->getBuffer().str();
772class TextFileHandler final :
public FileHandler {
777 std::string BundleStartString;
780 std::string BundleEndString;
783 size_t ReadChars = 0u;
786 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
789 ReadBundleStart(MemoryBuffer &Input)
final {
790 StringRef FC = Input.getBuffer();
793 ReadChars = FC.find(BundleStartString, ReadChars);
794 if (ReadChars == FC.npos)
798 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
801 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
802 if (TripleEnd == FC.npos)
808 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
811 Error ReadBundleEnd(MemoryBuffer &Input)
final {
812 StringRef FC = Input.getBuffer();
815 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
817 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
818 if (TripleEnd != FC.npos)
822 return Error::success();
825 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
826 StringRef FC = Input.getBuffer();
827 size_t BundleStart = ReadChars;
830 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
832 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
835 return Error::success();
838 Error WriteHeader(raw_ostream &OS,
839 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
840 return Error::success();
843 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
844 OS << BundleStartString << TargetTriple <<
"\n";
845 return Error::success();
848 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
849 OS << BundleEndString << TargetTriple <<
"\n";
850 return Error::success();
853 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
854 OS << Input.getBuffer();
855 return Error::success();
859 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
866 Error listBundleIDsCallback(MemoryBuffer &Input,
867 const BundleInfo &Info)
final {
872 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
873 if (Error Err = ReadBundleEnd(Input))
875 return Error::success();
883static std::unique_ptr<FileHandler>
891 if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
892 return std::make_unique<BinaryFileHandler>(BundlerConfig);
896 return std::make_unique<ObjectFileHandler>(
897 std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
905 std::string FilesType = BundlerConfig.
FilesType;
907 if (FilesType ==
"i")
908 return std::make_unique<TextFileHandler>(
"//");
909 if (FilesType ==
"ii")
910 return std::make_unique<TextFileHandler>(
"//");
911 if (FilesType ==
"cui")
912 return std::make_unique<TextFileHandler>(
"//");
913 if (FilesType ==
"hipi")
914 return std::make_unique<TextFileHandler>(
"//");
917 if (FilesType ==
"d")
918 return std::make_unique<TextFileHandler>(
"#");
919 if (FilesType ==
"ll")
920 return std::make_unique<TextFileHandler>(
";");
921 if (FilesType ==
"bc")
922 return std::make_unique<BinaryFileHandler>(BundlerConfig);
923 if (FilesType ==
"s")
924 return std::make_unique<TextFileHandler>(
"#");
925 if (FilesType ==
"o")
927 if (FilesType ==
"a")
929 if (FilesType ==
"gch")
930 return std::make_unique<BinaryFileHandler>(BundlerConfig);
931 if (FilesType ==
"ast")
932 return std::make_unique<BinaryFileHandler>(BundlerConfig);
934 return createStringError(errc::invalid_argument,
935 "'" + FilesType +
"': invalid file type specified");
939 if (llvm::compression::zstd::isAvailable()) {
944 }
else if (llvm::compression::zlib::isAvailable()) {
950 auto IgnoreEnvVarOpt =
951 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
952 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
955 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
956 if (VerboseEnvVarOpt.has_value())
957 Verbose = VerboseEnvVarOpt.value() ==
"1";
959 auto CompressEnvVarOpt =
960 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
961 if (CompressEnvVarOpt.has_value())
962 Compress = CompressEnvVarOpt.value() ==
"1";
964 auto CompressionLevelEnvVarOpt =
965 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
966 if (CompressionLevelEnvVarOpt.has_value()) {
967 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
969 if (!CompressionLevelStr.getAsInteger(10, Level))
973 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
974 << CompressionLevelStr.str() <<
". Ignoring it.\n";
980 std::string
Num = std::to_string(
Value);
981 int InsertPosition =
Num.length() - 3;
982 while (InsertPosition > 0) {
983 Num.insert(InsertPosition,
",");
991 const llvm::MemoryBuffer &Input,
993 if (!llvm::compression::zstd::isAvailable() &&
994 !llvm::compression::zlib::isAvailable())
995 return createStringError(llvm::inconvertibleErrorCode(),
996 "Compression not supported");
998 llvm::Timer HashTimer(
"Hash Calculation Timer",
"Hash calculation time",
1001 HashTimer.startTimer();
1003 llvm::MD5::MD5Result
Result;
1004 Hash.update(Input.getBuffer());
1006 uint64_t TruncatedHash =
Result.low();
1008 HashTimer.stopTimer();
1012 reinterpret_cast<const uint8_t *
>(Input.getBuffer().data()),
1013 Input.getBuffer().size());
1015 llvm::Timer CompressTimer(
"Compression Timer",
"Compression time",
1018 CompressTimer.startTimer();
1019 llvm::compression::compress(
P, BufferUint8, CompressedBuffer);
1021 CompressTimer.stopTimer();
1023 uint16_t CompressionMethod =
static_cast<uint16_t
>(
P.format);
1024 uint32_t UncompressedSize = Input.getBuffer().size();
1025 uint32_t TotalFileSize = MagicNumber.size() +
sizeof(TotalFileSize) +
1026 sizeof(Version) +
sizeof(CompressionMethod) +
1027 sizeof(UncompressedSize) +
sizeof(TruncatedHash) +
1028 CompressedBuffer.size();
1031 llvm::raw_svector_ostream OS(FinalBuffer);
1033 OS.write(
reinterpret_cast<const char *
>(&Version),
sizeof(Version));
1034 OS.write(
reinterpret_cast<const char *
>(&CompressionMethod),
1035 sizeof(CompressionMethod));
1036 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize),
1037 sizeof(TotalFileSize));
1038 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize),
1039 sizeof(UncompressedSize));
1040 OS.write(
reinterpret_cast<const char *
>(&TruncatedHash),
1041 sizeof(TruncatedHash));
1042 OS.write(
reinterpret_cast<const char *
>(CompressedBuffer.data()),
1043 CompressedBuffer.size());
1047 P.format == llvm::compression::Format::Zstd ?
"zstd" :
"zlib";
1048 double CompressionRate =
1049 static_cast<double>(UncompressedSize) / CompressedBuffer.size();
1050 double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
1051 double CompressionSpeedMBs =
1052 (UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;
1054 llvm::errs() <<
"Compressed bundle format version: " << Version <<
"\n"
1055 <<
"Total file size (including headers): "
1057 <<
"Compression method used: " << MethodUsed <<
"\n"
1058 <<
"Compression level: " <<
P.level <<
"\n"
1059 <<
"Binary size before compression: "
1061 <<
"Binary size after compression: "
1063 <<
"Compression rate: "
1064 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1065 <<
"Compression ratio: "
1066 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1067 <<
"Compression speed: "
1068 << llvm::format(
"%.2lf MB/s", CompressionSpeedMBs) <<
"\n"
1069 <<
"Truncated MD5 hash: "
1070 << llvm::format_hex(TruncatedHash, 16) <<
"\n";
1072 return llvm::MemoryBuffer::getMemBufferCopy(
1073 llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
1080 StringRef Blob = Input.getBuffer();
1082 if (Blob.size() < V1HeaderSize)
1083 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1085 if (llvm::identify_magic(Blob) !=
1086 llvm::file_magic::offload_bundle_compressed) {
1088 llvm::errs() <<
"Uncompressed bundle.\n";
1089 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1092 size_t CurrentOffset = MagicSize;
1094 uint16_t ThisVersion;
1095 memcpy(&ThisVersion, Blob.data() + CurrentOffset,
sizeof(uint16_t));
1096 CurrentOffset += VersionFieldSize;
1098 uint16_t CompressionMethod;
1099 memcpy(&CompressionMethod, Blob.data() + CurrentOffset,
sizeof(uint16_t));
1100 CurrentOffset += MethodFieldSize;
1102 uint32_t TotalFileSize;
1103 if (ThisVersion >= 2) {
1104 if (Blob.size() < V2HeaderSize)
1105 return createStringError(inconvertibleErrorCode(),
1106 "Compressed bundle header size too small");
1107 memcpy(&TotalFileSize, Blob.data() + CurrentOffset,
sizeof(uint32_t));
1108 CurrentOffset += FileSizeFieldSize;
1111 uint32_t UncompressedSize;
1112 memcpy(&UncompressedSize, Blob.data() + CurrentOffset,
sizeof(uint32_t));
1113 CurrentOffset += UncompressedSizeFieldSize;
1115 uint64_t StoredHash;
1116 memcpy(&StoredHash, Blob.data() + CurrentOffset,
sizeof(uint64_t));
1117 CurrentOffset += HashFieldSize;
1119 llvm::compression::Format CompressionFormat;
1120 if (CompressionMethod ==
1121 static_cast<uint16_t
>(llvm::compression::Format::Zlib))
1122 CompressionFormat = llvm::compression::Format::Zlib;
1123 else if (CompressionMethod ==
1124 static_cast<uint16_t
>(llvm::compression::Format::Zstd))
1125 CompressionFormat = llvm::compression::Format::Zstd;
1127 return createStringError(inconvertibleErrorCode(),
1128 "Unknown compressing method");
1130 llvm::Timer DecompressTimer(
"Decompression Timer",
"Decompression time",
1133 DecompressTimer.startTimer();
1136 StringRef CompressedData = Blob.substr(CurrentOffset);
1137 if (llvm::Error DecompressionError = llvm::compression::decompress(
1138 CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
1139 DecompressedData, UncompressedSize))
1140 return createStringError(inconvertibleErrorCode(),
1141 "Could not decompress embedded file contents: " +
1142 llvm::toString(std::move(DecompressionError)));
1145 DecompressTimer.stopTimer();
1147 double DecompressionTimeSeconds =
1148 DecompressTimer.getTotalTime().getWallTime();
1151 llvm::Timer HashRecalcTimer(
"Hash Recalculation Timer",
1152 "Hash recalculation time",
1154 HashRecalcTimer.startTimer();
1156 llvm::MD5::MD5Result
Result;
1158 DecompressedData.size()));
1160 uint64_t RecalculatedHash =
Result.low();
1161 HashRecalcTimer.stopTimer();
1162 bool HashMatch = (StoredHash == RecalculatedHash);
1164 double CompressionRate =
1165 static_cast<double>(UncompressedSize) / CompressedData.size();
1166 double DecompressionSpeedMBs =
1167 (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
1169 llvm::errs() <<
"Compressed bundle format version: " << ThisVersion <<
"\n";
1170 if (ThisVersion >= 2)
1171 llvm::errs() <<
"Total file size (from header): "
1173 llvm::errs() <<
"Decompression method: "
1174 << (CompressionFormat == llvm::compression::Format::Zlib
1178 <<
"Size before decompression: "
1180 <<
"Size after decompression: "
1182 <<
"Compression rate: "
1183 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1184 <<
"Compression ratio: "
1185 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1186 <<
"Decompression speed: "
1187 << llvm::format(
"%.2lf MB/s", DecompressionSpeedMBs) <<
"\n"
1188 <<
"Stored hash: " << llvm::format_hex(StoredHash, 16) <<
"\n"
1189 <<
"Recalculated hash: "
1190 << llvm::format_hex(RecalculatedHash, 16) <<
"\n"
1191 <<
"Hashes match: " << (HashMatch ?
"Yes" :
"No") <<
"\n";
1194 return llvm::MemoryBuffer::getMemBufferCopy(
1195 llvm::toStringRef(DecompressedData));
1202 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1203 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1204 if (std::error_code EC = CodeOrErr.getError())
1205 return createFileError(InputFileName, EC);
1210 if (!DecompressedBufferOrErr)
1211 return createStringError(
1212 inconvertibleErrorCode(),
1213 "Failed to decompress input: " +
1214 llvm::toString(DecompressedBufferOrErr.takeError()));
1216 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1221 if (!FileHandlerOrErr)
1222 return FileHandlerOrErr.takeError();
1224 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1226 return FH->listBundleIDs(DecompressedInput);
1237 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1238 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1239 << CodeObjectInfo.
str()
1240 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1248 "CodeObjectCompatibility",
1249 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1250 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1256 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1258 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1263 if (!TargetProc || !CodeObjectProc ||
1264 CodeObjectProc.value() != TargetProc.value()) {
1265 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1266 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1267 << CodeObjectInfo.
str()
1268 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1274 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1275 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1276 dbgs() <<
"Incompatible: CodeObject has more features "
1277 "than target \t[CodeObject: "
1278 << CodeObjectInfo.
str()
1279 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1287 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1288 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1289 if (TargetFeature == TargetFeatureMap.end()) {
1291 "CodeObjectCompatibility",
1293 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1294 "not matching with Target feature's ANY value \t[CodeObject: "
1295 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1298 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1300 "CodeObjectCompatibility",
1301 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1302 "not matching with Target feature's non-ANY value "
1304 << CodeObjectInfo.
str()
1305 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1315 "CodeObjectCompatibility",
1316 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1317 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1328 llvm::raw_svector_ostream BufferStream(Buffer);
1334 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1335 MemoryBuffer::getFileOrSTDIN(I,
true);
1336 if (std::error_code EC = CodeOrErr.getError())
1337 return createFileError(I, EC);
1338 InputBuffers.emplace_back(std::move(*CodeOrErr));
1343 "Host input index undefined??");
1348 if (!FileHandlerOrErr)
1349 return FileHandlerOrErr.takeError();
1351 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1355 if (Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1360 auto Input = InputBuffers.begin();
1362 if (Error Err = FH->WriteBundleStart(BufferStream, Triple))
1364 if (Error Err = FH->WriteBundle(BufferStream, **Input))
1366 if (Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1378 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1379 llvm::MemoryBuffer::getMemBufferCopy(
1380 llvm::StringRef(Buffer.data(), Buffer.size()));
1385 if (
auto Error = CompressionResult.takeError())
1388 auto CompressedMemBuffer = std::move(CompressionResult.get());
1389 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1390 CompressedMemBuffer->getBufferEnd());
1392 CompressedBuffer = Buffer;
1394 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1396 return FH->finalizeOutputFile();
1402 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1405 if (std::error_code EC = CodeOrErr.getError())
1411 if (!DecompressedBufferOrErr)
1412 return createStringError(
1413 inconvertibleErrorCode(),
1414 "Failed to decompress input: " +
1415 llvm::toString(DecompressedBufferOrErr.takeError()));
1417 MemoryBuffer &Input = **DecompressedBufferOrErr;
1422 if (!FileHandlerOrErr)
1423 return FileHandlerOrErr.takeError();
1425 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1429 if (Error Err = FH->ReadHeader(Input))
1433 StringMap<StringRef> Worklist;
1436 Worklist[Triple] = *Output;
1442 bool FoundHostBundle =
false;
1443 while (!Worklist.empty()) {
1445 FH->ReadBundleStart(Input);
1446 if (!CurTripleOrErr)
1447 return CurTripleOrErr.takeError();
1450 if (!*CurTripleOrErr)
1453 StringRef CurTriple = **CurTripleOrErr;
1454 assert(!CurTriple.empty());
1456 auto Output = Worklist.begin();
1457 for (
auto E = Worklist.end(); Output !=
E; Output++) {
1465 if (Output == Worklist.end())
1469 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1471 return createFileError((*Output).second, EC);
1472 if (Error Err = FH->ReadBundle(OutputFile, Input))
1474 if (Error Err = FH->ReadBundleEnd(Input))
1476 Worklist.erase(Output);
1480 if (OffloadInfo.hasHostKind())
1481 FoundHostBundle =
true;
1485 std::string ErrMsg =
"Can't find bundles for";
1486 std::set<StringRef> Sorted;
1487 for (
auto &
E : Worklist)
1488 Sorted.insert(
E.first());
1490 unsigned Last = Sorted.size() - 1;
1491 for (
auto &
E : Sorted) {
1492 if (I != 0 &&
Last > 1)
1495 if (I ==
Last && I != 0)
1500 return createStringError(inconvertibleErrorCode(), ErrMsg);
1506 for (
auto &
E : Worklist) {
1508 raw_fd_ostream OutputFile(
E.second, EC, sys::fs::OF_None);
1510 return createFileError(
E.second, EC);
1514 if (OffloadInfo.hasHostKind())
1515 OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
1517 return Error::success();
1524 return createStringError(inconvertibleErrorCode(),
1525 "Can't find bundle for the host target");
1528 for (
auto &
E : Worklist) {
1530 raw_fd_ostream OutputFile(
E.second, EC, sys::fs::OF_None);
1532 return createFileError(
E.second, EC);
1535 return Error::success();
1539 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1553 if (!CompatibleTargets.empty()) {
1554 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1555 dbgs() <<
"CompatibleTargets list should be empty\n");
1561 CompatibleTargets.push_back(
Target);
1563 return !CompatibleTargets.empty();
1573 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1574 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1575 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1576 if (std::error_code EC = BufOrErr.getError())
1577 return createFileError(ArchiveName, EC);
1579 ArchiveBuffers.push_back(std::move(*BufOrErr));
1581 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1583 return LibOrErr.takeError();
1585 auto Archive = std::move(*LibOrErr);
1587 Error ArchiveErr = Error::success();
1588 auto ChildEnd = Archive->child_end();
1591 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1592 ArchiveIter != ChildEnd; ++ArchiveIter) {
1595 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1596 if (!ArchiveChildNameOrErr)
1597 return ArchiveChildNameOrErr.takeError();
1599 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1600 if (!CodeObjectBufferRefOrErr)
1601 return CodeObjectBufferRefOrErr.takeError();
1603 auto CodeObjectBuffer =
1604 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1608 if (!FileHandlerOrErr)
1609 return FileHandlerOrErr.takeError();
1611 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1612 assert(FileHandler);
1614 std::set<StringRef> BundleIds;
1615 auto CodeObjectFileError =
1616 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1617 if (CodeObjectFileError)
1618 return CodeObjectFileError;
1621 if (ConflictingArchs) {
1622 std::string ErrMsg =
1623 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1624 ", " + ConflictingArchs.value().second +
"] found in " +
1625 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1627 return createStringError(inconvertibleErrorCode(), ErrMsg);
1642 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1646 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1649 StringMap<StringRef> TargetOutputFileNameMap;
1653 TargetOutputFileNameMap[
Target] = *Output;
1665 return ArchiveError;
1669 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1670 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1671 if (std::error_code EC = BufOrErr.getError())
1674 ArchiveBuffers.push_back(std::move(*BufOrErr));
1676 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1678 return LibOrErr.takeError();
1680 auto Archive = std::move(*LibOrErr);
1682 Error ArchiveErr = Error::success();
1683 auto ChildEnd = Archive->child_end();
1686 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1687 ArchiveIter != ChildEnd; ++ArchiveIter) {
1690 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1691 if (!ArchiveChildNameOrErr)
1692 return ArchiveChildNameOrErr.takeError();
1694 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1696 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1697 if (!CodeObjectBufferRefOrErr)
1698 return CodeObjectBufferRefOrErr.takeError();
1700 auto TempCodeObjectBuffer =
1701 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1707 if (!DecompressedBufferOrErr)
1708 return createStringError(
1709 inconvertibleErrorCode(),
1710 "Failed to decompress code object: " +
1711 llvm::toString(DecompressedBufferOrErr.takeError()));
1713 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1717 if (!FileHandlerOrErr)
1718 return FileHandlerOrErr.takeError();
1720 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1721 assert(FileHandler &&
1722 "FileHandle creation failed for file in the archive!");
1724 if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer))
1728 FileHandler->ReadBundleStart(CodeObjectBuffer);
1729 if (!CurBundleIDOrErr)
1730 return CurBundleIDOrErr.takeError();
1732 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1734 if (!OptionalCurBundleID)
1736 StringRef CodeObject = *OptionalCurBundleID;
1740 while (!CodeObject.empty()) {
1745 std::string BundleData;
1746 raw_string_ostream DataStream(BundleData);
1747 if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1750 for (
auto &CompatibleTarget : CompatibleTargets) {
1752 BundledObjectFileName.assign(BundledObjectFile);
1753 auto OutputBundleName =
1754 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1757 CodeObjectInfo.TargetID))
1761 std::replace(OutputBundleName.begin(), OutputBundleName.end(),
':',
1764 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1765 DataStream.str(), OutputBundleName);
1766 ArchiveBuffers.push_back(std::move(MemBuf));
1767 llvm::MemoryBufferRef MemBufRef =
1768 MemoryBufferRef(*(ArchiveBuffers.back()));
1772 OutputArchivesMap[CompatibleTarget].push_back(
1773 NewArchiveMember(MemBufRef));
1777 if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1781 FileHandler->ReadBundleStart(CodeObjectBuffer);
1782 if (!NextTripleOrErr)
1783 return NextTripleOrErr.takeError();
1785 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1789 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1794 StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
1795 OutputArchivesMap.find(
Target);
1796 if (CurArchiveMembers != OutputArchivesMap.end()) {
1797 if (Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1798 SymtabWritingMode::NormalSymtab,
1803 std::string ErrMsg =
1804 Twine(
"no compatible code object found for the target '" +
Target +
1805 "' in heterogeneous archive library: " + IFName)
1807 return createStringError(inconvertibleErrorCode(), ErrMsg);
1812 std::vector<llvm::NewArchiveMember> EmptyArchive;
1813 EmptyArchive.clear();
1814 if (Error WriteErr = writeArchive(
1815 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1821 return Error::success();
llvm::MachO::Target Target
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 > > 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.
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
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