Mercurial > hg > CbC > CbC_llvm
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 |