/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- clang-offload-packager/ClangOffloadPackager.cpp - file bundler ---===// |
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 | | // This tool takes several device object files and bundles them into a single |
10 | | // binary image using a custom binary format. This is intended to be used to |
11 | | // embed many device files into an application to create a fat binary. |
12 | | // |
13 | | //===---------------------------------------------------------------------===// |
14 | | |
15 | | #include "clang/Basic/Version.h" |
16 | | |
17 | | #include "llvm/Object/Binary.h" |
18 | | #include "llvm/Object/ObjectFile.h" |
19 | | #include "llvm/Object/OffloadBinary.h" |
20 | | #include "llvm/Support/CommandLine.h" |
21 | | #include "llvm/Support/FileOutputBuffer.h" |
22 | | #include "llvm/Support/MemoryBuffer.h" |
23 | | #include "llvm/Support/Path.h" |
24 | | #include "llvm/Support/Signals.h" |
25 | | #include "llvm/Support/StringSaver.h" |
26 | | #include "llvm/Support/WithColor.h" |
27 | | |
28 | | using namespace llvm; |
29 | | using namespace llvm::object; |
30 | | |
31 | | static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); |
32 | | |
33 | | static cl::OptionCategory |
34 | | ClangOffloadPackagerCategory("clang-offload-packager options"); |
35 | | |
36 | | static cl::opt<std::string> OutputFile("o", cl::Required, |
37 | | cl::desc("Write output to <file>."), |
38 | | cl::value_desc("file"), |
39 | | cl::cat(ClangOffloadPackagerCategory)); |
40 | | |
41 | | static cl::list<std::string> |
42 | | DeviceImages("image", |
43 | | cl::desc("List of key and value arguments. Required keywords " |
44 | | "are 'file' and 'triple'."), |
45 | | cl::value_desc("<key>=<value>,..."), |
46 | | cl::cat(ClangOffloadPackagerCategory)); |
47 | | |
48 | 0 | static void PrintVersion(raw_ostream &OS) { |
49 | 0 | OS << clang::getClangToolFullVersion("clang-offload-packager") << '\n'; |
50 | 0 | } |
51 | | |
52 | | int main(int argc, const char **argv) { |
53 | | sys::PrintStackTraceOnErrorSignal(argv[0]); |
54 | | cl::HideUnrelatedOptions(ClangOffloadPackagerCategory); |
55 | | cl::SetVersionPrinter(PrintVersion); |
56 | | cl::ParseCommandLineOptions( |
57 | | argc, argv, |
58 | | "A utility for bundling several object files into a single binary.\n" |
59 | | "The output binary can then be embedded into the host section table\n" |
60 | | "to create a fatbinary containing offloading code.\n"); |
61 | | |
62 | | if (Help) { |
63 | | cl::PrintHelpMessage(); |
64 | | return EXIT_SUCCESS; |
65 | | } |
66 | | |
67 | 0 | auto reportError = [argv](Error E) { |
68 | 0 | logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); |
69 | 0 | return EXIT_FAILURE; |
70 | 0 | }; |
71 | | |
72 | | SmallVector<char, 1024> BinaryData; |
73 | | raw_svector_ostream OS(BinaryData); |
74 | | for (StringRef Image : DeviceImages) { |
75 | | BumpPtrAllocator Alloc; |
76 | | StringSaver Saver(Alloc); |
77 | | |
78 | | StringMap<StringRef> Args; |
79 | | for (StringRef Arg : llvm::split(Image, ",")) { |
80 | | auto KeyAndValue = Arg.split("="); |
81 | | if (Args.count(KeyAndValue.first)) |
82 | | Args[KeyAndValue.first] = |
83 | | Saver.save(Args[KeyAndValue.first] + "," + KeyAndValue.second); |
84 | | else |
85 | | Args[KeyAndValue.first] = KeyAndValue.second; |
86 | | } |
87 | | |
88 | | if (!Args.count("triple") || !Args.count("file")) |
89 | | return reportError(createStringError( |
90 | | inconvertibleErrorCode(), |
91 | | "'file' and 'triple' are required image arguments")); |
92 | | |
93 | | OffloadBinary::OffloadingImage ImageBinary{}; |
94 | | std::unique_ptr<llvm::MemoryBuffer> DeviceImage; |
95 | | for (const auto &KeyAndValue : Args) { |
96 | | StringRef Key = KeyAndValue.getKey(); |
97 | | if (Key == "file") { |
98 | | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ObjectOrErr = |
99 | | llvm::MemoryBuffer::getFileOrSTDIN(KeyAndValue.getValue()); |
100 | | if (std::error_code EC = ObjectOrErr.getError()) |
101 | | return reportError(errorCodeToError(EC)); |
102 | | |
103 | | // Clang uses the '.o' suffix for LTO bitcode. |
104 | | if (identify_magic((*ObjectOrErr)->getBuffer()) == file_magic::bitcode) |
105 | | ImageBinary.TheImageKind = object::IMG_Bitcode; |
106 | | else |
107 | | ImageBinary.TheImageKind = getImageKind( |
108 | | sys::path::extension(KeyAndValue.getValue()).drop_front()); |
109 | | ImageBinary.Image = std::move(*ObjectOrErr); |
110 | | } else if (Key == "kind") { |
111 | | ImageBinary.TheOffloadKind = getOffloadKind(KeyAndValue.getValue()); |
112 | | } else { |
113 | | ImageBinary.StringData[Key] = KeyAndValue.getValue(); |
114 | | } |
115 | | } |
116 | | std::unique_ptr<MemoryBuffer> Buffer = OffloadBinary::write(ImageBinary); |
117 | | if (Buffer->getBufferSize() % OffloadBinary::getAlignment() != 0) |
118 | | return reportError( |
119 | | createStringError(inconvertibleErrorCode(), |
120 | | "Offload binary has invalid size alignment")); |
121 | | OS << Buffer->getBuffer(); |
122 | | } |
123 | | |
124 | | Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr = |
125 | | FileOutputBuffer::create(OutputFile, BinaryData.size()); |
126 | | if (!OutputOrErr) |
127 | | return reportError(OutputOrErr.takeError()); |
128 | | std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr); |
129 | | std::copy(BinaryData.begin(), BinaryData.end(), Output->getBufferStart()); |
130 | | if (Error E = Output->commit()) |
131 | | return reportError(std::move(E)); |
132 | | } |