Home | History | Annotate | Download | only in llvm-extract
      1 //===- llvm-extract.cpp - LLVM function extraction utility ----------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This utility changes the input module to only contain a single function,
     11 // which is primarily used for debugging transformations.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm/ADT/SetVector.h"
     16 #include "llvm/ADT/SmallPtrSet.h"
     17 #include "llvm/Bitcode/BitcodeWriterPass.h"
     18 #include "llvm/IR/DataLayout.h"
     19 #include "llvm/IR/IRPrintingPasses.h"
     20 #include "llvm/IR/LLVMContext.h"
     21 #include "llvm/IR/Module.h"
     22 #include "llvm/IRReader/IRReader.h"
     23 #include "llvm/PassManager.h"
     24 #include "llvm/Support/CommandLine.h"
     25 #include "llvm/Support/FileSystem.h"
     26 #include "llvm/Support/ManagedStatic.h"
     27 #include "llvm/Support/PrettyStackTrace.h"
     28 #include "llvm/Support/Regex.h"
     29 #include "llvm/Support/Signals.h"
     30 #include "llvm/Support/SourceMgr.h"
     31 #include "llvm/Support/SystemUtils.h"
     32 #include "llvm/Support/ToolOutputFile.h"
     33 #include "llvm/Transforms/IPO.h"
     34 #include <memory>
     35 using namespace llvm;
     36 
     37 // InputFilename - The filename to read from.
     38 static cl::opt<std::string>
     39 InputFilename(cl::Positional, cl::desc("<input bitcode file>"),
     40               cl::init("-"), cl::value_desc("filename"));
     41 
     42 static cl::opt<std::string>
     43 OutputFilename("o", cl::desc("Specify output filename"),
     44                cl::value_desc("filename"), cl::init("-"));
     45 
     46 static cl::opt<bool>
     47 Force("f", cl::desc("Enable binary output on terminals"));
     48 
     49 static cl::opt<bool>
     50 DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
     51 
     52 // ExtractFuncs - The functions to extract from the module.
     53 static cl::list<std::string>
     54 ExtractFuncs("func", cl::desc("Specify function to extract"),
     55              cl::ZeroOrMore, cl::value_desc("function"));
     56 
     57 // ExtractRegExpFuncs - The functions, matched via regular expression, to
     58 // extract from the module.
     59 static cl::list<std::string>
     60 ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a "
     61                                      "regular expression"),
     62                    cl::ZeroOrMore, cl::value_desc("rfunction"));
     63 
     64 // ExtractAlias - The alias to extract from the module.
     65 static cl::list<std::string>
     66 ExtractAliases("alias", cl::desc("Specify alias to extract"),
     67                cl::ZeroOrMore, cl::value_desc("alias"));
     68 
     69 
     70 // ExtractRegExpAliases - The aliases, matched via regular expression, to
     71 // extract from the module.
     72 static cl::list<std::string>
     73 ExtractRegExpAliases("ralias", cl::desc("Specify alias(es) to extract using a "
     74                                         "regular expression"),
     75                      cl::ZeroOrMore, cl::value_desc("ralias"));
     76 
     77 // ExtractGlobals - The globals to extract from the module.
     78 static cl::list<std::string>
     79 ExtractGlobals("glob", cl::desc("Specify global to extract"),
     80                cl::ZeroOrMore, cl::value_desc("global"));
     81 
     82 // ExtractRegExpGlobals - The globals, matched via regular expression, to
     83 // extract from the module...
     84 static cl::list<std::string>
     85 ExtractRegExpGlobals("rglob", cl::desc("Specify global(s) to extract using a "
     86                                        "regular expression"),
     87                      cl::ZeroOrMore, cl::value_desc("rglobal"));
     88 
     89 static cl::opt<bool>
     90 OutputAssembly("S",
     91                cl::desc("Write output as LLVM assembly"), cl::Hidden);
     92 
     93 int main(int argc, char **argv) {
     94   // Print a stack trace if we signal out.
     95   sys::PrintStackTraceOnErrorSignal();
     96   PrettyStackTraceProgram X(argc, argv);
     97 
     98   LLVMContext &Context = getGlobalContext();
     99   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
    100   cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n");
    101 
    102   // Use lazy loading, since we only care about selected global values.
    103   SMDiagnostic Err;
    104   std::unique_ptr<Module> M;
    105   M.reset(getLazyIRFileModule(InputFilename, Err, Context));
    106 
    107   if (!M.get()) {
    108     Err.print(argv[0], errs());
    109     return 1;
    110   }
    111 
    112   // Use SetVector to avoid duplicates.
    113   SetVector<GlobalValue *> GVs;
    114 
    115   // Figure out which aliases we should extract.
    116   for (size_t i = 0, e = ExtractAliases.size(); i != e; ++i) {
    117     GlobalAlias *GA = M->getNamedAlias(ExtractAliases[i]);
    118     if (!GA) {
    119       errs() << argv[0] << ": program doesn't contain alias named '"
    120              << ExtractAliases[i] << "'!\n";
    121       return 1;
    122     }
    123     GVs.insert(GA);
    124   }
    125 
    126   // Extract aliases via regular expression matching.
    127   for (size_t i = 0, e = ExtractRegExpAliases.size(); i != e; ++i) {
    128     std::string Error;
    129     Regex RegEx(ExtractRegExpAliases[i]);
    130     if (!RegEx.isValid(Error)) {
    131       errs() << argv[0] << ": '" << ExtractRegExpAliases[i] << "' "
    132         "invalid regex: " << Error;
    133     }
    134     bool match = false;
    135     for (Module::alias_iterator GA = M->alias_begin(), E = M->alias_end();
    136          GA != E; GA++) {
    137       if (RegEx.match(GA->getName())) {
    138         GVs.insert(&*GA);
    139         match = true;
    140       }
    141     }
    142     if (!match) {
    143       errs() << argv[0] << ": program doesn't contain global named '"
    144              << ExtractRegExpAliases[i] << "'!\n";
    145       return 1;
    146     }
    147   }
    148 
    149   // Figure out which globals we should extract.
    150   for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) {
    151     GlobalValue *GV = M->getNamedGlobal(ExtractGlobals[i]);
    152     if (!GV) {
    153       errs() << argv[0] << ": program doesn't contain global named '"
    154              << ExtractGlobals[i] << "'!\n";
    155       return 1;
    156     }
    157     GVs.insert(GV);
    158   }
    159 
    160   // Extract globals via regular expression matching.
    161   for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) {
    162     std::string Error;
    163     Regex RegEx(ExtractRegExpGlobals[i]);
    164     if (!RegEx.isValid(Error)) {
    165       errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' "
    166         "invalid regex: " << Error;
    167     }
    168     bool match = false;
    169     for (auto &GV : M->globals()) {
    170       if (RegEx.match(GV.getName())) {
    171         GVs.insert(&GV);
    172         match = true;
    173       }
    174     }
    175     if (!match) {
    176       errs() << argv[0] << ": program doesn't contain global named '"
    177              << ExtractRegExpGlobals[i] << "'!\n";
    178       return 1;
    179     }
    180   }
    181 
    182   // Figure out which functions we should extract.
    183   for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) {
    184     GlobalValue *GV = M->getFunction(ExtractFuncs[i]);
    185     if (!GV) {
    186       errs() << argv[0] << ": program doesn't contain function named '"
    187              << ExtractFuncs[i] << "'!\n";
    188       return 1;
    189     }
    190     GVs.insert(GV);
    191   }
    192   // Extract functions via regular expression matching.
    193   for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) {
    194     std::string Error;
    195     StringRef RegExStr = ExtractRegExpFuncs[i];
    196     Regex RegEx(RegExStr);
    197     if (!RegEx.isValid(Error)) {
    198       errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' "
    199         "invalid regex: " << Error;
    200     }
    201     bool match = false;
    202     for (Module::iterator F = M->begin(), E = M->end(); F != E;
    203          F++) {
    204       if (RegEx.match(F->getName())) {
    205         GVs.insert(&*F);
    206         match = true;
    207       }
    208     }
    209     if (!match) {
    210       errs() << argv[0] << ": program doesn't contain global named '"
    211              << ExtractRegExpFuncs[i] << "'!\n";
    212       return 1;
    213     }
    214   }
    215 
    216   // Materialize requisite global values.
    217   if (!DeleteFn)
    218     for (size_t i = 0, e = GVs.size(); i != e; ++i) {
    219       GlobalValue *GV = GVs[i];
    220       if (GV->isMaterializable()) {
    221         std::string ErrInfo;
    222         if (GV->Materialize(&ErrInfo)) {
    223           errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
    224           return 1;
    225         }
    226       }
    227     }
    228   else {
    229     // Deleting. Materialize every GV that's *not* in GVs.
    230     SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end());
    231     for (auto &G : M->globals()) {
    232       if (!GVSet.count(&G) && G.isMaterializable()) {
    233         std::string ErrInfo;
    234         if (G.Materialize(&ErrInfo)) {
    235           errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
    236           return 1;
    237         }
    238       }
    239     }
    240     for (auto &F : *M) {
    241       if (!GVSet.count(&F) && F.isMaterializable()) {
    242         std::string ErrInfo;
    243         if (F.Materialize(&ErrInfo)) {
    244           errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
    245           return 1;
    246         }
    247       }
    248     }
    249   }
    250 
    251   // In addition to deleting all other functions, we also want to spiff it
    252   // up a little bit.  Do this now.
    253   PassManager Passes;
    254   Passes.add(new DataLayoutPass(M.get())); // Use correct DataLayout
    255 
    256   std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end());
    257 
    258   Passes.add(createGVExtractionPass(Gvs, DeleteFn));
    259   if (!DeleteFn)
    260     Passes.add(createGlobalDCEPass());           // Delete unreachable globals
    261   Passes.add(createStripDeadDebugInfoPass());    // Remove dead debug info
    262   Passes.add(createStripDeadPrototypesPass());   // Remove dead func decls
    263 
    264   std::string ErrorInfo;
    265   tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None);
    266   if (!ErrorInfo.empty()) {
    267     errs() << ErrorInfo << '\n';
    268     return 1;
    269   }
    270 
    271   if (OutputAssembly)
    272     Passes.add(createPrintModulePass(Out.os()));
    273   else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true))
    274     Passes.add(createBitcodeWriterPass(Out.os()));
    275 
    276   Passes.run(*M.get());
    277 
    278   // Declare success.
    279   Out.keep();
    280 
    281   return 0;
    282 }
    283