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 {
361 CurBundleInfo = 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")
916 return std::make_unique<TextFileHandler>(
"//");
917 if (FilesType ==
"ii")
918 return std::make_unique<TextFileHandler>(
"//");
919 if (FilesType ==
"cui")
920 return std::make_unique<TextFileHandler>(
"//");
921 if (FilesType ==
"hipi")
922 return std::make_unique<TextFileHandler>(
"//");
925 if (FilesType ==
"d")
926 return std::make_unique<TextFileHandler>(
"#");
927 if (FilesType ==
"ll")
928 return std::make_unique<TextFileHandler>(
";");
929 if (FilesType ==
"bc")
930 return std::make_unique<BinaryFileHandler>(BundlerConfig);
931 if (FilesType ==
"s")
932 return std::make_unique<TextFileHandler>(
"#");
933 if (FilesType ==
"o")
935 if (FilesType ==
"a")
937 if (FilesType ==
"gch")
938 return std::make_unique<BinaryFileHandler>(BundlerConfig);
939 if (FilesType ==
"ast")
940 return std::make_unique<BinaryFileHandler>(BundlerConfig);
942 return createStringError(errc::invalid_argument,
943 "'" + FilesType +
"': invalid file type specified");
948 if (llvm::compression::zstd::isAvailable()) {
953 }
else if (llvm::compression::zlib::isAvailable()) {
959 auto IgnoreEnvVarOpt =
960 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
961 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
963 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
964 if (VerboseEnvVarOpt.has_value())
965 Verbose = VerboseEnvVarOpt.value() ==
"1";
966 auto CompressEnvVarOpt =
967 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
968 if (CompressEnvVarOpt.has_value())
969 Compress = CompressEnvVarOpt.value() ==
"1";
970 auto CompressionLevelEnvVarOpt =
971 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
972 if (CompressionLevelEnvVarOpt.has_value()) {
973 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
975 if (!CompressionLevelStr.getAsInteger(10, Level))
979 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
980 << CompressionLevelStr.str() <<
". Ignoring it.\n";
982 auto CompressedBundleFormatVersionOpt =
983 llvm::sys::Process::GetEnv(
"COMPRESSED_BUNDLE_FORMAT_VERSION");
984 if (CompressedBundleFormatVersionOpt.has_value()) {
985 llvm::StringRef VersionStr = CompressedBundleFormatVersionOpt.value();
987 if (!VersionStr.getAsInteger(10, Version)) {
988 if (Version >= 2 && Version <= 3)
992 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
994 <<
". Valid values are 2 or 3. Using default version "
998 <<
"Warning: Invalid value for COMPRESSED_BUNDLE_FORMAT_VERSION: "
999 << VersionStr.str() <<
". Using default version "
1008 CompressedOffloadBundle::CompressedBundleHeader::tryParse(Blob);
1010 consumeError(HeaderOrErr.takeError());
1011 return std::nullopt;
1013 return HeaderOrErr->FileSize;
1021 size_t NextBundleStart = 0;
1022 std::unique_ptr<MemoryBuffer> Buffer;
1025 ErrorOr<std::unique_ptr<MemoryBuffer>> Contents =
1026 MemoryBuffer::getFileOrSTDIN(InputFileName,
true);
1027 if (std::error_code EC = Contents.getError())
1028 return createFileError(InputFileName, EC);
1031 while ((NextBundleStart != StringRef::npos) &&
1032 (Offset < (**Contents).getBufferSize())) {
1033 Buffer = MemoryBuffer::getMemBuffer(
1034 (**Contents).getBuffer().drop_front(Offset),
"",
1037 size_t CurBundleEnd = StringRef::npos;
1038 if (identify_magic((*Buffer).getBuffer()) ==
1039 file_magic::offload_bundle_compressed) {
1041 if (std::optional<size_t> Size =
1043 CurBundleEnd = *Size;
1044 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1047 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1048 CurBundleEnd = NextBundleStart;
1051 NextBundleStart = StringRef::npos;
1053 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1054 MemoryBuffer::getMemBuffer(
1055 (*Buffer).getBuffer().take_front(CurBundleEnd),
1058 if (std::error_code EC = CodeOrErr.getError())
1059 return createFileError(InputFileName, EC);
1063 CompressedOffloadBundle::decompress(
1064 **CodeOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1065 if (!DecompressedBufferOrErr)
1066 return createStringError(
1067 inconvertibleErrorCode(),
1068 "Failed to decompress input: " +
1069 llvm::toString(DecompressedBufferOrErr.takeError()));
1071 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1076 if (!FileHandlerOrErr)
1077 return FileHandlerOrErr.takeError();
1078 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1080 Error E = FH->listBundleIDs(DecompressedInput);
1084 if (NextBundleStart != StringRef::npos)
1085 Offset += NextBundleStart;
1087 return Error::success();
1098 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1099 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1100 << CodeObjectInfo.
str()
1101 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1109 "CodeObjectCompatibility",
1110 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1111 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1117 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1119 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1124 if (!TargetProc || !CodeObjectProc ||
1125 CodeObjectProc.value() != TargetProc.value()) {
1126 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1127 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1128 << CodeObjectInfo.
str()
1129 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1135 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1136 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1137 dbgs() <<
"Incompatible: CodeObject has more features "
1138 "than target \t[CodeObject: "
1139 << CodeObjectInfo.
str()
1140 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1148 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1149 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1150 if (TargetFeature == TargetFeatureMap.end()) {
1152 "CodeObjectCompatibility",
1154 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1155 "not matching with Target feature's ANY value \t[CodeObject: "
1156 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1159 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1161 "CodeObjectCompatibility",
1162 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1163 "not matching with Target feature's non-ANY value "
1165 << CodeObjectInfo.
str()
1166 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1176 "CodeObjectCompatibility",
1177 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1178 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1189 llvm::raw_svector_ostream BufferStream(Buffer);
1195 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1196 MemoryBuffer::getFileOrSTDIN(I,
true);
1197 if (std::error_code EC = CodeOrErr.getError())
1198 return createFileError(I, EC);
1199 InputBuffers.emplace_back(std::move(*CodeOrErr));
1204 "Host input index undefined??");
1209 if (!FileHandlerOrErr)
1210 return FileHandlerOrErr.takeError();
1212 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1216 if (
Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1221 auto Input = InputBuffers.begin();
1223 if (
Error Err = FH->WriteBundleStart(BufferStream, Triple))
1225 if (
Error Err = FH->WriteBundle(BufferStream, **Input))
1227 if (
Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1232 raw_fd_ostream OutputFile(
BundlerConfig.OutputFileNames.front(), EC,
1235 return createFileError(
BundlerConfig.OutputFileNames.front(), EC);
1239 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1240 llvm::MemoryBuffer::getMemBufferCopy(
1241 llvm::StringRef(Buffer.data(), Buffer.size()));
1242 auto CompressionResult = CompressedOffloadBundle::compress(
1247 if (
auto Error = CompressionResult.takeError())
1250 auto CompressedMemBuffer = std::move(CompressionResult.get());
1251 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1252 CompressedMemBuffer->getBufferEnd());
1254 CompressedBuffer = std::move(Buffer);
1256 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1258 return FH->finalizeOutputFile();
1264 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1265 MemoryBuffer::getFileOrSTDIN(
BundlerConfig.InputFileNames.front(),
1267 if (std::error_code EC = CodeOrErr.getError())
1268 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1271 StringMap<StringRef> Worklist;
1275 return createStringError(errc::invalid_argument,
1276 "invalid bundle id from bundle config");
1277 Worklist[Triple] = *Output;
1285 bool FoundHostBundle =
false;
1287 size_t NextBundleStart = 0;
1288 std::unique_ptr<MemoryBuffer> Buffer;
1290 while ((NextBundleStart != StringRef::npos) &&
1291 (Offset < (**CodeOrErr).getBufferSize())) {
1293 Buffer = MemoryBuffer::getMemBuffer(
1294 (**CodeOrErr).getBuffer().drop_front(Offset),
"",
1297 size_t CurBundleEnd = StringRef::npos;
1298 if (identify_magic((*Buffer).getBuffer()) ==
1299 file_magic::offload_bundle_compressed) {
1301 if (std::optional<size_t> Size =
1303 CurBundleEnd = *Size;
1304 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", *Size);
1307 NextBundleStart = (*Buffer).getBuffer().find(
"CCOB", 4);
1308 CurBundleEnd = NextBundleStart;
1310 }
else if (identify_magic((*Buffer).getBuffer()) ==
1311 file_magic::offload_bundle) {
1312 NextBundleStart = (*Buffer).getBuffer().find(
1314 CurBundleEnd = NextBundleStart;
1316 NextBundleStart = StringRef::npos;
1318 ErrorOr<std::unique_ptr<MemoryBuffer>> BlobOrErr =
1319 MemoryBuffer::getMemBuffer(
1320 (*Buffer).getBuffer().take_front(CurBundleEnd),
1323 if (std::error_code EC = BlobOrErr.getError())
1324 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1328 CompressedOffloadBundle::decompress(
1329 **BlobOrErr,
BundlerConfig.Verbose ? &llvm::errs() :
nullptr);
1330 if (!DecompressedBufferOrErr)
1331 return createStringError(
1332 inconvertibleErrorCode(),
1333 "Failed to decompress input: " +
1334 llvm::toString(DecompressedBufferOrErr.takeError()));
1336 MemoryBuffer &Input = **DecompressedBufferOrErr;
1341 if (!FileHandlerOrErr)
1342 return FileHandlerOrErr.takeError();
1344 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1348 if (
Error Err = FH->ReadHeader(Input.getBuffer()))
1352 while (!Worklist.empty()) {
1354 FH->ReadBundleStart(Input.getBuffer());
1355 if (!CurTripleOrErr)
1356 return CurTripleOrErr.takeError();
1359 if (!*CurTripleOrErr)
1362 StringRef CurTriple = **CurTripleOrErr;
1363 assert(!CurTriple.empty());
1365 return createStringError(errc::invalid_argument,
1366 "invalid bundle id read from the bundle");
1368 auto Output = Worklist.begin();
1369 for (
auto E = Worklist.end(); Output != E; Output++) {
1376 if (Output == Worklist.end())
1381 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
1383 return createFileError((*Output).second, EC);
1384 if (
Error Err = FH->ReadBundle(OutputFile, Input))
1386 if (
Error Err = FH->ReadBundleEnd(Input))
1388 Worklist.erase(Output);
1392 if (OffloadInfo.hasHostKind())
1393 FoundHostBundle =
true;
1396 if (NextBundleStart != StringRef::npos)
1397 Offset += NextBundleStart;
1400 if (!
BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
1401 std::string ErrMsg =
"Can't find bundles for";
1402 std::set<StringRef> Sorted;
1403 for (
auto &E : Worklist)
1404 Sorted.insert(E.first());
1406 unsigned Last = Sorted.size() - 1;
1407 for (
auto &E : Sorted) {
1408 if (I != 0 &&
Last > 1)
1411 if (I ==
Last && I != 0)
1416 return createStringError(inconvertibleErrorCode(), ErrMsg);
1422 for (
auto &E : Worklist) {
1424 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1426 return createFileError(E.second, EC);
1432 if (OffloadInfo.hasHostKind())
1433 OutputFile.write((**CodeOrErr).getBufferStart(),
1434 (**CodeOrErr).getBufferSize());
1436 return Error::success();
1441 if (!(FoundHostBundle ||
BundlerConfig.HostInputIndex == ~0u ||
1443 return createStringError(inconvertibleErrorCode(),
1444 "Can't find bundle for the host target");
1447 for (
auto &E : Worklist) {
1449 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
1451 return createFileError(E.second, EC);
1454 return Error::success();
1458 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
1472 if (!CompatibleTargets.empty()) {
1473 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1474 dbgs() <<
"CompatibleTargets list should be empty\n");
1480 CompatibleTargets.push_back(
Target);
1482 return !CompatibleTargets.empty();
1492 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1493 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1494 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
1495 if (std::error_code EC = BufOrErr.getError())
1496 return createFileError(ArchiveName, EC);
1498 ArchiveBuffers.push_back(std::move(*BufOrErr));
1500 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1502 return LibOrErr.takeError();
1504 auto Archive = std::move(*LibOrErr);
1506 Error ArchiveErr = Error::success();
1507 auto ChildEnd = Archive->child_end();
1510 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1511 ArchiveIter != ChildEnd; ++ArchiveIter) {
1514 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1515 if (!ArchiveChildNameOrErr)
1516 return ArchiveChildNameOrErr.takeError();
1518 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1519 if (!CodeObjectBufferRefOrErr)
1520 return CodeObjectBufferRefOrErr.takeError();
1522 auto CodeObjectBuffer =
1523 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1527 if (!FileHandlerOrErr)
1528 return FileHandlerOrErr.takeError();
1530 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1531 assert(FileHandler);
1533 std::set<StringRef> BundleIds;
1534 auto CodeObjectFileError =
1535 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
1536 if (CodeObjectFileError)
1537 return CodeObjectFileError;
1540 if (ConflictingArchs) {
1541 std::string ErrMsg =
1542 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
1543 ", " + ConflictingArchs.value().second +
"] found in " +
1544 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
1546 return createStringError(inconvertibleErrorCode(), ErrMsg);
1561 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1565 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
1568 StringMap<StringRef> TargetOutputFileNameMap;
1572 TargetOutputFileNameMap[
Target] = *Output;
1584 return ArchiveError;
1588 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1589 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
1590 if (std::error_code EC = BufOrErr.getError())
1591 return createFileError(
BundlerConfig.InputFileNames.front(), EC);
1593 ArchiveBuffers.push_back(std::move(*BufOrErr));
1595 Archive::create(ArchiveBuffers.back()->getMemBufferRef());
1597 return LibOrErr.takeError();
1599 auto Archive = std::move(*LibOrErr);
1601 Error ArchiveErr = Error::success();
1602 auto ChildEnd = Archive->child_end();
1605 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
1606 ArchiveIter != ChildEnd; ++ArchiveIter) {
1609 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
1610 if (!ArchiveChildNameOrErr)
1611 return ArchiveChildNameOrErr.takeError();
1613 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
1615 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
1616 if (!CodeObjectBufferRefOrErr)
1617 return CodeObjectBufferRefOrErr.takeError();
1619 auto TempCodeObjectBuffer =
1620 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
1624 CompressedOffloadBundle::decompress(
1625 *TempCodeObjectBuffer,
1627 if (!DecompressedBufferOrErr)
1628 return createStringError(
1629 inconvertibleErrorCode(),
1630 "Failed to decompress code object: " +
1631 llvm::toString(DecompressedBufferOrErr.takeError()));
1633 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
1637 if (!FileHandlerOrErr)
1638 return FileHandlerOrErr.takeError();
1640 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
1641 assert(FileHandler &&
1642 "FileHandle creation failed for file in the archive!");
1644 if (
Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer.getBuffer()))
1648 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1649 if (!CurBundleIDOrErr)
1650 return CurBundleIDOrErr.takeError();
1652 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
1654 if (!OptionalCurBundleID)
1656 StringRef CodeObject = *OptionalCurBundleID;
1660 while (!CodeObject.empty()) {
1663 return createStringError(errc::invalid_argument,
1664 "Invalid bundle id read from code object");
1669 std::string BundleData;
1670 raw_string_ostream DataStream(BundleData);
1671 if (
Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
1674 for (
auto &CompatibleTarget : CompatibleTargets) {
1676 BundledObjectFileName.assign(BundledObjectFile);
1677 auto OutputBundleName =
1678 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
1681 CodeObjectInfo.TargetID))
1685 llvm::replace(OutputBundleName,
':',
'_');
1687 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
1688 DataStream.str(), OutputBundleName);
1689 ArchiveBuffers.push_back(std::move(MemBuf));
1690 llvm::MemoryBufferRef MemBufRef =
1691 MemoryBufferRef(*(ArchiveBuffers.back()));
1695 OutputArchivesMap[CompatibleTarget].push_back(
1696 NewArchiveMember(MemBufRef));
1700 if (
Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
1704 FileHandler->ReadBundleStart(CodeObjectBuffer.getBuffer());
1705 if (!NextTripleOrErr)
1706 return NextTripleOrErr.takeError();
1708 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
1712 assert(!ArchiveErr &&
"Error occurred while reading archive!");
1717 auto CurArchiveMembers = OutputArchivesMap.find(
Target);
1718 if (CurArchiveMembers != OutputArchivesMap.end()) {
1719 if (
Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
1720 SymtabWritingMode::NormalSymtab,
1725 std::string ErrMsg =
1726 Twine(
"no compatible code object found for the target '" +
Target +
1727 "' in heterogeneous archive library: " + IFName)
1729 return createStringError(inconvertibleErrorCode(), ErrMsg);
1734 std::vector<llvm::NewArchiveMember> EmptyArchive;
1735 EmptyArchive.clear();
1736 if (
Error WriteErr = writeArchive(
1737 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
1743 return Error::success();
1750 Str.split(Components,
'-', 5);
1751 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