llvm-extract.cpp revision e4f1a9b8a272ff7452759019ee7774e9dbdf1568
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/LLVMContext.h" 16#include "llvm/Module.h" 17#include "llvm/PassManager.h" 18#include "llvm/Assembly/PrintModulePass.h" 19#include "llvm/Bitcode/ReaderWriter.h" 20#include "llvm/Transforms/IPO.h" 21#include "llvm/Target/TargetData.h" 22#include "llvm/Support/CommandLine.h" 23#include "llvm/Support/IRReader.h" 24#include "llvm/Support/ManagedStatic.h" 25#include "llvm/Support/PrettyStackTrace.h" 26#include "llvm/Support/ToolOutputFile.h" 27#include "llvm/Support/SystemUtils.h" 28#include "llvm/System/Signals.h" 29#include "llvm/ADT/SmallPtrSet.h" 30#include <memory> 31using namespace llvm; 32 33// InputFilename - The filename to read from. 34static cl::opt<std::string> 35InputFilename(cl::Positional, cl::desc("<input bitcode file>"), 36 cl::init("-"), cl::value_desc("filename")); 37 38static cl::opt<std::string> 39OutputFilename("o", cl::desc("Specify output filename"), 40 cl::value_desc("filename"), cl::init("-")); 41 42static cl::opt<bool> 43Force("f", cl::desc("Enable binary output on terminals")); 44 45static cl::opt<bool> 46DeleteFn("delete", cl::desc("Delete specified Globals from Module")); 47 48// ExtractFuncs - The functions to extract from the module... 49static cl::list<std::string> 50ExtractFuncs("func", cl::desc("Specify function to extract"), 51 cl::ZeroOrMore, cl::value_desc("function")); 52 53// ExtractGlobals - The globals to extract from the module... 54static cl::list<std::string> 55ExtractGlobals("glob", cl::desc("Specify global to extract"), 56 cl::ZeroOrMore, cl::value_desc("global")); 57 58static cl::opt<bool> 59OutputAssembly("S", 60 cl::desc("Write output as LLVM assembly"), cl::Hidden); 61 62int main(int argc, char **argv) { 63 // Print a stack trace if we signal out. 64 sys::PrintStackTraceOnErrorSignal(); 65 PrettyStackTraceProgram X(argc, argv); 66 67 LLVMContext &Context = getGlobalContext(); 68 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 69 cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); 70 71 // Use lazy loading, since we only care about selected global values. 72 SMDiagnostic Err; 73 std::auto_ptr<Module> M; 74 M.reset(getLazyIRFileModule(InputFilename, Err, Context)); 75 76 if (M.get() == 0) { 77 Err.Print(argv[0], errs()); 78 return 1; 79 } 80 81 std::vector<GlobalValue *> GVs; 82 83 // Figure out which globals we should extract. 84 for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { 85 GlobalValue *GV = M.get()->getNamedGlobal(ExtractGlobals[i]); 86 if (!GV) { 87 errs() << argv[0] << ": program doesn't contain global named '" 88 << ExtractGlobals[i] << "'!\n"; 89 return 1; 90 } 91 GVs.push_back(GV); 92 } 93 94 // Figure out which functions we should extract. 95 for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) { 96 GlobalValue *GV = M.get()->getFunction(ExtractFuncs[i]); 97 if (!GV) { 98 errs() << argv[0] << ": program doesn't contain function named '" 99 << ExtractFuncs[i] << "'!\n"; 100 return 1; 101 } 102 GVs.push_back(GV); 103 } 104 105 // Materialize requisite global values. 106 if (!DeleteFn) 107 for (size_t i = 0, e = GVs.size(); i != e; ++i) { 108 GlobalValue *GV = GVs[i]; 109 if (GV->isMaterializable()) { 110 std::string ErrInfo; 111 if (GV->Materialize(&ErrInfo)) { 112 errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; 113 return 1; 114 } 115 } 116 } 117 else { 118 // Deleting. Materialize every GV that's *not* in GVs. 119 SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end()); 120 for (Module::global_iterator I = M->global_begin(), E = M->global_end(); 121 I != E; ++I) { 122 GlobalVariable *G = I; 123 if (!GVSet.count(G) && G->isMaterializable()) { 124 std::string ErrInfo; 125 if (G->Materialize(&ErrInfo)) { 126 errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; 127 return 1; 128 } 129 } 130 } 131 for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { 132 Function *F = I; 133 if (!GVSet.count(F) && F->isMaterializable()) { 134 std::string ErrInfo; 135 if (F->Materialize(&ErrInfo)) { 136 errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; 137 return 1; 138 } 139 } 140 } 141 } 142 143 // In addition to deleting all other functions, we also want to spiff it 144 // up a little bit. Do this now. 145 PassManager Passes; 146 Passes.add(new TargetData(M.get())); // Use correct TargetData 147 148 Passes.add(createGVExtractionPass(GVs, DeleteFn)); 149 if (!DeleteFn) 150 Passes.add(createGlobalDCEPass()); // Delete unreachable globals 151 Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info 152 Passes.add(createDeadTypeEliminationPass()); // Remove dead types... 153 Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls 154 155 std::string ErrorInfo; 156 tool_output_file Out(OutputFilename.c_str(), ErrorInfo, 157 raw_fd_ostream::F_Binary); 158 if (!ErrorInfo.empty()) { 159 errs() << ErrorInfo << '\n'; 160 return 1; 161 } 162 163 if (OutputAssembly) 164 Passes.add(createPrintModulePass(&Out.os())); 165 else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) 166 Passes.add(createBitcodeWriterPass(Out.os())); 167 168 Passes.run(*M.get()); 169 170 // Declare success. 171 Out.keep(); 172 173 return 0; 174} 175