21 #include "llvm/ADT/ArrayRef.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/ADT/StringMap.h"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Bitcode/BitcodeWriter.h"
28 #include "llvm/IR/Constants.h"
29 #include "llvm/IR/LLVMContext.h"
30 #include "llvm/IRReader/IRReader.h"
31 #include "llvm/BinaryFormat/Magic.h"
32 #include "llvm/Object/Archive.h"
33 #include "llvm/Object/ArchiveWriter.h"
34 #include "llvm/Object/Binary.h"
35 #include "llvm/Object/ObjectFile.h"
36 #include "llvm/Support/Casting.h"
37 #include "llvm/Support/Compression.h"
38 #include "llvm/Support/Debug.h"
39 #include "llvm/Support/EndianStream.h"
40 #include "llvm/Support/Errc.h"
41 #include "llvm/Support/Error.h"
42 #include "llvm/Support/ErrorOr.h"
43 #include "llvm/Support/FileSystem.h"
44 #include "llvm/Support/MD5.h"
45 #include "llvm/Support/MemoryBuffer.h"
46 #include "llvm/Support/Path.h"
47 #include "llvm/Support/Program.h"
48 #include "llvm/Support/Signals.h"
49 #include "llvm/Support/StringSaver.h"
50 #include "llvm/Support/TargetSelect.h"
51 #include "llvm/Support/Timer.h"
52 #include "llvm/Support/WithColor.h"
53 #include "llvm/Support/raw_ostream.h"
54 #include "llvm/Support/SourceMgr.h"
55 #include "llvm/TargetParser/Host.h"
56 #include "llvm/TargetParser/Triple.h"
61 #include <forward_list>
62 #include <llvm/Support/Process.h>
66 #include <system_error>
67 #include <unordered_set>
71 using namespace llvm::object;
72 using namespace clang;
74 static llvm::TimerGroup
76 "Timer group for clang offload bundler");
79 #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
82 #define SYMBOLS_SECTION_NAME ".tgtsym"
84 #define DEBUG_TYPE "clang-offload-bundler"
86 OffloadTargetInfo::OffloadTargetInfo(
const StringRef
Target,
91 auto TargetFeatures =
Target.split(
':');
92 auto TripleOrGPU = TargetFeatures.first.rsplit(
'-');
95 auto KindTriple = TripleOrGPU.first.split(
'-');
97 this->
Triple = llvm::Triple(KindTriple.second);
100 auto KindTriple = TargetFeatures.first.split(
'-');
102 this->
Triple = llvm::Triple(KindTriple.second);
118 const StringRef TargetOffloadKind)
const {
120 (
OffloadKind ==
"hip" && TargetOffloadKind ==
"hipv4") ||
121 (
OffloadKind ==
"hipv4" && TargetOffloadKind ==
"hip"))
125 bool HIPCompatibleWithOpenMP =
OffloadKind.starts_with_insensitive(
"hip") &&
126 TargetOffloadKind ==
"openmp";
127 bool OpenMPCompatibleWithHIP =
129 TargetOffloadKind.starts_with_insensitive(
"hip");
130 return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
136 return !
Triple.str().empty() &&
Triple.getArch() != Triple::UnknownArch;
151 return Triple(OffloadInfo.getTriple());
155 StringRef BundleFileName) {
156 if (
Device.contains(
"gfx"))
158 if (
Device.contains(
"sm_"))
160 return sys::path::extension(BundleFileName);
165 StringRef LibName = sys::path::stem(BundleFileName);
184 virtual ~FileHandler() {}
188 virtual Error ReadHeader(MemoryBuffer &Input) = 0;
194 ReadBundleStart(MemoryBuffer &Input) = 0;
197 virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
200 virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
204 virtual Error WriteHeader(raw_ostream &OS,
205 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
209 virtual Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) = 0;
213 virtual Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) = 0;
216 virtual Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
219 virtual Error finalizeOutputFile() {
return Error::success(); }
222 void SetTempFileNameBase(StringRef
Base) {
223 TempFileNameBase = std::string(
Base);
227 virtual Error listBundleIDs(MemoryBuffer &Input) {
228 if (Error Err = ReadHeader(Input))
230 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
231 llvm::outs() << Info.BundleID <<
'\n';
232 Error Err = listBundleIDsCallback(Input, Info);
235 return Error::success();
240 virtual Error getBundleIDs(MemoryBuffer &Input,
241 std::set<StringRef> &BundleIds) {
242 if (Error Err = ReadHeader(Input))
244 return forEachBundle(Input, [&](
const BundleInfo &Info) -> Error {
245 BundleIds.insert(Info.BundleID);
246 Error Err = listBundleIDsCallback(Input, Info);
249 return Error::success();
254 Error forEachBundle(MemoryBuffer &Input,
255 std::function<
Error(
const BundleInfo &)> Func) {
258 ReadBundleStart(Input);
260 return CurTripleOrErr.takeError();
263 if (!*CurTripleOrErr)
266 StringRef CurTriple = **CurTripleOrErr;
267 assert(!CurTriple.empty());
269 BundleInfo Info{CurTriple};
270 if (Error Err =
Func(Info))
273 return Error::success();
278 std::string TempFileNameBase;
280 virtual Error listBundleIDsCallback(MemoryBuffer &Input,
281 const BundleInfo &Info) {
282 return Error::success();
310 static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer,
size_t pos) {
311 return llvm::support::endian::read64le(Buffer.data() + pos);
315 static void Write8byteIntegerToBuffer(raw_ostream &OS,
uint64_t Val) {
316 llvm::support::endian::write(OS, Val, llvm::endianness::little);
319 class BinaryFileHandler final :
public FileHandler {
321 struct BinaryBundleInfo final :
public BundleInfo {
327 BinaryBundleInfo() {}
333 StringMap<BinaryBundleInfo> BundlesInfo;
336 StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
337 StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
340 std::string CurWriteBundleTarget;
349 ~BinaryFileHandler() final {}
351 Error ReadHeader(MemoryBuffer &Input)
final {
352 StringRef FC = Input.getBuffer();
355 CurBundleInfo = BundlesInfo.end();
359 if (ReadChars > FC.size())
360 return Error::success();
363 if (llvm::identify_magic(FC) != llvm::file_magic::offload_bundle)
364 return Error::success();
367 if (ReadChars + 8 > FC.size())
368 return Error::success();
370 uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
374 for (
uint64_t i = 0; i < NumberOfBundles; ++i) {
377 if (ReadChars + 8 > FC.size())
378 return Error::success();
384 if (ReadChars + 8 > FC.size())
385 return Error::success();
387 uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
391 if (ReadChars + 8 > FC.size())
392 return Error::success();
394 uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
398 if (ReadChars + TripleSize > FC.size())
399 return Error::success();
401 StringRef Triple(&FC.data()[ReadChars], TripleSize);
402 ReadChars += TripleSize;
406 return Error::success();
408 assert(!BundlesInfo.contains(Triple) &&
"Triple is duplicated??");
409 BundlesInfo[Triple] = BinaryBundleInfo(Size,
Offset);
412 CurBundleInfo = BundlesInfo.end();
413 NextBundleInfo = BundlesInfo.begin();
414 return Error::success();
418 ReadBundleStart(MemoryBuffer &Input)
final {
419 if (NextBundleInfo == BundlesInfo.end())
421 CurBundleInfo = NextBundleInfo++;
422 return CurBundleInfo->first();
425 Error ReadBundleEnd(MemoryBuffer &Input)
final {
426 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
427 return Error::success();
430 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
431 assert(CurBundleInfo != BundlesInfo.end() &&
"Invalid reader info!");
432 StringRef FC = Input.getBuffer();
433 OS.write(FC.data() + CurBundleInfo->second.Offset,
434 CurBundleInfo->second.Size);
435 return Error::success();
438 Error WriteHeader(raw_ostream &OS,
439 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
449 HeaderSize +=
T.size();
455 Write8byteIntegerToBuffer(OS, BundlerConfig.
TargetNames.size());
459 MemoryBuffer &MB = *Inputs[Idx++];
462 Write8byteIntegerToBuffer(OS, HeaderSize);
464 Write8byteIntegerToBuffer(OS, MB.getBufferSize());
465 BundlesInfo[
T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
466 HeaderSize += MB.getBufferSize();
468 Write8byteIntegerToBuffer(OS,
T.size());
472 return Error::success();
475 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
476 CurWriteBundleTarget = TargetTriple.str();
477 return Error::success();
480 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
481 return Error::success();
484 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
485 auto BI = BundlesInfo[CurWriteBundleTarget];
488 size_t CurrentPos = OS.tell();
489 size_t PaddingSize = BI.Offset > CurrentPos ? BI.Offset - CurrentPos : 0;
490 for (
size_t I = 0; I < PaddingSize; ++I)
492 assert(OS.tell() == BI.Offset);
494 OS.write(Input.getBufferStart(), Input.getBufferSize());
496 return Error::success();
502 class TempFileHandlerRAII {
504 ~TempFileHandlerRAII() {
505 for (
const auto &File : Files)
512 if (std::error_code EC =
513 sys::fs::createTemporaryFile(
"clang-offload-bundler",
"tmp", File))
514 return createFileError(File, EC);
515 Files.push_front(File);
519 raw_fd_ostream OS(File, EC);
521 return createFileError(File, EC);
522 OS.write(Contents->data(), Contents->size());
524 return Files.front().str();
528 std::forward_list<SmallString<128u>> Files;
556 class ObjectFileHandler final :
public FileHandler {
559 std::unique_ptr<ObjectFile> Obj;
562 StringRef getInputFileContents()
const {
return Obj->getData(); }
567 IsOffloadSection(SectionRef CurSection) {
570 return NameOrErr.takeError();
573 if (llvm::identify_magic(*NameOrErr) != llvm::file_magic::offload_bundle)
581 unsigned NumberOfInputs = 0;
585 unsigned NumberOfProcessedInputs = 0;
588 section_iterator CurrentSection;
589 section_iterator NextSection;
600 raw_svector_ostream SymbolsOS(SymbolsBuf);
603 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
609 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
612 return createFileError(BundlerConfig.
InputFileNames[I], BufOrErr.getError());
614 std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
621 if (isBitcode((
const unsigned char *)Buf->getBufferStart(),
622 (
const unsigned char *)Buf->getBufferEnd()))
626 std::unique_ptr<Module> Mod = parseIR(*Buf, Err, Context);
628 return createStringError(inconvertibleErrorCode(),
631 bool UpdateBuf =
false;
632 if (!Mod->getModuleInlineAsm().empty()) {
633 Mod->setModuleInlineAsm(
"");
636 for (
auto I = Mod->global_begin(), E = Mod->global_end(); I != E;) {
637 GlobalVariable &GV = *I++;
639 if (!GV.isDeclaration() && !GV.hasLocalLinkage() &&
640 GV.getAddressSpace() == 2) {
641 GV.replaceAllUsesWith(UndefValue::get(GV.getType()));
642 GV.dropAllReferences();
643 GV.eraseFromParent();
649 raw_svector_ostream ModuleOS(ModuleBuf);
650 WriteBitcodeToFile(*Mod, ModuleOS);
652 Buf = MemoryBuffer::getMemBufferCopy(ModuleOS.str(),
653 Buf->getBufferIdentifier());
658 createBinary(Buf->getMemBufferRef(), &Context);
663 if (
auto Err = isNotObjectErrorInvalidFileType(BinOrErr.takeError()))
664 return std::move(Err);
667 auto *SF = dyn_cast<SymbolicFile>(&**BinOrErr);
671 for (BasicSymbolRef Symbol : SF->symbols()) {
674 return FlagsOrErr.takeError();
678 bool Undefined = *FlagsOrErr & SymbolRef::SF_Undefined;
679 bool Global = *FlagsOrErr & SymbolRef::SF_Global;
685 raw_string_ostream NameOS(Name);
686 if (Error Err = Symbol.printName(NameOS))
687 return std::move(Err);
691 if (SF->isIR() && (Name ==
"llvm.used" || Name ==
"llvm.compiler.used"))
695 SymbolsOS << BundlerConfig.
TargetNames[I] <<
"." << Name <<
'\0';
703 ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
705 : Obj(
std::move(ObjIn)), CurrentSection(Obj->section_begin()),
706 NextSection(Obj->section_begin()), BundlerConfig(BC) {}
708 ~ObjectFileHandler() final {}
710 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
713 ReadBundleStart(MemoryBuffer &Input)
final {
714 while (NextSection != Obj->section_end()) {
715 CurrentSection = NextSection;
721 IsOffloadSection(*CurrentSection);
723 return TripleOrErr.takeError();
725 return **TripleOrErr;
730 Error ReadBundleEnd(MemoryBuffer &Input)
final {
return Error::success(); }
732 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
735 return ContentOrErr.takeError();
736 StringRef Content = *ContentOrErr;
739 std::string ModifiedContent;
740 if (Content.size() == 1u && Content.front() == 0) {
741 auto HostBundleOrErr = getHostBundle(
742 StringRef(Input.getBufferStart(), Input.getBufferSize()));
743 if (!HostBundleOrErr)
744 return HostBundleOrErr.takeError();
746 ModifiedContent = std::move(*HostBundleOrErr);
747 Content = ModifiedContent;
750 OS.write(Content.data(), Content.size());
751 return Error::success();
754 Error WriteHeader(raw_ostream &OS,
755 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
757 "Host input index not defined.");
760 NumberOfInputs = Inputs.size();
761 return Error::success();
764 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
765 ++NumberOfProcessedInputs;
766 return Error::success();
769 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
770 return Error::success();
773 Error finalizeOutputFile() final {
774 assert(NumberOfProcessedInputs <= NumberOfInputs &&
775 "Processing more inputs that actually exist!");
777 "Host input index not defined.");
780 if (NumberOfProcessedInputs != NumberOfInputs)
781 return Error::success();
789 "llvm-objcopy path not specified");
792 TempFileHandlerRAII TempFiles;
796 BumpPtrAllocator Alloc;
797 StringSaver SS{Alloc};
800 for (
unsigned I = 0; I < NumberOfInputs; ++I) {
809 return TempFileOrErr.takeError();
810 InputFile = *TempFileOrErr;
813 ObjcopyArgs.push_back(
816 ObjcopyArgs.push_back(
818 BundlerConfig.
TargetNames[I] +
"=readonly,exclude"));
825 return SymbolsOrErr.takeError();
827 if (!SymbolsOrErr->empty()) {
831 if (!SymbolsFileOrErr)
832 return SymbolsFileOrErr.takeError();
834 ObjcopyArgs.push_back(SS.save(Twine(
"--add-section=") +
839 ObjcopyArgs.push_back(
"--");
840 ObjcopyArgs.push_back(
844 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
847 return Error::success();
850 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
851 return Error::success();
859 errs() <<
"\"" << Objcopy <<
"\"";
860 for (StringRef Arg : drop_begin(Args, 1))
861 errs() <<
" \"" << Arg <<
"\"";
864 if (sys::ExecuteAndWait(Objcopy, Args))
865 return createStringError(inconvertibleErrorCode(),
866 "'llvm-objcopy' tool failed");
868 return Error::success();
872 TempFileHandlerRAII TempFiles;
874 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
875 if (!ModifiedObjPathOrErr)
876 return ModifiedObjPathOrErr.takeError();
877 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
879 BumpPtrAllocator Alloc;
880 StringSaver SS{Alloc};
883 ObjcopyArgs.push_back(
"--regex");
884 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
885 ObjcopyArgs.push_back(
"--");
887 StringRef ObjcopyInputFileName;
894 if (StringRef(BundlerConfig.
FilesType).starts_with(
"a")) {
895 auto InputFileOrErr =
898 return InputFileOrErr.takeError();
899 ObjcopyInputFileName = *InputFileOrErr;
903 ObjcopyArgs.push_back(ObjcopyInputFileName);
904 ObjcopyArgs.push_back(ModifiedObjPath);
906 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
907 return std::move(Err);
909 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
911 return createStringError(BufOrErr.getError(),
912 "Failed to read back the modified object file");
914 return BufOrErr->get()->getBuffer().str();
918 TempFileHandlerRAII TempFiles;
920 auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
921 if (!ModifiedObjPathOrErr)
922 return ModifiedObjPathOrErr.takeError();
923 StringRef ModifiedObjPath = *ModifiedObjPathOrErr;
925 BumpPtrAllocator Alloc;
926 StringSaver SS{Alloc};
929 ObjcopyArgs.push_back(
"--regex");
930 ObjcopyArgs.push_back(
"--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
931 ObjcopyArgs.push_back(
"--");
933 ObjcopyArgs.push_back(ModifiedObjPath);
935 if (Error Err = executeObjcopy(BundlerConfig.
ObjcopyPath, ObjcopyArgs))
936 return std::move(Err);
938 auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
940 return createStringError(BufOrErr.getError(),
941 "Failed to read back the modified object file");
943 return BufOrErr->get()->getBuffer().str();
956 class TextFileHandler final :
public FileHandler {
961 std::string BundleStartString;
964 std::string BundleEndString;
967 size_t ReadChars = 0u;
970 Error ReadHeader(MemoryBuffer &Input)
final {
return Error::success(); }
973 ReadBundleStart(MemoryBuffer &Input)
final {
974 StringRef FC = Input.getBuffer();
977 ReadChars = FC.find(BundleStartString, ReadChars);
978 if (ReadChars == FC.npos)
982 size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
985 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars);
986 if (TripleEnd == FC.npos)
992 return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
995 Error ReadBundleEnd(MemoryBuffer &Input)
final {
996 StringRef FC = Input.getBuffer();
999 assert(FC[ReadChars] ==
'\n' &&
"The bundle should end with a new line.");
1001 size_t TripleEnd = ReadChars = FC.find(
"\n", ReadChars + 1);
1002 if (TripleEnd != FC.npos)
1006 return Error::success();
1009 Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
1010 StringRef FC = Input.getBuffer();
1011 size_t BundleStart = ReadChars;
1014 size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
1016 StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
1019 return Error::success();
1022 Error WriteHeader(raw_ostream &OS,
1023 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
final {
1024 return Error::success();
1027 Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple)
final {
1028 OS << BundleStartString << TargetTriple <<
"\n";
1029 return Error::success();
1032 Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple)
final {
1033 OS << BundleEndString << TargetTriple <<
"\n";
1034 return Error::success();
1037 Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input)
final {
1038 OS << Input.getBuffer();
1039 return Error::success();
1043 TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
1050 Error listBundleIDsCallback(MemoryBuffer &Input,
1051 const BundleInfo &Info)
final {
1056 ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
1057 if (Error Err = ReadBundleEnd(Input))
1059 return Error::success();
1067 std::unique_ptr<Archive> Ar;
1074 StringMap<unsigned> Bundles;
1077 StringMap<unsigned>::iterator CurrBundle = Bundles.end();
1078 StringMap<unsigned>::iterator NextBundle = Bundles.end();
1081 enum class OutputType {
1087 const OutputType Mode =
1088 StringSwitch<OutputType>(BundlerConfig.
FilesType)
1089 .Cases(
"aoo",
"aocx",
"aocr", OutputType::FileList)
1090 .Case(
"ao", OutputType::Object)
1091 .Case(
"a", OutputType::Archive)
1096 std::unordered_set<size_t> ExcludedChildIndexes;
1108 return ArOrErr.takeError();
1109 Ar = std::move(*ArOrErr);
1112 ssize_t ChildIndex = -1;
1113 Error Err = Error::success();
1114 for (
auto &C : Ar->children(Err)) {
1116 auto BinOrErr = C.getAsBinary();
1118 std::unique_ptr<FileHandler> FH{
nullptr};
1119 std::unique_ptr<MemoryBuffer> Buf{
nullptr};
1122 if (
auto Err = isNotObjectErrorInvalidFileType(BinOrErr.takeError()))
1126 FH = std::make_unique<BinaryFileHandler>(BundlerConfig);
1127 auto MR = C.getMemoryBufferRef();
1129 Buf = MemoryBuffer::getMemBuffer(*MR,
false);
1131 auto &Bin = BinOrErr.get();
1132 if (!Bin->isObject())
1135 auto CheckOrErr = CheckIfObjectFileContainsExcludedTargets(C);
1137 return CheckOrErr.takeError();
1141 <<
"Add child to ban list. Index: " << ChildIndex <<
"\n");
1142 ExcludedChildIndexes.emplace(ChildIndex);
1145 auto Obj = std::unique_ptr<ObjectFile>(cast<ObjectFile>(Bin.release()));
1146 Buf = MemoryBuffer::getMemBuffer(Obj->getMemoryBufferRef(),
false);
1148 FH = std::make_unique<ObjectFileHandler>(std::move(Obj), BundlerConfig);
1152 if (Error Err = FH->ReadHeader(*Buf))
1156 return NameOrErr.takeError();
1157 while (*NameOrErr) {
1158 ++Bundles[**NameOrErr];
1159 NameOrErr = FH->ReadBundleStart(*Buf);
1161 return NameOrErr.takeError();
1167 CurrBundle = Bundles.end();
1168 NextBundle = Bundles.begin();
1169 return Error::success();
1174 if (NextBundle == Bundles.end())
1175 return std::nullopt;
1176 CurrBundle = NextBundle++;
1177 return CurrBundle->first();
1182 Error
ReadBundle(raw_ostream &OS, MemoryBuffer &Input)
override {
1183 assert(CurrBundle->second &&
"attempt to extract nonexistent bundle");
1186 if (Mode == OutputType::Object && CurrBundle->second > 1)
1187 return createStringError(
1188 errc::invalid_argument,
1189 "'ao' file type is requested, but the archive contains multiple "
1190 "device objects; use 'aoo' instead");
1193 if (Mode == OutputType::Archive &&
1195 OS << Input.getBuffer();
1196 return Error::success();
1203 Error Err = Error::success();
1204 ssize_t ChildIndex = -1;
1205 for (
auto &C : Ar->children(Err)) {
1207 if (ExcludedChildIndexes.count(ChildIndex)) {
1208 LLVM_DEBUG(outs() <<
"Skip Child. Index: " << ChildIndex <<
"\n");
1212 std::unique_ptr<FileHandler> FH{
nullptr};
1213 std::unique_ptr<MemoryBuffer> Buf{
nullptr};
1215 if (BundlerConfig.
FilesType ==
"aocr" ||
1219 auto BinOrErr = C.getAsBinary();
1222 if (
auto Err = isNotObjectErrorInvalidFileType(BinOrErr.takeError()))
1228 FH = std::make_unique<BinaryFileHandler>(BundlerConfig);
1229 auto MR = C.getMemoryBufferRef();
1231 Buf = MemoryBuffer::getMemBuffer(*MR,
false);
1235 auto &Bin = BinOrErr.get();
1236 if (!Bin->isObject())
1238 auto Obj = std::unique_ptr<ObjectFile>(cast<ObjectFile>(Bin.release()));
1239 Buf = MemoryBuffer::getMemBuffer(Obj->getMemoryBufferRef(),
false);
1240 FH = std::make_unique<ObjectFileHandler>(std::move(Obj), BundlerConfig);
1243 if (Error Err = FH->ReadHeader(*Buf))
1247 return NameOrErr.takeError();
1248 while (*NameOrErr) {
1249 auto TT = **NameOrErr;
1250 if (TT == CurrBundle->first()) {
1252 if (Mode == OutputType::FileList) {
1256 auto EC = sys::fs::createTemporaryFile(TempFileNameBase, Ext,
1259 return createFileError(ChildFileName, EC);
1261 raw_fd_ostream ChildOS(ChildFileName, EC);
1263 return createFileError(ChildFileName, EC);
1265 if (Error Err = FH->ReadBundle(ChildOS, *Buf))
1268 if (ChildOS.has_error())
1269 return createFileError(ChildFileName, ChildOS.error());
1273 OS << ChildFileName <<
"\n";
1274 }
else if (Mode == OutputType::Object) {
1276 if (Error Err = FH->ReadBundle(OS, *Buf))
1278 }
else if (Mode == OutputType::Archive) {
1279 auto ChildNameOrErr = C.getName();
1280 if (!ChildNameOrErr)
1281 return ChildNameOrErr.takeError();
1285 raw_svector_ostream ChildOS{
Data};
1286 if (Error Err = FH->ReadBundle(ChildOS, *Buf))
1290 NewArchiveMember &
Member = ArMembers.emplace_back();
1291 std::string Name = (TT +
"." + *ChildNameOrErr).str();
1292 Member.Buf = MemoryBuffer::getMemBufferCopy(ChildOS.str(), Name);
1295 if (Error Err = FH->ReadBundleEnd(*Buf))
1298 NameOrErr = FH->ReadBundleStart(*Buf);
1300 return NameOrErr.takeError();
1306 if (Mode == OutputType::Archive) {
1315 ArMembers, SymtabWritingMode::NormalSymtab, ArKind,
1318 return NewAr.takeError();
1319 OS << NewAr.get()->getBuffer();
1321 return Error::success();
1325 ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs)
override {
1326 llvm_unreachable(
"unsupported for the ArchiveFileHandler");
1330 llvm_unreachable(
"unsupported for the ArchiveFileHandler");
1334 llvm_unreachable(
"unsupported for the ArchiveFileHandler");
1338 llvm_unreachable(
"unsupported for the ArchiveFileHandler");
1344 ReadTargetsFromChild(
const Archive::Child &C) {
1347 return BinOrErr.takeError();
1349 std::unique_ptr<Binary> &Bin = BinOrErr.get();
1350 auto Obj = std::unique_ptr<ObjectFile>(cast<ObjectFile>(Bin.release()));
1351 std::unique_ptr<MemoryBuffer> Buf =
1352 MemoryBuffer::getMemBuffer(Obj->getMemoryBufferRef(),
false);
1353 ObjectFileHandler OFH(std::move(Obj), BundlerConfig);
1354 if (Error Err = OFH.ReadHeader(*Buf))
1355 return {std::move(Err)};
1358 return NameOrErr.takeError();
1360 std::vector<std::string> Targets;
1361 while (*NameOrErr) {
1363 Targets.emplace_back((**NameOrErr).str());
1364 NameOrErr = OFH.ReadBundleStart(*Buf);
1366 return NameOrErr.takeError();
1375 CheckIfObjectFileContainsExcludedTargets(
const Archive::Child &C) {
1379 auto TargetNamesOrErr = ReadTargetsFromChild(C);
1380 if (!TargetNamesOrErr)
1381 return TargetNamesOrErr.takeError();
1383 auto TargetNames = TargetNamesOrErr.get();
1385 return std::any_of(TargetNames.begin(), TargetNames.end(),
1386 [&ExcludedTargets](
const std::string &
Target) {
1387 auto It = std::find(ExcludedTargets.begin(),
1388 ExcludedTargets.end(), Target);
1389 return It != ExcludedTargets.end();
1397 static std::unique_ptr<FileHandler>
1405 if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
1406 return std::make_unique<BinaryFileHandler>(BundlerConfig);
1410 return std::make_unique<ObjectFileHandler>(
1411 std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
1416 return FilesType ==
"ao" || FilesType ==
"aoo" || FilesType ==
"aocr" ||
1417 FilesType ==
"aocx";
1428 std::string FilesType = BundlerConfig.
FilesType;
1430 if (FilesType ==
"i")
1431 return std::make_unique<TextFileHandler>(
"//");
1432 if (FilesType ==
"ii")
1433 return std::make_unique<TextFileHandler>(
"//");
1434 if (FilesType ==
"cui")
1435 return std::make_unique<TextFileHandler>(
"//");
1436 if (FilesType ==
"hipi")
1437 return std::make_unique<TextFileHandler>(
"//");
1440 if (FilesType ==
"d")
1441 return std::make_unique<TextFileHandler>(
"#");
1442 if (FilesType ==
"ll")
1443 return std::make_unique<TextFileHandler>(
";");
1444 if (FilesType ==
"bc")
1445 return std::make_unique<BinaryFileHandler>(BundlerConfig);
1446 if (FilesType ==
"s")
1447 return std::make_unique<TextFileHandler>(
"#");
1448 if (FilesType ==
"o")
1450 if (FilesType ==
"a")
1452 if (FilesType ==
"gch")
1453 return std::make_unique<BinaryFileHandler>(BundlerConfig);
1454 if (FilesType ==
"ast")
1455 return std::make_unique<BinaryFileHandler>(BundlerConfig);
1457 return std::make_unique<ArchiveFileHandler>(BundlerConfig);
1459 return createStringError(errc::invalid_argument,
1460 "'" + FilesType +
"': invalid file type specified");
1464 if (llvm::compression::zstd::isAvailable()) {
1469 }
else if (llvm::compression::zlib::isAvailable()) {
1475 auto IgnoreEnvVarOpt =
1476 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_IGNORE_ENV_VAR");
1477 if (IgnoreEnvVarOpt.has_value() && IgnoreEnvVarOpt.value() ==
"1")
1480 auto VerboseEnvVarOpt = llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_VERBOSE");
1481 if (VerboseEnvVarOpt.has_value())
1482 Verbose = VerboseEnvVarOpt.value() ==
"1";
1484 auto CompressEnvVarOpt =
1485 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESS");
1486 if (CompressEnvVarOpt.has_value())
1487 Compress = CompressEnvVarOpt.value() ==
"1";
1489 auto CompressionLevelEnvVarOpt =
1490 llvm::sys::Process::GetEnv(
"OFFLOAD_BUNDLER_COMPRESSION_LEVEL");
1491 if (CompressionLevelEnvVarOpt.has_value()) {
1492 llvm::StringRef CompressionLevelStr = CompressionLevelEnvVarOpt.value();
1494 if (!CompressionLevelStr.getAsInteger(10,
Level))
1498 <<
"Warning: Invalid value for OFFLOAD_BUNDLER_COMPRESSION_LEVEL: "
1499 << CompressionLevelStr.str() <<
". Ignoring it.\n";
1505 std::string Num = std::to_string(
Value);
1506 int InsertPosition = Num.length() - 3;
1507 while (InsertPosition > 0) {
1508 Num.insert(InsertPosition,
",");
1509 InsertPosition -= 3;
1516 const llvm::MemoryBuffer &Input,
1518 if (!llvm::compression::zstd::isAvailable() &&
1519 !llvm::compression::zlib::isAvailable())
1520 return createStringError(llvm::inconvertibleErrorCode(),
1521 "Compression not supported");
1523 llvm::Timer HashTimer(
"Hash Calculation Timer",
"Hash calculation time",
1526 HashTimer.startTimer();
1528 llvm::MD5::MD5Result Result;
1529 Hash.update(Input.getBuffer());
1531 uint64_t TruncatedHash = Result.low();
1533 HashTimer.stopTimer();
1537 reinterpret_cast<const uint8_t *
>(Input.getBuffer().data()),
1538 Input.getBuffer().size());
1540 llvm::Timer CompressTimer(
"Compression Timer",
"Compression time",
1543 CompressTimer.startTimer();
1544 llvm::compression::compress(
P, BufferUint8, CompressedBuffer);
1546 CompressTimer.stopTimer();
1548 uint16_t CompressionMethod =
static_cast<uint16_t
>(
P.format);
1549 uint32_t UncompressedSize = Input.getBuffer().size();
1550 uint32_t TotalFileSize = MagicNumber.size() +
sizeof(TotalFileSize) +
1551 sizeof(Version) +
sizeof(CompressionMethod) +
1552 sizeof(UncompressedSize) +
sizeof(TruncatedHash) +
1553 CompressedBuffer.size();
1556 llvm::raw_svector_ostream OS(FinalBuffer);
1558 OS.write(
reinterpret_cast<const char *
>(&Version),
sizeof(Version));
1559 OS.write(
reinterpret_cast<const char *
>(&CompressionMethod),
1560 sizeof(CompressionMethod));
1561 OS.write(
reinterpret_cast<const char *
>(&TotalFileSize),
1562 sizeof(TotalFileSize));
1563 OS.write(
reinterpret_cast<const char *
>(&UncompressedSize),
1564 sizeof(UncompressedSize));
1565 OS.write(
reinterpret_cast<const char *
>(&TruncatedHash),
1566 sizeof(TruncatedHash));
1567 OS.write(
reinterpret_cast<const char *
>(CompressedBuffer.data()),
1568 CompressedBuffer.size());
1572 P.format == llvm::compression::Format::Zstd ?
"zstd" :
"zlib";
1573 double CompressionRate =
1574 static_cast<double>(UncompressedSize) / CompressedBuffer.size();
1575 double CompressionTimeSeconds = CompressTimer.getTotalTime().getWallTime();
1576 double CompressionSpeedMBs =
1577 (UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;
1579 llvm::errs() <<
"Compressed bundle format version: " << Version <<
"\n"
1580 <<
"Total file size (including headers): "
1582 <<
"Compression method used: " << MethodUsed <<
"\n"
1583 <<
"Compression level: " <<
P.level <<
"\n"
1584 <<
"Binary size before compression: "
1586 <<
"Binary size after compression: "
1588 <<
"Compression rate: "
1589 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1590 <<
"Compression ratio: "
1591 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1592 <<
"Compression speed: "
1593 << llvm::format(
"%.2lf MB/s", CompressionSpeedMBs) <<
"\n"
1594 <<
"Truncated MD5 hash: "
1595 << llvm::format_hex(TruncatedHash, 16) <<
"\n";
1597 return llvm::MemoryBuffer::getMemBufferCopy(
1598 llvm::StringRef(FinalBuffer.data(), FinalBuffer.size()));
1605 StringRef Blob = Input.getBuffer();
1607 if (Blob.size() < V1HeaderSize)
1608 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1610 if (llvm::identify_magic(Blob) !=
1611 llvm::file_magic::offload_bundle_compressed) {
1613 llvm::errs() <<
"Uncompressed bundle.\n";
1614 return llvm::MemoryBuffer::getMemBufferCopy(Blob);
1617 size_t CurrentOffset = MagicSize;
1619 uint16_t ThisVersion;
1620 memcpy(&ThisVersion, Blob.data() + CurrentOffset,
sizeof(uint16_t));
1621 CurrentOffset += VersionFieldSize;
1623 uint16_t CompressionMethod;
1624 memcpy(&CompressionMethod, Blob.data() + CurrentOffset,
sizeof(uint16_t));
1625 CurrentOffset += MethodFieldSize;
1627 uint32_t TotalFileSize;
1628 if (ThisVersion >= 2) {
1629 if (Blob.size() < V2HeaderSize)
1630 return createStringError(inconvertibleErrorCode(),
1631 "Compressed bundle header size too small");
1632 memcpy(&TotalFileSize, Blob.data() + CurrentOffset,
sizeof(uint32_t));
1633 CurrentOffset += FileSizeFieldSize;
1636 uint32_t UncompressedSize;
1637 memcpy(&UncompressedSize, Blob.data() + CurrentOffset,
sizeof(uint32_t));
1638 CurrentOffset += UncompressedSizeFieldSize;
1641 memcpy(&StoredHash, Blob.data() + CurrentOffset,
sizeof(
uint64_t));
1642 CurrentOffset += HashFieldSize;
1644 llvm::compression::Format CompressionFormat;
1645 if (CompressionMethod ==
1646 static_cast<uint16_t
>(llvm::compression::Format::Zlib))
1647 CompressionFormat = llvm::compression::Format::Zlib;
1648 else if (CompressionMethod ==
1649 static_cast<uint16_t
>(llvm::compression::Format::Zstd))
1650 CompressionFormat = llvm::compression::Format::Zstd;
1652 return createStringError(inconvertibleErrorCode(),
1653 "Unknown compressing method");
1655 llvm::Timer DecompressTimer(
"Decompression Timer",
"Decompression time",
1658 DecompressTimer.startTimer();
1661 StringRef CompressedData = Blob.substr(CurrentOffset);
1662 if (llvm::Error DecompressionError = llvm::compression::decompress(
1663 CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
1664 DecompressedData, UncompressedSize))
1665 return createStringError(inconvertibleErrorCode(),
1666 "Could not decompress embedded file contents: " +
1670 DecompressTimer.stopTimer();
1672 double DecompressionTimeSeconds =
1673 DecompressTimer.getTotalTime().getWallTime();
1676 llvm::Timer HashRecalcTimer(
"Hash Recalculation Timer",
1677 "Hash recalculation time",
1679 HashRecalcTimer.startTimer();
1681 llvm::MD5::MD5Result Result;
1683 DecompressedData.size()));
1685 uint64_t RecalculatedHash = Result.low();
1686 HashRecalcTimer.stopTimer();
1687 bool HashMatch = (StoredHash == RecalculatedHash);
1689 double CompressionRate =
1690 static_cast<double>(UncompressedSize) / CompressedData.size();
1691 double DecompressionSpeedMBs =
1692 (UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;
1694 llvm::errs() <<
"Compressed bundle format version: " << ThisVersion <<
"\n";
1695 if (ThisVersion >= 2)
1696 llvm::errs() <<
"Total file size (from header): "
1698 llvm::errs() <<
"Decompression method: "
1699 << (CompressionFormat == llvm::compression::Format::Zlib
1703 <<
"Size before decompression: "
1705 <<
"Size after decompression: "
1707 <<
"Compression rate: "
1708 << llvm::format(
"%.2lf", CompressionRate) <<
"\n"
1709 <<
"Compression ratio: "
1710 << llvm::format(
"%.2lf%%", 100.0 / CompressionRate) <<
"\n"
1711 <<
"Decompression speed: "
1712 << llvm::format(
"%.2lf MB/s", DecompressionSpeedMBs) <<
"\n"
1713 <<
"Stored hash: " << llvm::format_hex(StoredHash, 16) <<
"\n"
1714 <<
"Recalculated hash: "
1715 << llvm::format_hex(RecalculatedHash, 16) <<
"\n"
1716 <<
"Hashes match: " << (HashMatch ?
"Yes" :
"No") <<
"\n";
1719 return llvm::MemoryBuffer::getMemBufferCopy(
1720 llvm::toStringRef(DecompressedData));
1727 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1728 MemoryBuffer::getFileOrSTDIN(InputFileName);
1729 if (std::error_code EC = CodeOrErr.getError())
1730 return createFileError(InputFileName, EC);
1735 if (!DecompressedBufferOrErr)
1736 return createStringError(
1737 inconvertibleErrorCode(),
1738 "Failed to decompress input: " +
1741 MemoryBuffer &DecompressedInput = **DecompressedBufferOrErr;
1746 if (!FileHandlerOrErr)
1747 return FileHandlerOrErr.takeError();
1749 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1751 return FH->listBundleIDs(DecompressedInput);
1762 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1763 dbgs() <<
"Compatible: Exact match: \t[CodeObject: "
1764 << CodeObjectInfo.
str()
1765 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1773 "CodeObjectCompatibility",
1774 dbgs() <<
"Incompatible: Kind/Triple mismatch \t[CodeObject: "
1775 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1781 llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1783 CodeObjectInfo.
Triple, CodeObjectInfo.
TargetID, &CodeObjectFeatureMap);
1788 if (!TargetProc || !CodeObjectProc ||
1789 CodeObjectProc.value() != TargetProc.value()) {
1790 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1791 dbgs() <<
"Incompatible: Processor mismatch \t[CodeObject: "
1792 << CodeObjectInfo.
str()
1793 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1799 if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1800 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
1801 dbgs() <<
"Incompatible: CodeObject has more features "
1802 "than target \t[CodeObject: "
1803 << CodeObjectInfo.
str()
1804 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1812 for (
const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1813 auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1814 if (TargetFeature == TargetFeatureMap.end()) {
1816 "CodeObjectCompatibility",
1818 <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1819 "not matching with Target feature's ANY value \t[CodeObject: "
1820 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1823 }
else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1825 "CodeObjectCompatibility",
1826 dbgs() <<
"Incompatible: Value of CodeObject's non-ANY feature is "
1827 "not matching with Target feature's non-ANY value "
1829 << CodeObjectInfo.
str()
1830 <<
"]\t:\t[Target: " <<
TargetInfo.str() <<
"]\n");
1840 "CodeObjectCompatibility",
1841 dbgs() <<
"Compatible: Target IDs are compatible \t[CodeObject: "
1842 << CodeObjectInfo.
str() <<
"]\t:\t[Target: " <<
TargetInfo.str()
1853 return createStringError(errc::invalid_argument,
1854 "bundling is not supported for archives");
1858 llvm::raw_svector_ostream BufferStream(Buffer);
1864 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1865 MemoryBuffer::getFileOrSTDIN(I);
1866 if (std::error_code EC = CodeOrErr.getError())
1867 return createFileError(I, EC);
1868 InputBuffers.emplace_back(std::move(*CodeOrErr));
1873 "Host input index undefined??");
1878 if (!FileHandlerOrErr)
1879 return FileHandlerOrErr.takeError();
1881 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1885 if (Error Err = FH->WriteHeader(BufferStream, InputBuffers))
1890 auto Input = InputBuffers.begin();
1892 if (Error Err = FH->WriteBundleStart(BufferStream, Triple))
1894 if (Error Err = FH->WriteBundle(BufferStream, **Input))
1896 if (Error Err = FH->WriteBundleEnd(BufferStream, Triple))
1908 std::unique_ptr<llvm::MemoryBuffer> BufferMemory =
1909 llvm::MemoryBuffer::getMemBufferCopy(
1910 llvm::StringRef(Buffer.data(), Buffer.size()));
1915 if (
auto Error = CompressionResult.takeError())
1918 auto CompressedMemBuffer = std::move(CompressionResult.get());
1919 CompressedBuffer.assign(CompressedMemBuffer->getBufferStart(),
1920 CompressedMemBuffer->getBufferEnd());
1922 CompressedBuffer = Buffer;
1924 OutputFile.write(CompressedBuffer.data(), CompressedBuffer.size());
1926 return FH->finalizeOutputFile();
1932 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
1934 if (std::error_code EC = CodeOrErr.getError())
1940 if (!DecompressedBufferOrErr)
1941 return createStringError(
1942 inconvertibleErrorCode(),
1943 "Failed to decompress input: " +
1946 MemoryBuffer &Input = **DecompressedBufferOrErr;
1951 if (!FileHandlerOrErr)
1952 return FileHandlerOrErr.takeError();
1954 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
1961 if (Error Err = FH->ReadHeader(Input))
1965 StringMap<StringRef> Worklist;
1968 Worklist[Triple] = *Output;
1974 bool FoundHostBundle =
false;
1975 while (!Worklist.empty()) {
1977 FH->ReadBundleStart(Input);
1978 if (!CurTripleOrErr)
1979 return CurTripleOrErr.takeError();
1982 if (!*CurTripleOrErr)
1985 StringRef CurTriple = **CurTripleOrErr;
1986 assert(!CurTriple.empty());
1988 auto Output = Worklist.begin();
1989 for (
auto E = Worklist.end(); Output != E; Output++) {
1997 if (Output == Worklist.end())
2001 raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
2003 return createFileError((*Output).second, EC);
2004 if (Error Err = FH->ReadBundle(OutputFile, Input))
2006 if (Error Err = FH->ReadBundleEnd(Input))
2008 Worklist.erase(Output);
2012 if (OffloadInfo.hasHostKind())
2013 FoundHostBundle =
true;
2017 std::string ErrMsg =
"Can't find bundles for";
2018 std::set<StringRef> Sorted;
2019 for (
auto &E : Worklist)
2020 Sorted.insert(E.first());
2022 unsigned Last = Sorted.size() - 1;
2023 for (
auto &E : Sorted) {
2024 if (I != 0 &&
Last > 1)
2027 if (I ==
Last && I != 0)
2032 return createStringError(inconvertibleErrorCode(), ErrMsg);
2038 for (
auto &E : Worklist) {
2040 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
2042 return createFileError(E.second, EC);
2047 if (OffloadInfo.hasHostKind() &&
2049 OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
2051 return Error::success();
2058 return createStringError(inconvertibleErrorCode(),
2059 "Can't find bundle for the host target");
2062 for (
auto &E : Worklist) {
2064 raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
2066 return createFileError(E.second, EC);
2069 return Error::success();
2076 ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
2077 MemoryBuffer::getFileOrSTDIN(BundlerConfig.
InputFileNames.front());
2078 if (std::error_code EC = CodeOrErr.getError())
2079 return createFileError(BundlerConfig.
InputFileNames.front(), EC);
2080 MemoryBuffer &Input = *CodeOrErr.get();
2085 if (!FileHandlerOrErr)
2086 return FileHandlerOrErr.takeError();
2088 std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
2095 FH->SetTempFileNameBase(llvm::sys::path::stem(BundlerConfig.
InputFileNames.front()));
2098 if (Error Err = FH->ReadHeader(Input))
2099 return std::move(Err);
2101 StringRef triple = BundlerConfig.
TargetNames.front();
2108 FH->ReadBundleStart(Input);
2109 if (!CurTripleOrErr)
2110 return CurTripleOrErr.takeError();
2113 if (!*CurTripleOrErr)
2116 if (*CurTripleOrErr == triple) {
2125 return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
2139 if (!CompatibleTargets.empty()) {
2140 DEBUG_WITH_TYPE(
"CodeObjectCompatibility",
2141 dbgs() <<
"CompatibleTargets list should be empty\n");
2147 CompatibleTargets.push_back(
Target);
2149 return !CompatibleTargets.empty();
2159 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
2160 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
2161 MemoryBuffer::getFileOrSTDIN(ArchiveName,
true,
false);
2162 if (std::error_code EC = BufOrErr.getError())
2163 return createFileError(ArchiveName, EC);
2165 ArchiveBuffers.push_back(std::move(*BufOrErr));
2169 return LibOrErr.takeError();
2171 auto Archive = std::move(*LibOrErr);
2173 Error ArchiveErr = Error::success();
2174 auto ChildEnd = Archive->child_end();
2177 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
2178 ArchiveIter != ChildEnd; ++ArchiveIter) {
2181 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
2182 if (!ArchiveChildNameOrErr)
2183 return ArchiveChildNameOrErr.takeError();
2185 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
2186 if (!CodeObjectBufferRefOrErr)
2187 return CodeObjectBufferRefOrErr.takeError();
2189 auto CodeObjectBuffer =
2190 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
2194 if (!FileHandlerOrErr)
2195 return FileHandlerOrErr.takeError();
2197 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
2198 assert(FileHandler);
2200 std::set<StringRef> BundleIds;
2201 auto CodeObjectFileError =
2202 FileHandler->getBundleIDs(*CodeObjectBuffer, BundleIds);
2203 if (CodeObjectFileError)
2204 return CodeObjectFileError;
2207 if (ConflictingArchs) {
2208 std::string ErrMsg =
2209 Twine(
"conflicting TargetIDs [" + ConflictingArchs.value().first +
2210 ", " + ConflictingArchs.value().second +
"] found in " +
2211 ArchiveChildNameOrErr.get() +
" of " + ArchiveName)
2213 return createStringError(inconvertibleErrorCode(), ErrMsg);
2228 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
2232 StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
2235 StringMap<StringRef> TargetOutputFileNameMap;
2239 TargetOutputFileNameMap[
Target] = *Output;
2251 return ArchiveError;
2255 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
2256 MemoryBuffer::getFileOrSTDIN(IFName,
true,
false);
2257 if (std::error_code EC = BufOrErr.getError())
2260 ArchiveBuffers.push_back(std::move(*BufOrErr));
2264 return LibOrErr.takeError();
2266 auto Archive = std::move(*LibOrErr);
2268 Error ArchiveErr = Error::success();
2269 auto ChildEnd = Archive->child_end();
2272 for (
auto ArchiveIter = Archive->child_begin(ArchiveErr);
2273 ArchiveIter != ChildEnd; ++ArchiveIter) {
2276 auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
2277 if (!ArchiveChildNameOrErr)
2278 return ArchiveChildNameOrErr.takeError();
2280 StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
2282 auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
2283 if (!CodeObjectBufferRefOrErr)
2284 return CodeObjectBufferRefOrErr.takeError();
2286 auto TempCodeObjectBuffer =
2287 MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr,
false);
2293 if (!DecompressedBufferOrErr)
2294 return createStringError(
2295 inconvertibleErrorCode(),
2296 "Failed to decompress code object: " +
2299 MemoryBuffer &CodeObjectBuffer = **DecompressedBufferOrErr;
2303 if (!FileHandlerOrErr)
2304 return FileHandlerOrErr.takeError();
2306 std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
2307 assert(FileHandler &&
2308 "FileHandle creation failed for file in the archive!");
2310 if (Error ReadErr = FileHandler->ReadHeader(CodeObjectBuffer))
2314 FileHandler->ReadBundleStart(CodeObjectBuffer);
2315 if (!CurBundleIDOrErr)
2316 return CurBundleIDOrErr.takeError();
2318 std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
2320 if (!OptionalCurBundleID)
2322 StringRef CodeObject = *OptionalCurBundleID;
2326 while (!CodeObject.empty()) {
2331 std::string BundleData;
2332 raw_string_ostream DataStream(BundleData);
2333 if (Error Err = FileHandler->ReadBundle(DataStream, CodeObjectBuffer))
2336 for (
auto &CompatibleTarget : CompatibleTargets) {
2338 BundledObjectFileName.assign(BundledObjectFile);
2339 auto OutputBundleName =
2340 Twine(llvm::sys::path::stem(BundledObjectFileName) +
"-" +
2343 CodeObjectInfo.TargetID))
2347 std::replace(OutputBundleName.begin(), OutputBundleName.end(),
':',
2350 std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
2351 DataStream.str(), OutputBundleName);
2352 ArchiveBuffers.push_back(std::move(MemBuf));
2353 llvm::MemoryBufferRef MemBufRef =
2354 MemoryBufferRef(*(ArchiveBuffers.back()));
2358 if (!OutputArchivesMap.contains(CompatibleTarget)) {
2360 std::vector<NewArchiveMember> ArchiveMembers;
2361 ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
2362 OutputArchivesMap.insert_or_assign(CompatibleTarget,
2363 std::move(ArchiveMembers));
2365 OutputArchivesMap[CompatibleTarget].push_back(
2366 NewArchiveMember(MemBufRef));
2371 if (Error Err = FileHandler->ReadBundleEnd(CodeObjectBuffer))
2375 FileHandler->ReadBundleStart(CodeObjectBuffer);
2376 if (!NextTripleOrErr)
2377 return NextTripleOrErr.takeError();
2379 CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr :
"";
2383 assert(!ArchiveErr &&
"Error occurred while reading archive!");
2388 StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
2389 OutputArchivesMap.find(
Target);
2390 if (CurArchiveMembers != OutputArchivesMap.end()) {
2391 if (Error WriteErr = writeArchive(
FileName, CurArchiveMembers->getValue(),
2392 SymtabWritingMode::NormalSymtab,
2397 std::string ErrMsg =
2398 Twine(
"no compatible code object found for the target '" +
Target +
2399 "' in heterogeneous archive library: " + IFName)
2401 return createStringError(inconvertibleErrorCode(), ErrMsg);
2406 std::vector<llvm::NewArchiveMember> EmptyArchive;
2407 EmptyArchive.clear();
2408 if (Error WriteErr = writeArchive(
2409 FileName, EmptyArchive, SymtabWritingMode::NormalSymtab,
2415 return Error::success();
llvm::MachO::Target Target
static std::string getDeviceLibraryFileName(StringRef BundleFileName, StringRef Device)
static std::unique_ptr< FileHandler > CreateObjectFileHandler(MemoryBuffer &FirstInput, const OffloadBundlerConfig &BundlerConfig)
Return an appropriate object file handler.
#define SYMBOLS_SECTION_NAME
Section name which holds target symbol names.
static StringRef getDeviceFileExtension(StringRef Device, StringRef BundleFileName)
static bool FilesTypeIsArchive(const std::string &FilesType)
#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 Triple getTargetTriple(StringRef Target, const OffloadBundlerConfig &BC)
static llvm::TimerGroup ClangOffloadBundlerTimerGroup("Clang Offload Bundler Timer Group", "Timer group for clang offload bundler")
static Error CheckHeterogeneousArchive(StringRef ArchiveName, const OffloadBundlerConfig &BundlerConfig)
static bool FilesTypeIsArchiveToList(const std::string &FilesType)
static Archive::Kind getDefaultArchiveKindForHost()
static std::string formatWithCommas(unsigned long long Value)
static Expected< std::unique_ptr< FileHandler > > CreateFileHandler(MemoryBuffer &FirstInput, const OffloadBundlerConfig &BundlerConfig)
Return an appropriate handler given the input files and options.
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...
Defines version macros and version-related utility functions for Clang.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
Archive file handler. Only unbundling is supported so far.
Error ReadHeader(MemoryBuffer &Input) override
Expected< std::optional< StringRef > > ReadBundleStart(MemoryBuffer &Input) override
Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) override
Error WriteHeader(raw_ostream &OS, ArrayRef< std::unique_ptr< MemoryBuffer >> Inputs) override
Error ReadBundleEnd(MemoryBuffer &Input) override
~ArchiveFileHandler()=default
Error WriteBundle(raw_ostream &OS, MemoryBuffer &Input) override
Error WriteBundleEnd(raw_ostream &OS, StringRef TargetTriple) override
Error WriteBundleStart(raw_ostream &OS, StringRef TargetTriple) override
ArchiveFileHandler(const OffloadBundlerConfig &BC)
static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input, bool Verbose=false)
static llvm::Expected< std::unique_ptr< llvm::MemoryBuffer > > decompress(const llvm::MemoryBuffer &Input, bool Verbose=false)
llvm::compression::Format CompressionFormat
std::vector< std::string > OutputFileNames
std::vector< std::string > TargetNames
std::vector< std::string > ExcludedTargetNames
std::vector< std::string > 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.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
std::string toString(const til::SExpr *E)
The JSON file list parser is used to communicate input to InstallAPI.
@ Create
'create' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...
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.
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 ...
CudaArch StringToCudaArch(llvm::StringRef S)
llvm::Expected< bool > CheckBundledSection(const OffloadBundlerConfig &)
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
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
llvm::StringRef OffloadKind
bool isOffloadKindValid() const
const OffloadBundlerConfig & BundlerConfig