1 | //===- BlockExtractor.cpp - Extracts blocks into their own functions ------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This pass extracts the specified basic blocks from the module into their |
10 | // own functions. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/Transforms/IPO/BlockExtractor.h" |
15 | #include "llvm/ADT/STLExtras.h" |
16 | #include "llvm/ADT/Statistic.h" |
17 | #include "llvm/IR/Instructions.h" |
18 | #include "llvm/IR/Module.h" |
19 | #include "llvm/IR/PassManager.h" |
20 | #include "llvm/Support/CommandLine.h" |
21 | #include "llvm/Support/Debug.h" |
22 | #include "llvm/Support/MemoryBuffer.h" |
23 | #include "llvm/Transforms/IPO.h" |
24 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
25 | #include "llvm/Transforms/Utils/CodeExtractor.h" |
26 | |
27 | using namespace llvm; |
28 | |
29 | #define DEBUG_TYPE "block-extractor" |
30 | |
31 | STATISTIC(, "Number of basic blocks extracted" ); |
32 | |
33 | static cl::opt<std::string> ( |
34 | "extract-blocks-file" , cl::value_desc("filename" ), |
35 | cl::desc("A file containing list of basic blocks to extract" ), cl::Hidden); |
36 | |
37 | static cl::opt<bool> |
38 | ("extract-blocks-erase-funcs" , |
39 | cl::desc("Erase the existing functions" ), |
40 | cl::Hidden); |
41 | namespace { |
42 | class { |
43 | public: |
44 | (bool EraseFunctions) : EraseFunctions(EraseFunctions) {} |
45 | bool runOnModule(Module &M); |
46 | void |
47 | (const std::vector<std::vector<BasicBlock *>> &) { |
48 | GroupsOfBlocks = GroupsOfBlocksToExtract; |
49 | if (!BlockExtractorFile.empty()) |
50 | loadFile(); |
51 | } |
52 | |
53 | private: |
54 | std::vector<std::vector<BasicBlock *>> ; |
55 | bool ; |
56 | /// Map a function name to groups of blocks. |
57 | SmallVector<std::pair<std::string, SmallVector<std::string, 4>>, 4> |
58 | ; |
59 | |
60 | void loadFile(); |
61 | void splitLandingPadPreds(Function &F); |
62 | }; |
63 | |
64 | } // end anonymous namespace |
65 | |
66 | /// Gets all of the blocks specified in the input file. |
67 | void BlockExtractor::() { |
68 | auto ErrOrBuf = MemoryBuffer::getFile(Filename: BlockExtractorFile); |
69 | if (ErrOrBuf.getError()) |
70 | report_fatal_error(reason: "BlockExtractor couldn't load the file." ); |
71 | // Read the file. |
72 | auto &Buf = *ErrOrBuf; |
73 | SmallVector<StringRef, 16> Lines; |
74 | Buf->getBuffer().split(A&: Lines, Separator: '\n', /*MaxSplit=*/-1, |
75 | /*KeepEmpty=*/false); |
76 | for (const auto &Line : Lines) { |
77 | SmallVector<StringRef, 4> LineSplit; |
78 | Line.split(A&: LineSplit, Separator: ' ', /*MaxSplit=*/-1, |
79 | /*KeepEmpty=*/false); |
80 | if (LineSplit.empty()) |
81 | continue; |
82 | if (LineSplit.size()!=2) |
83 | report_fatal_error(reason: "Invalid line format, expecting lines like: 'funcname bb1[;bb2..]'" , |
84 | /*GenCrashDiag=*/gen_crash_diag: false); |
85 | SmallVector<StringRef, 4> BBNames; |
86 | LineSplit[1].split(A&: BBNames, Separator: ';', /*MaxSplit=*/-1, |
87 | /*KeepEmpty=*/false); |
88 | if (BBNames.empty()) |
89 | report_fatal_error(reason: "Missing bbs name" ); |
90 | BlocksByName.push_back( |
91 | Elt: {std::string(LineSplit[0]), {BBNames.begin(), BBNames.end()}}); |
92 | } |
93 | } |
94 | |
95 | /// Extracts the landing pads to make sure all of them have only one |
96 | /// predecessor. |
97 | void BlockExtractor::splitLandingPadPreds(Function &F) { |
98 | for (BasicBlock &BB : F) { |
99 | for (Instruction &I : BB) { |
100 | if (!isa<InvokeInst>(Val: &I)) |
101 | continue; |
102 | InvokeInst *II = cast<InvokeInst>(Val: &I); |
103 | BasicBlock *Parent = II->getParent(); |
104 | BasicBlock *LPad = II->getUnwindDest(); |
105 | |
106 | // Look through the landing pad's predecessors. If one of them ends in an |
107 | // 'invoke', then we want to split the landing pad. |
108 | bool Split = false; |
109 | for (auto *PredBB : predecessors(BB: LPad)) { |
110 | if (PredBB->isLandingPad() && PredBB != Parent && |
111 | isa<InvokeInst>(Val: Parent->getTerminator())) { |
112 | Split = true; |
113 | break; |
114 | } |
115 | } |
116 | |
117 | if (!Split) |
118 | continue; |
119 | |
120 | SmallVector<BasicBlock *, 2> NewBBs; |
121 | SplitLandingPadPredecessors(OrigBB: LPad, Preds: Parent, Suffix: ".1" , Suffix2: ".2" , NewBBs); |
122 | } |
123 | } |
124 | } |
125 | |
126 | bool BlockExtractor::(Module &M) { |
127 | bool Changed = false; |
128 | |
129 | // Get all the functions. |
130 | SmallVector<Function *, 4> Functions; |
131 | for (Function &F : M) { |
132 | splitLandingPadPreds(F); |
133 | Functions.push_back(Elt: &F); |
134 | } |
135 | |
136 | // Get all the blocks specified in the input file. |
137 | unsigned NextGroupIdx = GroupsOfBlocks.size(); |
138 | GroupsOfBlocks.resize(new_size: NextGroupIdx + BlocksByName.size()); |
139 | for (const auto &BInfo : BlocksByName) { |
140 | Function *F = M.getFunction(Name: BInfo.first); |
141 | if (!F) |
142 | report_fatal_error(reason: "Invalid function name specified in the input file" , |
143 | /*GenCrashDiag=*/gen_crash_diag: false); |
144 | for (const auto &BBInfo : BInfo.second) { |
145 | auto Res = llvm::find_if( |
146 | Range&: *F, P: [&](const BasicBlock &BB) { return BB.getName() == BBInfo; }); |
147 | if (Res == F->end()) |
148 | report_fatal_error(reason: "Invalid block name specified in the input file" , |
149 | /*GenCrashDiag=*/gen_crash_diag: false); |
150 | GroupsOfBlocks[NextGroupIdx].push_back(x: &*Res); |
151 | } |
152 | ++NextGroupIdx; |
153 | } |
154 | |
155 | // Extract each group of basic blocks. |
156 | for (auto &BBs : GroupsOfBlocks) { |
157 | SmallVector<BasicBlock *, 32> ; |
158 | for (BasicBlock *BB : BBs) { |
159 | // Check if the module contains BB. |
160 | if (BB->getParent()->getParent() != &M) |
161 | report_fatal_error(reason: "Invalid basic block" , /*GenCrashDiag=*/gen_crash_diag: false); |
162 | LLVM_DEBUG(dbgs() << "BlockExtractor: Extracting " |
163 | << BB->getParent()->getName() << ":" << BB->getName() |
164 | << "\n" ); |
165 | BlocksToExtractVec.push_back(Elt: BB); |
166 | if (const InvokeInst *II = dyn_cast<InvokeInst>(Val: BB->getTerminator())) |
167 | BlocksToExtractVec.push_back(Elt: II->getUnwindDest()); |
168 | ++NumExtracted; |
169 | Changed = true; |
170 | } |
171 | CodeExtractorAnalysisCache CEAC(*BBs[0]->getParent()); |
172 | Function *F = CodeExtractor(BlocksToExtractVec).extractCodeRegion(CEAC); |
173 | if (F) |
174 | LLVM_DEBUG(dbgs() << "Extracted group '" << (*BBs.begin())->getName() |
175 | << "' in: " << F->getName() << '\n'); |
176 | else |
177 | LLVM_DEBUG(dbgs() << "Failed to extract for group '" |
178 | << (*BBs.begin())->getName() << "'\n" ); |
179 | } |
180 | |
181 | // Erase the functions. |
182 | if (EraseFunctions || BlockExtractorEraseFuncs) { |
183 | for (Function *F : Functions) { |
184 | LLVM_DEBUG(dbgs() << "BlockExtractor: Trying to delete " << F->getName() |
185 | << "\n" ); |
186 | F->deleteBody(); |
187 | } |
188 | // Set linkage as ExternalLinkage to avoid erasing unreachable functions. |
189 | for (Function &F : M) |
190 | F.setLinkage(GlobalValue::ExternalLinkage); |
191 | Changed = true; |
192 | } |
193 | |
194 | return Changed; |
195 | } |
196 | |
197 | BlockExtractorPass::( |
198 | std::vector<std::vector<BasicBlock *>> &&GroupsOfBlocks, |
199 | bool EraseFunctions) |
200 | : GroupsOfBlocks(GroupsOfBlocks), EraseFunctions(EraseFunctions) {} |
201 | |
202 | PreservedAnalyses BlockExtractorPass::(Module &M, |
203 | ModuleAnalysisManager &AM) { |
204 | BlockExtractor BE(EraseFunctions); |
205 | BE.init(GroupsOfBlocksToExtract: GroupsOfBlocks); |
206 | return BE.runOnModule(M) ? PreservedAnalyses::none() |
207 | : PreservedAnalyses::all(); |
208 | } |
209 | |