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