llvm-extract.cpp revision 2cccc6220cc351b52d2cd2d0b7139502e854b68d
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/IR/LLVMContext.h" 16#include "llvm/ADT/SetVector.h" 17#include "llvm/ADT/SmallPtrSet.h" 18#include "llvm/Assembly/PrintModulePass.h" 19#include "llvm/Bitcode/ReaderWriter.h" 20#include "llvm/IR/DataLayout.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/ManagedStatic.h" 26#include "llvm/Support/PrettyStackTrace.h" 27#include "llvm/Support/Regex.h" 28#include "llvm/Support/Signals.h" 29#include "llvm/Support/SourceMgr.h" 30#include "llvm/Support/SystemUtils.h" 31#include "llvm/Support/ToolOutputFile.h" 32#include "llvm/Transforms/IPO.h" 33#include <memory> 34using namespace llvm; 35 36// InputFilename - The filename to read from. 37static cl::opt<std::string> 38InputFilename(cl::Positional, cl::desc("<input bitcode file>"), 39 cl::init("-"), cl::value_desc("filename")); 40 41static cl::opt<std::string> 42OutputFilename("o", cl::desc("Specify output filename"), 43 cl::value_desc("filename"), cl::init("-")); 44 45static cl::opt<bool> 46Force("f", cl::desc("Enable binary output on terminals")); 47 48static cl::opt<bool> 49DeleteFn("delete", cl::desc("Delete specified Globals from Module")); 50 51// ExtractFuncs - The functions to extract from the module. 52static cl::list<std::string> 53ExtractFuncs("func", cl::desc("Specify function to extract"), 54 cl::ZeroOrMore, cl::value_desc("function")); 55 56// ExtractRegExpFuncs - The functions, matched via regular expression, to 57// extract from the module. 58static cl::list<std::string> 59ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a " 60 "regular expression"), 61 cl::ZeroOrMore, cl::value_desc("rfunction")); 62 63// ExtractAlias - The alias to extract from the module. 64static cl::list<std::string> 65ExtractAliases("alias", cl::desc("Specify alias to extract"), 66 cl::ZeroOrMore, cl::value_desc("alias")); 67 68 69// ExtractRegExpAliases - The aliases, matched via regular expression, to 70// extract from the module. 71static cl::list<std::string> 72ExtractRegExpAliases("ralias", cl::desc("Specify alias(es) to extract using a " 73 "regular expression"), 74 cl::ZeroOrMore, cl::value_desc("ralias")); 75 76// ExtractGlobals - The globals to extract from the module. 77static cl::list<std::string> 78ExtractGlobals("glob", cl::desc("Specify global to extract"), 79 cl::ZeroOrMore, cl::value_desc("global")); 80 81// ExtractRegExpGlobals - The globals, matched via regular expression, to 82// extract from the module... 83static cl::list<std::string> 84ExtractRegExpGlobals("rglob", cl::desc("Specify global(s) to extract using a " 85 "regular expression"), 86 cl::ZeroOrMore, cl::value_desc("rglobal")); 87 88static cl::opt<bool> 89OutputAssembly("S", 90 cl::desc("Write output as LLVM assembly"), cl::Hidden); 91 92int main(int argc, char **argv) { 93 // Print a stack trace if we signal out. 94 sys::PrintStackTraceOnErrorSignal(); 95 PrettyStackTraceProgram X(argc, argv); 96 97 LLVMContext &Context = getGlobalContext(); 98 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 99 cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); 100 101 // Use lazy loading, since we only care about selected global values. 102 SMDiagnostic Err; 103 OwningPtr<Module> M; 104 M.reset(getLazyIRFileModule(InputFilename, Err, Context)); 105 106 if (M.get() == 0) { 107 Err.print(argv[0], errs()); 108 return 1; 109 } 110 111 // Use SetVector to avoid duplicates. 112 SetVector<GlobalValue *> GVs; 113 114 // Figure out which aliases we should extract. 115 for (size_t i = 0, e = ExtractAliases.size(); i != e; ++i) { 116 GlobalAlias *GA = M->getNamedAlias(ExtractAliases[i]); 117 if (!GA) { 118 errs() << argv[0] << ": program doesn't contain alias named '" 119 << ExtractAliases[i] << "'!\n"; 120 return 1; 121 } 122 GVs.insert(GA); 123 } 124 125 // Extract aliases via regular expression matching. 126 for (size_t i = 0, e = ExtractRegExpAliases.size(); i != e; ++i) { 127 std::string Error; 128 Regex RegEx(ExtractRegExpAliases[i]); 129 if (!RegEx.isValid(Error)) { 130 errs() << argv[0] << ": '" << ExtractRegExpAliases[i] << "' " 131 "invalid regex: " << Error; 132 } 133 bool match = false; 134 for (Module::alias_iterator GA = M->alias_begin(), E = M->alias_end(); 135 GA != E; GA++) { 136 if (RegEx.match(GA->getName())) { 137 GVs.insert(&*GA); 138 match = true; 139 } 140 } 141 if (!match) { 142 errs() << argv[0] << ": program doesn't contain global named '" 143 << ExtractRegExpAliases[i] << "'!\n"; 144 return 1; 145 } 146 } 147 148 // Figure out which globals we should extract. 149 for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { 150 GlobalValue *GV = M->getNamedGlobal(ExtractGlobals[i]); 151 if (!GV) { 152 errs() << argv[0] << ": program doesn't contain global named '" 153 << ExtractGlobals[i] << "'!\n"; 154 return 1; 155 } 156 GVs.insert(GV); 157 } 158 159 // Extract globals via regular expression matching. 160 for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) { 161 std::string Error; 162 Regex RegEx(ExtractRegExpGlobals[i]); 163 if (!RegEx.isValid(Error)) { 164 errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' " 165 "invalid regex: " << Error; 166 } 167 bool match = false; 168 for (Module::global_iterator GV = M->global_begin(), 169 E = M->global_end(); GV != E; GV++) { 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 (Module::global_iterator I = M->global_begin(), E = M->global_end(); 232 I != E; ++I) { 233 GlobalVariable *G = I; 234 if (!GVSet.count(G) && G->isMaterializable()) { 235 std::string ErrInfo; 236 if (G->Materialize(&ErrInfo)) { 237 errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; 238 return 1; 239 } 240 } 241 } 242 for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { 243 Function *F = I; 244 if (!GVSet.count(F) && F->isMaterializable()) { 245 std::string ErrInfo; 246 if (F->Materialize(&ErrInfo)) { 247 errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; 248 return 1; 249 } 250 } 251 } 252 } 253 254 // In addition to deleting all other functions, we also want to spiff it 255 // up a little bit. Do this now. 256 PassManager Passes; 257 Passes.add(new DataLayout(M.get())); // Use correct DataLayout 258 259 std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); 260 261 Passes.add(createGVExtractionPass(Gvs, DeleteFn)); 262 if (!DeleteFn) 263 Passes.add(createGlobalDCEPass()); // Delete unreachable globals 264 Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info 265 Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls 266 267 std::string ErrorInfo; 268 tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary); 269 if (!ErrorInfo.empty()) { 270 errs() << ErrorInfo << '\n'; 271 return 1; 272 } 273 274 if (OutputAssembly) 275 Passes.add(createPrintModulePass(&Out.os())); 276 else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) 277 Passes.add(createBitcodeWriterPass(Out.os())); 278 279 Passes.run(*M.get()); 280 281 // Declare success. 282 Out.keep(); 283 284 return 0; 285} 286