1 | //===----------------------------------------------------------------------===// |
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 | #if HAVE_LLVM > 0x0390 |
10 | #include "llvm/Bitcode/BitcodeReader.h" |
11 | #include "llvm/Bitcode/BitcodeWriter.h" |
12 | #else |
13 | #include "llvm/Bitcode/ReaderWriter.h" |
14 | #endif |
15 | |
16 | #include "llvm/Config/llvm-config.h" |
17 | #include "llvm/IR/Function.h" |
18 | #include "llvm/IR/GlobalVariable.h" |
19 | #include "llvm/IR/LLVMContext.h" |
20 | #include "llvm/IR/Module.h" |
21 | #include "llvm/IRReader/IRReader.h" |
22 | #include "llvm/Support/CommandLine.h" |
23 | #include "llvm/Support/ErrorOr.h" |
24 | #include "llvm/Support/FileSystem.h" |
25 | #include "llvm/Support/ManagedStatic.h" |
26 | #include "llvm/Support/MemoryBuffer.h" |
27 | #include "llvm/Support/SourceMgr.h" |
28 | #include "llvm/Support/ToolOutputFile.h" |
29 | #include "llvm/Support/raw_ostream.h" |
30 | |
31 | #include <system_error> |
32 | |
33 | using namespace llvm; |
34 | |
35 | static ExitOnError ExitOnErr; |
36 | |
37 | static cl::opt<std::string> |
38 | InputFilename(cl::Positional, cl::desc("<input bitcode>" ), cl::init(Val: "-" )); |
39 | |
40 | static cl::opt<std::string> |
41 | OutputFilename("o" , cl::desc("Output filename" ), |
42 | cl::value_desc("filename" )); |
43 | |
44 | static cl::opt<bool> TextualOut("S" , cl::desc("Emit LLVM textual assembly" ), |
45 | cl::init(Val: false)); |
46 | |
47 | int main(int argc, char **argv) { |
48 | LLVMContext Context; |
49 | llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. |
50 | |
51 | cl::ParseCommandLineOptions(argc, argv, Overview: "libclc builtin preparation tool\n" ); |
52 | |
53 | std::string ErrorMessage; |
54 | Module *M = nullptr; |
55 | |
56 | { |
57 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = |
58 | MemoryBuffer::getFile(Filename: InputFilename); |
59 | if (std::error_code ec = BufferOrErr.getError()) { |
60 | ErrorMessage = ec.message(); |
61 | } else { |
62 | std::unique_ptr<MemoryBuffer> &BufferPtr = BufferOrErr.get(); |
63 | SMDiagnostic Err; |
64 | std::unique_ptr<llvm::Module> MPtr = |
65 | #if HAVE_LLVM > 0x0390 |
66 | ExitOnErr(Expected<std::unique_ptr<llvm::Module>>( |
67 | parseIR(Buffer: BufferPtr.get()->getMemBufferRef(), Err, Context))); |
68 | #else |
69 | parseIR(BufferPtr.get()->getMemBufferRef(), Err, Context); |
70 | #endif |
71 | M = MPtr.release(); |
72 | } |
73 | } |
74 | |
75 | if (!M) { |
76 | errs() << argv[0] << ": " ; |
77 | if (ErrorMessage.size()) |
78 | errs() << ErrorMessage << "\n" ; |
79 | else |
80 | errs() << "bitcode didn't read correctly.\n" ; |
81 | return 1; |
82 | } |
83 | |
84 | // Strip the OpenCL version metadata. There are a lot of linked |
85 | // modules in the library build, each spamming the same |
86 | // version. This may also report a different version than the user |
87 | // program is using. This should probably be uniqued when linking. |
88 | if (NamedMDNode *OCLVersion = M->getNamedMetadata(Name: "opencl.ocl.version" )) |
89 | M->eraseNamedMetadata(NMD: OCLVersion); |
90 | |
91 | // Set linkage of every external definition to linkonce_odr. |
92 | for (Module::iterator i = M->begin(), e = M->end(); i != e; ++i) { |
93 | if (!i->isDeclaration() && i->getLinkage() == GlobalValue::ExternalLinkage) |
94 | i->setLinkage(GlobalValue::LinkOnceODRLinkage); |
95 | } |
96 | |
97 | for (Module::global_iterator i = M->global_begin(), e = M->global_end(); |
98 | i != e; ++i) { |
99 | if (!i->isDeclaration() && i->getLinkage() == GlobalValue::ExternalLinkage) |
100 | i->setLinkage(GlobalValue::LinkOnceODRLinkage); |
101 | } |
102 | |
103 | if (OutputFilename.empty()) { |
104 | errs() << "no output file\n" ; |
105 | return 1; |
106 | } |
107 | |
108 | std::error_code EC; |
109 | #if HAVE_LLVM >= 0x0600 |
110 | std::unique_ptr<ToolOutputFile> Out( |
111 | new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); |
112 | #else |
113 | std::unique_ptr<tool_output_file> Out( |
114 | new tool_output_file(OutputFilename, EC, sys::fs::OF_None)); |
115 | #endif |
116 | if (EC) { |
117 | errs() << EC.message() << '\n'; |
118 | exit(status: 1); |
119 | } |
120 | |
121 | if (TextualOut) |
122 | M->print(OS&: Out->os(), AAW: nullptr, ShouldPreserveUseListOrder: true); |
123 | else |
124 | #if HAVE_LLVM >= 0x0700 |
125 | WriteBitcodeToFile(M: *M, Out&: Out->os()); |
126 | #else |
127 | WriteBitcodeToFile(M, Out->os()); |
128 | #endif |
129 | |
130 | // Declare success. |
131 | Out->keep(); |
132 | return 0; |
133 | } |
134 | |