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;
87 this->
TargetID = TargetIdWithFeature;
93 this->
Triple = llvm::Triple(llvm::join(TripleSlice,
"-"));
106 const StringRef TargetOffloadKind)
const {
108 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
109 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
113 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
114 TargetOffloadKind ==
"openmp";
115 bool OpenMPCompatibleWithHIP =
117 TargetOffloadKind.starts_with_insensitive(
"hip");
118 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
124 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
133 std::string NormalizedTriple;
138 if (
Triple.getOS() == Triple::OSType::AMDHSA) {
139 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::THREE_IDENT);
140 NormalizedTriple.push_back(
'-');
142 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::FOUR_IDENT);
148 StringRef BundleFileName) {
149 if (
Device.contains(
"gfx"))
151 if (
Device.contains(
"sm_"))
153 return sys::path::extension(BundleFileName);
158 StringRef LibName = sys::path::stem(BundleFileName);
177 virtual ~FileHandler() {}
181 virtual Error ReadHeader(StringRef FC) = 0;
186 virtual Expected<std::optional<StringRef>>
187 ReadBundleStart(StringRef Input) = 0;
190 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
193 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
197 virtual Error WriteHeader(raw_ostream &OS,
198 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
202 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
206 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
209 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
212 virtual Error finalizeOutputFile() {
return Error::success(); }
215 virtual Error listBundleIDs(MemoryBuffer &Input) {
216 size_t NextBundleStart = 0;
217 StringRef BufferString = Input.getBuffer();
218 while (NextBundleStart != StringRef::npos) {
221 BufferString = BufferString.drop_front(NextBundleStart);
224 Error Err = ReadHeader(BufferString);
228 Err = forEachBundle(BufferString, [&](
const BundleInfo &Info) ->
Error {
229 llvm::outs() << Info.BundleID <<
'\n';
230 Error Err = listBundleIDsCallback(Input, Info);
233 return Error::success();
243 return Error::success();
247 virtual Error getBundleIDs(MemoryBuffer &Input,
248 std::set<StringRef> &BundleIds) {
250 if (
Error Err = ReadHeader(Input.getBuffer()))
252 return forEachBundle(Input.getBuffer(),
253 [&](
const BundleInfo &Info) ->
Error {
254 BundleIds.insert(Info.BundleID);
255 Error Err = listBundleIDsCallback(Input, Info);
258 return Error::success();
263 Error forEachBundle(StringRef Input,
266 Expected<std::optional<StringRef>> CurTripleOrErr =
267 ReadBundleStart(Input);
269 return CurTripleOrErr.takeError();
272 if (!*CurTripleOrErr)
275 StringRef CurTriple = **CurTripleOrErr;
276 assert(!CurTriple.empty());
278 BundleInfo Info{CurTriple};
282 return Error::success();
286 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
287 const BundleInfo &Info) {
288 return Error::success();
316static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
317 return llvm::support::endian::read64le(Buffer.data() + pos);
321static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
322 llvm::support::endian::write(OS, Val, llvm::endianness::little);
325class BinaryFileHandler final :
public FileHandler {
327 struct BinaryBundleInfo final :
public BundleInfo {
333 BinaryBundleInfo() {}
334 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
339 StringMap<BinaryBundleInfo> BundlesInfo;
342 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
343 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
346 std::string CurWriteBundleTarget;
349 const OffloadBundlerConfig &BundlerConfig;
353 BinaryFileHandler(
const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
355 ~BinaryFileHandler() final {}
357 Error ReadHeader(StringRef FC)
final {
360 CurBundleInfo = BundlesInfo.end();
361 NextBundleInfo = BundlesInfo.end();
365 if (ReadChars > FC.size())
366 return Error::success();
369 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
370 return Error::success();
373 if (ReadChars + 8 > FC.size())
374 return Error::success();
376 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
380 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
383 if (ReadChars + 8 > FC.size())
384 return Error::success();
386 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
390 if (ReadChars + 8 > FC.size())
391 return Error::success();
393 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
397 if (ReadChars + 8 > FC.size())
398 return Error::success();
400 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
404 if (ReadChars + TripleSize > FC.size())
405 return Error::success();
407 StringRef Triple(&FC.data()[ReadChars], TripleSize);
408 ReadChars += TripleSize;
411 if (!Offset || Offset + Size > FC.size())
412 return Error::success();
414 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
417 CurBundleInfo = BundlesInfo.end();
418 NextBundleInfo = BundlesInfo.begin();
419 return Error::success();
422 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
423 if (NextBundleInfo == BundlesInfo.end())
425 CurBundleInfo = NextBundleInfo++;
426 return CurBundleInfo->first();
429 Error ReadBundleEnd(MemoryBuffer &Input)
final {
430 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
431 return Error::success();
434 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
435 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
436 StringRef FC = Input.getBuffer();
437 OS.write(FC.data() + CurBundleInfo->second.Offset,
438 CurBundleInfo->second.Size);
439 return Error::success();
442 Error WriteHeader(raw_ostream &OS,
443 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
453 HeaderSize +=
T.size();
459 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
463 MemoryBuffer &MB = *Inputs[Idx++];
466 Write8byteIntegerToBuffer(OS, HeaderSize);
468 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
469 BundlesInfo[
T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
470 HeaderSize += MB.getBufferSize();
472 Write8byteIntegerToBuffer(OS,
T.size());
476 return Error::success();
479 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
480 CurWriteBundleTarget = TargetTriple.str();
481 return Error::success();
484 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
485 return Error::success();
488 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
489 auto BI = BundlesInfo[CurWriteBundleTarget];
492 size_t CurrentPos =
OS.tell();
493 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
494 for (
size_t I = 0; I < PaddingSize; ++I)
496 assert(
OS.tell() == BI.Offset);
498 OS.write(Input.getBufferStart(), Input.getBufferSize());
500 return Error::success();
506class TempFileHandlerRAII {
508 ~TempFileHandlerRAII() {
509 for (
const auto &
File : Files)
510 sys::fs::remove(
File);
514 Expected<StringRef>
Create(std::optional<ArrayRef<char>> Contents) {
515 SmallString<128u>
File;
516 if (std::error_code EC =
517 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
518 return createFileError(
File, EC);
519 Files.push_front(
File);
523 raw_fd_ostream
OS(
File, EC);
525 return createFileError(
File, EC);
526 OS.write(Contents->data(), Contents->size());
528 return Files.front().str();
532 std::forward_list<SmallString<128u>> Files;
539class ObjectFileHandler final :
public FileHandler {
542 std::unique_ptr<ObjectFile> Obj;
545 StringRef getInputFileContents()
const {
return Obj->getData(); }
549 static Expected<std::optional<StringRef>>
550 IsOffloadSection(SectionRef CurSection) {
551 Expected<StringRef> NameOrErr = CurSection.getName();
553 return NameOrErr.takeError();
556 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
564 unsigned NumberOfInputs = 0;
568 unsigned NumberOfProcessedInputs = 0;
571 section_iterator CurrentSection;
572 section_iterator NextSection;
575 const OffloadBundlerConfig &BundlerConfig;
579 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
580 const OffloadBundlerConfig &BC)
581 : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
582 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
584 ~ObjectFileHandler() final {}
586 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
588 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
589 while (NextSection != Obj->section_end()) {
590 CurrentSection = NextSection;
595 Expected<std::optional<StringRef>> TripleOrErr =
596 IsOffloadSection(*CurrentSection);
598 return TripleOrErr.takeError();
600 return **TripleOrErr;
605 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
607 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
608 Expected<StringRef> ContentOrErr = CurrentSection->getContents();
610 return ContentOrErr.takeError();
611 StringRef Content = *ContentOrErr;
614 std::string ModifiedContent;
615 if (Content.size() == 1u && Content.front() == 0) {
616 auto HostBundleOrErr = getHostBundle(
617 StringRef(Input.getBufferStart(), Input.getBufferSize()));
618 if (!HostBundleOrErr)
619 return HostBundleOrErr.takeError();
621 ModifiedContent = std::move(*HostBundleOrErr);
622 Content = ModifiedContent;
625 OS.write(Content.data(), Content.size());
626 return Error::success();
629 Error WriteHeader(raw_ostream &OS,
630 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
632 "Host input index not defined.");
635 NumberOfInputs = Inputs.size();
636 return Error::success();
639 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
640 ++NumberOfProcessedInputs;
641 return Error::success();
644 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
645 return Error::success();
648 Error finalizeOutputFile() final {
649 assert(NumberOfProcessedInputs <= NumberOfInputs &&
650 "Processing more inputs that actually exist!");
652 "Host input index not defined.");
655 if (NumberOfProcessedInputs != NumberOfInputs)
656 return Error::success();
664 "llvm-objcopy path not specified");
667 TempFileHandlerRAII TempFiles;
671 BumpPtrAllocator
Alloc;
672 StringSaver SS{
Alloc};
673 SmallVector<StringRef, 8u> ObjcopyArgs{
"llvm-objcopy"};
675 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
682 Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
684 return TempFileOrErr.takeError();
685 InputFile = *TempFileOrErr;
688 ObjcopyArgs.push_back(
691 ObjcopyArgs.push_back(
693 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
695 ObjcopyArgs.push_back(
"--");
696 ObjcopyArgs.push_back(
703 return Error::success();
706 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
707 return Error::success();
711 Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
715 errs() <<
"\"" << Objcopy <<
"\"";
716 for (StringRef Arg : drop_begin(Args, 1))
717 errs() <<
" \"" << Arg <<
"\"";
720 if (sys::ExecuteAndWait(Objcopy, Args))
721 return createStringError(inconvertibleErrorCode(),
722 "'llvm-objcopy' tool failed");
724 return Error::success();
727 Expected<std::string> getHostBundle(StringRef Input) {
728 TempFileHandlerRAII TempFiles;
730 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
731 if (!ModifiedObjPathOrErr)
732 return ModifiedObjPathOrErr.takeError();
733 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
735 BumpPtrAllocator
Alloc;
736 StringSaver SS{
Alloc};
737 SmallVector<StringRef, 16> ObjcopyArgs{
"llvm-objcopy"};
739 ObjcopyArgs.push_back(
"--regex");
740 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
741 ObjcopyArgs.push_back(
"--");
743 StringRef ObjcopyInputFileName;
750 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
751 auto InputFileOrErr = TempFiles.Create(ArrayRef<char>(Input));
753 return InputFileOrErr.takeError();
754 ObjcopyInputFileName = *InputFileOrErr;
758 ObjcopyArgs.push_back(ObjcopyInputFileName);
759 ObjcopyArgs.push_back(ModifiedObjPath);
762 return std::move(Err);
764 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
766 return createStringError(BufOrErr.getError(),
767 "Failed to read back the modified object file");
769 return BufOrErr->get()->getBuffer().str();
782class TextFileHandler final :
public FileHandler {
787 std::string BundleStartString;
790 std::string BundleEndString;
793 size_t ReadChars = 0u;
796 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
798 Expected<std::optional<StringRef>> ReadBundleStart(StringRef FC)
final {
801 ReadChars = FC.find(BundleStartString, ReadChars);
802 if (ReadChars == FC.npos)
806 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
809 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
810 if (TripleEnd == FC.npos)
816 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
819 Error ReadBundleEnd(MemoryBuffer &Input)
final {
820 StringRef FC = Input.getBuffer();
823 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
825 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
826 if (TripleEnd != FC.npos)
830 return Error::success();
833 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
834 StringRef FC = Input.getBuffer();
835 size_t BundleStart = ReadChars;
838 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
840 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
843 return Error::success();
846 Error WriteHeader(raw_ostream &OS,
847 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
848 return Error::success();
851 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
852 OS << BundleStartString << TargetTriple <<
"\n";
853 return Error::success();
856 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
857 OS << BundleEndString << TargetTriple <<
"\n";
858 return Error::success();
861 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
862 OS << Input.getBuffer();
863 return Error::success();
867 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
874 Error listBundleIDsCallback(MemoryBuffer &Input,
875 const BundleInfo &Info)
final {
880 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
881 if (
Error Err = ReadBundleEnd(Input))
883 return Error::success();
891static std::unique_ptr<FileHandler>
899 if (errorToBool(BinaryOrErr.takeError()) || !
isa<ObjectFile>(*BinaryOrErr))
900 return std::make_unique<BinaryFileHandler>(BundlerConfig);
904 return std::make_unique<ObjectFileHandler>(
913 std::string FilesType = BundlerConfig.
FilesType;
915 if (FilesType ==
"i" || FilesType ==
"ii" || FilesType ==
"cui" ||
917 return std::make_unique<TextFileHandler>(
"//");
920 if (FilesType ==
"d" || FilesType ==
"s")
921 return std::make_unique<TextFileHandler>(
"#");
922 if (FilesType ==
"ll")
923 return std::make_unique<TextFileHandler>(
";");
924 if (FilesType ==
"bc" || FilesType ==
"gch" || FilesType ==
"ast")
925 return std::make_unique<BinaryFileHandler>(BundlerConfig);
926 if (FilesType ==
"o" || FilesType ==
"a")
929 return createStringError(errc::invalid_argument,
930 "'" + FilesType +
"': invalid file type specified");
935 if (llvm::compression::zstd::isAvailable()) {
940 }
else if (llvm::compression::zlib::isAvailable()) {
946 auto IgnoreEnvVarOpt =
947 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
948 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
950 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
951 if (VerboseEnvVarOpt.has_value())
952 Verbose = VerboseEnvVarOpt.value() ==
"1";
953 auto CompressEnvVarOpt =
954 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
955 if (CompressEnvVarOpt.has_value())
956 Compress = CompressEnvVarOpt.value() ==
"1";
957 auto CompressionLevelEnvVarOpt =
958 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
959 if (CompressionLevelEnvVarOpt.has_value()) {
960 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
962 if (!CompressionLevelStr.getAsInteger(10, Level))
966 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
967 << CompressionLevelStr.str() <<
". Ignoring it.\n";
969 auto CompressedBundleFormatVersionOpt =
970 llvm::sys::Process::GetEnv(
"COMPRESSED_BUNDLE_FORMAT_VERSION");
971 if (CompressedBundleFormatVersionOpt.has_value()) {
972 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();
974 if (!VersionStr.getAsInteger(10, Version)) {
975 if (Version >= 2 && Version <= 3)
979 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
981 <<
". Valid values are 2 or 3. Using default version "
985 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
986 << VersionStr.str() <<
". Using default version "
995 CompressedOffloadBundle::CompressedBundleHeader::tryParse(Blob);
997 consumeError(HeaderOrErr.takeError());
1000 return HeaderOrErr->FileSize;
1008 size_t NextBundleStart = 0;
1009 std::unique_ptr<MemoryBuffer> Buffer;
1012 ErrorOr<std::unique_ptr<MemoryBuffer>> Contents =
1013 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1014 if (std::error_code EC = Contents.getError())
1015 return createFileError(InputFileName, EC);
1018 while ((NextBundleStart != StringRef::npos) &&
1019 (Offset < (**Contents).getBufferSize())) {
1020 Buffer = MemoryBuffer::getMemBuffer(
1021 (**Contents).getBuffer().drop_front(Offset),
"",
1024 size_t CurBundleEnd = StringRef::npos;
1025 if (identify_magic((*Buffer).getBuffer()) ==
1026 file_magic::offload_bundle_compressed) {
1028 if (std::optional<size_t> Size =
1030 CurBundleEnd = *Size;
1031 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1034 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1035 CurBundleEnd = NextBundleStart;
1038 NextBundleStart = StringRef::npos;
1040 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1041 MemoryBuffer::getMemBuffer(
1042 (*Buffer).getBuffer().take_front(CurBundleEnd),
1045 if (std::error_code EC = CodeOrErr.getError())
1046 return createFileError(InputFileName, EC);
1050 CompressedOffloadBundle::decompress(
1051 **CodeOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1052 if (!DecompressedBufferOrErr)
1053 return createStringError(
1054 inconvertibleErrorCode(),
1055 "Failed to decompress input: " +
1056 llvm::toString(DecompressedBufferOrErr.takeError()));
1058 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1063 if (!FileHandlerOrErr)
1064 return FileHandlerOrErr.takeError();
1065 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1067 Error E = FH->listBundleIDs(DecompressedInput);
1071 if (NextBundleStart != StringRef::npos)
1072 Offset += NextBundleStart;
1074 return Error::success();
1085 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1086 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1087 << CodeObjectInfo.
str()
1088 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1096 "CodeObjectCompatibility",
1097 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1098 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1104 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1106 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1111 if (!TargetProc || !CodeObjectProc ||
1112 CodeObjectProc.value() != TargetProc.value()) {
1113 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1114 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1115 << CodeObjectInfo.
str()
1116 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1122 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1123 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1124 dbgs() <<
"Incompatible: CodeObject has more features "
1125 "than target \t[CodeObject: "
1126 << CodeObjectInfo.
str()
1127 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1135 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1136 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1137 if (TargetFeature == TargetFeatureMap.end()) {
1139 "CodeObjectCompatibility",
1141 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1142 "not matching with Target feature's ANY value \t[CodeObject: "
1143 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1146 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1148 "CodeObjectCompatibility",
1149 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1150 "not matching with Target feature's non-ANY value "
1152 << CodeObjectInfo.
str()
1153 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1163 "CodeObjectCompatibility",
1164 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1165 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1176 llvm::raw_svector_ostream BufferStream(Buffer);
1182 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1183 MemoryBuffer::getFileOrSTDIN(I,
true);
1184 if (std::error_code EC = CodeOrErr.getError())
1185 return createFileError(I, EC);
1186 InputBuffers.emplace_back(std::move(*CodeOrErr));
1191 "Host input index undefined??");
1196 if (!FileHandlerOrErr)
1197 return FileHandlerOrErr.takeError();
1199 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1203 if (
Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1208 auto Input = InputBuffers.begin();
1210 if (
Error Err = FH->WriteBundleStart(BufferStream, Triple))
1212 if (
Error Err = FH->WriteBundle(BufferStream, **Input))
1214 if (
Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1219 raw_fd_ostream OutputFile(
BundlerConfig.OutputFileNames.front(), EC,
1222 return createFileError(
BundlerConfig.OutputFileNames.front(), EC);
1226 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1227 llvm::MemoryBuffer::getMemBufferCopy(
1228 llvm::StringRef(Buffer.data(), Buffer.size()));
1229 auto CompressionResult = CompressedOffloadBundle::compress(
1234 if (
auto Error = CompressionResult.takeError())
1237 auto CompressedMemBuffer = std::move(CompressionResult.get());
1238 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1239 CompressedMemBuffer->getBufferEnd());
1241 CompressedBuffer = std::move(Buffer);
1243 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1245 return FH->finalizeOutputFile();
1251 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1252 MemoryBuffer::getFileOrSTDIN(
BundlerConfig.InputFileNames.front(),
1254 if (std::error_code EC = CodeOrErr.getError())
1255 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1258 StringMap<StringRef> Worklist;
1262 return createStringError(errc::invalid_argument,
1263 "invalid bundle id from bundle config");
1264 Worklist[Triple] = *Output;
1272 bool FoundHostBundle =
false;
1274 size_t NextBundleStart = 0;
1275 std::unique_ptr<MemoryBuffer> Buffer;
1277 while ((NextBundleStart != StringRef::npos) &&
1278 (Offset < (**CodeOrErr).getBufferSize())) {
1280 Buffer = MemoryBuffer::getMemBuffer(
1281 (**CodeOrErr).getBuffer().drop_front(Offset),
"",
1284 size_t CurBundleEnd = StringRef::npos;
1285 if (identify_magic((*Buffer).getBuffer()) ==
1286 file_magic::offload_bundle_compressed) {
1288 if (std::optional<size_t> Size =
1290 CurBundleEnd = *Size;
1291 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1294 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1295 CurBundleEnd = NextBundleStart;
1297 }
else if (identify_magic((*Buffer).getBuffer()) ==
1298 file_magic::offload_bundle) {
1299 NextBundleStart = (*Buffer).getBuffer().find(
1301 CurBundleEnd = NextBundleStart;
1303 NextBundleStart = StringRef::npos;
1305 ErrorOr<std::unique_ptr<MemoryBuffer>> BlobOrErr =
1306 MemoryBuffer::getMemBuffer(
1307 (*Buffer).getBuffer().take_front(CurBundleEnd),
1310 if (std::error_code EC = BlobOrErr.getError())
1311 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1315 CompressedOffloadBundle::decompress(
1316 **BlobOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1317 if (!DecompressedBufferOrErr)
1318 return createStringError(
1319 inconvertibleErrorCode(),
1320 "Failed to decompress input: " +
1321 llvm::toString(DecompressedBufferOrErr.takeError()));
1323 MemoryBuffer &Input = **DecompressedBufferOrErr;
1328 if (!FileHandlerOrErr)
1329 return FileHandlerOrErr.takeError();
1331 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1335 if (
Error Err = FH->ReadHeader(Input.getBuffer()))
1339 while (!Worklist.empty()) {
1341 FH->ReadBundleStart(Input.getBuffer());
1342 if (!CurTripleOrErr)
1343 return CurTripleOrErr.takeError();
1346 if (!*CurTripleOrErr)
1349 StringRef CurTriple = **CurTripleOrErr;
1350 assert(!CurTriple.empty());
1352 return createStringError(errc::invalid_argument,
1353 "invalid bundle id read from the bundle");
1355 auto Output = Worklist.begin();
1356 for (
auto E = Worklist.end(); Output != E; Output++) {
1363 if (Output == Worklist.end())
1368 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1370 return createFileError((*Output).second, EC);
1371 if (
Error Err = FH->ReadBundle(OutputFile, Input))
1373 if (
Error Err = FH->ReadBundleEnd(Input))
1375 Worklist.erase(Output);
1379 if (OffloadInfo.hasHostKind())
1380 FoundHostBundle =
true;
1383 if (NextBundleStart != StringRef::npos)
1384 Offset += NextBundleStart;
1387 if (!
BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1388 std::string ErrMsg =
"Can't find bundles for";
1389 std::set<StringRef> Sorted;
1390 for (
auto &E : Worklist)
1391 Sorted.insert(E.first());
1393 unsigned Last = Sorted.size() - 1;
1394 for (
auto &E : Sorted) {
1395 if (I != 0 &&
Last > 1)
1398 if (I ==
Last && I != 0)
1403 return createStringError(inconvertibleErrorCode(), ErrMsg);
1409 for (
auto &E : Worklist) {
1411 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1413 return createFileError(E.second, EC);
1419 if (OffloadInfo.hasHostKind())
1420 OutputFile.write((**CodeOrErr).getBufferStart(),
1421 (**CodeOrErr).getBufferSize());
1423 return Error::success();
1428 if (!(FoundHostBundle ||
BundlerConfig.HostInputIndex == ~0u ||
1430 return createStringError(inconvertibleErrorCode(),
1431 "Can't find bundle for the host target");
1434 for (
auto &E : Worklist) {
1436 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1438 return createFileError(E.second, EC);
1441 return Error::success();
1445 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1459 if (!CompatibleTargets.empty()) {
1460 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1461 dbgs() <<
"CompatibleTargets list should be empty\n");
1467 CompatibleTargets.push_back(
Target);
1469 return !CompatibleTargets.empty();
1479 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1480 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1481 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1482 if (std::error_code EC = BufOrErr.getError())
1483 return createFileError(ArchiveName, EC);
1485 ArchiveBuffers.push_back(std::move(*BufOrErr));
1487 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1489 return LibOrErr.takeError();
1491 auto Archive = std::move(*LibOrErr);
1493 Error ArchiveErr = Error::success();
1494 auto ChildEnd = Archive->child_end();
1497 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1498 ArchiveIter != ChildEnd; ++ArchiveIter) {
1501 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1502 if (!ArchiveChildNameOrErr)
1503 return ArchiveChildNameOrErr.takeError();
1505 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1506 if (!CodeObjectBufferRefOrErr)
1507 return CodeObjectBufferRefOrErr.takeError();
1509 auto CodeObjectBuffer =
1510 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1514 if (!FileHandlerOrErr)
1515 return FileHandlerOrErr.takeError();
1517 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1518 assert(FileHandler);
1520 std::set<StringRef> BundleIds;
1521 auto CodeObjectFileError =
1522 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1523 if (CodeObjectFileError)
1524 return CodeObjectFileError;
1527 if (ConflictingArchs) {
1528 std::string ErrMsg =
1529 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1530 ", " + ConflictingArchs.value().second +
"] found in " +
1531 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1533 return createStringError(inconvertibleErrorCode(), ErrMsg);
1548 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1552 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1555 StringMap<StringRef> TargetOutputFileNameMap;
1559 TargetOutputFileNameMap[
Target] = *Output;
1571 return ArchiveError;
1575 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1576 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1577 if (std::error_code EC = BufOrErr.getError())
1578 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1580 ArchiveBuffers.push_back(std::move(*BufOrErr));
1582 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1584 return LibOrErr.takeError();
1586 auto Archive = std::move(*LibOrErr);
1588 Error ArchiveErr = Error::success();
1589 auto ChildEnd = Archive->child_end();
1592 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1593 ArchiveIter != ChildEnd; ++ArchiveIter) {
1596 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1597 if (!ArchiveChildNameOrErr)
1598 return ArchiveChildNameOrErr.takeError();
1600 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1602 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1603 if (!CodeObjectBufferRefOrErr)
1604 return CodeObjectBufferRefOrErr.takeError();
1606 auto TempCodeObjectBuffer =
1607 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1611 CompressedOffloadBundle::decompress(
1612 *TempCodeObjectBuffer,
1614 if (!DecompressedBufferOrErr)
1615 return createStringError(
1616 inconvertibleErrorCode(),
1617 "Failed to decompress code object: " +
1618 llvm::toString(DecompressedBufferOrErr.takeError()));
1620 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1624 if (!FileHandlerOrErr)
1625 return FileHandlerOrErr.takeError();
1627 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1628 assert(FileHandler &&
1629 "FileHandle creation failed for file in the archive!");
1631 if (
Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer.getBuffer()))
1635 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1636 if (!CurBundleIDOrErr)
1637 return CurBundleIDOrErr.takeError();
1639 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1641 if (!OptionalCurBundleID)
1643 StringRef CodeObject = *OptionalCurBundleID;
1647 while (!CodeObject.empty()) {
1650 return createStringError(errc::invalid_argument,
1651 "Invalid bundle id read from code object");
1656 std::string BundleData;
1657 raw_string_ostream DataStream(BundleData);
1658 if (
Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1661 for (
auto &CompatibleTarget : CompatibleTargets) {
1663 BundledObjectFileName.assign(BundledObjectFile);
1664 auto OutputBundleName =
1665 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1668 CodeObjectInfo.TargetID))
1672 llvm::replace(OutputBundleName,
':',
'_');
1674 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1675 DataStream.str(), OutputBundleName);
1676 ArchiveBuffers.push_back(std::move(MemBuf));
1677 llvm::MemoryBufferRef MemBufRef =
1678 MemoryBufferRef(*(ArchiveBuffers.back()));
1682 OutputArchivesMap[CompatibleTarget].push_back(
1683 NewArchiveMember(MemBufRef));
1687 if (
Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1691 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1692 if (!NextTripleOrErr)
1693 return NextTripleOrErr.takeError();
1695 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1699 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1704 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
1705 if (CurArchiveMembers != OutputArchivesMap.end()) {
1706 if (
Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1707 SymtabWritingMode::NormalSymtab,
1712 std::string ErrMsg =
1713 Twine(
"no compatible code object found for the target '" +
Target +
1714 "' in heterogeneous archive library: " + IFName)
1716 return createStringError(inconvertibleErrorCode(), ErrMsg);
1721 std::vector<llvm::NewArchiveMember> EmptyArchive;
1722 EmptyArchive.clear();
1723 if (
Error WriteErr = writeArchive(
1724 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1730 return Error::success();
1737 Str.split(Components,
'-', 5);
1738 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)
Top level wrappers for InstallAPI frontend operations.
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 ...
const FunctionProtoType * T
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