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 llvm::Triple
T = llvm::Triple(llvm::join(TripleSlice,
"-"));
94 this->
Triple = llvm::Triple(
T.getArchName(),
T.getVendorName(),
T.getOSName(),
95 T.getEnvironmentName());
108 const StringRef TargetOffloadKind)
const {
110 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
111 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
115 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
116 TargetOffloadKind ==
"openmp";
117 bool OpenMPCompatibleWithHIP =
119 TargetOffloadKind.starts_with_insensitive(
"hip");
120 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
126 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
135 std::string NormalizedTriple;
140 if (
Triple.getOS() == Triple::OSType::AMDHSA) {
141 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::THREE_IDENT);
142 NormalizedTriple.push_back(
'-');
144 NormalizedTriple =
Triple.normalize(Triple::CanonicalForm::FOUR_IDENT);
150 StringRef BundleFileName) {
151 if (
Device.contains(
"gfx"))
153 if (
Device.contains(
"sm_"))
155 return sys::path::extension(BundleFileName);
160 StringRef LibName = sys::path::stem(BundleFileName);
179 virtual ~FileHandler() {}
183 virtual Error ReadHeader(StringRef FC) = 0;
188 virtual Expected<std::optional<StringRef>>
189 ReadBundleStart(StringRef Input) = 0;
192 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
195 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
199 virtual Error WriteHeader(raw_ostream &OS,
200 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
204 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
208 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
211 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
214 virtual Error finalizeOutputFile() {
return Error::success(); }
217 virtual Error listBundleIDs(MemoryBuffer &Input) {
218 size_t NextBundleStart = 0;
219 StringRef BufferString = Input.getBuffer();
220 while (NextBundleStart != StringRef::npos) {
223 BufferString = BufferString.drop_front(NextBundleStart);
226 Error Err = ReadHeader(BufferString);
230 Err = forEachBundle(BufferString, [&](
const BundleInfo &Info) ->
Error {
231 llvm::outs() << Info.BundleID <<
'\n';
232 Error Err = listBundleIDsCallback(Input, Info);
235 return Error::success();
245 return Error::success();
249 virtual Error getBundleIDs(MemoryBuffer &Input,
250 std::set<StringRef> &BundleIds) {
252 if (
Error Err = ReadHeader(Input.getBuffer()))
254 return forEachBundle(Input.getBuffer(),
255 [&](
const BundleInfo &Info) ->
Error {
256 BundleIds.insert(Info.BundleID);
257 Error Err = listBundleIDsCallback(Input, Info);
260 return Error::success();
265 Error forEachBundle(StringRef Input,
268 Expected<std::optional<StringRef>> CurTripleOrErr =
269 ReadBundleStart(Input);
271 return CurTripleOrErr.takeError();
274 if (!*CurTripleOrErr)
277 StringRef CurTriple = **CurTripleOrErr;
278 assert(!CurTriple.empty());
280 BundleInfo Info{CurTriple};
284 return Error::success();
288 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
289 const BundleInfo &Info) {
290 return Error::success();
318static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
319 return llvm::support::endian::read64le(Buffer.data() + pos);
323static void Write8byteIntegerToBuffer(raw_ostream &OS, uint64_t Val) {
324 llvm::support::endian::write(OS, Val, llvm::endianness::little);
327class BinaryFileHandler final :
public FileHandler {
329 struct BinaryBundleInfo final :
public BundleInfo {
335 BinaryBundleInfo() {}
336 BinaryBundleInfo(uint64_t Size, uint64_t Offset)
341 StringMap<BinaryBundleInfo> BundlesInfo;
344 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
345 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
348 std::string CurWriteBundleTarget;
351 const OffloadBundlerConfig &BundlerConfig;
355 BinaryFileHandler(
const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
357 ~BinaryFileHandler() final {}
359 Error ReadHeader(StringRef FC)
final {
362 CurBundleInfo = BundlesInfo.end();
363 NextBundleInfo = BundlesInfo.end();
367 if (ReadChars > FC.size())
368 return Error::success();
371 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
372 return Error::success();
375 if (ReadChars + 8 > FC.size())
376 return Error::success();
378 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
382 for (uint64_t i = 0; i < NumberOfBundles; ++i) {
385 if (ReadChars + 8 > FC.size())
386 return Error::success();
388 uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
392 if (ReadChars + 8 > FC.size())
393 return Error::success();
395 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
399 if (ReadChars + 8 > FC.size())
400 return Error::success();
402 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
406 if (ReadChars + TripleSize > FC.size())
407 return Error::success();
409 StringRef Triple(&FC.data()[ReadChars], TripleSize);
410 ReadChars += TripleSize;
413 if (!Offset || Offset + Size > FC.size())
414 return Error::success();
416 BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
419 CurBundleInfo = BundlesInfo.end();
420 NextBundleInfo = BundlesInfo.begin();
421 return Error::success();
424 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
425 if (NextBundleInfo == BundlesInfo.end())
427 CurBundleInfo = NextBundleInfo++;
428 return CurBundleInfo->first();
431 Error ReadBundleEnd(MemoryBuffer &Input)
final {
432 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
433 return Error::success();
436 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
437 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
438 StringRef FC = Input.getBuffer();
439 OS.write(FC.data() + CurBundleInfo->second.Offset,
440 CurBundleInfo->second.Size);
441 return Error::success();
444 Error WriteHeader(raw_ostream &OS,
445 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
455 HeaderSize +=
T.size();
461 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
465 MemoryBuffer &MB = *Inputs[Idx++];
468 Write8byteIntegerToBuffer(OS, HeaderSize);
470 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
471 BundlesInfo[
T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
472 HeaderSize += MB.getBufferSize();
474 Write8byteIntegerToBuffer(OS,
T.size());
478 return Error::success();
481 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
482 CurWriteBundleTarget = TargetTriple.str();
483 return Error::success();
486 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
487 return Error::success();
490 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
491 auto BI = BundlesInfo[CurWriteBundleTarget];
494 size_t CurrentPos =
OS.tell();
495 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
496 for (
size_t I = 0; I < PaddingSize; ++I)
498 assert(
OS.tell() == BI.Offset);
500 OS.write(Input.getBufferStart(), Input.getBufferSize());
502 return Error::success();
508class TempFileHandlerRAII {
510 ~TempFileHandlerRAII() {
511 for (
const auto &
File : Files)
512 sys::fs::remove(
File);
516 Expected<StringRef>
Create(std::optional<ArrayRef<char>> Contents) {
517 SmallString<128u>
File;
518 if (std::error_code EC =
519 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp",
File))
520 return createFileError(
File, EC);
521 Files.push_front(
File);
525 raw_fd_ostream
OS(
File, EC);
527 return createFileError(
File, EC);
528 OS.write(Contents->data(), Contents->size());
530 return Files.front().str();
534 std::forward_list<SmallString<128u>> Files;
541class ObjectFileHandler final :
public FileHandler {
544 std::unique_ptr<ObjectFile> Obj;
547 StringRef getInputFileContents()
const {
return Obj->getData(); }
551 static Expected<std::optional<StringRef>>
552 IsOffloadSection(SectionRef CurSection) {
553 Expected<StringRef> NameOrErr = CurSection.getName();
555 return NameOrErr.takeError();
558 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
566 unsigned NumberOfInputs = 0;
570 unsigned NumberOfProcessedInputs = 0;
573 section_iterator CurrentSection;
574 section_iterator NextSection;
577 const OffloadBundlerConfig &BundlerConfig;
581 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
582 const OffloadBundlerConfig &BC)
583 : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
584 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
586 ~ObjectFileHandler() final {}
588 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
590 Expected<std::optional<StringRef>> ReadBundleStart(StringRef Input)
final {
591 while (NextSection != Obj->section_end()) {
592 CurrentSection = NextSection;
597 Expected<std::optional<StringRef>> TripleOrErr =
598 IsOffloadSection(*CurrentSection);
600 return TripleOrErr.takeError();
602 return **TripleOrErr;
607 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
609 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
610 Expected<StringRef> ContentOrErr = CurrentSection->getContents();
612 return ContentOrErr.takeError();
613 StringRef Content = *ContentOrErr;
616 std::string ModifiedContent;
617 if (Content.size() == 1u && Content.front() == 0) {
618 auto HostBundleOrErr = getHostBundle(
619 StringRef(Input.getBufferStart(), Input.getBufferSize()));
620 if (!HostBundleOrErr)
621 return HostBundleOrErr.takeError();
623 ModifiedContent = std::move(*HostBundleOrErr);
624 Content = ModifiedContent;
627 OS.write(Content.data(), Content.size());
628 return Error::success();
631 Error WriteHeader(raw_ostream &OS,
632 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
634 "Host input index not defined.");
637 NumberOfInputs = Inputs.size();
638 return Error::success();
641 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
642 ++NumberOfProcessedInputs;
643 return Error::success();
646 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
647 return Error::success();
650 Error finalizeOutputFile() final {
651 assert(NumberOfProcessedInputs <= NumberOfInputs &&
652 "Processing more inputs that actually exist!");
654 "Host input index not defined.");
657 if (NumberOfProcessedInputs != NumberOfInputs)
658 return Error::success();
666 "llvm-objcopy path not specified");
669 TempFileHandlerRAII TempFiles;
673 BumpPtrAllocator
Alloc;
674 StringSaver SS{
Alloc};
675 SmallVector<StringRef, 8u> ObjcopyArgs{
"llvm-objcopy"};
677 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
684 Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
686 return TempFileOrErr.takeError();
687 InputFile = *TempFileOrErr;
690 ObjcopyArgs.push_back(
693 ObjcopyArgs.push_back(
695 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
697 ObjcopyArgs.push_back(
"--");
698 ObjcopyArgs.push_back(
705 return Error::success();
708 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
709 return Error::success();
713 Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
717 errs() <<
"\"" << Objcopy <<
"\"";
718 for (StringRef Arg : drop_begin(Args, 1))
719 errs() <<
" \"" << Arg <<
"\"";
722 if (sys::ExecuteAndWait(Objcopy, Args))
723 return createStringError(inconvertibleErrorCode(),
724 "'llvm-objcopy' tool failed");
726 return Error::success();
729 Expected<std::string> getHostBundle(StringRef Input) {
730 TempFileHandlerRAII TempFiles;
732 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
733 if (!ModifiedObjPathOrErr)
734 return ModifiedObjPathOrErr.takeError();
735 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
737 BumpPtrAllocator
Alloc;
738 StringSaver SS{
Alloc};
739 SmallVector<StringRef, 16> ObjcopyArgs{
"llvm-objcopy"};
741 ObjcopyArgs.push_back(
"--regex");
742 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
743 ObjcopyArgs.push_back(
"--");
745 StringRef ObjcopyInputFileName;
752 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
753 auto InputFileOrErr = TempFiles.Create(ArrayRef<char>(Input));
755 return InputFileOrErr.takeError();
756 ObjcopyInputFileName = *InputFileOrErr;
760 ObjcopyArgs.push_back(ObjcopyInputFileName);
761 ObjcopyArgs.push_back(ModifiedObjPath);
764 return std::move(Err);
766 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
768 return createStringError(BufOrErr.getError(),
769 "Failed to read back the modified object file");
771 return BufOrErr->get()->getBuffer().str();
784class TextFileHandler final :
public FileHandler {
789 std::string BundleStartString;
792 std::string BundleEndString;
795 size_t ReadChars = 0u;
798 Error ReadHeader(StringRef Input)
final {
return Error::success(); }
800 Expected<std::optional<StringRef>> ReadBundleStart(StringRef FC)
final {
803 ReadChars = FC.find(BundleStartString, ReadChars);
804 if (ReadChars == FC.npos)
808 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
811 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
812 if (TripleEnd == FC.npos)
818 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
821 Error ReadBundleEnd(MemoryBuffer &Input)
final {
822 StringRef FC = Input.getBuffer();
825 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
827 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
828 if (TripleEnd != FC.npos)
832 return Error::success();
835 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
836 StringRef FC = Input.getBuffer();
837 size_t BundleStart = ReadChars;
840 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
842 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
845 return Error::success();
848 Error WriteHeader(raw_ostream &OS,
849 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
850 return Error::success();
853 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
854 OS << BundleStartString << TargetTriple <<
"\n";
855 return Error::success();
858 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
859 OS << BundleEndString << TargetTriple <<
"\n";
860 return Error::success();
863 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
864 OS << Input.getBuffer();
865 return Error::success();
869 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
876 Error listBundleIDsCallback(MemoryBuffer &Input,
877 const BundleInfo &Info)
final {
882 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
883 if (
Error Err = ReadBundleEnd(Input))
885 return Error::success();
893static std::unique_ptr<FileHandler>
901 if (errorToBool(BinaryOrErr.takeError()) || !
isa<ObjectFile>(*BinaryOrErr))
902 return std::make_unique<BinaryFileHandler>(BundlerConfig);
906 return std::make_unique<ObjectFileHandler>(
915 std::string FilesType = BundlerConfig.
FilesType;
917 if (FilesType ==
"i")
918 return std::make_unique<TextFileHandler>(
"//");
919 if (FilesType ==
"ii")
920 return std::make_unique<TextFileHandler>(
"//");
921 if (FilesType ==
"cui")
922 return std::make_unique<TextFileHandler>(
"//");
923 if (FilesType ==
"hipi")
924 return std::make_unique<TextFileHandler>(
"//");
927 if (FilesType ==
"d")
928 return std::make_unique<TextFileHandler>(
"#");
929 if (FilesType ==
"ll")
930 return std::make_unique<TextFileHandler>(
";");
931 if (FilesType ==
"bc")
932 return std::make_unique<BinaryFileHandler>(BundlerConfig);
933 if (FilesType ==
"s")
934 return std::make_unique<TextFileHandler>(
"#");
935 if (FilesType ==
"o")
937 if (FilesType ==
"a")
939 if (FilesType ==
"gch")
940 return std::make_unique<BinaryFileHandler>(BundlerConfig);
941 if (FilesType ==
"ast")
942 return std::make_unique<BinaryFileHandler>(BundlerConfig);
944 return createStringError(errc::invalid_argument,
945 "'" + FilesType +
"': invalid file type specified");
950 if (llvm::compression::zstd::isAvailable()) {
955 }
else if (llvm::compression::zlib::isAvailable()) {
961 auto IgnoreEnvVarOpt =
962 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
963 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
965 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
966 if (VerboseEnvVarOpt.has_value())
967 Verbose = VerboseEnvVarOpt.value() ==
"1";
968 auto CompressEnvVarOpt =
969 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
970 if (CompressEnvVarOpt.has_value())
971 Compress = CompressEnvVarOpt.value() ==
"1";
972 auto CompressionLevelEnvVarOpt =
973 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
974 if (CompressionLevelEnvVarOpt.has_value()) {
975 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
977 if (!CompressionLevelStr.getAsInteger(10, Level))
981 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
982 << CompressionLevelStr.str() <<
". Ignoring it.\n";
984 auto CompressedBundleFormatVersionOpt =
985 llvm::sys::Process::GetEnv(
"COMPRESSED_BUNDLE_FORMAT_VERSION");
986 if (CompressedBundleFormatVersionOpt.has_value()) {
987 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();
989 if (!VersionStr.getAsInteger(10, Version)) {
990 if (Version >= 2 && Version <= 3)
994 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
996 <<
". Valid values are 2 or 3. Using default version "
1000 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
1001 << VersionStr.str() <<
". Using default version "
1010 CompressedOffloadBundle::CompressedBundleHeader::tryParse(Blob);
1012 consumeError(HeaderOrErr.takeError());
1013 return std::nullopt;
1015 return HeaderOrErr->FileSize;
1023 size_t NextBundleStart = 0;
1024 std::unique_ptr<MemoryBuffer> Buffer;
1027 ErrorOr<std::unique_ptr<MemoryBuffer>> Contents =
1028 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1029 if (std::error_code EC = Contents.getError())
1030 return createFileError(InputFileName, EC);
1033 while ((NextBundleStart != StringRef::npos) &&
1034 (Offset < (**Contents).getBufferSize())) {
1035 Buffer = MemoryBuffer::getMemBuffer(
1036 (**Contents).getBuffer().drop_front(Offset),
"",
1039 size_t CurBundleEnd = StringRef::npos;
1040 if (identify_magic((*Buffer).getBuffer()) ==
1041 file_magic::offload_bundle_compressed) {
1043 if (std::optional<size_t> Size =
1045 CurBundleEnd = *Size;
1046 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1049 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1050 CurBundleEnd = NextBundleStart;
1053 NextBundleStart = StringRef::npos;
1055 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1056 MemoryBuffer::getMemBuffer(
1057 (*Buffer).getBuffer().take_front(CurBundleEnd),
1060 if (std::error_code EC = CodeOrErr.getError())
1061 return createFileError(InputFileName, EC);
1065 CompressedOffloadBundle::decompress(
1066 **CodeOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1067 if (!DecompressedBufferOrErr)
1068 return createStringError(
1069 inconvertibleErrorCode(),
1070 "Failed to decompress input: " +
1071 llvm::toString(DecompressedBufferOrErr.takeError()));
1073 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1078 if (!FileHandlerOrErr)
1079 return FileHandlerOrErr.takeError();
1080 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1082 Error E = FH->listBundleIDs(DecompressedInput);
1086 if (NextBundleStart != StringRef::npos)
1087 Offset += NextBundleStart;
1089 return Error::success();
1100 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1101 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1102 << CodeObjectInfo.
str()
1103 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1111 "CodeObjectCompatibility",
1112 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1113 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1119 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1121 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1126 if (!TargetProc || !CodeObjectProc ||
1127 CodeObjectProc.value() != TargetProc.value()) {
1128 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1129 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1130 << CodeObjectInfo.
str()
1131 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1137 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1138 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1139 dbgs() <<
"Incompatible: CodeObject has more features "
1140 "than target \t[CodeObject: "
1141 << CodeObjectInfo.
str()
1142 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1150 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1151 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1152 if (TargetFeature == TargetFeatureMap.end()) {
1154 "CodeObjectCompatibility",
1156 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1157 "not matching with Target feature's ANY value \t[CodeObject: "
1158 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1161 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1163 "CodeObjectCompatibility",
1164 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1165 "not matching with Target feature's non-ANY value "
1167 << CodeObjectInfo.
str()
1168 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1178 "CodeObjectCompatibility",
1179 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1180 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1191 llvm::raw_svector_ostream BufferStream(Buffer);
1197 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1198 MemoryBuffer::getFileOrSTDIN(I,
true);
1199 if (std::error_code EC = CodeOrErr.getError())
1200 return createFileError(I, EC);
1201 InputBuffers.emplace_back(std::move(*CodeOrErr));
1206 "Host input index undefined??");
1211 if (!FileHandlerOrErr)
1212 return FileHandlerOrErr.takeError();
1214 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1218 if (
Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1223 auto Input = InputBuffers.begin();
1225 if (
Error Err = FH->WriteBundleStart(BufferStream, Triple))
1227 if (
Error Err = FH->WriteBundle(BufferStream, **Input))
1229 if (
Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1234 raw_fd_ostream OutputFile(
BundlerConfig.OutputFileNames.front(), EC,
1237 return createFileError(
BundlerConfig.OutputFileNames.front(), EC);
1241 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1242 llvm::MemoryBuffer::getMemBufferCopy(
1243 llvm::StringRef(Buffer.data(), Buffer.size()));
1244 auto CompressionResult = CompressedOffloadBundle::compress(
1249 if (
auto Error = CompressionResult.takeError())
1252 auto CompressedMemBuffer = std::move(CompressionResult.get());
1253 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1254 CompressedMemBuffer->getBufferEnd());
1256 CompressedBuffer = std::move(Buffer);
1258 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1260 return FH->finalizeOutputFile();
1266 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1267 MemoryBuffer::getFileOrSTDIN(
BundlerConfig.InputFileNames.front(),
1269 if (std::error_code EC = CodeOrErr.getError())
1270 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1273 StringMap<StringRef> Worklist;
1277 return createStringError(errc::invalid_argument,
1278 "invalid bundle id from bundle config");
1279 Worklist[Triple] = *Output;
1287 bool FoundHostBundle =
false;
1289 size_t NextBundleStart = 0;
1290 std::unique_ptr<MemoryBuffer> Buffer;
1292 while ((NextBundleStart != StringRef::npos) &&
1293 (Offset < (**CodeOrErr).getBufferSize())) {
1295 Buffer = MemoryBuffer::getMemBuffer(
1296 (**CodeOrErr).getBuffer().drop_front(Offset),
"",
1299 size_t CurBundleEnd = StringRef::npos;
1300 if (identify_magic((*Buffer).getBuffer()) ==
1301 file_magic::offload_bundle_compressed) {
1303 if (std::optional<size_t> Size =
1305 CurBundleEnd = *Size;
1306 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1309 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1310 CurBundleEnd = NextBundleStart;
1312 }
else if (identify_magic((*Buffer).getBuffer()) ==
1313 file_magic::offload_bundle) {
1314 NextBundleStart = (*Buffer).getBuffer().find(
1316 CurBundleEnd = NextBundleStart;
1318 NextBundleStart = StringRef::npos;
1320 ErrorOr<std::unique_ptr<MemoryBuffer>> BlobOrErr =
1321 MemoryBuffer::getMemBuffer(
1322 (*Buffer).getBuffer().take_front(CurBundleEnd),
1325 if (std::error_code EC = BlobOrErr.getError())
1326 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1330 CompressedOffloadBundle::decompress(
1331 **BlobOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1332 if (!DecompressedBufferOrErr)
1333 return createStringError(
1334 inconvertibleErrorCode(),
1335 "Failed to decompress input: " +
1336 llvm::toString(DecompressedBufferOrErr.takeError()));
1338 MemoryBuffer &Input = **DecompressedBufferOrErr;
1343 if (!FileHandlerOrErr)
1344 return FileHandlerOrErr.takeError();
1346 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1350 if (
Error Err = FH->ReadHeader(Input.getBuffer()))
1354 while (!Worklist.empty()) {
1356 FH->ReadBundleStart(Input.getBuffer());
1357 if (!CurTripleOrErr)
1358 return CurTripleOrErr.takeError();
1361 if (!*CurTripleOrErr)
1364 StringRef CurTriple = **CurTripleOrErr;
1365 assert(!CurTriple.empty());
1367 return createStringError(errc::invalid_argument,
1368 "invalid bundle id read from the bundle");
1370 auto Output = Worklist.begin();
1371 for (
auto E = Worklist.end(); Output != E; Output++) {
1378 if (Output == Worklist.end())
1383 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1385 return createFileError((*Output).second, EC);
1386 if (
Error Err = FH->ReadBundle(OutputFile, Input))
1388 if (
Error Err = FH->ReadBundleEnd(Input))
1390 Worklist.erase(Output);
1394 if (OffloadInfo.hasHostKind())
1395 FoundHostBundle =
true;
1398 if (NextBundleStart != StringRef::npos)
1399 Offset += NextBundleStart;
1402 if (!
BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1403 std::string ErrMsg =
"Can't find bundles for";
1404 std::set<StringRef> Sorted;
1405 for (
auto &E : Worklist)
1406 Sorted.insert(E.first());
1408 unsigned Last = Sorted.size() - 1;
1409 for (
auto &E : Sorted) {
1410 if (I != 0 &&
Last > 1)
1413 if (I ==
Last && I != 0)
1418 return createStringError(inconvertibleErrorCode(), ErrMsg);
1424 for (
auto &E : Worklist) {
1426 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1428 return createFileError(E.second, EC);
1434 if (OffloadInfo.hasHostKind())
1435 OutputFile.write((**CodeOrErr).getBufferStart(),
1436 (**CodeOrErr).getBufferSize());
1438 return Error::success();
1443 if (!(FoundHostBundle ||
BundlerConfig.HostInputIndex == ~0u ||
1445 return createStringError(inconvertibleErrorCode(),
1446 "Can't find bundle for the host target");
1449 for (
auto &E : Worklist) {
1451 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1453 return createFileError(E.second, EC);
1456 return Error::success();
1460 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1474 if (!CompatibleTargets.empty()) {
1475 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1476 dbgs() <<
"CompatibleTargets list should be empty\n");
1482 CompatibleTargets.push_back(
Target);
1484 return !CompatibleTargets.empty();
1494 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1495 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1496 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1497 if (std::error_code EC = BufOrErr.getError())
1498 return createFileError(ArchiveName, EC);
1500 ArchiveBuffers.push_back(std::move(*BufOrErr));
1502 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1504 return LibOrErr.takeError();
1506 auto Archive = std::move(*LibOrErr);
1508 Error ArchiveErr = Error::success();
1509 auto ChildEnd = Archive->child_end();
1512 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1513 ArchiveIter != ChildEnd; ++ArchiveIter) {
1516 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1517 if (!ArchiveChildNameOrErr)
1518 return ArchiveChildNameOrErr.takeError();
1520 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1521 if (!CodeObjectBufferRefOrErr)
1522 return CodeObjectBufferRefOrErr.takeError();
1524 auto CodeObjectBuffer =
1525 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1529 if (!FileHandlerOrErr)
1530 return FileHandlerOrErr.takeError();
1532 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1533 assert(FileHandler);
1535 std::set<StringRef> BundleIds;
1536 auto CodeObjectFileError =
1537 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1538 if (CodeObjectFileError)
1539 return CodeObjectFileError;
1542 if (ConflictingArchs) {
1543 std::string ErrMsg =
1544 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1545 ", " + ConflictingArchs.value().second +
"] found in " +
1546 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1548 return createStringError(inconvertibleErrorCode(), ErrMsg);
1563 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1567 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1570 StringMap<StringRef> TargetOutputFileNameMap;
1574 TargetOutputFileNameMap[
Target] = *Output;
1586 return ArchiveError;
1590 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1591 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1592 if (std::error_code EC = BufOrErr.getError())
1593 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1595 ArchiveBuffers.push_back(std::move(*BufOrErr));
1597 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1599 return LibOrErr.takeError();
1601 auto Archive = std::move(*LibOrErr);
1603 Error ArchiveErr = Error::success();
1604 auto ChildEnd = Archive->child_end();
1607 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1608 ArchiveIter != ChildEnd; ++ArchiveIter) {
1611 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1612 if (!ArchiveChildNameOrErr)
1613 return ArchiveChildNameOrErr.takeError();
1615 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1617 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1618 if (!CodeObjectBufferRefOrErr)
1619 return CodeObjectBufferRefOrErr.takeError();
1621 auto TempCodeObjectBuffer =
1622 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1626 CompressedOffloadBundle::decompress(
1627 *TempCodeObjectBuffer,
1629 if (!DecompressedBufferOrErr)
1630 return createStringError(
1631 inconvertibleErrorCode(),
1632 "Failed to decompress code object: " +
1633 llvm::toString(DecompressedBufferOrErr.takeError()));
1635 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1639 if (!FileHandlerOrErr)
1640 return FileHandlerOrErr.takeError();
1642 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1643 assert(FileHandler &&
1644 "FileHandle creation failed for file in the archive!");
1646 if (
Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer.getBuffer()))
1650 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1651 if (!CurBundleIDOrErr)
1652 return CurBundleIDOrErr.takeError();
1654 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1656 if (!OptionalCurBundleID)
1658 StringRef CodeObject = *OptionalCurBundleID;
1662 while (!CodeObject.empty()) {
1665 return createStringError(errc::invalid_argument,
1666 "Invalid bundle id read from code object");
1671 std::string BundleData;
1672 raw_string_ostream DataStream(BundleData);
1673 if (
Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1676 for (
auto &CompatibleTarget : CompatibleTargets) {
1678 BundledObjectFileName.assign(BundledObjectFile);
1679 auto OutputBundleName =
1680 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1683 CodeObjectInfo.TargetID))
1687 llvm::replace(OutputBundleName,
':',
'_');
1689 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1690 DataStream.str(), OutputBundleName);
1691 ArchiveBuffers.push_back(std::move(MemBuf));
1692 llvm::MemoryBufferRef MemBufRef =
1693 MemoryBufferRef(*(ArchiveBuffers.back()));
1697 OutputArchivesMap[CompatibleTarget].push_back(
1698 NewArchiveMember(MemBufRef));
1702 if (
Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1706 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1707 if (!NextTripleOrErr)
1708 return NextTripleOrErr.takeError();
1710 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1714 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1719 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
1720 if (CurArchiveMembers != OutputArchivesMap.end()) {
1721 if (
Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1722 SymtabWritingMode::NormalSymtab,
1727 std::string ErrMsg =
1728 Twine(
"no compatible code object found for the target '" +
Target +
1729 "' in heterogeneous archive library: " + IFName)
1731 return createStringError(inconvertibleErrorCode(), ErrMsg);
1736 std::vector<llvm::NewArchiveMember> EmptyArchive;
1737 EmptyArchive.clear();
1738 if (
Error WriteErr = writeArchive(
1739 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1745 return Error::success();
1752 Str.split(Components,
'-', 5);
1753 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