1c58f2166SChandler Carruth //===- IndirectBrExpandPass.cpp - Expand indirectbr to switch -------------===//
2c58f2166SChandler Carruth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c58f2166SChandler Carruth //
7c58f2166SChandler Carruth //===----------------------------------------------------------------------===//
8c58f2166SChandler Carruth /// \file
9c58f2166SChandler Carruth ///
10c58f2166SChandler Carruth /// Implements an expansion pass to turn `indirectbr` instructions in the IR
11c58f2166SChandler Carruth /// into `switch` instructions. This works by enumerating the basic blocks in
12c58f2166SChandler Carruth /// a dense range of integers, replacing each `blockaddr` constant with the
13c58f2166SChandler Carruth /// corresponding integer constant, and then building a switch that maps from
14c58f2166SChandler Carruth /// the integers to the actual blocks. All of the indirectbr instructions in the
15c58f2166SChandler Carruth /// function are redirected to this common switch.
16c58f2166SChandler Carruth ///
17c58f2166SChandler Carruth /// While this is generically useful if a target is unable to codegen
18c58f2166SChandler Carruth /// `indirectbr` natively, it is primarily useful when there is some desire to
19c58f2166SChandler Carruth /// get the builtin non-jump-table lowering of a switch even when the input
20c58f2166SChandler Carruth /// source contained an explicit indirect branch construct.
21c58f2166SChandler Carruth ///
22c58f2166SChandler Carruth /// Note that it doesn't make any sense to enable this pass unless a target also
23c58f2166SChandler Carruth /// disables jump-table lowering of switches. Doing that is likely to pessimize
24c58f2166SChandler Carruth /// the code.
25c58f2166SChandler Carruth ///
26c58f2166SChandler Carruth //===----------------------------------------------------------------------===//
27c58f2166SChandler Carruth
28c58f2166SChandler Carruth #include "llvm/ADT/STLExtras.h"
29c58f2166SChandler Carruth #include "llvm/ADT/Sequence.h"
30c58f2166SChandler Carruth #include "llvm/ADT/SmallVector.h"
317e88942dSRoman Lebedev #include "llvm/Analysis/DomTreeUpdater.h"
32c58f2166SChandler Carruth #include "llvm/CodeGen/TargetPassConfig.h"
33c58f2166SChandler Carruth #include "llvm/CodeGen/TargetSubtargetInfo.h"
34c58f2166SChandler Carruth #include "llvm/IR/BasicBlock.h"
35*989f1c72Sserge-sans-paille #include "llvm/IR/Constants.h"
367e88942dSRoman Lebedev #include "llvm/IR/Dominators.h"
37c58f2166SChandler Carruth #include "llvm/IR/Function.h"
38c58f2166SChandler Carruth #include "llvm/IR/Instructions.h"
3905da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
40c58f2166SChandler Carruth #include "llvm/Pass.h"
41c58f2166SChandler Carruth #include "llvm/Support/ErrorHandling.h"
42c58f2166SChandler Carruth #include "llvm/Target/TargetMachine.h"
43c58f2166SChandler Carruth
44c58f2166SChandler Carruth using namespace llvm;
45c58f2166SChandler Carruth
46c58f2166SChandler Carruth #define DEBUG_TYPE "indirectbr-expand"
47c58f2166SChandler Carruth
48c58f2166SChandler Carruth namespace {
49c58f2166SChandler Carruth
50c58f2166SChandler Carruth class IndirectBrExpandPass : public FunctionPass {
51c58f2166SChandler Carruth const TargetLowering *TLI = nullptr;
52c58f2166SChandler Carruth
53c58f2166SChandler Carruth public:
54c58f2166SChandler Carruth static char ID; // Pass identification, replacement for typeid
55c58f2166SChandler Carruth
IndirectBrExpandPass()56c58f2166SChandler Carruth IndirectBrExpandPass() : FunctionPass(ID) {
57c58f2166SChandler Carruth initializeIndirectBrExpandPassPass(*PassRegistry::getPassRegistry());
58c58f2166SChandler Carruth }
59c58f2166SChandler Carruth
getAnalysisUsage(AnalysisUsage & AU) const607e88942dSRoman Lebedev void getAnalysisUsage(AnalysisUsage &AU) const override {
617e88942dSRoman Lebedev AU.addPreserved<DominatorTreeWrapperPass>();
627e88942dSRoman Lebedev }
637e88942dSRoman Lebedev
64c58f2166SChandler Carruth bool runOnFunction(Function &F) override;
65c58f2166SChandler Carruth };
66c58f2166SChandler Carruth
67c58f2166SChandler Carruth } // end anonymous namespace
68c58f2166SChandler Carruth
69c58f2166SChandler Carruth char IndirectBrExpandPass::ID = 0;
70c58f2166SChandler Carruth
717e88942dSRoman Lebedev INITIALIZE_PASS_BEGIN(IndirectBrExpandPass, DEBUG_TYPE,
727e88942dSRoman Lebedev "Expand indirectbr instructions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)737e88942dSRoman Lebedev INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
747e88942dSRoman Lebedev INITIALIZE_PASS_END(IndirectBrExpandPass, DEBUG_TYPE,
75c58f2166SChandler Carruth "Expand indirectbr instructions", false, false)
76c58f2166SChandler Carruth
77c58f2166SChandler Carruth FunctionPass *llvm::createIndirectBrExpandPass() {
78c58f2166SChandler Carruth return new IndirectBrExpandPass();
79c58f2166SChandler Carruth }
80c58f2166SChandler Carruth
runOnFunction(Function & F)81c58f2166SChandler Carruth bool IndirectBrExpandPass::runOnFunction(Function &F) {
82c58f2166SChandler Carruth auto &DL = F.getParent()->getDataLayout();
83c58f2166SChandler Carruth auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
84c58f2166SChandler Carruth if (!TPC)
85c58f2166SChandler Carruth return false;
86c58f2166SChandler Carruth
87c58f2166SChandler Carruth auto &TM = TPC->getTM<TargetMachine>();
88c58f2166SChandler Carruth auto &STI = *TM.getSubtargetImpl(F);
89c58f2166SChandler Carruth if (!STI.enableIndirectBrExpand())
90c58f2166SChandler Carruth return false;
91c58f2166SChandler Carruth TLI = STI.getTargetLowering();
92c58f2166SChandler Carruth
937e88942dSRoman Lebedev Optional<DomTreeUpdater> DTU;
947e88942dSRoman Lebedev if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
957e88942dSRoman Lebedev DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
967e88942dSRoman Lebedev
97c58f2166SChandler Carruth SmallVector<IndirectBrInst *, 1> IndirectBrs;
98c58f2166SChandler Carruth
99c58f2166SChandler Carruth // Set of all potential successors for indirectbr instructions.
100c58f2166SChandler Carruth SmallPtrSet<BasicBlock *, 4> IndirectBrSuccs;
101c58f2166SChandler Carruth
102c58f2166SChandler Carruth // Build a list of indirectbrs that we want to rewrite.
103c58f2166SChandler Carruth for (BasicBlock &BB : F)
104c58f2166SChandler Carruth if (auto *IBr = dyn_cast<IndirectBrInst>(BB.getTerminator())) {
105c58f2166SChandler Carruth // Handle the degenerate case of no successors by replacing the indirectbr
106c58f2166SChandler Carruth // with unreachable as there is no successor available.
107c58f2166SChandler Carruth if (IBr->getNumSuccessors() == 0) {
108c58f2166SChandler Carruth (void)new UnreachableInst(F.getContext(), IBr);
109c58f2166SChandler Carruth IBr->eraseFromParent();
110c58f2166SChandler Carruth continue;
111c58f2166SChandler Carruth }
112c58f2166SChandler Carruth
113c58f2166SChandler Carruth IndirectBrs.push_back(IBr);
114c58f2166SChandler Carruth for (BasicBlock *SuccBB : IBr->successors())
115c58f2166SChandler Carruth IndirectBrSuccs.insert(SuccBB);
116c58f2166SChandler Carruth }
117c58f2166SChandler Carruth
118c58f2166SChandler Carruth if (IndirectBrs.empty())
119c58f2166SChandler Carruth return false;
120c58f2166SChandler Carruth
121c58f2166SChandler Carruth // If we need to replace any indirectbrs we need to establish integer
122c58f2166SChandler Carruth // constants that will correspond to each of the basic blocks in the function
123c58f2166SChandler Carruth // whose address escapes. We do that here and rewrite all the blockaddress
124c58f2166SChandler Carruth // constants to just be those integer constants cast to a pointer type.
125c58f2166SChandler Carruth SmallVector<BasicBlock *, 4> BBs;
126c58f2166SChandler Carruth
127c58f2166SChandler Carruth for (BasicBlock &BB : F) {
128c58f2166SChandler Carruth // Skip blocks that aren't successors to an indirectbr we're going to
129c58f2166SChandler Carruth // rewrite.
130c58f2166SChandler Carruth if (!IndirectBrSuccs.count(&BB))
131c58f2166SChandler Carruth continue;
132c58f2166SChandler Carruth
133c58f2166SChandler Carruth auto IsBlockAddressUse = [&](const Use &U) {
134c58f2166SChandler Carruth return isa<BlockAddress>(U.getUser());
135c58f2166SChandler Carruth };
136c58f2166SChandler Carruth auto BlockAddressUseIt = llvm::find_if(BB.uses(), IsBlockAddressUse);
137c58f2166SChandler Carruth if (BlockAddressUseIt == BB.use_end())
138c58f2166SChandler Carruth continue;
139c58f2166SChandler Carruth
140c58f2166SChandler Carruth assert(std::find_if(std::next(BlockAddressUseIt), BB.use_end(),
141c58f2166SChandler Carruth IsBlockAddressUse) == BB.use_end() &&
142c58f2166SChandler Carruth "There should only ever be a single blockaddress use because it is "
143c58f2166SChandler Carruth "a constant and should be uniqued.");
144c58f2166SChandler Carruth
145c58f2166SChandler Carruth auto *BA = cast<BlockAddress>(BlockAddressUseIt->getUser());
146c58f2166SChandler Carruth
147c58f2166SChandler Carruth // Skip if the constant was formed but ended up not being used (due to DCE
148c58f2166SChandler Carruth // or whatever).
149c58f2166SChandler Carruth if (!BA->isConstantUsed())
150c58f2166SChandler Carruth continue;
151c58f2166SChandler Carruth
152c58f2166SChandler Carruth // Compute the index we want to use for this basic block. We can't use zero
153c58f2166SChandler Carruth // because null can be compared with block addresses.
154c58f2166SChandler Carruth int BBIndex = BBs.size() + 1;
155c58f2166SChandler Carruth BBs.push_back(&BB);
156c58f2166SChandler Carruth
157c58f2166SChandler Carruth auto *ITy = cast<IntegerType>(DL.getIntPtrType(BA->getType()));
158c58f2166SChandler Carruth ConstantInt *BBIndexC = ConstantInt::get(ITy, BBIndex);
159c58f2166SChandler Carruth
160c58f2166SChandler Carruth // Now rewrite the blockaddress to an integer constant based on the index.
161784929d0SCraig Topper // FIXME: This part doesn't properly recognize other uses of blockaddress
162784929d0SCraig Topper // expressions, for instance, where they are used to pass labels to
163784929d0SCraig Topper // asm-goto. This part of the pass needs a rework.
164c58f2166SChandler Carruth BA->replaceAllUsesWith(ConstantExpr::getIntToPtr(BBIndexC, BA->getType()));
165c58f2166SChandler Carruth }
166c58f2166SChandler Carruth
167c58f2166SChandler Carruth if (BBs.empty()) {
168c58f2166SChandler Carruth // There are no blocks whose address is taken, so any indirectbr instruction
169c58f2166SChandler Carruth // cannot get a valid input and we can replace all of them with unreachable.
1707e88942dSRoman Lebedev SmallVector<DominatorTree::UpdateType, 8> Updates;
1717e88942dSRoman Lebedev if (DTU)
1727e88942dSRoman Lebedev Updates.reserve(IndirectBrSuccs.size());
173c58f2166SChandler Carruth for (auto *IBr : IndirectBrs) {
1747e88942dSRoman Lebedev if (DTU) {
1757e88942dSRoman Lebedev for (BasicBlock *SuccBB : IBr->successors())
1767e88942dSRoman Lebedev Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
1777e88942dSRoman Lebedev }
178c58f2166SChandler Carruth (void)new UnreachableInst(F.getContext(), IBr);
179c58f2166SChandler Carruth IBr->eraseFromParent();
180c58f2166SChandler Carruth }
1817e88942dSRoman Lebedev if (DTU) {
1827e88942dSRoman Lebedev assert(Updates.size() == IndirectBrSuccs.size() &&
1837e88942dSRoman Lebedev "Got unexpected update count.");
1847e88942dSRoman Lebedev DTU->applyUpdates(Updates);
1857e88942dSRoman Lebedev }
186c58f2166SChandler Carruth return true;
187c58f2166SChandler Carruth }
188c58f2166SChandler Carruth
189c58f2166SChandler Carruth BasicBlock *SwitchBB;
190c58f2166SChandler Carruth Value *SwitchValue;
191c58f2166SChandler Carruth
192c58f2166SChandler Carruth // Compute a common integer type across all the indirectbr instructions.
193c58f2166SChandler Carruth IntegerType *CommonITy = nullptr;
194c58f2166SChandler Carruth for (auto *IBr : IndirectBrs) {
195c58f2166SChandler Carruth auto *ITy =
196c58f2166SChandler Carruth cast<IntegerType>(DL.getIntPtrType(IBr->getAddress()->getType()));
197c58f2166SChandler Carruth if (!CommonITy || ITy->getBitWidth() > CommonITy->getBitWidth())
198c58f2166SChandler Carruth CommonITy = ITy;
199c58f2166SChandler Carruth }
200c58f2166SChandler Carruth
201c58f2166SChandler Carruth auto GetSwitchValue = [DL, CommonITy](IndirectBrInst *IBr) {
202c58f2166SChandler Carruth return CastInst::CreatePointerCast(
203c58f2166SChandler Carruth IBr->getAddress(), CommonITy,
204c58f2166SChandler Carruth Twine(IBr->getAddress()->getName()) + ".switch_cast", IBr);
205c58f2166SChandler Carruth };
206c58f2166SChandler Carruth
2077e88942dSRoman Lebedev SmallVector<DominatorTree::UpdateType, 8> Updates;
2087e88942dSRoman Lebedev
209c58f2166SChandler Carruth if (IndirectBrs.size() == 1) {
210c58f2166SChandler Carruth // If we only have one indirectbr, we can just directly replace it within
211c58f2166SChandler Carruth // its block.
2127e88942dSRoman Lebedev IndirectBrInst *IBr = IndirectBrs[0];
2137e88942dSRoman Lebedev SwitchBB = IBr->getParent();
2147e88942dSRoman Lebedev SwitchValue = GetSwitchValue(IBr);
2157e88942dSRoman Lebedev if (DTU) {
2167e88942dSRoman Lebedev Updates.reserve(IndirectBrSuccs.size());
2177e88942dSRoman Lebedev for (BasicBlock *SuccBB : IBr->successors())
2187e88942dSRoman Lebedev Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
2197e88942dSRoman Lebedev assert(Updates.size() == IndirectBrSuccs.size() &&
2207e88942dSRoman Lebedev "Got unexpected update count.");
2217e88942dSRoman Lebedev }
2227e88942dSRoman Lebedev IBr->eraseFromParent();
223c58f2166SChandler Carruth } else {
224c58f2166SChandler Carruth // Otherwise we need to create a new block to hold the switch across BBs,
225c58f2166SChandler Carruth // jump to that block instead of each indirectbr, and phi together the
226c58f2166SChandler Carruth // values for the switch.
227c58f2166SChandler Carruth SwitchBB = BasicBlock::Create(F.getContext(), "switch_bb", &F);
228c58f2166SChandler Carruth auto *SwitchPN = PHINode::Create(CommonITy, IndirectBrs.size(),
229c58f2166SChandler Carruth "switch_value_phi", SwitchBB);
230c58f2166SChandler Carruth SwitchValue = SwitchPN;
231c58f2166SChandler Carruth
232c58f2166SChandler Carruth // Now replace the indirectbr instructions with direct branches to the
233c58f2166SChandler Carruth // switch block and fill out the PHI operands.
2347e88942dSRoman Lebedev if (DTU)
2357e88942dSRoman Lebedev Updates.reserve(IndirectBrs.size() + 2 * IndirectBrSuccs.size());
236c58f2166SChandler Carruth for (auto *IBr : IndirectBrs) {
237c58f2166SChandler Carruth SwitchPN->addIncoming(GetSwitchValue(IBr), IBr->getParent());
238c58f2166SChandler Carruth BranchInst::Create(SwitchBB, IBr);
2397e88942dSRoman Lebedev if (DTU) {
2407e88942dSRoman Lebedev Updates.push_back({DominatorTree::Insert, IBr->getParent(), SwitchBB});
2417e88942dSRoman Lebedev for (BasicBlock *SuccBB : IBr->successors())
2427e88942dSRoman Lebedev Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
2437e88942dSRoman Lebedev }
244c58f2166SChandler Carruth IBr->eraseFromParent();
245c58f2166SChandler Carruth }
246c58f2166SChandler Carruth }
247c58f2166SChandler Carruth
248c58f2166SChandler Carruth // Now build the switch in the block. The block will have no terminator
249c58f2166SChandler Carruth // already.
250c58f2166SChandler Carruth auto *SI = SwitchInst::Create(SwitchValue, BBs[0], BBs.size(), SwitchBB);
251c58f2166SChandler Carruth
252c58f2166SChandler Carruth // Add a case for each block.
253c58f2166SChandler Carruth for (int i : llvm::seq<int>(1, BBs.size()))
254c58f2166SChandler Carruth SI->addCase(ConstantInt::get(CommonITy, i + 1), BBs[i]);
255c58f2166SChandler Carruth
2567e88942dSRoman Lebedev if (DTU) {
2577e88942dSRoman Lebedev // If there were multiple indirectbr's, they may have common successors,
2587e88942dSRoman Lebedev // but in the dominator tree, we only track unique edges.
259297fb664SBjorn Pettersson SmallPtrSet<BasicBlock *, 8> UniqueSuccessors;
260297fb664SBjorn Pettersson Updates.reserve(Updates.size() + BBs.size());
261297fb664SBjorn Pettersson for (BasicBlock *BB : BBs) {
262297fb664SBjorn Pettersson if (UniqueSuccessors.insert(BB).second)
2637e88942dSRoman Lebedev Updates.push_back({DominatorTree::Insert, SwitchBB, BB});
264297fb664SBjorn Pettersson }
2657e88942dSRoman Lebedev DTU->applyUpdates(Updates);
2667e88942dSRoman Lebedev }
2677e88942dSRoman Lebedev
268c58f2166SChandler Carruth return true;
269c58f2166SChandler Carruth }
270