1/*
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
17#include <list>
18#include <memory>
19#include <string>
20#include <vector>
21
22#include "llvm/Analysis/Verifier.h"
23
24#include "llvm/Bitcode/ReaderWriter.h"
25
26#include "llvm/Linker.h"
27#include "llvm/LLVMContext.h"
28#include "llvm/Metadata.h"
29#include "llvm/Module.h"
30
31#include "llvm/Support/CommandLine.h"
32#include "llvm/Support/ManagedStatic.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/raw_ostream.h"
35#include "llvm/Support/ToolOutputFile.h"
36#include "llvm/Support/system_error.h"
37
38#include "llvm/PassManager.h"
39#include "llvm/Transforms/IPO.h"
40#include "llvm/Transforms/IPO/PassManagerBuilder.h"
41
42#include "llvm/Target/TargetData.h"
43
44#include "slang_rs_metadata.h"
45
46using llvm::errs;
47using llvm::LLVMContext;
48using llvm::MemoryBuffer;
49using llvm::Module;
50
51static llvm::cl::list<std::string>
52InputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore,
53               llvm::cl::desc("<input bitcode files>"));
54
55static llvm::cl::list<std::string>
56OutputFilenames("o", llvm::cl::desc("Override output filename"),
57                llvm::cl::value_desc("<output bitcode file>"));
58
59static llvm::cl::opt<bool>
60NoStdLib("nostdlib", llvm::cl::desc("Don't link RS default libraries"));
61
62static llvm::cl::list<std::string>
63    AdditionalLibs("l", llvm::cl::Prefix,
64                   llvm::cl::desc("Specify additional libraries to link to"),
65                   llvm::cl::value_desc("<library bitcode>"));
66
67static bool GetExportSymbolNames(llvm::NamedMDNode *N,
68                                 unsigned NameOpIdx,
69                                 std::vector<const char *> &Names) {
70  if (N == NULL)
71    return true;
72
73  for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
74    llvm::MDNode *V = N->getOperand(i);
75    if (V == NULL)
76      continue;
77
78    if (V->getNumOperands() < (NameOpIdx + 1)) {
79      errs() << "Invalid metadata spec of " << N->getName()
80             << " in Renderscript executable. (#op)\n";
81      return false;
82    }
83
84    llvm::MDString *Name =
85        llvm::dyn_cast<llvm::MDString>(V->getOperand(NameOpIdx));
86    if (Name == NULL) {
87      errs() << "Invalid metadata spec of " << N->getName()
88             << " in Renderscript executable. (#name)\n";
89      return false;
90    }
91
92    Names.push_back(Name->getString().data());
93  }
94  return true;
95}
96
97static bool GetExportSymbols(Module *M, std::vector<const char *> &Names) {
98  bool Result = true;
99  // Variables marked as export must be externally visible
100  if (llvm::NamedMDNode *EV = M->getNamedMetadata(RS_EXPORT_VAR_MN))
101    Result |= GetExportSymbolNames(EV, RS_EXPORT_VAR_NAME, Names);
102  // So are those exported functions
103  if (llvm::NamedMDNode *EF = M->getNamedMetadata(RS_EXPORT_FUNC_MN))
104    Result |= GetExportSymbolNames(EF, RS_EXPORT_FUNC_NAME, Names);
105  return Result;
106}
107
108static inline MemoryBuffer *LoadFileIntoMemory(const std::string &F) {
109  llvm::OwningPtr<MemoryBuffer> MB;
110
111  if (llvm::error_code EC = MemoryBuffer::getFile(F, MB)) {
112    errs() << "Failed to load `" << F << "' (" + EC.message() + ")\n";
113  }
114
115  return MB.take();
116}
117
118static inline Module *ParseBitcodeFromMemoryBuffer(MemoryBuffer *MB,
119                                                   LLVMContext& Context) {
120  std::string Err;
121  Module *M = ParseBitcodeFile(MB, Context, &Err);
122
123  if (M == NULL)
124    errs() << "Corrupted bitcode file `" << MB->getBufferIdentifier()
125           <<  "' (" << Err << ")\n";
126
127  return M;
128}
129
130// LoadBitcodeFile - Read the specified bitcode file in and return it.
131static inline Module *LoadBitcodeFile(const std::string &F,
132                                      LLVMContext& Context) {
133  MemoryBuffer *MB = LoadFileIntoMemory(F);
134  if (MB == NULL)
135    return NULL;
136
137  Module *M = ParseBitcodeFromMemoryBuffer(MB, Context);
138  if (M == NULL)
139    delete MB;
140
141  return M;
142}
143
144extern const char rslib_bc[];
145extern unsigned rslib_bc_size;
146
147static bool PreloadLibraries(bool NoStdLib,
148                             const std::vector<std::string> &AdditionalLibs,
149                             std::list<MemoryBuffer *> &LibBitcode) {
150  MemoryBuffer *MB;
151
152  LibBitcode.clear();
153
154  if (!NoStdLib) {
155    // rslib.bc
156    MB = MemoryBuffer::getMemBuffer(llvm::StringRef(rslib_bc, rslib_bc_size),
157                                    "rslib.bc");
158    if (MB == NULL) {
159      errs() << "Failed to load (in-memory) `rslib.bc'!\n";
160      return false;
161    }
162
163    LibBitcode.push_back(MB);
164  }
165
166  // Load additional libraries
167  for (std::vector<std::string>::const_iterator
168          I = AdditionalLibs.begin(), E = AdditionalLibs.end();
169       I != E;
170       I++) {
171    MB = LoadFileIntoMemory(*I);
172    if (MB == NULL)
173      return false;
174    LibBitcode.push_back(MB);
175  }
176
177  return true;
178}
179
180static void UnloadLibraries(std::list<MemoryBuffer *>& LibBitcode) {
181  for (std::list<MemoryBuffer *>::iterator
182          I = LibBitcode.begin(), E = LibBitcode.end();
183       I != E;
184       I++)
185    delete *I;
186  LibBitcode.clear();
187  return;
188}
189
190Module *PerformLinking(const std::string &InputFile,
191                       const std::list<MemoryBuffer *> &LibBitcode,
192                       LLVMContext &Context) {
193  std::string Err;
194  std::auto_ptr<Module> Composite(LoadBitcodeFile(InputFile, Context));
195
196  if (Composite.get() == NULL)
197    return NULL;
198
199  for (std::list<MemoryBuffer *>::const_iterator I = LibBitcode.begin(),
200          E = LibBitcode.end();
201       I != E;
202       I++) {
203    Module *Lib = ParseBitcodeFromMemoryBuffer(*I, Context);
204    if (Lib == NULL)
205      return NULL;
206
207    if (llvm::Linker::LinkModules(Composite.get(), Lib,
208                                  llvm::Linker::DestroySource, &Err)) {
209      errs() << "Failed to link `" << InputFile << "' with library bitcode `"
210             << (*I)->getBufferIdentifier() << "' (" << Err << ")\n";
211      return NULL;
212    }
213  }
214
215  return Composite.release();
216}
217
218bool OptimizeModule(Module *M) {
219  llvm::PassManager Passes;
220
221  const std::string &ModuleDataLayout = M->getDataLayout();
222  if (!ModuleDataLayout.empty())
223    if (llvm::TargetData *TD = new llvm::TargetData(ModuleDataLayout))
224      Passes.add(TD);
225
226  // Some symbols must not be internalized
227  std::vector<const char *> ExportList;
228  ExportList.push_back("init");
229  ExportList.push_back("root");
230  ExportList.push_back(".rs.dtor");
231
232  if (!GetExportSymbols(M, ExportList)) {
233    return false;
234  }
235
236  Passes.add(llvm::createInternalizePass(ExportList));
237
238  // TODO(sliao): Do we need to run all LTO passes?
239  llvm::PassManagerBuilder PMBuilder;
240  PMBuilder.populateLTOPassManager(Passes,
241                                   /* Internalize = */false,
242                                   /* RunInliner = */true);
243  Passes.run(*M);
244
245  return true;
246}
247
248int main(int argc, char **argv) {
249  llvm::llvm_shutdown_obj X;  // Call llvm_shutdown() on exit.
250
251  llvm::cl::ParseCommandLineOptions(argc, argv, "llvm-rs-link\n");
252
253  std::list<MemoryBuffer *> LibBitcode;
254
255  if (!PreloadLibraries(NoStdLib, AdditionalLibs, LibBitcode))
256    return 1;
257
258  // No libraries specified to be linked
259  if (LibBitcode.size() == 0)
260    return 0;
261
262  LLVMContext &Context = llvm::getGlobalContext();
263  bool HasError = true;
264  std::string Err;
265
266  for (unsigned i = 0, e = InputFilenames.size(); i != e; i++) {
267    std::auto_ptr<Module> Linked(
268        PerformLinking(InputFilenames[i], LibBitcode, Context));
269
270    // Failed to link with InputFilenames[i] with LibBitcode
271    if (Linked.get() == NULL)
272      break;
273
274    // Verify linked module
275    if (verifyModule(*Linked, llvm::ReturnStatusAction, &Err)) {
276      errs() << InputFilenames[i] << " linked, but does not verify as "
277                                     "correct! (" << Err << ")\n";
278      break;
279    }
280
281    if (!OptimizeModule(Linked.get()))
282      break;
283
284    // Write out the module
285    llvm::tool_output_file Out(InputFilenames[i].c_str(), Err,
286                               llvm::raw_fd_ostream::F_Binary);
287
288    if (!Err.empty()) {
289      errs() << InputFilenames[i] << " linked, but failed to write out! "
290                                     "(" << Err << ")\n";
291      break;
292    }
293
294    WriteBitcodeToFile(Linked.get(), Out.os());
295
296    Out.keep();
297    Linked.reset();
298
299    if (i == (InputFilenames.size() - 1))
300      // This is the last file and no error occured.
301      HasError = false;
302  }
303
304  UnloadLibraries(LibBitcode);
305
306  return HasError;
307}
308