OffloadBundler.cpp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. //===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file
  10. /// This file implements an offload bundling API that bundles different files
  11. /// that relate with the same source code but different targets into a single
  12. /// one. Also the implements the opposite functionality, i.e. unbundle files
  13. /// previous created by this API.
  14. ///
  15. //===----------------------------------------------------------------------===//
  16. #include "clang/Driver/OffloadBundler.h"
  17. #include "clang/Basic/Cuda.h"
  18. #include "clang/Basic/TargetID.h"
  19. #include "clang/Basic/Version.h"
  20. #include "llvm/ADT/ArrayRef.h"
  21. #include "llvm/ADT/SmallString.h"
  22. #include "llvm/ADT/SmallVector.h"
  23. #include "llvm/ADT/StringMap.h"
  24. #include "llvm/ADT/StringRef.h"
  25. #include "llvm/ADT/Triple.h"
  26. #include "llvm/Object/Archive.h"
  27. #include "llvm/Object/ArchiveWriter.h"
  28. #include "llvm/Object/Binary.h"
  29. #include "llvm/Object/ObjectFile.h"
  30. #include "llvm/Support/Casting.h"
  31. #include "llvm/Support/Debug.h"
  32. #include "llvm/Support/EndianStream.h"
  33. #include "llvm/Support/Errc.h"
  34. #include "llvm/Support/Error.h"
  35. #include "llvm/Support/ErrorOr.h"
  36. #include "llvm/Support/FileSystem.h"
  37. #include "llvm/Support/Host.h"
  38. #include "llvm/Support/MemoryBuffer.h"
  39. #include "llvm/Support/Path.h"
  40. #include "llvm/Support/Program.h"
  41. #include "llvm/Support/Signals.h"
  42. #include "llvm/Support/StringSaver.h"
  43. #include "llvm/Support/WithColor.h"
  44. #include "llvm/Support/raw_ostream.h"
  45. #include <algorithm>
  46. #include <cassert>
  47. #include <cstddef>
  48. #include <cstdint>
  49. #include <forward_list>
  50. #include <memory>
  51. #include <set>
  52. #include <string>
  53. #include <system_error>
  54. #include <utility>
  55. using namespace llvm;
  56. using namespace llvm::object;
  57. using namespace clang;
  58. /// Magic string that marks the existence of offloading data.
  59. #define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
  60. OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
  61. const OffloadBundlerConfig &BC)
  62. : BundlerConfig(BC) {
  63. // TODO: Add error checking from ClangOffloadBundler.cpp
  64. auto TargetFeatures = Target.split(':');
  65. auto TripleOrGPU = TargetFeatures.first.rsplit('-');
  66. if (clang::StringToCudaArch(TripleOrGPU.second) != clang::CudaArch::UNKNOWN) {
  67. auto KindTriple = TripleOrGPU.first.split('-');
  68. this->OffloadKind = KindTriple.first;
  69. this->Triple = llvm::Triple(KindTriple.second);
  70. this->TargetID = Target.substr(Target.find(TripleOrGPU.second));
  71. } else {
  72. auto KindTriple = TargetFeatures.first.split('-');
  73. this->OffloadKind = KindTriple.first;
  74. this->Triple = llvm::Triple(KindTriple.second);
  75. this->TargetID = "";
  76. }
  77. }
  78. bool OffloadTargetInfo::hasHostKind() const {
  79. return this->OffloadKind == "host";
  80. }
  81. bool OffloadTargetInfo::isOffloadKindValid() const {
  82. return OffloadKind == "host" || OffloadKind == "openmp" ||
  83. OffloadKind == "hip" || OffloadKind == "hipv4";
  84. }
  85. bool OffloadTargetInfo::isOffloadKindCompatible(
  86. const StringRef TargetOffloadKind) const {
  87. if (OffloadKind == TargetOffloadKind)
  88. return true;
  89. if (BundlerConfig.HipOpenmpCompatible) {
  90. bool HIPCompatibleWithOpenMP = OffloadKind.startswith_insensitive("hip") &&
  91. TargetOffloadKind == "openmp";
  92. bool OpenMPCompatibleWithHIP =
  93. OffloadKind == "openmp" &&
  94. TargetOffloadKind.startswith_insensitive("hip");
  95. return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
  96. }
  97. return false;
  98. }
  99. bool OffloadTargetInfo::isTripleValid() const {
  100. return !Triple.str().empty() && Triple.getArch() != Triple::UnknownArch;
  101. }
  102. bool OffloadTargetInfo::operator==(const OffloadTargetInfo &Target) const {
  103. return OffloadKind == Target.OffloadKind &&
  104. Triple.isCompatibleWith(Target.Triple) && TargetID == Target.TargetID;
  105. }
  106. std::string OffloadTargetInfo::str() const {
  107. return Twine(OffloadKind + "-" + Triple.str() + "-" + TargetID).str();
  108. }
  109. static StringRef getDeviceFileExtension(StringRef Device,
  110. StringRef BundleFileName) {
  111. if (Device.contains("gfx"))
  112. return ".bc";
  113. if (Device.contains("sm_"))
  114. return ".cubin";
  115. return sys::path::extension(BundleFileName);
  116. }
  117. static std::string getDeviceLibraryFileName(StringRef BundleFileName,
  118. StringRef Device) {
  119. StringRef LibName = sys::path::stem(BundleFileName);
  120. StringRef Extension = getDeviceFileExtension(Device, BundleFileName);
  121. std::string Result;
  122. Result += LibName;
  123. Result += Extension;
  124. return Result;
  125. }
  126. /// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
  127. /// target \p TargetInfo.
  128. /// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
  129. bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
  130. const OffloadTargetInfo &TargetInfo) {
  131. // Compatible in case of exact match.
  132. if (CodeObjectInfo == TargetInfo) {
  133. DEBUG_WITH_TYPE("CodeObjectCompatibility",
  134. dbgs() << "Compatible: Exact match: \t[CodeObject: "
  135. << CodeObjectInfo.str()
  136. << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
  137. return true;
  138. }
  139. // Incompatible if Kinds or Triples mismatch.
  140. if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
  141. !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
  142. DEBUG_WITH_TYPE(
  143. "CodeObjectCompatibility",
  144. dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
  145. << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
  146. << "]\n");
  147. return false;
  148. }
  149. // Incompatible if target IDs are incompatible.
  150. if (!clang::isCompatibleTargetID(CodeObjectInfo.TargetID,
  151. TargetInfo.TargetID)) {
  152. DEBUG_WITH_TYPE(
  153. "CodeObjectCompatibility",
  154. dbgs() << "Incompatible: target IDs are incompatible \t[CodeObject: "
  155. << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
  156. << "]\n");
  157. return false;
  158. }
  159. DEBUG_WITH_TYPE(
  160. "CodeObjectCompatibility",
  161. dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
  162. << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
  163. << "]\n");
  164. return true;
  165. }
  166. namespace {
  167. /// Generic file handler interface.
  168. class FileHandler {
  169. public:
  170. struct BundleInfo {
  171. StringRef BundleID;
  172. };
  173. FileHandler() {}
  174. virtual ~FileHandler() {}
  175. /// Update the file handler with information from the header of the bundled
  176. /// file.
  177. virtual Error ReadHeader(MemoryBuffer &Input) = 0;
  178. /// Read the marker of the next bundled to be read in the file. The bundle
  179. /// name is returned if there is one in the file, or `std::nullopt` if there
  180. /// are no more bundles to be read.
  181. virtual Expected<std::optional<StringRef>>
  182. ReadBundleStart(MemoryBuffer &Input) = 0;
  183. /// Read the marker that closes the current bundle.
  184. virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
  185. /// Read the current bundle and write the result into the stream \a OS.
  186. virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
  187. /// Write the header of the bundled file to \a OS based on the information
  188. /// gathered from \a Inputs.
  189. virtual Error WriteHeader(raw_fd_ostream &OS,
  190. ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
  191. /// Write the marker that initiates a bundle for the triple \a TargetTriple to
  192. /// \a OS.
  193. virtual Error WriteBundleStart(raw_fd_ostream &OS,
  194. StringRef TargetTriple) = 0;
  195. /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
  196. /// OS.
  197. virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
  198. /// Write the bundle from \a Input into \a OS.
  199. virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
  200. /// List bundle IDs in \a Input.
  201. virtual Error listBundleIDs(MemoryBuffer &Input) {
  202. if (Error Err = ReadHeader(Input))
  203. return Err;
  204. return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
  205. llvm::outs() << Info.BundleID << '\n';
  206. Error Err = listBundleIDsCallback(Input, Info);
  207. if (Err)
  208. return Err;
  209. return Error::success();
  210. });
  211. }
  212. /// For each bundle in \a Input, do \a Func.
  213. Error forEachBundle(MemoryBuffer &Input,
  214. std::function<Error(const BundleInfo &)> Func) {
  215. while (true) {
  216. Expected<std::optional<StringRef>> CurTripleOrErr =
  217. ReadBundleStart(Input);
  218. if (!CurTripleOrErr)
  219. return CurTripleOrErr.takeError();
  220. // No more bundles.
  221. if (!*CurTripleOrErr)
  222. break;
  223. StringRef CurTriple = **CurTripleOrErr;
  224. assert(!CurTriple.empty());
  225. BundleInfo Info{CurTriple};
  226. if (Error Err = Func(Info))
  227. return Err;
  228. }
  229. return Error::success();
  230. }
  231. protected:
  232. virtual Error listBundleIDsCallback(MemoryBuffer &Input,
  233. const BundleInfo &Info) {
  234. return Error::success();
  235. }
  236. };
  237. /// Handler for binary files. The bundled file will have the following format
  238. /// (all integers are stored in little-endian format):
  239. ///
  240. /// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
  241. ///
  242. /// NumberOfOffloadBundles (8-byte integer)
  243. ///
  244. /// OffsetOfBundle1 (8-byte integer)
  245. /// SizeOfBundle1 (8-byte integer)
  246. /// NumberOfBytesInTripleOfBundle1 (8-byte integer)
  247. /// TripleOfBundle1 (byte length defined before)
  248. ///
  249. /// ...
  250. ///
  251. /// OffsetOfBundleN (8-byte integer)
  252. /// SizeOfBundleN (8-byte integer)
  253. /// NumberOfBytesInTripleOfBundleN (8-byte integer)
  254. /// TripleOfBundleN (byte length defined before)
  255. ///
  256. /// Bundle1
  257. /// ...
  258. /// BundleN
  259. /// Read 8-byte integers from a buffer in little-endian format.
  260. static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
  261. return llvm::support::endian::read64le(Buffer.data() + pos);
  262. }
  263. /// Write 8-byte integers to a buffer in little-endian format.
  264. static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
  265. llvm::support::endian::write(OS, Val, llvm::support::little);
  266. }
  267. class BinaryFileHandler final : public FileHandler {
  268. /// Information about the bundles extracted from the header.
  269. struct BinaryBundleInfo final : public BundleInfo {
  270. /// Size of the bundle.
  271. uint64_t Size = 0u;
  272. /// Offset at which the bundle starts in the bundled file.
  273. uint64_t Offset = 0u;
  274. BinaryBundleInfo() {}
  275. BinaryBundleInfo(uint64_t Size, uint64_t Offset)
  276. : Size(Size), Offset(Offset) {}
  277. };
  278. /// Map between a triple and the corresponding bundle information.
  279. StringMap<BinaryBundleInfo> BundlesInfo;
  280. /// Iterator for the bundle information that is being read.
  281. StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
  282. StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
  283. /// Current bundle target to be written.
  284. std::string CurWriteBundleTarget;
  285. /// Configuration options and arrays for this bundler job
  286. const OffloadBundlerConfig &BundlerConfig;
  287. public:
  288. // TODO: Add error checking from ClangOffloadBundler.cpp
  289. BinaryFileHandler(const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
  290. ~BinaryFileHandler() final {}
  291. Error ReadHeader(MemoryBuffer &Input) final {
  292. StringRef FC = Input.getBuffer();
  293. // Initialize the current bundle with the end of the container.
  294. CurBundleInfo = BundlesInfo.end();
  295. // Check if buffer is smaller than magic string.
  296. size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
  297. if (ReadChars > FC.size())
  298. return Error::success();
  299. // Check if no magic was found.
  300. StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
  301. if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
  302. return Error::success();
  303. // Read number of bundles.
  304. if (ReadChars + 8 > FC.size())
  305. return Error::success();
  306. uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
  307. ReadChars += 8;
  308. // Read bundle offsets, sizes and triples.
  309. for (uint64_t i = 0; i < NumberOfBundles; ++i) {
  310. // Read offset.
  311. if (ReadChars + 8 > FC.size())
  312. return Error::success();
  313. uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
  314. ReadChars += 8;
  315. // Read size.
  316. if (ReadChars + 8 > FC.size())
  317. return Error::success();
  318. uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
  319. ReadChars += 8;
  320. // Read triple size.
  321. if (ReadChars + 8 > FC.size())
  322. return Error::success();
  323. uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
  324. ReadChars += 8;
  325. // Read triple.
  326. if (ReadChars + TripleSize > FC.size())
  327. return Error::success();
  328. StringRef Triple(&FC.data()[ReadChars], TripleSize);
  329. ReadChars += TripleSize;
  330. // Check if the offset and size make sense.
  331. if (!Offset || Offset + Size > FC.size())
  332. return Error::success();
  333. assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
  334. "Triple is duplicated??");
  335. BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
  336. }
  337. // Set the iterator to where we will start to read.
  338. CurBundleInfo = BundlesInfo.end();
  339. NextBundleInfo = BundlesInfo.begin();
  340. return Error::success();
  341. }
  342. Expected<std::optional<StringRef>>
  343. ReadBundleStart(MemoryBuffer &Input) final {
  344. if (NextBundleInfo == BundlesInfo.end())
  345. return std::nullopt;
  346. CurBundleInfo = NextBundleInfo++;
  347. return CurBundleInfo->first();
  348. }
  349. Error ReadBundleEnd(MemoryBuffer &Input) final {
  350. assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
  351. return Error::success();
  352. }
  353. Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
  354. assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
  355. StringRef FC = Input.getBuffer();
  356. OS.write(FC.data() + CurBundleInfo->second.Offset,
  357. CurBundleInfo->second.Size);
  358. return Error::success();
  359. }
  360. Error WriteHeader(raw_fd_ostream &OS,
  361. ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
  362. // Compute size of the header.
  363. uint64_t HeaderSize = 0;
  364. HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
  365. HeaderSize += 8; // Number of Bundles
  366. for (auto &T : BundlerConfig.TargetNames) {
  367. HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
  368. HeaderSize += T.size(); // The triple.
  369. }
  370. // Write to the buffer the header.
  371. OS << OFFLOAD_BUNDLER_MAGIC_STR;
  372. Write8byteIntegerToBuffer(OS, BundlerConfig.TargetNames.size());
  373. unsigned Idx = 0;
  374. for (auto &T : BundlerConfig.TargetNames) {
  375. MemoryBuffer &MB = *Inputs[Idx++];
  376. HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);
  377. // Bundle offset.
  378. Write8byteIntegerToBuffer(OS, HeaderSize);
  379. // Size of the bundle (adds to the next bundle's offset)
  380. Write8byteIntegerToBuffer(OS, MB.getBufferSize());
  381. BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
  382. HeaderSize += MB.getBufferSize();
  383. // Size of the triple
  384. Write8byteIntegerToBuffer(OS, T.size());
  385. // Triple
  386. OS << T;
  387. }
  388. return Error::success();
  389. }
  390. Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
  391. CurWriteBundleTarget = TargetTriple.str();
  392. return Error::success();
  393. }
  394. Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
  395. return Error::success();
  396. }
  397. Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
  398. auto BI = BundlesInfo[CurWriteBundleTarget];
  399. OS.seek(BI.Offset);
  400. OS.write(Input.getBufferStart(), Input.getBufferSize());
  401. return Error::success();
  402. }
  403. };
  404. // This class implements a list of temporary files that are removed upon
  405. // object destruction.
  406. class TempFileHandlerRAII {
  407. public:
  408. ~TempFileHandlerRAII() {
  409. for (const auto &File : Files)
  410. sys::fs::remove(File);
  411. }
  412. // Creates temporary file with given contents.
  413. Expected<StringRef> Create(std::optional<ArrayRef<char>> Contents) {
  414. SmallString<128u> File;
  415. if (std::error_code EC =
  416. sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))
  417. return createFileError(File, EC);
  418. Files.push_front(File);
  419. if (Contents) {
  420. std::error_code EC;
  421. raw_fd_ostream OS(File, EC);
  422. if (EC)
  423. return createFileError(File, EC);
  424. OS.write(Contents->data(), Contents->size());
  425. }
  426. return Files.front().str();
  427. }
  428. private:
  429. std::forward_list<SmallString<128u>> Files;
  430. };
  431. /// Handler for object files. The bundles are organized by sections with a
  432. /// designated name.
  433. ///
  434. /// To unbundle, we just copy the contents of the designated section.
  435. class ObjectFileHandler final : public FileHandler {
  436. /// The object file we are currently dealing with.
  437. std::unique_ptr<ObjectFile> Obj;
  438. /// Return the input file contents.
  439. StringRef getInputFileContents() const { return Obj->getData(); }
  440. /// Return bundle name (<kind>-<triple>) if the provided section is an offload
  441. /// section.
  442. static Expected<std::optional<StringRef>>
  443. IsOffloadSection(SectionRef CurSection) {
  444. Expected<StringRef> NameOrErr = CurSection.getName();
  445. if (!NameOrErr)
  446. return NameOrErr.takeError();
  447. // If it does not start with the reserved suffix, just skip this section.
  448. if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
  449. return std::nullopt;
  450. // Return the triple that is right after the reserved prefix.
  451. return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
  452. }
  453. /// Total number of inputs.
  454. unsigned NumberOfInputs = 0;
  455. /// Total number of processed inputs, i.e, inputs that were already
  456. /// read from the buffers.
  457. unsigned NumberOfProcessedInputs = 0;
  458. /// Iterator of the current and next section.
  459. section_iterator CurrentSection;
  460. section_iterator NextSection;
  461. /// Configuration options and arrays for this bundler job
  462. const OffloadBundlerConfig &BundlerConfig;
  463. public:
  464. // TODO: Add error checking from ClangOffloadBundler.cpp
  465. ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
  466. const OffloadBundlerConfig &BC)
  467. : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
  468. NextSection(Obj->section_begin()), BundlerConfig(BC) {}
  469. ~ObjectFileHandler() final {}
  470. Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
  471. Expected<std::optional<StringRef>>
  472. ReadBundleStart(MemoryBuffer &Input) final {
  473. while (NextSection != Obj->section_end()) {
  474. CurrentSection = NextSection;
  475. ++NextSection;
  476. // Check if the current section name starts with the reserved prefix. If
  477. // so, return the triple.
  478. Expected<std::optional<StringRef>> TripleOrErr =
  479. IsOffloadSection(*CurrentSection);
  480. if (!TripleOrErr)
  481. return TripleOrErr.takeError();
  482. if (*TripleOrErr)
  483. return **TripleOrErr;
  484. }
  485. return std::nullopt;
  486. }
  487. Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
  488. Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
  489. Expected<StringRef> ContentOrErr = CurrentSection->getContents();
  490. if (!ContentOrErr)
  491. return ContentOrErr.takeError();
  492. StringRef Content = *ContentOrErr;
  493. // Copy fat object contents to the output when extracting host bundle.
  494. if (Content.size() == 1u && Content.front() == 0)
  495. Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
  496. OS.write(Content.data(), Content.size());
  497. return Error::success();
  498. }
  499. Error WriteHeader(raw_fd_ostream &OS,
  500. ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
  501. assert(BundlerConfig.HostInputIndex != ~0u &&
  502. "Host input index not defined.");
  503. // Record number of inputs.
  504. NumberOfInputs = Inputs.size();
  505. return Error::success();
  506. }
  507. Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
  508. ++NumberOfProcessedInputs;
  509. return Error::success();
  510. }
  511. Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
  512. assert(NumberOfProcessedInputs <= NumberOfInputs &&
  513. "Processing more inputs that actually exist!");
  514. assert(BundlerConfig.HostInputIndex != ~0u &&
  515. "Host input index not defined.");
  516. // If this is not the last output, we don't have to do anything.
  517. if (NumberOfProcessedInputs != NumberOfInputs)
  518. return Error::success();
  519. // We will use llvm-objcopy to add target objects sections to the output
  520. // fat object. These sections should have 'exclude' flag set which tells
  521. // link editor to remove them from linker inputs when linking executable or
  522. // shared library.
  523. assert(BundlerConfig.ObjcopyPath != "" &&
  524. "llvm-objcopy path not specified");
  525. // We write to the output file directly. So, we close it and use the name
  526. // to pass down to llvm-objcopy.
  527. OS.close();
  528. // Temporary files that need to be removed.
  529. TempFileHandlerRAII TempFiles;
  530. // Compose llvm-objcopy command line for add target objects' sections with
  531. // appropriate flags.
  532. BumpPtrAllocator Alloc;
  533. StringSaver SS{Alloc};
  534. SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
  535. for (unsigned I = 0; I < NumberOfInputs; ++I) {
  536. StringRef InputFile = BundlerConfig.InputFileNames[I];
  537. if (I == BundlerConfig.HostInputIndex) {
  538. // Special handling for the host bundle. We do not need to add a
  539. // standard bundle for the host object since we are going to use fat
  540. // object as a host object. Therefore use dummy contents (one zero byte)
  541. // when creating section for the host bundle.
  542. Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
  543. if (!TempFileOrErr)
  544. return TempFileOrErr.takeError();
  545. InputFile = *TempFileOrErr;
  546. }
  547. ObjcopyArgs.push_back(
  548. SS.save(Twine("--add-section=") + OFFLOAD_BUNDLER_MAGIC_STR +
  549. BundlerConfig.TargetNames[I] + "=" + InputFile));
  550. ObjcopyArgs.push_back(
  551. SS.save(Twine("--set-section-flags=") + OFFLOAD_BUNDLER_MAGIC_STR +
  552. BundlerConfig.TargetNames[I] + "=readonly,exclude"));
  553. }
  554. ObjcopyArgs.push_back("--");
  555. ObjcopyArgs.push_back(
  556. BundlerConfig.InputFileNames[BundlerConfig.HostInputIndex]);
  557. ObjcopyArgs.push_back(BundlerConfig.OutputFileNames.front());
  558. if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
  559. return Err;
  560. return Error::success();
  561. }
  562. Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
  563. return Error::success();
  564. }
  565. private:
  566. Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
  567. // If the user asked for the commands to be printed out, we do that
  568. // instead of executing it.
  569. if (BundlerConfig.PrintExternalCommands) {
  570. errs() << "\"" << Objcopy << "\"";
  571. for (StringRef Arg : drop_begin(Args, 1))
  572. errs() << " \"" << Arg << "\"";
  573. errs() << "\n";
  574. } else {
  575. if (sys::ExecuteAndWait(Objcopy, Args))
  576. return createStringError(inconvertibleErrorCode(),
  577. "'llvm-objcopy' tool failed");
  578. }
  579. return Error::success();
  580. }
  581. };
  582. /// Handler for text files. The bundled file will have the following format.
  583. ///
  584. /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
  585. /// Bundle 1
  586. /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
  587. /// ...
  588. /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
  589. /// Bundle N
  590. /// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
  591. class TextFileHandler final : public FileHandler {
  592. /// String that begins a line comment.
  593. StringRef Comment;
  594. /// String that initiates a bundle.
  595. std::string BundleStartString;
  596. /// String that closes a bundle.
  597. std::string BundleEndString;
  598. /// Number of chars read from input.
  599. size_t ReadChars = 0u;
  600. protected:
  601. Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
  602. Expected<std::optional<StringRef>>
  603. ReadBundleStart(MemoryBuffer &Input) final {
  604. StringRef FC = Input.getBuffer();
  605. // Find start of the bundle.
  606. ReadChars = FC.find(BundleStartString, ReadChars);
  607. if (ReadChars == FC.npos)
  608. return std::nullopt;
  609. // Get position of the triple.
  610. size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
  611. // Get position that closes the triple.
  612. size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
  613. if (TripleEnd == FC.npos)
  614. return std::nullopt;
  615. // Next time we read after the new line.
  616. ++ReadChars;
  617. return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
  618. }
  619. Error ReadBundleEnd(MemoryBuffer &Input) final {
  620. StringRef FC = Input.getBuffer();
  621. // Read up to the next new line.
  622. assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
  623. size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
  624. if (TripleEnd != FC.npos)
  625. // Next time we read after the new line.
  626. ++ReadChars;
  627. return Error::success();
  628. }
  629. Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
  630. StringRef FC = Input.getBuffer();
  631. size_t BundleStart = ReadChars;
  632. // Find end of the bundle.
  633. size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
  634. StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
  635. OS << Bundle;
  636. return Error::success();
  637. }
  638. Error WriteHeader(raw_fd_ostream &OS,
  639. ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
  640. return Error::success();
  641. }
  642. Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
  643. OS << BundleStartString << TargetTriple << "\n";
  644. return Error::success();
  645. }
  646. Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
  647. OS << BundleEndString << TargetTriple << "\n";
  648. return Error::success();
  649. }
  650. Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
  651. OS << Input.getBuffer();
  652. return Error::success();
  653. }
  654. public:
  655. TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
  656. BundleStartString =
  657. "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
  658. BundleEndString =
  659. "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
  660. }
  661. Error listBundleIDsCallback(MemoryBuffer &Input,
  662. const BundleInfo &Info) final {
  663. // TODO: To list bundle IDs in a bundled text file we need to go through
  664. // all bundles. The format of bundled text file may need to include a
  665. // header if the performance of listing bundle IDs of bundled text file is
  666. // important.
  667. ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
  668. if (Error Err = ReadBundleEnd(Input))
  669. return Err;
  670. return Error::success();
  671. }
  672. };
  673. } // namespace
  674. /// Return an appropriate object file handler. We use the specific object
  675. /// handler if we know how to deal with that format, otherwise we use a default
  676. /// binary file handler.
  677. static std::unique_ptr<FileHandler>
  678. CreateObjectFileHandler(MemoryBuffer &FirstInput,
  679. const OffloadBundlerConfig &BundlerConfig) {
  680. // Check if the input file format is one that we know how to deal with.
  681. Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
  682. // We only support regular object files. If failed to open the input as a
  683. // known binary or this is not an object file use the default binary handler.
  684. if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
  685. return std::make_unique<BinaryFileHandler>(BundlerConfig);
  686. // Otherwise create an object file handler. The handler will be owned by the
  687. // client of this function.
  688. return std::make_unique<ObjectFileHandler>(
  689. std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
  690. BundlerConfig);
  691. }
  692. /// Return an appropriate handler given the input files and options.
  693. static Expected<std::unique_ptr<FileHandler>>
  694. CreateFileHandler(MemoryBuffer &FirstInput,
  695. const OffloadBundlerConfig &BundlerConfig) {
  696. std::string FilesType = BundlerConfig.FilesType;
  697. if (FilesType == "i")
  698. return std::make_unique<TextFileHandler>(/*Comment=*/"//");
  699. if (FilesType == "ii")
  700. return std::make_unique<TextFileHandler>(/*Comment=*/"//");
  701. if (FilesType == "cui")
  702. return std::make_unique<TextFileHandler>(/*Comment=*/"//");
  703. if (FilesType == "hipi")
  704. return std::make_unique<TextFileHandler>(/*Comment=*/"//");
  705. // TODO: `.d` should be eventually removed once `-M` and its variants are
  706. // handled properly in offload compilation.
  707. if (FilesType == "d")
  708. return std::make_unique<TextFileHandler>(/*Comment=*/"#");
  709. if (FilesType == "ll")
  710. return std::make_unique<TextFileHandler>(/*Comment=*/";");
  711. if (FilesType == "bc")
  712. return std::make_unique<BinaryFileHandler>(BundlerConfig);
  713. if (FilesType == "s")
  714. return std::make_unique<TextFileHandler>(/*Comment=*/"#");
  715. if (FilesType == "o")
  716. return CreateObjectFileHandler(FirstInput, BundlerConfig);
  717. if (FilesType == "a")
  718. return CreateObjectFileHandler(FirstInput, BundlerConfig);
  719. if (FilesType == "gch")
  720. return std::make_unique<BinaryFileHandler>(BundlerConfig);
  721. if (FilesType == "ast")
  722. return std::make_unique<BinaryFileHandler>(BundlerConfig);
  723. return createStringError(errc::invalid_argument,
  724. "'" + FilesType + "': invalid file type specified");
  725. }
  726. // List bundle IDs. Return true if an error was found.
  727. Error OffloadBundler::ListBundleIDsInFile(
  728. StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig) {
  729. // Open Input file.
  730. ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
  731. MemoryBuffer::getFileOrSTDIN(InputFileName);
  732. if (std::error_code EC = CodeOrErr.getError())
  733. return createFileError(InputFileName, EC);
  734. MemoryBuffer &Input = **CodeOrErr;
  735. // Select the right files handler.
  736. Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
  737. CreateFileHandler(Input, BundlerConfig);
  738. if (!FileHandlerOrErr)
  739. return FileHandlerOrErr.takeError();
  740. std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
  741. assert(FH);
  742. return FH->listBundleIDs(Input);
  743. }
  744. /// Bundle the files. Return true if an error was found.
  745. Error OffloadBundler::BundleFiles() {
  746. std::error_code EC;
  747. // Create output file.
  748. raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC,
  749. sys::fs::OF_None);
  750. if (EC)
  751. return createFileError(BundlerConfig.OutputFileNames.front(), EC);
  752. // Open input files.
  753. SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
  754. InputBuffers.reserve(BundlerConfig.InputFileNames.size());
  755. for (auto &I : BundlerConfig.InputFileNames) {
  756. ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
  757. MemoryBuffer::getFileOrSTDIN(I);
  758. if (std::error_code EC = CodeOrErr.getError())
  759. return createFileError(I, EC);
  760. InputBuffers.emplace_back(std::move(*CodeOrErr));
  761. }
  762. // Get the file handler. We use the host buffer as reference.
  763. assert((BundlerConfig.HostInputIndex != ~0u || BundlerConfig.AllowNoHost) &&
  764. "Host input index undefined??");
  765. Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = CreateFileHandler(
  766. *InputBuffers[BundlerConfig.AllowNoHost ? 0
  767. : BundlerConfig.HostInputIndex],
  768. BundlerConfig);
  769. if (!FileHandlerOrErr)
  770. return FileHandlerOrErr.takeError();
  771. std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
  772. assert(FH);
  773. // Write header.
  774. if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
  775. return Err;
  776. // Write all bundles along with the start/end markers. If an error was found
  777. // writing the end of the bundle component, abort the bundle writing.
  778. auto Input = InputBuffers.begin();
  779. for (auto &Triple : BundlerConfig.TargetNames) {
  780. if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
  781. return Err;
  782. if (Error Err = FH->WriteBundle(OutputFile, **Input))
  783. return Err;
  784. if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
  785. return Err;
  786. ++Input;
  787. }
  788. return Error::success();
  789. }
  790. // Unbundle the files. Return true if an error was found.
  791. Error OffloadBundler::UnbundleFiles() {
  792. // Open Input file.
  793. ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
  794. MemoryBuffer::getFileOrSTDIN(BundlerConfig.InputFileNames.front());
  795. if (std::error_code EC = CodeOrErr.getError())
  796. return createFileError(BundlerConfig.InputFileNames.front(), EC);
  797. MemoryBuffer &Input = **CodeOrErr;
  798. // Select the right files handler.
  799. Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
  800. CreateFileHandler(Input, BundlerConfig);
  801. if (!FileHandlerOrErr)
  802. return FileHandlerOrErr.takeError();
  803. std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
  804. assert(FH);
  805. // Read the header of the bundled file.
  806. if (Error Err = FH->ReadHeader(Input))
  807. return Err;
  808. // Create a work list that consist of the map triple/output file.
  809. StringMap<StringRef> Worklist;
  810. auto Output = BundlerConfig.OutputFileNames.begin();
  811. for (auto &Triple : BundlerConfig.TargetNames) {
  812. Worklist[Triple] = *Output;
  813. ++Output;
  814. }
  815. // Read all the bundles that are in the work list. If we find no bundles we
  816. // assume the file is meant for the host target.
  817. bool FoundHostBundle = false;
  818. while (!Worklist.empty()) {
  819. Expected<std::optional<StringRef>> CurTripleOrErr =
  820. FH->ReadBundleStart(Input);
  821. if (!CurTripleOrErr)
  822. return CurTripleOrErr.takeError();
  823. // We don't have more bundles.
  824. if (!*CurTripleOrErr)
  825. break;
  826. StringRef CurTriple = **CurTripleOrErr;
  827. assert(!CurTriple.empty());
  828. auto Output = Worklist.begin();
  829. for (auto E = Worklist.end(); Output != E; Output++) {
  830. if (isCodeObjectCompatible(
  831. OffloadTargetInfo(CurTriple, BundlerConfig),
  832. OffloadTargetInfo((*Output).first(), BundlerConfig))) {
  833. break;
  834. }
  835. }
  836. if (Output == Worklist.end())
  837. continue;
  838. // Check if the output file can be opened and copy the bundle to it.
  839. std::error_code EC;
  840. raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
  841. if (EC)
  842. return createFileError((*Output).second, EC);
  843. if (Error Err = FH->ReadBundle(OutputFile, Input))
  844. return Err;
  845. if (Error Err = FH->ReadBundleEnd(Input))
  846. return Err;
  847. Worklist.erase(Output);
  848. // Record if we found the host bundle.
  849. auto OffloadInfo = OffloadTargetInfo(CurTriple, BundlerConfig);
  850. if (OffloadInfo.hasHostKind())
  851. FoundHostBundle = true;
  852. }
  853. if (!BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
  854. std::string ErrMsg = "Can't find bundles for";
  855. std::set<StringRef> Sorted;
  856. for (auto &E : Worklist)
  857. Sorted.insert(E.first());
  858. unsigned I = 0;
  859. unsigned Last = Sorted.size() - 1;
  860. for (auto &E : Sorted) {
  861. if (I != 0 && Last > 1)
  862. ErrMsg += ",";
  863. ErrMsg += " ";
  864. if (I == Last && I != 0)
  865. ErrMsg += "and ";
  866. ErrMsg += E.str();
  867. ++I;
  868. }
  869. return createStringError(inconvertibleErrorCode(), ErrMsg);
  870. }
  871. // If no bundles were found, assume the input file is the host bundle and
  872. // create empty files for the remaining targets.
  873. if (Worklist.size() == BundlerConfig.TargetNames.size()) {
  874. for (auto &E : Worklist) {
  875. std::error_code EC;
  876. raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
  877. if (EC)
  878. return createFileError(E.second, EC);
  879. // If this entry has a host kind, copy the input file to the output file.
  880. auto OffloadInfo = OffloadTargetInfo(E.getKey(), BundlerConfig);
  881. if (OffloadInfo.hasHostKind())
  882. OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
  883. }
  884. return Error::success();
  885. }
  886. // If we found elements, we emit an error if none of those were for the host
  887. // in case host bundle name was provided in command line.
  888. if (!(FoundHostBundle || BundlerConfig.HostInputIndex == ~0u ||
  889. BundlerConfig.AllowMissingBundles))
  890. return createStringError(inconvertibleErrorCode(),
  891. "Can't find bundle for the host target");
  892. // If we still have any elements in the worklist, create empty files for them.
  893. for (auto &E : Worklist) {
  894. std::error_code EC;
  895. raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
  896. if (EC)
  897. return createFileError(E.second, EC);
  898. }
  899. return Error::success();
  900. }
  901. static Archive::Kind getDefaultArchiveKindForHost() {
  902. return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
  903. : Archive::K_GNU;
  904. }
  905. /// @brief Computes a list of targets among all given targets which are
  906. /// compatible with this code object
  907. /// @param [in] CodeObjectInfo Code Object
  908. /// @param [out] CompatibleTargets List of all compatible targets among all
  909. /// given targets
  910. /// @return false, if no compatible target is found.
  911. static bool
  912. getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
  913. SmallVectorImpl<StringRef> &CompatibleTargets,
  914. const OffloadBundlerConfig &BundlerConfig) {
  915. if (!CompatibleTargets.empty()) {
  916. DEBUG_WITH_TYPE("CodeObjectCompatibility",
  917. dbgs() << "CompatibleTargets list should be empty\n");
  918. return false;
  919. }
  920. for (auto &Target : BundlerConfig.TargetNames) {
  921. auto TargetInfo = OffloadTargetInfo(Target, BundlerConfig);
  922. if (isCodeObjectCompatible(CodeObjectInfo, TargetInfo))
  923. CompatibleTargets.push_back(Target);
  924. }
  925. return !CompatibleTargets.empty();
  926. }
  927. /// UnbundleArchive takes an archive file (".a") as input containing bundled
  928. /// code object files, and a list of offload targets (not host), and extracts
  929. /// the code objects into a new archive file for each offload target. Each
  930. /// resulting archive file contains all code object files corresponding to that
  931. /// particular offload target. The created archive file does not
  932. /// contain an index of the symbols and code object files are named as
  933. /// <<Parent Bundle Name>-<CodeObject's GPUArch>>, with ':' replaced with '_'.
  934. Error OffloadBundler::UnbundleArchive() {
  935. std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
  936. /// Map of target names with list of object files that will form the device
  937. /// specific archive for that target
  938. StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
  939. // Map of target names and output archive filenames
  940. StringMap<StringRef> TargetOutputFileNameMap;
  941. auto Output = BundlerConfig.OutputFileNames.begin();
  942. for (auto &Target : BundlerConfig.TargetNames) {
  943. TargetOutputFileNameMap[Target] = *Output;
  944. ++Output;
  945. }
  946. StringRef IFName = BundlerConfig.InputFileNames.front();
  947. ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
  948. MemoryBuffer::getFileOrSTDIN(IFName, true, false);
  949. if (std::error_code EC = BufOrErr.getError())
  950. return createFileError(BundlerConfig.InputFileNames.front(), EC);
  951. ArchiveBuffers.push_back(std::move(*BufOrErr));
  952. Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
  953. Archive::create(ArchiveBuffers.back()->getMemBufferRef());
  954. if (!LibOrErr)
  955. return LibOrErr.takeError();
  956. auto Archive = std::move(*LibOrErr);
  957. Error ArchiveErr = Error::success();
  958. auto ChildEnd = Archive->child_end();
  959. /// Iterate over all bundled code object files in the input archive.
  960. for (auto ArchiveIter = Archive->child_begin(ArchiveErr);
  961. ArchiveIter != ChildEnd; ++ArchiveIter) {
  962. if (ArchiveErr)
  963. return ArchiveErr;
  964. auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
  965. if (!ArchiveChildNameOrErr)
  966. return ArchiveChildNameOrErr.takeError();
  967. StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
  968. auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
  969. if (!CodeObjectBufferRefOrErr)
  970. return CodeObjectBufferRefOrErr.takeError();
  971. auto CodeObjectBuffer =
  972. MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);
  973. Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
  974. CreateFileHandler(*CodeObjectBuffer, BundlerConfig);
  975. if (!FileHandlerOrErr)
  976. return FileHandlerOrErr.takeError();
  977. std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
  978. assert(FileHandler &&
  979. "FileHandle creation failed for file in the archive!");
  980. if (Error ReadErr = FileHandler->ReadHeader(*CodeObjectBuffer))
  981. return ReadErr;
  982. Expected<std::optional<StringRef>> CurBundleIDOrErr =
  983. FileHandler->ReadBundleStart(*CodeObjectBuffer);
  984. if (!CurBundleIDOrErr)
  985. return CurBundleIDOrErr.takeError();
  986. std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
  987. // No device code in this child, skip.
  988. if (!OptionalCurBundleID)
  989. continue;
  990. StringRef CodeObject = *OptionalCurBundleID;
  991. // Process all bundle entries (CodeObjects) found in this child of input
  992. // archive.
  993. while (!CodeObject.empty()) {
  994. SmallVector<StringRef> CompatibleTargets;
  995. auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig);
  996. if (CodeObjectInfo.hasHostKind()) {
  997. // Do nothing, we don't extract host code yet.
  998. } else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
  999. BundlerConfig)) {
  1000. std::string BundleData;
  1001. raw_string_ostream DataStream(BundleData);
  1002. if (Error Err = FileHandler->ReadBundle(DataStream, *CodeObjectBuffer))
  1003. return Err;
  1004. for (auto &CompatibleTarget : CompatibleTargets) {
  1005. SmallString<128> BundledObjectFileName;
  1006. BundledObjectFileName.assign(BundledObjectFile);
  1007. auto OutputBundleName =
  1008. Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
  1009. CodeObject +
  1010. getDeviceLibraryFileName(BundledObjectFileName,
  1011. CodeObjectInfo.TargetID))
  1012. .str();
  1013. // Replace ':' in optional target feature list with '_' to ensure
  1014. // cross-platform validity.
  1015. std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
  1016. '_');
  1017. std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
  1018. DataStream.str(), OutputBundleName);
  1019. ArchiveBuffers.push_back(std::move(MemBuf));
  1020. llvm::MemoryBufferRef MemBufRef =
  1021. MemoryBufferRef(*(ArchiveBuffers.back()));
  1022. // For inserting <CompatibleTarget, list<CodeObject>> entry in
  1023. // OutputArchivesMap.
  1024. if (OutputArchivesMap.find(CompatibleTarget) ==
  1025. OutputArchivesMap.end()) {
  1026. std::vector<NewArchiveMember> ArchiveMembers;
  1027. ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
  1028. OutputArchivesMap.insert_or_assign(CompatibleTarget,
  1029. std::move(ArchiveMembers));
  1030. } else {
  1031. OutputArchivesMap[CompatibleTarget].push_back(
  1032. NewArchiveMember(MemBufRef));
  1033. }
  1034. }
  1035. }
  1036. if (Error Err = FileHandler->ReadBundleEnd(*CodeObjectBuffer))
  1037. return Err;
  1038. Expected<std::optional<StringRef>> NextTripleOrErr =
  1039. FileHandler->ReadBundleStart(*CodeObjectBuffer);
  1040. if (!NextTripleOrErr)
  1041. return NextTripleOrErr.takeError();
  1042. CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr : "";
  1043. } // End of processing of all bundle entries of this child of input archive.
  1044. } // End of while over children of input archive.
  1045. assert(!ArchiveErr && "Error occurred while reading archive!");
  1046. /// Write out an archive for each target
  1047. for (auto &Target : BundlerConfig.TargetNames) {
  1048. StringRef FileName = TargetOutputFileNameMap[Target];
  1049. StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
  1050. OutputArchivesMap.find(Target);
  1051. if (CurArchiveMembers != OutputArchivesMap.end()) {
  1052. if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
  1053. true, getDefaultArchiveKindForHost(),
  1054. true, false, nullptr))
  1055. return WriteErr;
  1056. } else if (!BundlerConfig.AllowMissingBundles) {
  1057. std::string ErrMsg =
  1058. Twine("no compatible code object found for the target '" + Target +
  1059. "' in heterogeneous archive library: " + IFName)
  1060. .str();
  1061. return createStringError(inconvertibleErrorCode(), ErrMsg);
  1062. } else { // Create an empty archive file if no compatible code object is
  1063. // found and "allow-missing-bundles" is enabled. It ensures that
  1064. // the linker using output of this step doesn't complain about
  1065. // the missing input file.
  1066. std::vector<llvm::NewArchiveMember> EmptyArchive;
  1067. EmptyArchive.clear();
  1068. if (Error WriteErr = writeArchive(FileName, EmptyArchive, true,
  1069. getDefaultArchiveKindForHost(), true,
  1070. false, nullptr))
  1071. return WriteErr;
  1072. }
  1073. }
  1074. return Error::success();
  1075. }