/src/llvm-project/llvm/lib/CodeGen/IndirectBrExpandPass.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- IndirectBrExpandPass.cpp - Expand indirectbr to switch -------------===// |
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 | | /// \file |
9 | | /// |
10 | | /// Implements an expansion pass to turn `indirectbr` instructions in the IR |
11 | | /// into `switch` instructions. This works by enumerating the basic blocks in |
12 | | /// a dense range of integers, replacing each `blockaddr` constant with the |
13 | | /// corresponding integer constant, and then building a switch that maps from |
14 | | /// the integers to the actual blocks. All of the indirectbr instructions in the |
15 | | /// function are redirected to this common switch. |
16 | | /// |
17 | | /// While this is generically useful if a target is unable to codegen |
18 | | /// `indirectbr` natively, it is primarily useful when there is some desire to |
19 | | /// get the builtin non-jump-table lowering of a switch even when the input |
20 | | /// source contained an explicit indirect branch construct. |
21 | | /// |
22 | | /// Note that it doesn't make any sense to enable this pass unless a target also |
23 | | /// disables jump-table lowering of switches. Doing that is likely to pessimize |
24 | | /// the code. |
25 | | /// |
26 | | //===----------------------------------------------------------------------===// |
27 | | |
28 | | #include "llvm/ADT/STLExtras.h" |
29 | | #include "llvm/ADT/Sequence.h" |
30 | | #include "llvm/ADT/SmallVector.h" |
31 | | #include "llvm/Analysis/DomTreeUpdater.h" |
32 | | #include "llvm/CodeGen/IndirectBrExpand.h" |
33 | | #include "llvm/CodeGen/TargetPassConfig.h" |
34 | | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
35 | | #include "llvm/IR/BasicBlock.h" |
36 | | #include "llvm/IR/Constants.h" |
37 | | #include "llvm/IR/Dominators.h" |
38 | | #include "llvm/IR/Function.h" |
39 | | #include "llvm/IR/Instructions.h" |
40 | | #include "llvm/InitializePasses.h" |
41 | | #include "llvm/Pass.h" |
42 | | #include "llvm/Support/ErrorHandling.h" |
43 | | #include "llvm/Target/TargetMachine.h" |
44 | | #include <optional> |
45 | | |
46 | | using namespace llvm; |
47 | | |
48 | | #define DEBUG_TYPE "indirectbr-expand" |
49 | | |
50 | | namespace { |
51 | | |
52 | | class IndirectBrExpandLegacyPass : public FunctionPass { |
53 | | public: |
54 | | static char ID; // Pass identification, replacement for typeid |
55 | | |
56 | 763 | IndirectBrExpandLegacyPass() : FunctionPass(ID) { |
57 | 763 | initializeIndirectBrExpandLegacyPassPass(*PassRegistry::getPassRegistry()); |
58 | 763 | } |
59 | | |
60 | 763 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
61 | 763 | AU.addPreserved<DominatorTreeWrapperPass>(); |
62 | 763 | } |
63 | | |
64 | | bool runOnFunction(Function &F) override; |
65 | | }; |
66 | | |
67 | | } // end anonymous namespace |
68 | | |
69 | | static bool runImpl(Function &F, const TargetLowering *TLI, |
70 | | DomTreeUpdater *DTU); |
71 | | |
72 | | PreservedAnalyses IndirectBrExpandPass::run(Function &F, |
73 | 0 | FunctionAnalysisManager &FAM) { |
74 | 0 | auto *STI = TM->getSubtargetImpl(F); |
75 | 0 | if (!STI->enableIndirectBrExpand()) |
76 | 0 | return PreservedAnalyses::all(); |
77 | | |
78 | 0 | auto *TLI = STI->getTargetLowering(); |
79 | 0 | auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F); |
80 | 0 | DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); |
81 | |
|
82 | 0 | bool Changed = runImpl(F, TLI, DT ? &DTU : nullptr); |
83 | 0 | if (!Changed) |
84 | 0 | return PreservedAnalyses::all(); |
85 | 0 | PreservedAnalyses PA; |
86 | 0 | PA.preserve<DominatorTreeAnalysis>(); |
87 | 0 | return PA; |
88 | 0 | } |
89 | | |
90 | | char IndirectBrExpandLegacyPass::ID = 0; |
91 | | |
92 | 12 | INITIALIZE_PASS_BEGIN(IndirectBrExpandLegacyPass, DEBUG_TYPE, |
93 | 12 | "Expand indirectbr instructions", false, false) |
94 | 12 | INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) |
95 | 12 | INITIALIZE_PASS_END(IndirectBrExpandLegacyPass, DEBUG_TYPE, |
96 | | "Expand indirectbr instructions", false, false) |
97 | | |
98 | 763 | FunctionPass *llvm::createIndirectBrExpandPass() { |
99 | 763 | return new IndirectBrExpandLegacyPass(); |
100 | 763 | } |
101 | | |
102 | 6.72k | bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU) { |
103 | 6.72k | auto &DL = F.getParent()->getDataLayout(); |
104 | | |
105 | 6.72k | SmallVector<IndirectBrInst *, 1> IndirectBrs; |
106 | | |
107 | | // Set of all potential successors for indirectbr instructions. |
108 | 6.72k | SmallPtrSet<BasicBlock *, 4> IndirectBrSuccs; |
109 | | |
110 | | // Build a list of indirectbrs that we want to rewrite. |
111 | 6.72k | for (BasicBlock &BB : F) |
112 | 15.5k | if (auto *IBr = dyn_cast<IndirectBrInst>(BB.getTerminator())) { |
113 | | // Handle the degenerate case of no successors by replacing the indirectbr |
114 | | // with unreachable as there is no successor available. |
115 | 10 | if (IBr->getNumSuccessors() == 0) { |
116 | 0 | (void)new UnreachableInst(F.getContext(), IBr); |
117 | 0 | IBr->eraseFromParent(); |
118 | 0 | continue; |
119 | 0 | } |
120 | | |
121 | 10 | IndirectBrs.push_back(IBr); |
122 | 10 | for (BasicBlock *SuccBB : IBr->successors()) |
123 | 33 | IndirectBrSuccs.insert(SuccBB); |
124 | 10 | } |
125 | | |
126 | 6.72k | if (IndirectBrs.empty()) |
127 | 6.71k | return false; |
128 | | |
129 | | // If we need to replace any indirectbrs we need to establish integer |
130 | | // constants that will correspond to each of the basic blocks in the function |
131 | | // whose address escapes. We do that here and rewrite all the blockaddress |
132 | | // constants to just be those integer constants cast to a pointer type. |
133 | 8 | SmallVector<BasicBlock *, 4> BBs; |
134 | | |
135 | 47 | for (BasicBlock &BB : F) { |
136 | | // Skip blocks that aren't successors to an indirectbr we're going to |
137 | | // rewrite. |
138 | 47 | if (!IndirectBrSuccs.count(&BB)) |
139 | 20 | continue; |
140 | | |
141 | 71 | auto IsBlockAddressUse = [&](const Use &U) { |
142 | 71 | return isa<BlockAddress>(U.getUser()); |
143 | 71 | }; |
144 | 27 | auto BlockAddressUseIt = llvm::find_if(BB.uses(), IsBlockAddressUse); |
145 | 27 | if (BlockAddressUseIt == BB.use_end()) |
146 | 1 | continue; |
147 | | |
148 | 26 | assert(std::find_if(std::next(BlockAddressUseIt), BB.use_end(), |
149 | 26 | IsBlockAddressUse) == BB.use_end() && |
150 | 26 | "There should only ever be a single blockaddress use because it is " |
151 | 26 | "a constant and should be uniqued."); |
152 | | |
153 | 0 | auto *BA = cast<BlockAddress>(BlockAddressUseIt->getUser()); |
154 | | |
155 | | // Skip if the constant was formed but ended up not being used (due to DCE |
156 | | // or whatever). |
157 | 26 | if (!BA->isConstantUsed()) |
158 | 0 | continue; |
159 | | |
160 | | // Compute the index we want to use for this basic block. We can't use zero |
161 | | // because null can be compared with block addresses. |
162 | 26 | int BBIndex = BBs.size() + 1; |
163 | 26 | BBs.push_back(&BB); |
164 | | |
165 | 26 | auto *ITy = cast<IntegerType>(DL.getIntPtrType(BA->getType())); |
166 | 26 | ConstantInt *BBIndexC = ConstantInt::get(ITy, BBIndex); |
167 | | |
168 | | // Now rewrite the blockaddress to an integer constant based on the index. |
169 | | // FIXME: This part doesn't properly recognize other uses of blockaddress |
170 | | // expressions, for instance, where they are used to pass labels to |
171 | | // asm-goto. This part of the pass needs a rework. |
172 | 26 | BA->replaceAllUsesWith(ConstantExpr::getIntToPtr(BBIndexC, BA->getType())); |
173 | 26 | } |
174 | | |
175 | 8 | if (BBs.empty()) { |
176 | | // There are no blocks whose address is taken, so any indirectbr instruction |
177 | | // cannot get a valid input and we can replace all of them with unreachable. |
178 | 1 | SmallVector<DominatorTree::UpdateType, 8> Updates; |
179 | 1 | if (DTU) |
180 | 0 | Updates.reserve(IndirectBrSuccs.size()); |
181 | 1 | for (auto *IBr : IndirectBrs) { |
182 | 1 | if (DTU) { |
183 | 0 | for (BasicBlock *SuccBB : IBr->successors()) |
184 | 0 | Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB}); |
185 | 0 | } |
186 | 1 | (void)new UnreachableInst(F.getContext(), IBr); |
187 | 1 | IBr->eraseFromParent(); |
188 | 1 | } |
189 | 1 | if (DTU) { |
190 | 0 | assert(Updates.size() == IndirectBrSuccs.size() && |
191 | 0 | "Got unexpected update count."); |
192 | 0 | DTU->applyUpdates(Updates); |
193 | 0 | } |
194 | 0 | return true; |
195 | 1 | } |
196 | | |
197 | 7 | BasicBlock *SwitchBB; |
198 | 7 | Value *SwitchValue; |
199 | | |
200 | | // Compute a common integer type across all the indirectbr instructions. |
201 | 7 | IntegerType *CommonITy = nullptr; |
202 | 9 | for (auto *IBr : IndirectBrs) { |
203 | 9 | auto *ITy = |
204 | 9 | cast<IntegerType>(DL.getIntPtrType(IBr->getAddress()->getType())); |
205 | 9 | if (!CommonITy || ITy->getBitWidth() > CommonITy->getBitWidth()) |
206 | 7 | CommonITy = ITy; |
207 | 9 | } |
208 | | |
209 | 9 | auto GetSwitchValue = [CommonITy](IndirectBrInst *IBr) { |
210 | 9 | return CastInst::CreatePointerCast( |
211 | 9 | IBr->getAddress(), CommonITy, |
212 | 9 | Twine(IBr->getAddress()->getName()) + ".switch_cast", IBr); |
213 | 9 | }; |
214 | | |
215 | 7 | SmallVector<DominatorTree::UpdateType, 8> Updates; |
216 | | |
217 | 7 | if (IndirectBrs.size() == 1) { |
218 | | // If we only have one indirectbr, we can just directly replace it within |
219 | | // its block. |
220 | 5 | IndirectBrInst *IBr = IndirectBrs[0]; |
221 | 5 | SwitchBB = IBr->getParent(); |
222 | 5 | SwitchValue = GetSwitchValue(IBr); |
223 | 5 | if (DTU) { |
224 | 0 | Updates.reserve(IndirectBrSuccs.size()); |
225 | 0 | for (BasicBlock *SuccBB : IBr->successors()) |
226 | 0 | Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB}); |
227 | 0 | assert(Updates.size() == IndirectBrSuccs.size() && |
228 | 0 | "Got unexpected update count."); |
229 | 0 | } |
230 | 0 | IBr->eraseFromParent(); |
231 | 5 | } else { |
232 | | // Otherwise we need to create a new block to hold the switch across BBs, |
233 | | // jump to that block instead of each indirectbr, and phi together the |
234 | | // values for the switch. |
235 | 2 | SwitchBB = BasicBlock::Create(F.getContext(), "switch_bb", &F); |
236 | 2 | auto *SwitchPN = PHINode::Create(CommonITy, IndirectBrs.size(), |
237 | 2 | "switch_value_phi", SwitchBB); |
238 | 2 | SwitchValue = SwitchPN; |
239 | | |
240 | | // Now replace the indirectbr instructions with direct branches to the |
241 | | // switch block and fill out the PHI operands. |
242 | 2 | if (DTU) |
243 | 0 | Updates.reserve(IndirectBrs.size() + 2 * IndirectBrSuccs.size()); |
244 | 4 | for (auto *IBr : IndirectBrs) { |
245 | 4 | SwitchPN->addIncoming(GetSwitchValue(IBr), IBr->getParent()); |
246 | 4 | BranchInst::Create(SwitchBB, IBr); |
247 | 4 | if (DTU) { |
248 | 0 | Updates.push_back({DominatorTree::Insert, IBr->getParent(), SwitchBB}); |
249 | 0 | for (BasicBlock *SuccBB : IBr->successors()) |
250 | 0 | Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB}); |
251 | 0 | } |
252 | 4 | IBr->eraseFromParent(); |
253 | 4 | } |
254 | 2 | } |
255 | | |
256 | | // Now build the switch in the block. The block will have no terminator |
257 | | // already. |
258 | 0 | auto *SI = SwitchInst::Create(SwitchValue, BBs[0], BBs.size(), SwitchBB); |
259 | | |
260 | | // Add a case for each block. |
261 | 7 | for (int i : llvm::seq<int>(1, BBs.size())) |
262 | 19 | SI->addCase(ConstantInt::get(CommonITy, i + 1), BBs[i]); |
263 | | |
264 | 7 | if (DTU) { |
265 | | // If there were multiple indirectbr's, they may have common successors, |
266 | | // but in the dominator tree, we only track unique edges. |
267 | 0 | SmallPtrSet<BasicBlock *, 8> UniqueSuccessors; |
268 | 0 | Updates.reserve(Updates.size() + BBs.size()); |
269 | 0 | for (BasicBlock *BB : BBs) { |
270 | 0 | if (UniqueSuccessors.insert(BB).second) |
271 | 0 | Updates.push_back({DominatorTree::Insert, SwitchBB, BB}); |
272 | 0 | } |
273 | 0 | DTU->applyUpdates(Updates); |
274 | 0 | } |
275 | | |
276 | 7 | return true; |
277 | 8 | } |
278 | | |
279 | 28.9k | bool IndirectBrExpandLegacyPass::runOnFunction(Function &F) { |
280 | 28.9k | auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); |
281 | 28.9k | if (!TPC) |
282 | 0 | return false; |
283 | | |
284 | 28.9k | auto &TM = TPC->getTM<TargetMachine>(); |
285 | 28.9k | auto &STI = *TM.getSubtargetImpl(F); |
286 | 28.9k | if (!STI.enableIndirectBrExpand()) |
287 | 22.2k | return false; |
288 | 6.72k | auto *TLI = STI.getTargetLowering(); |
289 | | |
290 | 6.72k | std::optional<DomTreeUpdater> DTU; |
291 | 6.72k | if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) |
292 | 0 | DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy); |
293 | | |
294 | 6.72k | return runImpl(F, TLI, DTU ? &*DTU : nullptr); |
295 | 28.9k | } |