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/Object/OffloadBundle.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/Compiler.h"
34#include "llvm/Support/Compression.h"
35#include "llvm/Support/Debug.h"
36#include "llvm/Support/EndianStream.h"
37#include "llvm/Support/Errc.h"
38#include "llvm/Support/Error.h"
39#include "llvm/Support/ErrorOr.h"
40#include "llvm/Support/FileSystem.h"
41#include "llvm/Support/MD5.h"
42#include "llvm/Support/ManagedStatic.h"
43#include "llvm/Support/MemoryBuffer.h"
44#include "llvm/Support/Path.h"
45#include "llvm/Support/Program.h"
46#include "llvm/Support/Signals.h"
47#include "llvm/Support/StringSaver.h"
48#include "llvm/Support/Timer.h"
49#include "llvm/Support/WithColor.h"
50#include "llvm/Support/raw_ostream.h"
51#include "llvm/TargetParser/Host.h"
52#include "llvm/TargetParser/Triple.h"
57#include <forward_list>
58#include <llvm/Support/Process.h>
62#include <system_error>
66using namespace llvm::object;
70#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
79 Target.split(Components,
'-', 5);
80 assert((Components.size() == 5 || Components.size() == 6) &&
81 "malformed target string");
83 StringRef TargetIdWithFeature =
84 Components.size() == 6 ? Components.back() :
"";
85 StringRef TargetId = TargetIdWithFeature.split(
':').first;
86 if (!TargetId.empty() &&
88 this->
TargetID = TargetIdWithFeature;
94 llvm::Triple T = llvm::Triple(llvm::join(TripleSlice,
"-"));
95 this->
Triple = llvm::Triple(T.getArchName(), T.getVendorName(), T.getOSName(),
96 T.getEnvironmentName());
109 const StringRef TargetOffloadKind)
const {
111 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
112 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
116 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
117 TargetOffloadKind ==
"openmp";
118 bool OpenMPCompatibleWithHIP =
120 TargetOffloadKind.starts_with_insensitive(
"hip");
121 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
127 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
136 std::string NormalizedTriple;
141 if (
Triple.getOS() == Triple::OSType::AMDHSA) {
142 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::THREE_IDENT);
143 NormalizedTriple.push_back(
'-');
145 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::FOUR_IDENT);
151 StringRef BundleFileName) {
152 if (
Device.contains(
"gfx"))
154 if (
Device.contains(
"sm_"))
156 return sys::path::extension(BundleFileName);
161 StringRef LibName = sys::path::stem(BundleFileName);
180 virtual ~FileHandler() {}
184 virtual Error ReadHeader(StringRef FC) = 0;
189 virtual Expected<std::optional<StringRef>>
190 ReadBundleStart(StringRef Input) = 0;
193 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
196 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
200 virtual Error WriteHeader(raw_ostream &OS,
201 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
205 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
209 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
212 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
215 virtual Error finalizeOutputFile() {
return Error::success(); }
218 virtual Error listBundleIDs(MemoryBuffer &Input) {
219 size_t NextBundleStart = 0;
220 StringRef BufferString = Input.getBuffer();
221 while (NextBundleStart != StringRef::npos) {
224 BufferString = BufferString.drop_front(NextBundleStart);
227 Error Err = ReadHeader(BufferString);
231 Err = forEachBundle(BufferString, [&](
const BundleInfo &Info) ->
Error {
232 llvm::outs() << Info.BundleID <<
'\n';
233 Error Err = listBundleIDsCallback(Input, Info);
236 return Error::success();
246 return Error::success();
250 virtual Error getBundleIDs(MemoryBuffer &Input,
251 std::set<StringRef> &BundleIds) {
253 if (
Error Err = ReadHeader(Input.getBuffer()))
255 return forEachBundle(Input.getBuffer(),
256 [&](
const BundleInfo &Info) ->
Error {
257 BundleIds.insert(Info.BundleID);
258 Error Err = listBundleIDsCallback(Input, Info);
261 return Error::success();
266 Error forEachBundle(StringRef Input,
269 Expected<std::optional<StringRef>> CurTripleOrErr =
270 ReadBundleStart(Input);
272 return CurTripleOrErr.takeError();
275 if (!*CurTripleOrErr)
278 StringRef CurTriple = **CurTripleOrErr;
279 assert(!CurTriple.empty());
281 BundleInfo Info{CurTriple};
285 return Error::success();
289 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
290 const BundleInfo &Info) {
291 return Error::success();
319static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
320 return llvm::support::endian::read64le(Buffer.data() + pos);
324static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
325 llvm::support::endian::write(OS, Val, llvm::endianness::little);
328class BinaryFileHandler final :
public FileHandler {
330 struct BinaryBundleInfo final :
public BundleInfo {
336 BinaryBundleInfo() {}
337 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
342 StringMap<BinaryBundleInfo> BundlesInfo;
345 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
346 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
349 std::string CurWriteBundleTarget;
352 const OffloadBundlerConfig &BundlerConfig;
356 BinaryFileHandler(
const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
358 ~BinaryFileHandler() final {}
360 Error ReadHeader(StringRef FC)
final {
362 CurBundleInfo = BundlesInfo.end();
366 if (ReadChars > FC.size())
367 return Error::success();
370 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
371 return Error::success();
374 if (ReadChars + 8 > FC.size())
375 return Error::success();
377 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
381 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
384 if (ReadChars + 8 > FC.size())
385 return Error::success();
387 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
391 if (ReadChars + 8 > FC.size())
392 return Error::success();
394 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
398 if (ReadChars + 8 > FC.size())
399 return Error::success();
401 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
405 if (ReadChars + TripleSize > FC.size())
406 return Error::success();
408 StringRef Triple(&FC.data()[ReadChars], TripleSize);
409 ReadChars += TripleSize;
412 if (!Offset || Offset + Size > FC.size())
413 return Error::success();
415 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
418 CurBundleInfo = BundlesInfo.end();
419 NextBundleInfo = BundlesInfo.begin();
420 return Error::success();
423 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
424 if (NextBundleInfo == BundlesInfo.end())
426 CurBundleInfo = NextBundleInfo++;
427 return CurBundleInfo->first();
430 Error ReadBundleEnd(MemoryBuffer &Input)
final {
431 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
432 return Error::success();
435 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
436 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
437 StringRef FC = Input.getBuffer();
438 OS.write(FC.data() + CurBundleInfo->second.Offset,
439 CurBundleInfo->second.Size);
440 return Error::success();
443 Error WriteHeader(raw_ostream &OS,
444 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
454 HeaderSize += T.size();
460 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
464 MemoryBuffer &MB = *Inputs[Idx++];
467 Write8byteIntegerToBuffer(OS, HeaderSize);
469 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
470 BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
471 HeaderSize += MB.getBufferSize();
473 Write8byteIntegerToBuffer(OS, T.size());
477 return Error::success();
480 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
481 CurWriteBundleTarget = TargetTriple.str();
482 return Error::success();
485 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
486 return Error::success();
489 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
490 auto BI = BundlesInfo[CurWriteBundleTarget];
493 size_t CurrentPos =
OS.tell();
494 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
495 for (
size_t I = 0; I < PaddingSize; ++I)
497 assert(
OS.tell() == BI.Offset);
499 OS.write(Input.getBufferStart(), Input.getBufferSize());
501 return Error::success();
507class TempFileHandlerRAII {
509 ~TempFileHandlerRAII() {
510 for (
const auto &
File : Files)
511 sys::fs::remove(
File);
515 Expected<StringRef>
Create(std::optional<ArrayRef<char>> Contents) {
516 SmallString<128u>
File;
517 if (std::error_code EC =
518 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
519 return createFileError(
File, EC);
520 Files.push_front(
File);
524 raw_fd_ostream
OS(
File, EC);
526 return createFileError(
File, EC);
527 OS.write(Contents->data(), Contents->size());
529 return Files.front().str();
533 std::forward_list<SmallString<128u>> Files;
540class ObjectFileHandler final :
public FileHandler {
543 std::unique_ptr<ObjectFile> Obj;
546 StringRef getInputFileContents()
const {
return Obj->getData(); }
550 static Expected<std::optional<StringRef>>
551 IsOffloadSection(SectionRef CurSection) {
552 Expected<StringRef> NameOrErr = CurSection.getName();
554 return NameOrErr.takeError();
557 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
565 unsigned NumberOfInputs = 0;
569 unsigned NumberOfProcessedInputs = 0;
572 section_iterator CurrentSection;
573 section_iterator NextSection;
576 const OffloadBundlerConfig &BundlerConfig;
580 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
581 const OffloadBundlerConfig &BC)
582 : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
583 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
585 ~ObjectFileHandler() final {}
587 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
589 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
590 while (NextSection != Obj->section_end()) {
591 CurrentSection = NextSection;
596 Expected<std::optional<StringRef>> TripleOrErr =
597 IsOffloadSection(*CurrentSection);
599 return TripleOrErr.takeError();
601 return **TripleOrErr;
606 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
608 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
609 Expected<StringRef> ContentOrErr = CurrentSection->getContents();
611 return ContentOrErr.takeError();
612 StringRef Content = *ContentOrErr;
615 std::string ModifiedContent;
616 if (Content.size() == 1u && Content.front() == 0) {
617 auto HostBundleOrErr = getHostBundle(
618 StringRef(Input.getBufferStart(), Input.getBufferSize()));
619 if (!HostBundleOrErr)
620 return HostBundleOrErr.takeError();
622 ModifiedContent = std::move(*HostBundleOrErr);
623 Content = ModifiedContent;
626 OS.write(Content.data(), Content.size());
627 return Error::success();
630 Error WriteHeader(raw_ostream &OS,
631 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
633 "Host input index not defined.");
636 NumberOfInputs = Inputs.size();
637 return Error::success();
640 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
641 ++NumberOfProcessedInputs;
642 return Error::success();
645 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
646 return Error::success();
649 Error finalizeOutputFile() final {
650 assert(NumberOfProcessedInputs <= NumberOfInputs &&
651 "Processing more inputs that actually exist!");
653 "Host input index not defined.");
656 if (NumberOfProcessedInputs != NumberOfInputs)
657 return Error::success();
665 "llvm-objcopy path not specified");
668 TempFileHandlerRAII TempFiles;
672 BumpPtrAllocator
Alloc;
673 StringSaver SS{
Alloc};
674 SmallVector<StringRef, 8u> ObjcopyArgs{
"llvm-objcopy"};
676 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
683 Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
685 return TempFileOrErr.takeError();
686 InputFile = *TempFileOrErr;
689 ObjcopyArgs.push_back(
692 ObjcopyArgs.push_back(
694 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
696 ObjcopyArgs.push_back(
"--");
697 ObjcopyArgs.push_back(
704 return Error::success();
707 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
708 return Error::success();
712 Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
716 errs() <<
"\"" << Objcopy <<
"\"";
717 for (StringRef Arg : drop_begin(Args, 1))
718 errs() <<
" \"" << Arg <<
"\"";
721 if (sys::ExecuteAndWait(Objcopy, Args))
722 return createStringError(inconvertibleErrorCode(),
723 "'llvm-objcopy' tool failed");
725 return Error::success();
728 Expected<std::string> getHostBundle(StringRef Input) {
729 TempFileHandlerRAII TempFiles;
731 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
732 if (!ModifiedObjPathOrErr)
733 return ModifiedObjPathOrErr.takeError();
734 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
736 BumpPtrAllocator
Alloc;
737 StringSaver SS{
Alloc};
738 SmallVector<StringRef, 16> ObjcopyArgs{
"llvm-objcopy"};
740 ObjcopyArgs.push_back(
"--regex");
741 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
742 ObjcopyArgs.push_back(
"--");
744 StringRef ObjcopyInputFileName;
751 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
752 auto InputFileOrErr = TempFiles.Create(ArrayRef<char>(Input));
754 return InputFileOrErr.takeError();
755 ObjcopyInputFileName = *InputFileOrErr;
759 ObjcopyArgs.push_back(ObjcopyInputFileName);
760 ObjcopyArgs.push_back(ModifiedObjPath);
763 return std::move(Err);
765 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
767 return createStringError(BufOrErr.getError(),
768 "Failed to read back the modified object file");
770 return BufOrErr->get()->getBuffer().str();
783class TextFileHandler final :
public FileHandler {
788 std::string BundleStartString;
791 std::string BundleEndString;
794 size_t ReadChars = 0u;
797 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
799 Expected<std::optional<StringRef>> ReadBundleStart(StringRef FC)
final {
802 ReadChars = FC.find(BundleStartString, ReadChars);
803 if (ReadChars == FC.npos)
807 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
810 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
811 if (TripleEnd == FC.npos)
817 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
820 Error ReadBundleEnd(MemoryBuffer &Input)
final {
821 StringRef FC = Input.getBuffer();
824 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
826 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
827 if (TripleEnd != FC.npos)
831 return Error::success();
834 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
835 StringRef FC = Input.getBuffer();
836 size_t BundleStart = ReadChars;
839 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
841 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
844 return Error::success();
847 Error WriteHeader(raw_ostream &OS,
848 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
849 return Error::success();
852 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
853 OS << BundleStartString << TargetTriple <<
"\n";
854 return Error::success();
857 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
858 OS << BundleEndString << TargetTriple <<
"\n";
859 return Error::success();
862 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
863 OS << Input.getBuffer();
864 return Error::success();
868 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
875 Error listBundleIDsCallback(MemoryBuffer &Input,
876 const BundleInfo &Info)
final {
881 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
882 if (
Error Err = ReadBundleEnd(Input))
884 return Error::success();
892static std::unique_ptr<FileHandler>
900 if (errorToBool(BinaryOrErr.takeError()) || !
isa<ObjectFile>(*BinaryOrErr))
901 return std::make_unique<BinaryFileHandler>(BundlerConfig);
905 return std::make_unique<ObjectFileHandler>(
914 std::string FilesType = BundlerConfig.
FilesType;
916 if (FilesType ==
"i")
917 return std::make_unique<TextFileHandler>(
"//");
918 if (FilesType ==
"ii")
919 return std::make_unique<TextFileHandler>(
"//");
920 if (FilesType ==
"cui")
921 return std::make_unique<TextFileHandler>(
"//");
922 if (FilesType ==
"hipi")
923 return std::make_unique<TextFileHandler>(
"//");
926 if (FilesType ==
"d")
927 return std::make_unique<TextFileHandler>(
"#");
928 if (FilesType ==
"ll")
929 return std::make_unique<TextFileHandler>(
";");
930 if (FilesType ==
"bc")
931 return std::make_unique<BinaryFileHandler>(BundlerConfig);
932 if (FilesType ==
"s")
933 return std::make_unique<TextFileHandler>(
"#");
934 if (FilesType ==
"o")
936 if (FilesType ==
"a")
938 if (FilesType ==
"gch")
939 return std::make_unique<BinaryFileHandler>(BundlerConfig);
940 if (FilesType ==
"ast")
941 return std::make_unique<BinaryFileHandler>(BundlerConfig);
943 return createStringError(errc::invalid_argument,
944 "'" + FilesType +
"': invalid file type specified");
949 if (llvm::compression::zstd::isAvailable()) {
954 }
else if (llvm::compression::zlib::isAvailable()) {
960 auto IgnoreEnvVarOpt =
961 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
962 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
964 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
965 if (VerboseEnvVarOpt.has_value())
966 Verbose = VerboseEnvVarOpt.value() ==
"1";
967 auto CompressEnvVarOpt =
968 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
969 if (CompressEnvVarOpt.has_value())
970 Compress = CompressEnvVarOpt.value() ==
"1";
971 auto CompressionLevelEnvVarOpt =
972 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
973 if (CompressionLevelEnvVarOpt.has_value()) {
974 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
976 if (!CompressionLevelStr.getAsInteger(10, Level))
980 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
981 << CompressionLevelStr.str() <<
". Ignoring it.\n";
983 auto CompressedBundleFormatVersionOpt =
984 llvm::sys::Process::GetEnv(
"COMPRESSED_BUNDLE_FORMAT_VERSION");
985 if (CompressedBundleFormatVersionOpt.has_value()) {
986 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();
988 if (!VersionStr.getAsInteger(10, Version)) {
989 if (Version >= 2 && Version <= 3)
993 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
995 <<
". Valid values are 2 or 3. Using default version "
999 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
1000 << VersionStr.str() <<
". Using default version "
1009 CompressedOffloadBundle::CompressedBundleHeader::tryParse(Blob);
1011 consumeError(HeaderOrErr.takeError());
1012 return std::nullopt;
1014 return HeaderOrErr->FileSize;
1022 size_t NextBundleStart = 0;
1023 std::unique_ptr<MemoryBuffer> Buffer;
1026 ErrorOr<std::unique_ptr<MemoryBuffer>> Contents =
1027 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1028 if (std::error_code EC = Contents.getError())
1029 return createFileError(InputFileName, EC);
1032 while ((NextBundleStart != StringRef::npos) &&
1033 (Offset < (**Contents).getBufferSize())) {
1034 Buffer = MemoryBuffer::getMemBuffer(
1035 (**Contents).getBuffer().drop_front(Offset),
"",
1038 size_t CurBundleEnd = StringRef::npos;
1039 if (identify_magic((*Buffer).getBuffer()) ==
1040 file_magic::offload_bundle_compressed) {
1042 if (std::optional<size_t> Size =
1044 CurBundleEnd = *Size;
1045 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1048 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1049 CurBundleEnd = NextBundleStart;
1052 NextBundleStart = StringRef::npos;
1054 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1055 MemoryBuffer::getMemBuffer(
1056 (*Buffer).getBuffer().take_front(CurBundleEnd),
1059 if (std::error_code EC = CodeOrErr.getError())
1060 return createFileError(InputFileName, EC);
1064 CompressedOffloadBundle::decompress(
1065 **CodeOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1066 if (!DecompressedBufferOrErr)
1067 return createStringError(
1068 inconvertibleErrorCode(),
1069 "Failed to decompress input: " +
1070 llvm::toString(DecompressedBufferOrErr.takeError()));
1072 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1077 if (!FileHandlerOrErr)
1078 return FileHandlerOrErr.takeError();
1079 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1081 Error E = FH->listBundleIDs(DecompressedInput);
1085 if (NextBundleStart != StringRef::npos)
1086 Offset += NextBundleStart;
1088 return Error::success();
1099 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1100 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1101 << CodeObjectInfo.
str()
1102 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1110 "CodeObjectCompatibility",
1111 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1112 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1118 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1120 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1125 if (!TargetProc || !CodeObjectProc ||
1126 CodeObjectProc.value() != TargetProc.value()) {
1127 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1128 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1129 << CodeObjectInfo.
str()
1130 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1136 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1137 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1138 dbgs() <<
"Incompatible: CodeObject has more features "
1139 "than target \t[CodeObject: "
1140 << CodeObjectInfo.
str()
1141 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1149 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1150 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1151 if (TargetFeature == TargetFeatureMap.end()) {
1153 "CodeObjectCompatibility",
1155 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1156 "not matching with Target feature's ANY value \t[CodeObject: "
1157 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1160 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1162 "CodeObjectCompatibility",
1163 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1164 "not matching with Target feature's non-ANY value "
1166 << CodeObjectInfo.
str()
1167 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1177 "CodeObjectCompatibility",
1178 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1179 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1190 llvm::raw_svector_ostream BufferStream(Buffer);
1196 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1197 MemoryBuffer::getFileOrSTDIN(I,
true);
1198 if (std::error_code EC = CodeOrErr.getError())
1199 return createFileError(I, EC);
1200 InputBuffers.emplace_back(std::move(*CodeOrErr));
1205 "Host input index undefined??");
1210 if (!FileHandlerOrErr)
1211 return FileHandlerOrErr.takeError();
1213 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1217 if (
Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1222 auto Input = InputBuffers.begin();
1224 if (
Error Err = FH->WriteBundleStart(BufferStream, Triple))
1226 if (
Error Err = FH->WriteBundle(BufferStream, **Input))
1228 if (
Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1233 raw_fd_ostream OutputFile(
BundlerConfig.OutputFileNames.front(), EC,
1236 return createFileError(
BundlerConfig.OutputFileNames.front(), EC);
1240 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1241 llvm::MemoryBuffer::getMemBufferCopy(
1242 llvm::StringRef(Buffer.data(), Buffer.size()));
1243 auto CompressionResult = CompressedOffloadBundle::compress(
1248 if (
auto Error = CompressionResult.takeError())
1251 auto CompressedMemBuffer = std::move(CompressionResult.get());
1252 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1253 CompressedMemBuffer->getBufferEnd());
1255 CompressedBuffer = std::move(Buffer);
1257 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1259 return FH->finalizeOutputFile();
1265 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1266 MemoryBuffer::getFileOrSTDIN(
BundlerConfig.InputFileNames.front(),
1268 if (std::error_code EC = CodeOrErr.getError())
1269 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1272 StringMap<StringRef> Worklist;
1276 return createStringError(errc::invalid_argument,
1277 "invalid bundle id from bundle config");
1278 Worklist[Triple] = *Output;
1286 bool FoundHostBundle =
false;
1288 size_t NextBundleStart = 0;
1289 std::unique_ptr<MemoryBuffer> Buffer;
1291 while ((NextBundleStart != StringRef::npos) &&
1292 (Offset < (**CodeOrErr).getBufferSize())) {
1294 Buffer = MemoryBuffer::getMemBuffer(
1295 (**CodeOrErr).getBuffer().drop_front(Offset),
"",
1298 size_t CurBundleEnd = StringRef::npos;
1299 if (identify_magic((*Buffer).getBuffer()) ==
1300 file_magic::offload_bundle_compressed) {
1302 if (std::optional<size_t> Size =
1304 CurBundleEnd = *Size;
1305 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1308 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1309 CurBundleEnd = NextBundleStart;
1311 }
else if (identify_magic((*Buffer).getBuffer()) ==
1312 file_magic::offload_bundle) {
1313 NextBundleStart = (*Buffer).getBuffer().find(
1315 CurBundleEnd = NextBundleStart;
1317 NextBundleStart = StringRef::npos;
1319 ErrorOr<std::unique_ptr<MemoryBuffer>> BlobOrErr =
1320 MemoryBuffer::getMemBuffer(
1321 (*Buffer).getBuffer().take_front(CurBundleEnd),
1324 if (std::error_code EC = BlobOrErr.getError())
1325 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1329 CompressedOffloadBundle::decompress(
1330 **BlobOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1331 if (!DecompressedBufferOrErr)
1332 return createStringError(
1333 inconvertibleErrorCode(),
1334 "Failed to decompress input: " +
1335 llvm::toString(DecompressedBufferOrErr.takeError()));
1337 MemoryBuffer &Input = **DecompressedBufferOrErr;
1342 if (!FileHandlerOrErr)
1343 return FileHandlerOrErr.takeError();
1345 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1349 if (
Error Err = FH->ReadHeader(Input.getBuffer()))
1353 while (!Worklist.empty()) {
1355 FH->ReadBundleStart(Input.getBuffer());
1356 if (!CurTripleOrErr)
1357 return CurTripleOrErr.takeError();
1360 if (!*CurTripleOrErr)
1363 StringRef CurTriple = **CurTripleOrErr;
1364 assert(!CurTriple.empty());
1366 return createStringError(errc::invalid_argument,
1367 "invalid bundle id read from the bundle");
1369 auto Output = Worklist.begin();
1370 for (
auto E = Worklist.end(); Output != E; Output++) {
1377 if (Output == Worklist.end())
1382 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1384 return createFileError((*Output).second, EC);
1385 if (
Error Err = FH->ReadBundle(OutputFile, Input))
1387 if (
Error Err = FH->ReadBundleEnd(Input))
1389 Worklist.erase(Output);
1393 if (OffloadInfo.hasHostKind())
1394 FoundHostBundle =
true;
1397 if (NextBundleStart != StringRef::npos)
1398 Offset += NextBundleStart;
1401 if (!
BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1402 std::string ErrMsg =
"Can't find bundles for";
1403 std::set<StringRef> Sorted;
1404 for (
auto &E : Worklist)
1405 Sorted.insert(E.first());
1407 unsigned Last = Sorted.size() - 1;
1408 for (
auto &E : Sorted) {
1409 if (I != 0 &&
Last > 1)
1412 if (I ==
Last && I != 0)
1417 return createStringError(inconvertibleErrorCode(), ErrMsg);
1423 for (
auto &E : Worklist) {
1425 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1427 return createFileError(E.second, EC);
1433 if (OffloadInfo.hasHostKind())
1434 OutputFile.write((**CodeOrErr).getBufferStart(),
1435 (**CodeOrErr).getBufferSize());
1437 return Error::success();
1442 if (!(FoundHostBundle ||
BundlerConfig.HostInputIndex == ~0u ||
1444 return createStringError(inconvertibleErrorCode(),
1445 "Can't find bundle for the host target");
1448 for (
auto &E : Worklist) {
1450 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1452 return createFileError(E.second, EC);
1455 return Error::success();
1459 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1473 if (!CompatibleTargets.empty()) {
1474 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1475 dbgs() <<
"CompatibleTargets list should be empty\n");
1481 CompatibleTargets.push_back(
Target);
1483 return !CompatibleTargets.empty();
1493 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1494 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1495 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1496 if (std::error_code EC = BufOrErr.getError())
1497 return createFileError(ArchiveName, EC);
1499 ArchiveBuffers.push_back(std::move(*BufOrErr));
1501 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1503 return LibOrErr.takeError();
1505 auto Archive = std::move(*LibOrErr);
1507 Error ArchiveErr = Error::success();
1508 auto ChildEnd = Archive->child_end();
1511 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1512 ArchiveIter != ChildEnd; ++ArchiveIter) {
1515 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1516 if (!ArchiveChildNameOrErr)
1517 return ArchiveChildNameOrErr.takeError();
1519 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1520 if (!CodeObjectBufferRefOrErr)
1521 return CodeObjectBufferRefOrErr.takeError();
1523 auto CodeObjectBuffer =
1524 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1528 if (!FileHandlerOrErr)
1529 return FileHandlerOrErr.takeError();
1531 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1532 assert(FileHandler);
1534 std::set<StringRef> BundleIds;
1535 auto CodeObjectFileError =
1536 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1537 if (CodeObjectFileError)
1538 return CodeObjectFileError;
1541 if (ConflictingArchs) {
1542 std::string ErrMsg =
1543 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1544 ", " + ConflictingArchs.value().second +
"] found in " +
1545 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1547 return createStringError(inconvertibleErrorCode(), ErrMsg);
1562 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1566 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1569 StringMap<StringRef> TargetOutputFileNameMap;
1573 TargetOutputFileNameMap[
Target] = *Output;
1585 return ArchiveError;
1589 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1590 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1591 if (std::error_code EC = BufOrErr.getError())
1592 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1594 ArchiveBuffers.push_back(std::move(*BufOrErr));
1596 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1598 return LibOrErr.takeError();
1600 auto Archive = std::move(*LibOrErr);
1602 Error ArchiveErr = Error::success();
1603 auto ChildEnd = Archive->child_end();
1606 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1607 ArchiveIter != ChildEnd; ++ArchiveIter) {
1610 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1611 if (!ArchiveChildNameOrErr)
1612 return ArchiveChildNameOrErr.takeError();
1614 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1616 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1617 if (!CodeObjectBufferRefOrErr)
1618 return CodeObjectBufferRefOrErr.takeError();
1620 auto TempCodeObjectBuffer =
1621 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1625 CompressedOffloadBundle::decompress(
1626 *TempCodeObjectBuffer,
1628 if (!DecompressedBufferOrErr)
1629 return createStringError(
1630 inconvertibleErrorCode(),
1631 "Failed to decompress code object: " +
1632 llvm::toString(DecompressedBufferOrErr.takeError()));
1634 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1638 if (!FileHandlerOrErr)
1639 return FileHandlerOrErr.takeError();
1641 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1642 assert(FileHandler &&
1643 "FileHandle creation failed for file in the archive!");
1645 if (
Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer.getBuffer()))
1649 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1650 if (!CurBundleIDOrErr)
1651 return CurBundleIDOrErr.takeError();
1653 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1655 if (!OptionalCurBundleID)
1657 StringRef CodeObject = *OptionalCurBundleID;
1661 while (!CodeObject.empty()) {
1664 return createStringError(errc::invalid_argument,
1665 "Invalid bundle id read from code object");
1670 std::string BundleData;
1671 raw_string_ostream DataStream(BundleData);
1672 if (
Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1675 for (
auto &CompatibleTarget : CompatibleTargets) {
1677 BundledObjectFileName.assign(BundledObjectFile);
1678 auto OutputBundleName =
1679 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1682 CodeObjectInfo.TargetID))
1686 llvm::replace(OutputBundleName,
':',
'_');
1688 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1689 DataStream.str(), OutputBundleName);
1690 ArchiveBuffers.push_back(std::move(MemBuf));
1691 llvm::MemoryBufferRef MemBufRef =
1692 MemoryBufferRef(*(ArchiveBuffers.back()));
1696 OutputArchivesMap[CompatibleTarget].push_back(
1697 NewArchiveMember(MemBufRef));
1701 if (
Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1705 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1706 if (!NextTripleOrErr)
1707 return NextTripleOrErr.takeError();
1709 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1713 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1718 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
1719 if (CurArchiveMembers != OutputArchivesMap.end()) {
1720 if (
Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1721 SymtabWritingMode::NormalSymtab,
1726 std::string ErrMsg =
1727 Twine(
"no compatible code object found for the target '" +
Target +
1728 "' in heterogeneous archive library: " + IFName)
1730 return createStringError(inconvertibleErrorCode(), ErrMsg);
1735 std::vector<llvm::NewArchiveMember> EmptyArchive;
1736 EmptyArchive.clear();
1737 if (
Error WriteErr = writeArchive(
1738 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1744 return Error::success();
1751 Str.split(Components,
'-', 5);
1752 return Components.size() == 5 || Components.size() == 6;
Result
Implement __builtin_bit_cast and related operations.
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 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::optional< size_t > getCompressedBundleSize(StringRef Blob)
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...
llvm::SmallVector< std::string, 4 > TargetNames
llvm::compression::Format CompressionFormat
llvm::SmallVector< std::string, 4 > OutputFileNames
uint16_t CompressedBundleVersion
llvm::SmallVector< std::string, 4 > InputFileNames
bool PrintExternalCommands
llvm::Error BundleFiles()
Bundle the files. Return true if an error was found.
llvm::Error UnbundleFiles()
llvm::Error UnbundleArchive()
UnbundleArchive takes an archive file (".a") as input containing bundled code object files,...
static llvm::Error ListBundleIDsInFile(llvm::StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig)
const OffloadBundlerConfig & BundlerConfig
Exposes information about the current target.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
std::optional< llvm::StringRef > parseTargetID(const llvm::Triple &T, llvm::StringRef OffloadArch, llvm::StringMap< bool > *FeatureMap)
Parse a target ID to get processor and feature map.
@ Create
'create' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...
std::optional< std::pair< llvm::StringRef, llvm::StringRef > > getConflictTargetIDCombination(const std::set< llvm::StringRef > &TargetIDs)
Get the conflicted pair of target IDs for a compilation or a bundled code object, assuming TargetIDs ...
OffloadArch StringToOffloadArch(llvm::StringRef S)
bool checkOffloadBundleID(const llvm::StringRef Str)
Check whether the bundle id is in the following format: <kind>-<triple>[-<target id>[:target features...
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.
int const char * function
Obtain the offload kind, real machine triple, and an optional TargetID out of the target information ...
bool operator==(const OffloadTargetInfo &Target) const
bool isOffloadKindCompatible(const llvm::StringRef TargetOffloadKind) const
bool isTripleValid() const
OffloadTargetInfo(const llvm::StringRef Target, const OffloadBundlerConfig &BC)
llvm::StringRef OffloadKind
bool isOffloadKindValid() const
const OffloadBundlerConfig & BundlerConfig