comparison tools/llvm-extract/llvm-extract.cpp @ 148:63bd29f05246

merged
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 14 Aug 2019 19:46:37 +0900
parents c2174574ed3a
children
comparison
equal deleted inserted replaced
146:3fc4d5c3e21e 148:63bd29f05246
1 //===- llvm-extract.cpp - LLVM function extraction utility ----------------===// 1 //===- llvm-extract.cpp - LLVM function extraction utility ----------------===//
2 // 2 //
3 // The LLVM Compiler Infrastructure 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // 4 // See https://llvm.org/LICENSE.txt for license information.
5 // This file is distributed under the University of Illinois Open Source 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 // License. See LICENSE.TXT for details.
7 // 6 //
8 //===----------------------------------------------------------------------===// 7 //===----------------------------------------------------------------------===//
9 // 8 //
10 // This utility changes the input module to only contain a single function, 9 // This utility changes the input module to only contain a single function,
11 // which is primarily used for debugging transformations. 10 // which is primarily used for debugging transformations.
23 #include "llvm/IR/Module.h" 22 #include "llvm/IR/Module.h"
24 #include "llvm/IRReader/IRReader.h" 23 #include "llvm/IRReader/IRReader.h"
25 #include "llvm/Support/CommandLine.h" 24 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/Error.h" 25 #include "llvm/Support/Error.h"
27 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/ManagedStatic.h" 27 #include "llvm/Support/InitLLVM.h"
29 #include "llvm/Support/PrettyStackTrace.h"
30 #include "llvm/Support/Regex.h" 28 #include "llvm/Support/Regex.h"
31 #include "llvm/Support/Signals.h"
32 #include "llvm/Support/SourceMgr.h" 29 #include "llvm/Support/SourceMgr.h"
33 #include "llvm/Support/SystemUtils.h" 30 #include "llvm/Support/SystemUtils.h"
34 #include "llvm/Support/ToolOutputFile.h" 31 #include "llvm/Support/ToolOutputFile.h"
35 #include "llvm/Transforms/IPO.h" 32 #include "llvm/Transforms/IPO.h"
36 #include <memory> 33 #include <memory>
37 using namespace llvm; 34 using namespace llvm;
38 35
36 cl::OptionCategory ExtractCat("llvm-extract Options");
37
39 // InputFilename - The filename to read from. 38 // InputFilename - The filename to read from.
40 static cl::opt<std::string> 39 static cl::opt<std::string> InputFilename(cl::Positional,
41 InputFilename(cl::Positional, cl::desc("<input bitcode file>"), 40 cl::desc("<input bitcode file>"),
42 cl::init("-"), cl::value_desc("filename")); 41 cl::init("-"),
43 42 cl::value_desc("filename"));
44 static cl::opt<std::string> 43
45 OutputFilename("o", cl::desc("Specify output filename"), 44 static cl::opt<std::string> OutputFilename("o",
46 cl::value_desc("filename"), cl::init("-")); 45 cl::desc("Specify output filename"),
46 cl::value_desc("filename"),
47 cl::init("-"), cl::cat(ExtractCat));
48
49 static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"),
50 cl::cat(ExtractCat));
51
52 static cl::opt<bool> DeleteFn("delete",
53 cl::desc("Delete specified Globals from Module"),
54 cl::cat(ExtractCat));
47 55
48 static cl::opt<bool> 56 static cl::opt<bool>
49 Force("f", cl::desc("Enable binary output on terminals")); 57 Recursive("recursive", cl::desc("Recursively extract all called functions"),
50 58 cl::cat(ExtractCat));
51 static cl::opt<bool>
52 DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
53
54 static cl::opt<bool>
55 Recursive("recursive",
56 cl::desc("Recursively extract all called functions"));
57 59
58 // ExtractFuncs - The functions to extract from the module. 60 // ExtractFuncs - The functions to extract from the module.
59 static cl::list<std::string> 61 static cl::list<std::string>
60 ExtractFuncs("func", cl::desc("Specify function to extract"), 62 ExtractFuncs("func", cl::desc("Specify function to extract"),
61 cl::ZeroOrMore, cl::value_desc("function")); 63 cl::ZeroOrMore, cl::value_desc("function"),
64 cl::cat(ExtractCat));
62 65
63 // ExtractRegExpFuncs - The functions, matched via regular expression, to 66 // ExtractRegExpFuncs - The functions, matched via regular expression, to
64 // extract from the module. 67 // extract from the module.
65 static cl::list<std::string> 68 static cl::list<std::string>
66 ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a " 69 ExtractRegExpFuncs("rfunc",
67 "regular expression"), 70 cl::desc("Specify function(s) to extract using a "
68 cl::ZeroOrMore, cl::value_desc("rfunction")); 71 "regular expression"),
72 cl::ZeroOrMore, cl::value_desc("rfunction"),
73 cl::cat(ExtractCat));
69 74
70 // ExtractBlocks - The blocks to extract from the module. 75 // ExtractBlocks - The blocks to extract from the module.
71 static cl::list<std::string> 76 static cl::list<std::string> ExtractBlocks(
72 ExtractBlocks("bb", 77 "bb", cl::desc("Specify <function, basic block> pairs to extract"),
73 cl::desc("Specify <function, basic block> pairs to extract"), 78 cl::ZeroOrMore, cl::value_desc("function:bb"), cl::cat(ExtractCat));
74 cl::ZeroOrMore, cl::value_desc("function:bb"));
75 79
76 // ExtractAlias - The alias to extract from the module. 80 // ExtractAlias - The alias to extract from the module.
77 static cl::list<std::string> 81 static cl::list<std::string>
78 ExtractAliases("alias", cl::desc("Specify alias to extract"), 82 ExtractAliases("alias", cl::desc("Specify alias to extract"),
79 cl::ZeroOrMore, cl::value_desc("alias")); 83 cl::ZeroOrMore, cl::value_desc("alias"),
80 84 cl::cat(ExtractCat));
81 85
82 // ExtractRegExpAliases - The aliases, matched via regular expression, to 86 // ExtractRegExpAliases - The aliases, matched via regular expression, to
83 // extract from the module. 87 // extract from the module.
84 static cl::list<std::string> 88 static cl::list<std::string>
85 ExtractRegExpAliases("ralias", cl::desc("Specify alias(es) to extract using a " 89 ExtractRegExpAliases("ralias",
86 "regular expression"), 90 cl::desc("Specify alias(es) to extract using a "
87 cl::ZeroOrMore, cl::value_desc("ralias")); 91 "regular expression"),
92 cl::ZeroOrMore, cl::value_desc("ralias"),
93 cl::cat(ExtractCat));
88 94
89 // ExtractGlobals - The globals to extract from the module. 95 // ExtractGlobals - The globals to extract from the module.
90 static cl::list<std::string> 96 static cl::list<std::string>
91 ExtractGlobals("glob", cl::desc("Specify global to extract"), 97 ExtractGlobals("glob", cl::desc("Specify global to extract"),
92 cl::ZeroOrMore, cl::value_desc("global")); 98 cl::ZeroOrMore, cl::value_desc("global"),
99 cl::cat(ExtractCat));
93 100
94 // ExtractRegExpGlobals - The globals, matched via regular expression, to 101 // ExtractRegExpGlobals - The globals, matched via regular expression, to
95 // extract from the module... 102 // extract from the module...
96 static cl::list<std::string> 103 static cl::list<std::string>
97 ExtractRegExpGlobals("rglob", cl::desc("Specify global(s) to extract using a " 104 ExtractRegExpGlobals("rglob",
98 "regular expression"), 105 cl::desc("Specify global(s) to extract using a "
99 cl::ZeroOrMore, cl::value_desc("rglobal")); 106 "regular expression"),
100 107 cl::ZeroOrMore, cl::value_desc("rglobal"),
101 static cl::opt<bool> 108 cl::cat(ExtractCat));
102 OutputAssembly("S", 109
103 cl::desc("Write output as LLVM assembly"), cl::Hidden); 110 static cl::opt<bool> OutputAssembly("S",
111 cl::desc("Write output as LLVM assembly"),
112 cl::Hidden, cl::cat(ExtractCat));
104 113
105 static cl::opt<bool> PreserveBitcodeUseListOrder( 114 static cl::opt<bool> PreserveBitcodeUseListOrder(
106 "preserve-bc-uselistorder", 115 "preserve-bc-uselistorder",
107 cl::desc("Preserve use-list order when writing LLVM bitcode."), 116 cl::desc("Preserve use-list order when writing LLVM bitcode."),
108 cl::init(true), cl::Hidden); 117 cl::init(true), cl::Hidden, cl::cat(ExtractCat));
109 118
110 static cl::opt<bool> PreserveAssemblyUseListOrder( 119 static cl::opt<bool> PreserveAssemblyUseListOrder(
111 "preserve-ll-uselistorder", 120 "preserve-ll-uselistorder",
112 cl::desc("Preserve use-list order when writing LLVM assembly."), 121 cl::desc("Preserve use-list order when writing LLVM assembly."),
113 cl::init(false), cl::Hidden); 122 cl::init(false), cl::Hidden, cl::cat(ExtractCat));
114 123
115 int main(int argc, char **argv) { 124 int main(int argc, char **argv) {
116 // Print a stack trace if we signal out. 125 InitLLVM X(argc, argv);
117 sys::PrintStackTraceOnErrorSignal(argv[0]);
118 PrettyStackTraceProgram X(argc, argv);
119 126
120 LLVMContext Context; 127 LLVMContext Context;
121 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 128 cl::HideUnrelatedOptions(ExtractCat);
122 cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); 129 cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n");
123 130
124 // Use lazy loading, since we only care about selected global values. 131 // Use lazy loading, since we only care about selected global values.
125 SMDiagnostic Err; 132 SMDiagnostic Err;
126 std::unique_ptr<Module> M = getLazyIRFileModule(InputFilename, Err, Context); 133 std::unique_ptr<Module> M = getLazyIRFileModule(InputFilename, Err, Context);
233 return 1; 240 return 1;
234 } 241 }
235 } 242 }
236 243
237 // Figure out which BasicBlocks we should extract. 244 // Figure out which BasicBlocks we should extract.
238 SmallVector<BasicBlock *, 4> BBs; 245 SmallVector<SmallVector<BasicBlock *, 16>, 4> GroupOfBBs;
239 for (StringRef StrPair : ExtractBlocks) { 246 for (StringRef StrPair : ExtractBlocks) {
240 auto BBInfo = StrPair.split(':'); 247 auto BBInfo = StrPair.split(':');
241 // Get the function. 248 // Get the function.
242 Function *F = M->getFunction(BBInfo.first); 249 Function *F = M->getFunction(BBInfo.first);
243 if (!F) { 250 if (!F) {
245 << BBInfo.first << "'!\n"; 252 << BBInfo.first << "'!\n";
246 return 1; 253 return 1;
247 } 254 }
248 // Do not materialize this function. 255 // Do not materialize this function.
249 GVs.insert(F); 256 GVs.insert(F);
250 // Get the basic block. 257 // Get the basic blocks.
251 auto Res = llvm::find_if(*F, [&](const BasicBlock &BB) { 258 SmallVector<BasicBlock *, 16> BBs;
252 return BB.getName().equals(BBInfo.second); 259 SmallVector<StringRef, 16> BBNames;
253 }); 260 BBInfo.second.split(BBNames, ';', /*MaxSplit=*/-1,
254 if (Res == F->end()) { 261 /*KeepEmpty=*/false);
255 errs() << argv[0] << ": function " << F->getName() 262 for (StringRef BBName : BBNames) {
256 << " doesn't contain a basic block named '" << BBInfo.second 263 auto Res = llvm::find_if(*F, [&](const BasicBlock &BB) {
257 << "'!\n"; 264 return BB.getName().equals(BBName);
258 return 1; 265 });
259 } 266 if (Res == F->end()) {
260 BBs.push_back(&*Res); 267 errs() << argv[0] << ": function " << F->getName()
268 << " doesn't contain a basic block named '" << BBInfo.second
269 << "'!\n";
270 return 1;
271 }
272 BBs.push_back(&*Res);
273 }
274 GroupOfBBs.push_back(BBs);
261 } 275 }
262 276
263 // Use *argv instead of argv[0] to work around a wrong GCC warning. 277 // Use *argv instead of argv[0] to work around a wrong GCC warning.
264 ExitOnError ExitOnErr(std::string(*argv) + ": error reading input: "); 278 ExitOnError ExitOnErr(std::string(*argv) + ": error reading input: ");
265 279
274 Function *F = &*Workqueue.back(); 288 Function *F = &*Workqueue.back();
275 Workqueue.pop_back(); 289 Workqueue.pop_back();
276 ExitOnErr(F->materialize()); 290 ExitOnErr(F->materialize());
277 for (auto &BB : *F) { 291 for (auto &BB : *F) {
278 for (auto &I : BB) { 292 for (auto &I : BB) {
279 auto *CI = dyn_cast<CallInst>(&I); 293 CallBase *CB = dyn_cast<CallBase>(&I);
280 if (!CI) 294 if (!CB)
281 continue; 295 continue;
282 Function *CF = CI->getCalledFunction(); 296 Function *CF = CB->getCalledFunction();
283 if (!CF) 297 if (!CF)
284 continue; 298 continue;
285 if (CF->isDeclaration() || GVs.count(CF)) 299 if (CF->isDeclaration() || GVs.count(CF))
286 continue; 300 continue;
287 GVs.insert(CF); 301 GVs.insert(CF);
320 334
321 // Extract the specified basic blocks from the module and erase the existing 335 // Extract the specified basic blocks from the module and erase the existing
322 // functions. 336 // functions.
323 if (!ExtractBlocks.empty()) { 337 if (!ExtractBlocks.empty()) {
324 legacy::PassManager PM; 338 legacy::PassManager PM;
325 PM.add(createBlockExtractorPass(BBs, true)); 339 PM.add(createBlockExtractorPass(GroupOfBBs, true));
326 PM.run(*M); 340 PM.run(*M);
327 } 341 }
328 342
329 // In addition to deleting all other functions, we also want to spiff it 343 // In addition to deleting all other functions, we also want to spiff it
330 // up a little bit. Do this now. 344 // up a little bit. Do this now.
334 Passes.add(createGlobalDCEPass()); // Delete unreachable globals 348 Passes.add(createGlobalDCEPass()); // Delete unreachable globals
335 Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info 349 Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info
336 Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls 350 Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls
337 351
338 std::error_code EC; 352 std::error_code EC;
339 ToolOutputFile Out(OutputFilename, EC, sys::fs::F_None); 353 ToolOutputFile Out(OutputFilename, EC, sys::fs::OF_None);
340 if (EC) { 354 if (EC) {
341 errs() << EC.message() << '\n'; 355 errs() << EC.message() << '\n';
342 return 1; 356 return 1;
343 } 357 }
344 358