10b57cec5SDimitry Andric //===- llvm-extract.cpp - LLVM function extraction utility ----------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This utility changes the input module to only contain a single function, 100b57cec5SDimitry Andric // which is primarily used for debugging transformations. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h" 150b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 160b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeWriterPass.h" 170b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 180b57cec5SDimitry Andric #include "llvm/IR/IRPrintingPasses.h" 190b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 200b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 210b57cec5SDimitry Andric #include "llvm/IR/Module.h" 22bdd1243dSDimitry Andric #include "llvm/IRPrinter/IRPrintingPasses.h" 230b57cec5SDimitry Andric #include "llvm/IRReader/IRReader.h" 24bdd1243dSDimitry Andric #include "llvm/Passes/PassBuilder.h" 250b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 260b57cec5SDimitry Andric #include "llvm/Support/Error.h" 270b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 280b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h" 290b57cec5SDimitry Andric #include "llvm/Support/Regex.h" 300b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 310b57cec5SDimitry Andric #include "llvm/Support/SystemUtils.h" 320b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h" 330b57cec5SDimitry Andric #include "llvm/Transforms/IPO.h" 34bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/BlockExtractor.h" 35bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/ExtractGV.h" 36bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/GlobalDCE.h" 37bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/StripDeadPrototypes.h" 38bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/StripSymbols.h" 390b57cec5SDimitry Andric #include <memory> 405ffd83dbSDimitry Andric #include <utility> 41bdd1243dSDimitry Andric 420b57cec5SDimitry Andric using namespace llvm; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric cl::OptionCategory ExtractCat("llvm-extract Options"); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // InputFilename - The filename to read from. 470b57cec5SDimitry Andric static cl::opt<std::string> InputFilename(cl::Positional, 480b57cec5SDimitry Andric cl::desc("<input bitcode file>"), 490b57cec5SDimitry Andric cl::init("-"), 500b57cec5SDimitry Andric cl::value_desc("filename")); 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric static cl::opt<std::string> OutputFilename("o", 530b57cec5SDimitry Andric cl::desc("Specify output filename"), 540b57cec5SDimitry Andric cl::value_desc("filename"), 550b57cec5SDimitry Andric cl::init("-"), cl::cat(ExtractCat)); 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"), 580b57cec5SDimitry Andric cl::cat(ExtractCat)); 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric static cl::opt<bool> DeleteFn("delete", 610b57cec5SDimitry Andric cl::desc("Delete specified Globals from Module"), 620b57cec5SDimitry Andric cl::cat(ExtractCat)); 630b57cec5SDimitry Andric 645ffd83dbSDimitry Andric static cl::opt<bool> KeepConstInit("keep-const-init", 655ffd83dbSDimitry Andric cl::desc("Keep initializers of constants"), 665ffd83dbSDimitry Andric cl::cat(ExtractCat)); 675ffd83dbSDimitry Andric 680b57cec5SDimitry Andric static cl::opt<bool> 690b57cec5SDimitry Andric Recursive("recursive", cl::desc("Recursively extract all called functions"), 700b57cec5SDimitry Andric cl::cat(ExtractCat)); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric // ExtractFuncs - The functions to extract from the module. 730b57cec5SDimitry Andric static cl::list<std::string> 740b57cec5SDimitry Andric ExtractFuncs("func", cl::desc("Specify function to extract"), 7581ad6265SDimitry Andric cl::value_desc("function"), cl::cat(ExtractCat)); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // ExtractRegExpFuncs - The functions, matched via regular expression, to 780b57cec5SDimitry Andric // extract from the module. 790b57cec5SDimitry Andric static cl::list<std::string> 800b57cec5SDimitry Andric ExtractRegExpFuncs("rfunc", 810b57cec5SDimitry Andric cl::desc("Specify function(s) to extract using a " 820b57cec5SDimitry Andric "regular expression"), 8381ad6265SDimitry Andric cl::value_desc("rfunction"), cl::cat(ExtractCat)); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // ExtractBlocks - The blocks to extract from the module. 860b57cec5SDimitry Andric static cl::list<std::string> ExtractBlocks( 878bcb0991SDimitry Andric "bb", 888bcb0991SDimitry Andric cl::desc( 898bcb0991SDimitry Andric "Specify <function, basic block1[;basic block2...]> pairs to extract.\n" 908bcb0991SDimitry Andric "Each pair will create a function.\n" 918bcb0991SDimitry Andric "If multiple basic blocks are specified in one pair,\n" 928bcb0991SDimitry Andric "the first block in the sequence should dominate the rest.\n" 938bcb0991SDimitry Andric "eg:\n" 948bcb0991SDimitry Andric " --bb=f:bb1;bb2 will extract one function with both bb1 and bb2;\n" 958bcb0991SDimitry Andric " --bb=f:bb1 --bb=f:bb2 will extract two functions, one with bb1, one " 968bcb0991SDimitry Andric "with bb2."), 9781ad6265SDimitry Andric cl::value_desc("function:bb1[;bb2...]"), cl::cat(ExtractCat)); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric // ExtractAlias - The alias to extract from the module. 1000b57cec5SDimitry Andric static cl::list<std::string> 1010b57cec5SDimitry Andric ExtractAliases("alias", cl::desc("Specify alias to extract"), 10281ad6265SDimitry Andric cl::value_desc("alias"), cl::cat(ExtractCat)); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // ExtractRegExpAliases - The aliases, matched via regular expression, to 1050b57cec5SDimitry Andric // extract from the module. 1060b57cec5SDimitry Andric static cl::list<std::string> 1070b57cec5SDimitry Andric ExtractRegExpAliases("ralias", 1080b57cec5SDimitry Andric cl::desc("Specify alias(es) to extract using a " 1090b57cec5SDimitry Andric "regular expression"), 11081ad6265SDimitry Andric cl::value_desc("ralias"), cl::cat(ExtractCat)); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric // ExtractGlobals - The globals to extract from the module. 1130b57cec5SDimitry Andric static cl::list<std::string> 1140b57cec5SDimitry Andric ExtractGlobals("glob", cl::desc("Specify global to extract"), 11581ad6265SDimitry Andric cl::value_desc("global"), cl::cat(ExtractCat)); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // ExtractRegExpGlobals - The globals, matched via regular expression, to 1180b57cec5SDimitry Andric // extract from the module... 1190b57cec5SDimitry Andric static cl::list<std::string> 1200b57cec5SDimitry Andric ExtractRegExpGlobals("rglob", 1210b57cec5SDimitry Andric cl::desc("Specify global(s) to extract using a " 1220b57cec5SDimitry Andric "regular expression"), 12381ad6265SDimitry Andric cl::value_desc("rglobal"), cl::cat(ExtractCat)); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric static cl::opt<bool> OutputAssembly("S", 1260b57cec5SDimitry Andric cl::desc("Write output as LLVM assembly"), 1270b57cec5SDimitry Andric cl::Hidden, cl::cat(ExtractCat)); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric static cl::opt<bool> PreserveBitcodeUseListOrder( 1300b57cec5SDimitry Andric "preserve-bc-uselistorder", 1310b57cec5SDimitry Andric cl::desc("Preserve use-list order when writing LLVM bitcode."), 1320b57cec5SDimitry Andric cl::init(true), cl::Hidden, cl::cat(ExtractCat)); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric static cl::opt<bool> PreserveAssemblyUseListOrder( 1350b57cec5SDimitry Andric "preserve-ll-uselistorder", 1360b57cec5SDimitry Andric cl::desc("Preserve use-list order when writing LLVM assembly."), 1370b57cec5SDimitry Andric cl::init(false), cl::Hidden, cl::cat(ExtractCat)); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric int main(int argc, char **argv) { 1400b57cec5SDimitry Andric InitLLVM X(argc, argv); 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric LLVMContext Context; 1430b57cec5SDimitry Andric cl::HideUnrelatedOptions(ExtractCat); 1440b57cec5SDimitry Andric cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric // Use lazy loading, since we only care about selected global values. 1470b57cec5SDimitry Andric SMDiagnostic Err; 1480b57cec5SDimitry Andric std::unique_ptr<Module> M = getLazyIRFileModule(InputFilename, Err, Context); 1490b57cec5SDimitry Andric 150*0fca6ea1SDimitry Andric if (!M) { 1510b57cec5SDimitry Andric Err.print(argv[0], errs()); 1520b57cec5SDimitry Andric return 1; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // Use SetVector to avoid duplicates. 1560b57cec5SDimitry Andric SetVector<GlobalValue *> GVs; 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Figure out which aliases we should extract. 1590b57cec5SDimitry Andric for (size_t i = 0, e = ExtractAliases.size(); i != e; ++i) { 1600b57cec5SDimitry Andric GlobalAlias *GA = M->getNamedAlias(ExtractAliases[i]); 1610b57cec5SDimitry Andric if (!GA) { 1620b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain alias named '" 1630b57cec5SDimitry Andric << ExtractAliases[i] << "'!\n"; 1640b57cec5SDimitry Andric return 1; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric GVs.insert(GA); 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric // Extract aliases via regular expression matching. 1700b57cec5SDimitry Andric for (size_t i = 0, e = ExtractRegExpAliases.size(); i != e; ++i) { 1710b57cec5SDimitry Andric std::string Error; 1720b57cec5SDimitry Andric Regex RegEx(ExtractRegExpAliases[i]); 1730b57cec5SDimitry Andric if (!RegEx.isValid(Error)) { 1740b57cec5SDimitry Andric errs() << argv[0] << ": '" << ExtractRegExpAliases[i] << "' " 1750b57cec5SDimitry Andric "invalid regex: " << Error; 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric bool match = false; 1780b57cec5SDimitry Andric for (Module::alias_iterator GA = M->alias_begin(), E = M->alias_end(); 1790b57cec5SDimitry Andric GA != E; GA++) { 1800b57cec5SDimitry Andric if (RegEx.match(GA->getName())) { 1810b57cec5SDimitry Andric GVs.insert(&*GA); 1820b57cec5SDimitry Andric match = true; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric if (!match) { 1860b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain global named '" 1870b57cec5SDimitry Andric << ExtractRegExpAliases[i] << "'!\n"; 1880b57cec5SDimitry Andric return 1; 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric // Figure out which globals we should extract. 1930b57cec5SDimitry Andric for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { 1940b57cec5SDimitry Andric GlobalValue *GV = M->getNamedGlobal(ExtractGlobals[i]); 1950b57cec5SDimitry Andric if (!GV) { 1960b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain global named '" 1970b57cec5SDimitry Andric << ExtractGlobals[i] << "'!\n"; 1980b57cec5SDimitry Andric return 1; 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric GVs.insert(GV); 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // Extract globals via regular expression matching. 2040b57cec5SDimitry Andric for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) { 2050b57cec5SDimitry Andric std::string Error; 2060b57cec5SDimitry Andric Regex RegEx(ExtractRegExpGlobals[i]); 2070b57cec5SDimitry Andric if (!RegEx.isValid(Error)) { 2080b57cec5SDimitry Andric errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' " 2090b57cec5SDimitry Andric "invalid regex: " << Error; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric bool match = false; 2120b57cec5SDimitry Andric for (auto &GV : M->globals()) { 2130b57cec5SDimitry Andric if (RegEx.match(GV.getName())) { 2140b57cec5SDimitry Andric GVs.insert(&GV); 2150b57cec5SDimitry Andric match = true; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric if (!match) { 2190b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain global named '" 2200b57cec5SDimitry Andric << ExtractRegExpGlobals[i] << "'!\n"; 2210b57cec5SDimitry Andric return 1; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric // Figure out which functions we should extract. 2260b57cec5SDimitry Andric for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) { 2270b57cec5SDimitry Andric GlobalValue *GV = M->getFunction(ExtractFuncs[i]); 2280b57cec5SDimitry Andric if (!GV) { 2290b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain function named '" 2300b57cec5SDimitry Andric << ExtractFuncs[i] << "'!\n"; 2310b57cec5SDimitry Andric return 1; 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric GVs.insert(GV); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric // Extract functions via regular expression matching. 2360b57cec5SDimitry Andric for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) { 2370b57cec5SDimitry Andric std::string Error; 2380b57cec5SDimitry Andric StringRef RegExStr = ExtractRegExpFuncs[i]; 2390b57cec5SDimitry Andric Regex RegEx(RegExStr); 2400b57cec5SDimitry Andric if (!RegEx.isValid(Error)) { 2410b57cec5SDimitry Andric errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' " 2420b57cec5SDimitry Andric "invalid regex: " << Error; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric bool match = false; 2450b57cec5SDimitry Andric for (Module::iterator F = M->begin(), E = M->end(); F != E; 2460b57cec5SDimitry Andric F++) { 2470b57cec5SDimitry Andric if (RegEx.match(F->getName())) { 2480b57cec5SDimitry Andric GVs.insert(&*F); 2490b57cec5SDimitry Andric match = true; 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric if (!match) { 2530b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain global named '" 2540b57cec5SDimitry Andric << ExtractRegExpFuncs[i] << "'!\n"; 2550b57cec5SDimitry Andric return 1; 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric // Figure out which BasicBlocks we should extract. 2605ffd83dbSDimitry Andric SmallVector<std::pair<Function *, SmallVector<StringRef, 16>>, 2> BBMap; 2610b57cec5SDimitry Andric for (StringRef StrPair : ExtractBlocks) { 2625ffd83dbSDimitry Andric SmallVector<StringRef, 16> BBNames; 2630b57cec5SDimitry Andric auto BBInfo = StrPair.split(':'); 2640b57cec5SDimitry Andric // Get the function. 2650b57cec5SDimitry Andric Function *F = M->getFunction(BBInfo.first); 2660b57cec5SDimitry Andric if (!F) { 2670b57cec5SDimitry Andric errs() << argv[0] << ": program doesn't contain a function named '" 2680b57cec5SDimitry Andric << BBInfo.first << "'!\n"; 2690b57cec5SDimitry Andric return 1; 2700b57cec5SDimitry Andric } 2715ffd83dbSDimitry Andric // Add the function to the materialize list, and store the basic block names 2725ffd83dbSDimitry Andric // to check after materialization. 2730b57cec5SDimitry Andric GVs.insert(F); 2745ffd83dbSDimitry Andric BBInfo.second.split(BBNames, ';', /*MaxSplit=*/-1, /*KeepEmpty=*/false); 2755ffd83dbSDimitry Andric BBMap.push_back({F, std::move(BBNames)}); 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric // Use *argv instead of argv[0] to work around a wrong GCC warning. 2790b57cec5SDimitry Andric ExitOnError ExitOnErr(std::string(*argv) + ": error reading input: "); 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric if (Recursive) { 2820b57cec5SDimitry Andric std::vector<llvm::Function *> Workqueue; 2830b57cec5SDimitry Andric for (GlobalValue *GV : GVs) { 2840b57cec5SDimitry Andric if (auto *F = dyn_cast<Function>(GV)) { 2850b57cec5SDimitry Andric Workqueue.push_back(F); 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric while (!Workqueue.empty()) { 2890b57cec5SDimitry Andric Function *F = &*Workqueue.back(); 2900b57cec5SDimitry Andric Workqueue.pop_back(); 2910b57cec5SDimitry Andric ExitOnErr(F->materialize()); 2920b57cec5SDimitry Andric for (auto &BB : *F) { 2930b57cec5SDimitry Andric for (auto &I : BB) { 2940b57cec5SDimitry Andric CallBase *CB = dyn_cast<CallBase>(&I); 2950b57cec5SDimitry Andric if (!CB) 2960b57cec5SDimitry Andric continue; 2970b57cec5SDimitry Andric Function *CF = CB->getCalledFunction(); 2980b57cec5SDimitry Andric if (!CF) 2990b57cec5SDimitry Andric continue; 3000b57cec5SDimitry Andric if (CF->isDeclaration() || GVs.count(CF)) 3010b57cec5SDimitry Andric continue; 3020b57cec5SDimitry Andric GVs.insert(CF); 3030b57cec5SDimitry Andric Workqueue.push_back(CF); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric auto Materialize = [&](GlobalValue &GV) { ExitOnErr(GV.materialize()); }; 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric // Materialize requisite global values. 3120b57cec5SDimitry Andric if (!DeleteFn) { 3130b57cec5SDimitry Andric for (size_t i = 0, e = GVs.size(); i != e; ++i) 3140b57cec5SDimitry Andric Materialize(*GVs[i]); 3150b57cec5SDimitry Andric } else { 3160b57cec5SDimitry Andric // Deleting. Materialize every GV that's *not* in GVs. 3170b57cec5SDimitry Andric SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end()); 3180b57cec5SDimitry Andric for (auto &F : *M) { 3190b57cec5SDimitry Andric if (!GVSet.count(&F)) 3200b57cec5SDimitry Andric Materialize(F); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric { 3250b57cec5SDimitry Andric std::vector<GlobalValue *> Gvs(GVs.begin(), GVs.end()); 326bdd1243dSDimitry Andric LoopAnalysisManager LAM; 327bdd1243dSDimitry Andric FunctionAnalysisManager FAM; 328bdd1243dSDimitry Andric CGSCCAnalysisManager CGAM; 329bdd1243dSDimitry Andric ModuleAnalysisManager MAM; 330bdd1243dSDimitry Andric 331bdd1243dSDimitry Andric PassBuilder PB; 332bdd1243dSDimitry Andric 333bdd1243dSDimitry Andric PB.registerModuleAnalyses(MAM); 334bdd1243dSDimitry Andric PB.registerCGSCCAnalyses(CGAM); 335bdd1243dSDimitry Andric PB.registerFunctionAnalyses(FAM); 336bdd1243dSDimitry Andric PB.registerLoopAnalyses(LAM); 337bdd1243dSDimitry Andric PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 338bdd1243dSDimitry Andric 339bdd1243dSDimitry Andric ModulePassManager PM; 340bdd1243dSDimitry Andric PM.addPass(ExtractGVPass(Gvs, DeleteFn, KeepConstInit)); 341bdd1243dSDimitry Andric PM.run(*M, MAM); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric // Now that we have all the GVs we want, mark the module as fully 3440b57cec5SDimitry Andric // materialized. 3450b57cec5SDimitry Andric // FIXME: should the GVExtractionPass handle this? 3460b57cec5SDimitry Andric ExitOnErr(M->materializeAll()); 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric // Extract the specified basic blocks from the module and erase the existing 3500b57cec5SDimitry Andric // functions. 3510b57cec5SDimitry Andric if (!ExtractBlocks.empty()) { 3525ffd83dbSDimitry Andric // Figure out which BasicBlocks we should extract. 353bdd1243dSDimitry Andric std::vector<std::vector<BasicBlock *>> GroupOfBBs; 3545ffd83dbSDimitry Andric for (auto &P : BBMap) { 355bdd1243dSDimitry Andric std::vector<BasicBlock *> BBs; 3565ffd83dbSDimitry Andric for (StringRef BBName : P.second) { 3575ffd83dbSDimitry Andric // The function has been materialized, so add its matching basic blocks 3585ffd83dbSDimitry Andric // to the block extractor list, or fail if a name is not found. 3595ffd83dbSDimitry Andric auto Res = llvm::find_if(*P.first, [&](const BasicBlock &BB) { 360*0fca6ea1SDimitry Andric return BB.getName() == BBName; 3615ffd83dbSDimitry Andric }); 3625ffd83dbSDimitry Andric if (Res == P.first->end()) { 3635ffd83dbSDimitry Andric errs() << argv[0] << ": function " << P.first->getName() 3645ffd83dbSDimitry Andric << " doesn't contain a basic block named '" << BBName 3655ffd83dbSDimitry Andric << "'!\n"; 3665ffd83dbSDimitry Andric return 1; 3675ffd83dbSDimitry Andric } 3685ffd83dbSDimitry Andric BBs.push_back(&*Res); 3695ffd83dbSDimitry Andric } 3705ffd83dbSDimitry Andric GroupOfBBs.push_back(BBs); 3715ffd83dbSDimitry Andric } 3725ffd83dbSDimitry Andric 373bdd1243dSDimitry Andric LoopAnalysisManager LAM; 374bdd1243dSDimitry Andric FunctionAnalysisManager FAM; 375bdd1243dSDimitry Andric CGSCCAnalysisManager CGAM; 376bdd1243dSDimitry Andric ModuleAnalysisManager MAM; 377bdd1243dSDimitry Andric 378bdd1243dSDimitry Andric PassBuilder PB; 379bdd1243dSDimitry Andric 380bdd1243dSDimitry Andric PB.registerModuleAnalyses(MAM); 381bdd1243dSDimitry Andric PB.registerCGSCCAnalyses(CGAM); 382bdd1243dSDimitry Andric PB.registerFunctionAnalyses(FAM); 383bdd1243dSDimitry Andric PB.registerLoopAnalyses(LAM); 384bdd1243dSDimitry Andric PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 385bdd1243dSDimitry Andric 386bdd1243dSDimitry Andric ModulePassManager PM; 387bdd1243dSDimitry Andric PM.addPass(BlockExtractorPass(std::move(GroupOfBBs), true)); 388bdd1243dSDimitry Andric PM.run(*M, MAM); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric // In addition to deleting all other functions, we also want to spiff it 3920b57cec5SDimitry Andric // up a little bit. Do this now. 3930b57cec5SDimitry Andric 394bdd1243dSDimitry Andric LoopAnalysisManager LAM; 395bdd1243dSDimitry Andric FunctionAnalysisManager FAM; 396bdd1243dSDimitry Andric CGSCCAnalysisManager CGAM; 397bdd1243dSDimitry Andric ModuleAnalysisManager MAM; 398bdd1243dSDimitry Andric 399bdd1243dSDimitry Andric PassBuilder PB; 400bdd1243dSDimitry Andric 401bdd1243dSDimitry Andric PB.registerModuleAnalyses(MAM); 402bdd1243dSDimitry Andric PB.registerCGSCCAnalyses(CGAM); 403bdd1243dSDimitry Andric PB.registerFunctionAnalyses(FAM); 404bdd1243dSDimitry Andric PB.registerLoopAnalyses(LAM); 405bdd1243dSDimitry Andric PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 406bdd1243dSDimitry Andric 407bdd1243dSDimitry Andric ModulePassManager PM; 4080b57cec5SDimitry Andric if (!DeleteFn) 409bdd1243dSDimitry Andric PM.addPass(GlobalDCEPass()); 410bdd1243dSDimitry Andric PM.addPass(StripDeadDebugInfoPass()); 411bdd1243dSDimitry Andric PM.addPass(StripDeadPrototypesPass()); 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric std::error_code EC; 4148bcb0991SDimitry Andric ToolOutputFile Out(OutputFilename, EC, sys::fs::OF_None); 4150b57cec5SDimitry Andric if (EC) { 4160b57cec5SDimitry Andric errs() << EC.message() << '\n'; 4170b57cec5SDimitry Andric return 1; 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric if (OutputAssembly) 421bdd1243dSDimitry Andric PM.addPass(PrintModulePass(Out.os(), "", PreserveAssemblyUseListOrder)); 4225ffd83dbSDimitry Andric else if (Force || !CheckBitcodeOutputToConsole(Out.os())) 423bdd1243dSDimitry Andric PM.addPass(BitcodeWriterPass(Out.os(), PreserveBitcodeUseListOrder)); 4240b57cec5SDimitry Andric 425bdd1243dSDimitry Andric PM.run(*M, MAM); 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric // Declare success. 4280b57cec5SDimitry Andric Out.keep(); 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric return 0; 4310b57cec5SDimitry Andric } 432