Home | History | Annotate | Download | only in slang
      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 
     46 using llvm::errs;
     47 using llvm::LLVMContext;
     48 using llvm::MemoryBuffer;
     49 using llvm::Module;
     50 
     51 static llvm::cl::list<std::string>
     52 InputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore,
     53                llvm::cl::desc("<input bitcode files>"));
     54 
     55 static llvm::cl::list<std::string>
     56 OutputFilenames("o", llvm::cl::desc("Override output filename"),
     57                 llvm::cl::value_desc("<output bitcode file>"));
     58 
     59 static llvm::cl::opt<bool>
     60 NoStdLib("nostdlib", llvm::cl::desc("Don't link RS default libraries"));
     61 
     62 static 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 
     67 static 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 
     97 static 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 
    108 static 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 
    118 static 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.
    131 static 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 
    144 extern const char rslib_bc[];
    145 extern unsigned rslib_bc_size;
    146 
    147 static 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 
    180 static 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 
    190 Module *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 
    218 bool 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 
    248 int 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