blob: 1e37593c35539bfa2f807aeec04bf6c84f23efa2 [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Zonr Changa02010c2010-10-11 20:54:28 +080017#include <list>
zonr6315f762010-10-05 15:35:14 +080018#include <memory>
19#include <string>
20#include <vector>
21
Stephen Hinese639eb52010-11-08 19:27:20 -080022#include "llvm/Analysis/Verifier.h"
23
24#include "llvm/Bitcode/ReaderWriter.h"
25
Shih-wei Liao835a7b72010-08-06 02:29:11 -070026#include "llvm/Linker.h"
27#include "llvm/LLVMContext.h"
28#include "llvm/Metadata.h"
29#include "llvm/Module.h"
Zonr Chang7f2f3852010-10-07 19:12:23 +080030
Shih-wei Liao835a7b72010-08-06 02:29:11 -070031#include "llvm/Support/CommandLine.h"
32#include "llvm/Support/ManagedStatic.h"
33#include "llvm/Support/MemoryBuffer.h"
Shih-wei Liao835a7b72010-08-06 02:29:11 -070034#include "llvm/Support/StandardPasses.h"
Shih-wei Liao835a7b72010-08-06 02:29:11 -070035#include "llvm/Support/raw_ostream.h"
Zonr Chang7f2f3852010-10-07 19:12:23 +080036
Shih-wei Liao835a7b72010-08-06 02:29:11 -070037#include "llvm/Target/TargetData.h"
Zonr Chang7f2f3852010-10-07 19:12:23 +080038
39#include "slang_rs_metadata.h"
Shih-wei Liao835a7b72010-08-06 02:29:11 -070040
Stephen Hinese639eb52010-11-08 19:27:20 -080041using llvm::errs;
42using llvm::LLVMContext;
43using llvm::MemoryBuffer;
44using llvm::Module;
Shih-wei Liao835a7b72010-08-06 02:29:11 -070045
Stephen Hinese639eb52010-11-08 19:27:20 -080046static llvm::cl::list<std::string>
47InputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore,
48 llvm::cl::desc("<input bitcode files>"));
Shih-wei Liao835a7b72010-08-06 02:29:11 -070049
Stephen Hinese639eb52010-11-08 19:27:20 -080050static llvm::cl::list<std::string>
51OutputFilenames("o", llvm::cl::desc("Override output filename"),
52 llvm::cl::value_desc("<output bitcode file>"));
Zonr Changa02010c2010-10-11 20:54:28 +080053
Stephen Hinese639eb52010-11-08 19:27:20 -080054static llvm::cl::opt<bool>
55NoStdLib("nostdlib", llvm::cl::desc("Don't link RS default libraries"));
Zonr Changa02010c2010-10-11 20:54:28 +080056
Stephen Hinese639eb52010-11-08 19:27:20 -080057static llvm::cl::list<std::string>
58 AdditionalLibs("l", llvm::cl::Prefix,
59 llvm::cl::desc("Specify additional libraries to link to"),
60 llvm::cl::value_desc("<library bitcode>"));
Shih-wei Liao835a7b72010-08-06 02:29:11 -070061
Stephen Hinese639eb52010-11-08 19:27:20 -080062static bool GetExportSymbolNames(llvm::NamedMDNode *N,
Zonr Chang7f2f3852010-10-07 19:12:23 +080063 unsigned NameOpIdx,
64 std::vector<const char *> &Names) {
65 if (N == NULL)
66 return true;
Shih-wei Liao9c9bbc82010-08-18 03:08:44 -070067
Zonr Chang7f2f3852010-10-07 19:12:23 +080068 for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
Stephen Hinese639eb52010-11-08 19:27:20 -080069 llvm::MDNode *V = N->getOperand(i);
Zonr Chang7f2f3852010-10-07 19:12:23 +080070 if (V == NULL)
71 continue;
Shih-wei Liao835a7b72010-08-06 02:29:11 -070072
Zonr Chang7f2f3852010-10-07 19:12:23 +080073 if (V->getNumOperands() < (NameOpIdx + 1)) {
74 errs() << "Invalid metadata spec of " << N->getName()
75 << " in RenderScript executable. (#op)\n";
76 return false;
Shih-wei Liao835a7b72010-08-06 02:29:11 -070077 }
78
Stephen Hinese639eb52010-11-08 19:27:20 -080079 llvm::MDString *Name =
80 llvm::dyn_cast<llvm::MDString>(V->getOperand(NameOpIdx));
Zonr Chang7f2f3852010-10-07 19:12:23 +080081 if (Name == NULL) {
82 errs() << "Invalid metadata spec of " << N->getName()
83 << " in RenderScript executable. (#name)\n";
84 return false;
Shih-wei Liao835a7b72010-08-06 02:29:11 -070085 }
86
Zonr Chang7f2f3852010-10-07 19:12:23 +080087 Names.push_back(Name->getString().data());
Shih-wei Liao835a7b72010-08-06 02:29:11 -070088 }
Zonr Chang7f2f3852010-10-07 19:12:23 +080089 return true;
Shih-wei Liao835a7b72010-08-06 02:29:11 -070090}
91
Zonr Chang7f2f3852010-10-07 19:12:23 +080092static bool GetExportSymbols(Module *M, std::vector<const char *> &Names) {
93 bool Result = true;
94 // Variables marked as export must be externally visible
Stephen Hinese639eb52010-11-08 19:27:20 -080095 if (llvm::NamedMDNode *EV = M->getNamedMetadata(RS_EXPORT_VAR_MN))
Zonr Chang7f2f3852010-10-07 19:12:23 +080096 Result |= GetExportSymbolNames(EV, RS_EXPORT_VAR_NAME, Names);
97 // So are those exported functions
Stephen Hinese639eb52010-11-08 19:27:20 -080098 if (llvm::NamedMDNode *EF = M->getNamedMetadata(RS_EXPORT_FUNC_MN))
Zonr Chang7f2f3852010-10-07 19:12:23 +080099 Result |= GetExportSymbolNames(EF, RS_EXPORT_FUNC_NAME, Names);
100 return Result;
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700101}
102
Zonr Changa02010c2010-10-11 20:54:28 +0800103static inline MemoryBuffer *LoadFileIntoMemory(const std::string &F) {
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700104 std::string Err;
Zonr Changa02010c2010-10-11 20:54:28 +0800105 MemoryBuffer *MB = MemoryBuffer::getFile(F, &Err);
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700106
Zonr Changa02010c2010-10-11 20:54:28 +0800107 if (MB == NULL)
108 errs() << "Failed to load `" << F << "' (" << Err << ")\n";
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700109
Zonr Changa02010c2010-10-11 20:54:28 +0800110 return MB;
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700111}
112
Zonr Changa02010c2010-10-11 20:54:28 +0800113static inline Module *ParseBitcodeFromMemoryBuffer(MemoryBuffer *MB,
114 LLVMContext& Context) {
115 std::string Err;
116 Module *M = ParseBitcodeFile(MB, Context, &Err);
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700117
Zonr Changa02010c2010-10-11 20:54:28 +0800118 if (M == NULL)
119 errs() << "Corrupted bitcode file `" << MB->getBufferIdentifier()
120 << "' (" << Err << ")\n";
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700121
Zonr Changa02010c2010-10-11 20:54:28 +0800122 return M;
123}
124
125// LoadBitcodeFile - Read the specified bitcode file in and return it.
126static inline Module *LoadBitcodeFile(const std::string &F,
127 LLVMContext& Context) {
128 MemoryBuffer *MB = LoadFileIntoMemory(F);
129 if (MB == NULL)
130 return NULL;
131
132 Module *M = ParseBitcodeFromMemoryBuffer(MB, Context);
133 if (M == NULL)
134 delete MB;
135
136 return M;
137}
138
139extern const char rslib_bc[];
140extern unsigned rslib_bc_size;
141
142static bool PreloadLibraries(bool NoStdLib,
143 const std::vector<std::string> &AdditionalLibs,
Shih-wei Liao552b5812010-11-16 05:51:19 -0800144 std::list<MemoryBuffer *> &LibBitcode) {
Zonr Changa02010c2010-10-11 20:54:28 +0800145 MemoryBuffer *MB;
146
147 LibBitcode.clear();
148
149 if (!NoStdLib) {
150 // rslib.bc
Stephen Hinese639eb52010-11-08 19:27:20 -0800151 MB = MemoryBuffer::getMemBuffer(llvm::StringRef(rslib_bc, rslib_bc_size),
Zonr Changd124ee62010-10-22 18:26:25 +0800152 "rslib.bc");
Zonr Changa02010c2010-10-11 20:54:28 +0800153 if (MB == NULL) {
154 errs() << "Failed to load (in-memory) `rslib.bc'!\n";
155 return false;
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700156 }
Zonr Changa02010c2010-10-11 20:54:28 +0800157
158 LibBitcode.push_back(MB);
159 }
160
161 // Load additional libraries
162 for (std::vector<std::string>::const_iterator
163 I = AdditionalLibs.begin(), E = AdditionalLibs.end();
164 I != E;
165 I++) {
166 MB = LoadFileIntoMemory(*I);
167 if (MB == NULL)
168 return false;
169 LibBitcode.push_back(MB);
170 }
171
172 return true;
173}
174
175static void UnloadLibraries(std::list<MemoryBuffer *>& LibBitcode) {
176 for (std::list<MemoryBuffer *>::iterator
177 I = LibBitcode.begin(), E = LibBitcode.end();
178 I != E;
179 I++)
180 delete *I;
181 LibBitcode.clear();
182 return;
183}
184
185Module *PerformLinking(const std::string &InputFile,
186 const std::list<MemoryBuffer *> &LibBitcode,
187 LLVMContext &Context) {
188 std::string Err;
189 std::auto_ptr<Module> Composite(LoadBitcodeFile(InputFile, Context));
190
191 if (Composite.get() == NULL)
192 return NULL;
193
194 for (std::list<MemoryBuffer *>::const_iterator I = LibBitcode.begin(),
195 E = LibBitcode.end();
196 I != E;
197 I++) {
198 Module *Lib = ParseBitcodeFromMemoryBuffer(*I, Context);
199 if (Lib == NULL)
200 return NULL;
201
Stephen Hinese639eb52010-11-08 19:27:20 -0800202 if (llvm::Linker::LinkModules(Composite.get(), Lib, &Err)) {
Zonr Changa02010c2010-10-11 20:54:28 +0800203 errs() << "Failed to link `" << InputFile << "' with library bitcode `"
204 << (*I)->getBufferIdentifier() << "' (" << Err << ")\n";
205 return NULL;
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700206 }
207 }
208
Zonr Changa02010c2010-10-11 20:54:28 +0800209 return Composite.release();
210}
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700211
Zonr Changa02010c2010-10-11 20:54:28 +0800212bool OptimizeModule(Module *M) {
Stephen Hinese639eb52010-11-08 19:27:20 -0800213 llvm::PassManager Passes;
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700214
Zonr Changa02010c2010-10-11 20:54:28 +0800215 const std::string &ModuleDataLayout = M->getDataLayout();
Zonr Chang7f2f3852010-10-07 19:12:23 +0800216 if (!ModuleDataLayout.empty())
Stephen Hinese639eb52010-11-08 19:27:20 -0800217 if (llvm::TargetData *TD = new llvm::TargetData(ModuleDataLayout))
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700218 Passes.add(TD);
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700219
Zonr Chang7f2f3852010-10-07 19:12:23 +0800220 // Some symbols must not be internalized
221 std::vector<const char *> ExportList;
222 ExportList.push_back("init");
223 ExportList.push_back("root");
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700224
Zonr Changa02010c2010-10-11 20:54:28 +0800225 if (!GetExportSymbols(M, ExportList)) {
226 return false;
227 }
Shih-wei Liao9c9bbc82010-08-18 03:08:44 -0700228
Stephen Hinese639eb52010-11-08 19:27:20 -0800229 Passes.add(llvm::createInternalizePass(ExportList));
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700230
Zonr Changa02010c2010-10-11 20:54:28 +0800231 // TODO(zonr): Do we need to run all LTO passes?
Zonr Chang7f2f3852010-10-07 19:12:23 +0800232 createStandardLTOPasses(&Passes,
233 /* Internalize = */false,
234 /* RunInliner = */true,
235 /* VerifyEach = */false);
Zonr Changa02010c2010-10-11 20:54:28 +0800236 Passes.run(*M);
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700237
Zonr Changa02010c2010-10-11 20:54:28 +0800238 return true;
239}
Zonr Chang7f2f3852010-10-07 19:12:23 +0800240
Zonr Changa02010c2010-10-11 20:54:28 +0800241int main(int argc, char **argv) {
Stephen Hinese639eb52010-11-08 19:27:20 -0800242 llvm::llvm_shutdown_obj X; // Call llvm_shutdown() on exit.
Zonr Changa02010c2010-10-11 20:54:28 +0800243
Stephen Hinese639eb52010-11-08 19:27:20 -0800244 llvm::cl::ParseCommandLineOptions(argc, argv, "llvm-rs-link\n");
Zonr Changa02010c2010-10-11 20:54:28 +0800245
246 std::list<MemoryBuffer *> LibBitcode;
247
248 if (!PreloadLibraries(NoStdLib, AdditionalLibs, LibBitcode))
249 return 1;
250
251 // No libraries specified to be linked
252 if (LibBitcode.size() == 0)
253 return 0;
254
Stephen Hinese639eb52010-11-08 19:27:20 -0800255 LLVMContext &Context = llvm::getGlobalContext();
Zonr Changa02010c2010-10-11 20:54:28 +0800256 bool HasError = true;
257 std::string Err;
258
259 for (unsigned i = 0, e = InputFilenames.size(); i != e; i++) {
260 std::auto_ptr<Module> Linked(
261 PerformLinking(InputFilenames[i], LibBitcode, Context));
262
263 // Failed to link with InputFilenames[i] with LibBitcode
264 if (Linked.get() == NULL)
265 break;
266
267 // Verify linked module
Stephen Hinese639eb52010-11-08 19:27:20 -0800268 if (verifyModule(*Linked, llvm::ReturnStatusAction, &Err)) {
Zonr Changa02010c2010-10-11 20:54:28 +0800269 errs() << InputFilenames[i] << " linked, but does not verify as "
270 "correct! (" << Err << ")\n";
271 break;
272 }
273
274 if (!OptimizeModule(Linked.get()))
275 break;
276
277 // Write out the module
Stephen Hinese639eb52010-11-08 19:27:20 -0800278 llvm::tool_output_file Out(InputFilenames[i].c_str(), Err,
279 llvm::raw_fd_ostream::F_Binary);
Zonr Changa02010c2010-10-11 20:54:28 +0800280
281 if (!Err.empty()) {
282 errs() << InputFilenames[i] << " linked, but failed to write out! "
283 "(" << Err << ")\n";
284 break;
285 }
286
287 WriteBitcodeToFile(Linked.get(), Out);
288
289 Out.keep();
290 Linked.reset();
291
292 if (i == (InputFilenames.size() - 1))
293 // This is the last file and no error occured.
294 HasError = false;
295 }
296
297 UnloadLibraries(LibBitcode);
298
299 return HasError;
Shih-wei Liao835a7b72010-08-06 02:29:11 -0700300}