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 "
1010 size_t NextBundleStart = 0;
1011 std::unique_ptr<MemoryBuffer> Buffer;
1014 ErrorOr<std::unique_ptr<MemoryBuffer>> Contents =
1015 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1016 if (std::error_code EC = Contents.getError())
1017 return createFileError(InputFileName, EC);
1020 while ((NextBundleStart != StringRef::npos) &&
1021 (Offset < (**Contents).getBufferSize())) {
1022 Buffer = MemoryBuffer::getMemBuffer(
1023 (**Contents).getBuffer().drop_front(Offset),
"",
1026 if (identify_magic((*Buffer).getBuffer()) ==
1027 file_magic::offload_bundle_compressed) {
1028 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1030 NextBundleStart = StringRef::npos;
1032 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1033 MemoryBuffer::getMemBuffer(
1034 (*Buffer).getBuffer().take_front(NextBundleStart),
1037 if (std::error_code EC = CodeOrErr.getError())
1038 return createFileError(InputFileName, EC);
1042 CompressedOffloadBundle::decompress(
1043 **CodeOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1044 if (!DecompressedBufferOrErr)
1045 return createStringError(
1046 inconvertibleErrorCode(),
1047 "Failed to decompress input: " +
1048 llvm::toString(DecompressedBufferOrErr.takeError()));
1050 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1055 if (!FileHandlerOrErr)
1056 return FileHandlerOrErr.takeError();
1057 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1059 Error E = FH->listBundleIDs(DecompressedInput);
1063 if (NextBundleStart != StringRef::npos)
1064 Offset += NextBundleStart;
1066 return Error::success();
1077 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1078 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1079 << CodeObjectInfo.
str()
1080 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1088 "CodeObjectCompatibility",
1089 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1090 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1096 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1098 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1103 if (!TargetProc || !CodeObjectProc ||
1104 CodeObjectProc.value() != TargetProc.value()) {
1105 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1106 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1107 << CodeObjectInfo.
str()
1108 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1114 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1115 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1116 dbgs() <<
"Incompatible: CodeObject has more features "
1117 "than target \t[CodeObject: "
1118 << CodeObjectInfo.
str()
1119 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1127 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1128 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1129 if (TargetFeature == TargetFeatureMap.end()) {
1131 "CodeObjectCompatibility",
1133 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1134 "not matching with Target feature's ANY value \t[CodeObject: "
1135 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1138 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1140 "CodeObjectCompatibility",
1141 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1142 "not matching with Target feature's non-ANY value "
1144 << CodeObjectInfo.
str()
1145 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1155 "CodeObjectCompatibility",
1156 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1157 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1168 llvm::raw_svector_ostream BufferStream(Buffer);
1174 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1175 MemoryBuffer::getFileOrSTDIN(I,
true);
1176 if (std::error_code EC = CodeOrErr.getError())
1177 return createFileError(I, EC);
1178 InputBuffers.emplace_back(std::move(*CodeOrErr));
1183 "Host input index undefined??");
1188 if (!FileHandlerOrErr)
1189 return FileHandlerOrErr.takeError();
1191 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1195 if (
Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1200 auto Input = InputBuffers.begin();
1202 if (
Error Err = FH->WriteBundleStart(BufferStream, Triple))
1204 if (
Error Err = FH->WriteBundle(BufferStream, **Input))
1206 if (
Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1211 raw_fd_ostream OutputFile(
BundlerConfig.OutputFileNames.front(), EC,
1214 return createFileError(
BundlerConfig.OutputFileNames.front(), EC);
1218 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1219 llvm::MemoryBuffer::getMemBufferCopy(
1220 llvm::StringRef(Buffer.data(), Buffer.size()));
1221 auto CompressionResult = CompressedOffloadBundle::compress(
1226 if (
auto Error = CompressionResult.takeError())
1229 auto CompressedMemBuffer = std::move(CompressionResult.get());
1230 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1231 CompressedMemBuffer->getBufferEnd());
1233 CompressedBuffer = std::move(Buffer);
1235 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1237 return FH->finalizeOutputFile();
1243 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1244 MemoryBuffer::getFileOrSTDIN(
BundlerConfig.InputFileNames.front(),
1246 if (std::error_code EC = CodeOrErr.getError())
1247 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1250 StringMap<StringRef> Worklist;
1254 return createStringError(errc::invalid_argument,
1255 "invalid bundle id from bundle config");
1256 Worklist[Triple] = *Output;
1264 bool FoundHostBundle =
false;
1266 size_t NextBundleStart = 0;
1267 std::unique_ptr<MemoryBuffer> Buffer;
1269 while ((NextBundleStart != StringRef::npos) &&
1270 (Offset < (**CodeOrErr).getBufferSize())) {
1272 Buffer = MemoryBuffer::getMemBuffer(
1273 (**CodeOrErr).getBuffer().drop_front(Offset),
"",
1276 if (identify_magic((*Buffer).getBuffer()) ==
1277 file_magic::offload_bundle_compressed) {
1278 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1279 }
else if (identify_magic((*Buffer).getBuffer()) ==
1280 file_magic::offload_bundle) {
1281 NextBundleStart = (*Buffer).getBuffer().find(
1284 NextBundleStart = StringRef::npos;
1286 ErrorOr<std::unique_ptr<MemoryBuffer>> BlobOrErr =
1287 MemoryBuffer::getMemBuffer(
1288 (*Buffer).getBuffer().take_front(NextBundleStart),
1291 if (std::error_code EC = BlobOrErr.getError())
1292 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1296 CompressedOffloadBundle::decompress(
1297 **BlobOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1298 if (!DecompressedBufferOrErr)
1299 return createStringError(
1300 inconvertibleErrorCode(),
1301 "Failed to decompress input: " +
1302 llvm::toString(DecompressedBufferOrErr.takeError()));
1304 MemoryBuffer &Input = **DecompressedBufferOrErr;
1309 if (!FileHandlerOrErr)
1310 return FileHandlerOrErr.takeError();
1312 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1316 if (
Error Err = FH->ReadHeader(Input.getBuffer()))
1320 while (!Worklist.empty()) {
1322 FH->ReadBundleStart(Input.getBuffer());
1323 if (!CurTripleOrErr)
1324 return CurTripleOrErr.takeError();
1327 if (!*CurTripleOrErr)
1330 StringRef CurTriple = **CurTripleOrErr;
1331 assert(!CurTriple.empty());
1333 return createStringError(errc::invalid_argument,
1334 "invalid bundle id read from the bundle");
1336 auto Output = Worklist.begin();
1337 for (
auto E = Worklist.end(); Output != E; Output++) {
1344 if (Output == Worklist.end())
1349 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1351 return createFileError((*Output).second, EC);
1352 if (
Error Err = FH->ReadBundle(OutputFile, Input))
1354 if (
Error Err = FH->ReadBundleEnd(Input))
1356 Worklist.erase(Output);
1360 if (OffloadInfo.hasHostKind())
1361 FoundHostBundle =
true;
1364 if (NextBundleStart != StringRef::npos)
1365 Offset += NextBundleStart;
1368 if (!
BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1369 std::string ErrMsg =
"Can't find bundles for";
1370 std::set<StringRef> Sorted;
1371 for (
auto &E : Worklist)
1372 Sorted.insert(E.first());
1374 unsigned Last = Sorted.size() - 1;
1375 for (
auto &E : Sorted) {
1376 if (I != 0 &&
Last > 1)
1379 if (I ==
Last && I != 0)
1384 return createStringError(inconvertibleErrorCode(), ErrMsg);
1390 for (
auto &E : Worklist) {
1392 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1394 return createFileError(E.second, EC);
1400 if (OffloadInfo.hasHostKind())
1401 OutputFile.write((**CodeOrErr).getBufferStart(),
1402 (**CodeOrErr).getBufferSize());
1404 return Error::success();
1409 if (!(FoundHostBundle ||
BundlerConfig.HostInputIndex == ~0u ||
1411 return createStringError(inconvertibleErrorCode(),
1412 "Can't find bundle for the host target");
1415 for (
auto &E : Worklist) {
1417 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1419 return createFileError(E.second, EC);
1422 return Error::success();
1426 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1440 if (!CompatibleTargets.empty()) {
1441 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1442 dbgs() <<
"CompatibleTargets list should be empty\n");
1448 CompatibleTargets.push_back(
Target);
1450 return !CompatibleTargets.empty();
1460 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1461 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1462 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1463 if (std::error_code EC = BufOrErr.getError())
1464 return createFileError(ArchiveName, EC);
1466 ArchiveBuffers.push_back(std::move(*BufOrErr));
1468 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1470 return LibOrErr.takeError();
1472 auto Archive = std::move(*LibOrErr);
1474 Error ArchiveErr = Error::success();
1475 auto ChildEnd = Archive->child_end();
1478 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1479 ArchiveIter != ChildEnd; ++ArchiveIter) {
1482 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1483 if (!ArchiveChildNameOrErr)
1484 return ArchiveChildNameOrErr.takeError();
1486 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1487 if (!CodeObjectBufferRefOrErr)
1488 return CodeObjectBufferRefOrErr.takeError();
1490 auto CodeObjectBuffer =
1491 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1495 if (!FileHandlerOrErr)
1496 return FileHandlerOrErr.takeError();
1498 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1499 assert(FileHandler);
1501 std::set<StringRef> BundleIds;
1502 auto CodeObjectFileError =
1503 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1504 if (CodeObjectFileError)
1505 return CodeObjectFileError;
1508 if (ConflictingArchs) {
1509 std::string ErrMsg =
1510 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1511 ", " + ConflictingArchs.value().second +
"] found in " +
1512 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1514 return createStringError(inconvertibleErrorCode(), ErrMsg);
1529 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1533 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1536 StringMap<StringRef> TargetOutputFileNameMap;
1540 TargetOutputFileNameMap[
Target] = *Output;
1552 return ArchiveError;
1556 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1557 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1558 if (std::error_code EC = BufOrErr.getError())
1559 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1561 ArchiveBuffers.push_back(std::move(*BufOrErr));
1563 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1565 return LibOrErr.takeError();
1567 auto Archive = std::move(*LibOrErr);
1569 Error ArchiveErr = Error::success();
1570 auto ChildEnd = Archive->child_end();
1573 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1574 ArchiveIter != ChildEnd; ++ArchiveIter) {
1577 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1578 if (!ArchiveChildNameOrErr)
1579 return ArchiveChildNameOrErr.takeError();
1581 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1583 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1584 if (!CodeObjectBufferRefOrErr)
1585 return CodeObjectBufferRefOrErr.takeError();
1587 auto TempCodeObjectBuffer =
1588 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1592 CompressedOffloadBundle::decompress(
1593 *TempCodeObjectBuffer,
1595 if (!DecompressedBufferOrErr)
1596 return createStringError(
1597 inconvertibleErrorCode(),
1598 "Failed to decompress code object: " +
1599 llvm::toString(DecompressedBufferOrErr.takeError()));
1601 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1605 if (!FileHandlerOrErr)
1606 return FileHandlerOrErr.takeError();
1608 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1609 assert(FileHandler &&
1610 "FileHandle creation failed for file in the archive!");
1612 if (
Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer.getBuffer()))
1616 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1617 if (!CurBundleIDOrErr)
1618 return CurBundleIDOrErr.takeError();
1620 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1622 if (!OptionalCurBundleID)
1624 StringRef CodeObject = *OptionalCurBundleID;
1628 while (!CodeObject.empty()) {
1631 return createStringError(errc::invalid_argument,
1632 "Invalid bundle id read from code object");
1637 std::string BundleData;
1638 raw_string_ostream DataStream(BundleData);
1639 if (
Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1642 for (
auto &CompatibleTarget : CompatibleTargets) {
1644 BundledObjectFileName.assign(BundledObjectFile);
1645 auto OutputBundleName =
1646 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1649 CodeObjectInfo.TargetID))
1653 llvm::replace(OutputBundleName,
':',
'_');
1655 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1656 DataStream.str(), OutputBundleName);
1657 ArchiveBuffers.push_back(std::move(MemBuf));
1658 llvm::MemoryBufferRef MemBufRef =
1659 MemoryBufferRef(*(ArchiveBuffers.back()));
1663 OutputArchivesMap[CompatibleTarget].push_back(
1664 NewArchiveMember(MemBufRef));
1668 if (
Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1672 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1673 if (!NextTripleOrErr)
1674 return NextTripleOrErr.takeError();
1676 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1680 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1685 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
1686 if (CurArchiveMembers != OutputArchivesMap.end()) {
1687 if (
Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1688 SymtabWritingMode::NormalSymtab,
1693 std::string ErrMsg =
1694 Twine(
"no compatible code object found for the target '" +
Target +
1695 "' in heterogeneous archive library: " + IFName)
1697 return createStringError(inconvertibleErrorCode(), ErrMsg);
1702 std::vector<llvm::NewArchiveMember> EmptyArchive;
1703 EmptyArchive.clear();
1704 if (
Error WriteErr = writeArchive(
1705 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1711 return Error::success();
1718 Str.split(Components,
'-', 5);
1719 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 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