1 | //===- ReduceBasicBlocks.cpp - Specialized Delta Pass ---------------------===// |
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 file implements a function which calls the Generic Delta pass in order |
10 | // to reduce uninteresting BasicBlocks from defined functions. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "ReduceBasicBlocks.h" |
15 | #include "Utils.h" |
16 | #include "llvm/IR/BasicBlock.h" |
17 | #include "llvm/IR/Instruction.h" |
18 | #include "llvm/IR/Instructions.h" |
19 | #include "llvm/IR/LLVMContext.h" |
20 | #include "llvm/IR/Value.h" |
21 | #include "llvm/Support/Casting.h" |
22 | #include "llvm/Support/raw_ostream.h" |
23 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
24 | #include "llvm/Transforms/Utils/Cloning.h" |
25 | #include "llvm/Transforms/Utils/Local.h" |
26 | #include <vector> |
27 | |
28 | #define DEBUG_TYPE "llvm-reduce" |
29 | |
30 | using namespace llvm; |
31 | |
32 | using BlockSet = SetVector<BasicBlock *>; |
33 | |
34 | /// Replaces BB Terminator with one that only contains Chunk BBs |
35 | static void replaceBranchTerminator(BasicBlock &BB, |
36 | const BlockSet &BBsToDelete) { |
37 | auto *Term = BB.getTerminator(); |
38 | std::vector<BasicBlock *> ChunkSuccessors; |
39 | for (auto *Succ : successors(BB: &BB)) { |
40 | if (!BBsToDelete.count(key: Succ)) |
41 | ChunkSuccessors.push_back(x: Succ); |
42 | } |
43 | |
44 | // BB only references Chunk BBs |
45 | if (ChunkSuccessors.size() == Term->getNumSuccessors()) |
46 | return; |
47 | |
48 | // TODO: Handle these without failing verifier. |
49 | if (isa<CatchSwitchInst>(Val: Term)) |
50 | return; |
51 | |
52 | bool IsBranch = isa<BranchInst>(Val: Term); |
53 | if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Val: Term)) { |
54 | BasicBlock *UnwindDest = Invoke->getUnwindDest(); |
55 | BasicBlock::iterator LP = UnwindDest->getFirstNonPHIIt(); |
56 | |
57 | // Remove landingpad instruction if the containing block isn't used by other |
58 | // invokes. |
59 | |
60 | // TODO: Handle catchswitch, catchpad, catchret, and cleanupret |
61 | if (isa<LandingPadInst>(Val: LP) && |
62 | none_of(Range: UnwindDest->users(), P: [Invoke](User *U) { |
63 | return U != Invoke && isa<InvokeInst>(Val: U); |
64 | })) { |
65 | LP->replaceAllUsesWith(V: getDefaultValue(T: LP->getType())); |
66 | LP->eraseFromParent(); |
67 | } else if (!ChunkSuccessors.empty() && |
68 | ChunkSuccessors[0] == LP->getParent()) { |
69 | // If the selected successor is the landing pad, clear the chunk |
70 | // successors to avoid creating a regular branch to the landing pad which |
71 | // would result in invalid IR. |
72 | ChunkSuccessors.clear(); |
73 | } |
74 | IsBranch = true; |
75 | } |
76 | |
77 | Value *Address = nullptr; |
78 | if (auto *IndBI = dyn_cast<IndirectBrInst>(Val: Term)) |
79 | Address = IndBI->getAddress(); |
80 | |
81 | Term->replaceAllUsesWith(V: getDefaultValue(T: Term->getType())); |
82 | Term->eraseFromParent(); |
83 | |
84 | if (ChunkSuccessors.empty()) { |
85 | // If that fails then resort to replacing with a ret. |
86 | auto *FnRetTy = BB.getParent()->getReturnType(); |
87 | ReturnInst::Create(C&: BB.getContext(), |
88 | retVal: FnRetTy->isVoidTy() ? nullptr : getDefaultValue(T: FnRetTy), |
89 | InsertBefore: &BB); |
90 | return; |
91 | } |
92 | |
93 | if (IsBranch) |
94 | BranchInst::Create(IfTrue: ChunkSuccessors[0], InsertBefore: &BB); |
95 | |
96 | if (Address) { |
97 | auto *NewIndBI = |
98 | IndirectBrInst::Create(Address, NumDests: ChunkSuccessors.size(), InsertBefore: &BB); |
99 | for (auto *Dest : ChunkSuccessors) |
100 | NewIndBI->addDestination(Dest); |
101 | } |
102 | } |
103 | |
104 | /// Removes uninteresting BBs from switch, if the default case ends up being |
105 | /// uninteresting, the switch is replaced with a void return (since it has to be |
106 | /// replace with something) |
107 | static void removeUninterestingBBsFromSwitch(SwitchInst &SwInst, |
108 | const BlockSet &BBsToDelete) { |
109 | for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) { |
110 | auto Case = SwInst.case_begin() + I; |
111 | if (BBsToDelete.count(key: Case->getCaseSuccessor())) { |
112 | SwInst.removeCase(I: Case); |
113 | --I; |
114 | --E; |
115 | } |
116 | } |
117 | |
118 | if (BBsToDelete.count(key: SwInst.getDefaultDest())) { |
119 | if (SwInst.getNumCases() == 0) { |
120 | auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType(); |
121 | Value *RetValue = |
122 | FnRetTy->isVoidTy() ? nullptr : getDefaultValue(T: FnRetTy); |
123 | ReturnInst::Create(C&: SwInst.getContext(), retVal: RetValue, InsertBefore: SwInst.getParent()); |
124 | SwInst.eraseFromParent(); |
125 | return; |
126 | } |
127 | |
128 | // Replace the default dest with one of the other cases |
129 | auto Case = SwInst.case_begin(); |
130 | |
131 | BasicBlock *NewDefault = Case->getCaseSuccessor(); |
132 | SwInst.setDefaultDest(NewDefault); |
133 | |
134 | for (PHINode &SuccPHI : NewDefault->phis()) { |
135 | SuccPHI.addIncoming(V: SuccPHI.getIncomingValueForBlock(BB: SwInst.getParent()), |
136 | BB: SwInst.getParent()); |
137 | } |
138 | } |
139 | } |
140 | |
141 | /// Removes out-of-chunk arguments from functions, and modifies their calls |
142 | /// accordingly. It also removes allocations of out-of-chunk arguments. |
143 | void llvm::reduceBasicBlocksDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { |
144 | BlockSet BBsToDelete; |
145 | |
146 | df_iterator_default_set<BasicBlock *> Reachable; |
147 | |
148 | for (auto &F : WorkItem.getModule()) { |
149 | if (F.empty()) |
150 | continue; |
151 | |
152 | BasicBlock &Entry = F.getEntryBlock(); |
153 | for (auto *BB : depth_first_ext(G: &Entry, S&: Reachable)) |
154 | (void)BB; |
155 | |
156 | // Skip any function with unreachable blocks. It's somewhat difficult to |
157 | // avoid producing invalid IR without deleting them. |
158 | // |
159 | // We also do not want to unconditionally delete them, as doing so would |
160 | // break the invariant of changing the number of chunks during counting. |
161 | |
162 | const bool HasUnreachableBlocks = Reachable.size() != F.size(); |
163 | Reachable.clear(); |
164 | |
165 | if (HasUnreachableBlocks) { |
166 | LLVM_DEBUG(dbgs() << "Skipping function with unreachable blocks\n" ); |
167 | continue; |
168 | } |
169 | |
170 | for (BasicBlock &BB : F) { |
171 | if (&BB != &Entry && !O.shouldKeep()) |
172 | BBsToDelete.insert(X: &BB); |
173 | } |
174 | |
175 | // Replace terminators that reference out-of-chunk BBs |
176 | for (BasicBlock &BB : F) { |
177 | if (auto *SwInst = dyn_cast<SwitchInst>(Val: BB.getTerminator())) |
178 | removeUninterestingBBsFromSwitch(SwInst&: *SwInst, BBsToDelete); |
179 | else |
180 | replaceBranchTerminator(BB, BBsToDelete); |
181 | } |
182 | |
183 | // Cleanup any blocks that are now dead after eliminating this set. This |
184 | // will likely be larger than the number of blocks the oracle told us to |
185 | // delete. |
186 | simpleSimplifyCFG(F, BBs: BBsToDelete.getArrayRef()); |
187 | |
188 | BBsToDelete.clear(); |
189 | } |
190 | } |
191 | |
192 | void llvm::reduceUnreachableBasicBlocksDeltaPass(Oracle &O, |
193 | ReducerWorkItem &WorkItem) { |
194 | std::vector<BasicBlock *> DeadBlocks; |
195 | df_iterator_default_set<BasicBlock *> Reachable; |
196 | |
197 | for (Function &F : WorkItem.getModule()) { |
198 | if (F.empty()) |
199 | continue; |
200 | |
201 | // Mark all reachable blocks. |
202 | for (BasicBlock *BB : depth_first_ext(G: &F, S&: Reachable)) |
203 | (void)BB; |
204 | |
205 | if (Reachable.size() != F.size() && !O.shouldKeep()) { |
206 | for (BasicBlock &BB : F) { |
207 | if (!Reachable.count(Ptr: &BB)) |
208 | DeadBlocks.push_back(x: &BB); |
209 | } |
210 | |
211 | // Delete the dead blocks. |
212 | DeleteDeadBlocks(BBs: DeadBlocks, DTU: nullptr, /*KeepOneInputPHIs*/ false); |
213 | DeadBlocks.clear(); |
214 | } |
215 | |
216 | Reachable.clear(); |
217 | } |
218 | } |
219 | |