LLVM 23.0.0git
IndirectBrExpandPass.cpp
Go to the documentation of this file.
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"
35#include "llvm/IR/BasicBlock.h"
36#include "llvm/IR/Constants.h"
37#include "llvm/IR/Dominators.h"
38#include "llvm/IR/Function.h"
41#include "llvm/Pass.h"
44#include <optional>
45
46using namespace llvm;
47
48#define DEBUG_TYPE "indirectbr-expand"
49
50namespace {
51
52class IndirectBrExpandLegacyPass : public FunctionPass {
53public:
54 static char ID; // Pass identification, replacement for typeid
55
56 IndirectBrExpandLegacyPass() : FunctionPass(ID) {}
57
58 void getAnalysisUsage(AnalysisUsage &AU) const override {
60 }
61
62 bool runOnFunction(Function &F) override;
63};
64
65} // end anonymous namespace
66
67static bool runImpl(Function &F, const TargetLowering *TLI,
68 DomTreeUpdater *DTU);
69
72 auto *STI = TM->getSubtargetImpl(F);
73 if (!STI->enableIndirectBrExpand())
75
76 auto *TLI = STI->getTargetLowering();
77 auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
78 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
79
80 bool Changed = runImpl(F, TLI, DT ? &DTU : nullptr);
81 if (!Changed)
85 return PA;
86}
87
88char IndirectBrExpandLegacyPass::ID = 0;
89
90INITIALIZE_PASS_BEGIN(IndirectBrExpandLegacyPass, DEBUG_TYPE,
91 "Expand indirectbr instructions", false, false)
93INITIALIZE_PASS_END(IndirectBrExpandLegacyPass, DEBUG_TYPE,
94 "Expand indirectbr instructions", false, false)
95
97 return new IndirectBrExpandLegacyPass();
98}
99
101 auto &DL = F.getDataLayout();
102
104
105 // Set of all potential successors for indirectbr instructions.
106 SmallPtrSet<BasicBlock *, 4> IndirectBrSuccs;
107
108 // Build a list of indirectbrs that we want to rewrite.
109 for (BasicBlock &BB : F)
110 if (auto *IBr = dyn_cast<IndirectBrInst>(BB.getTerminator())) {
111 // Handle the degenerate case of no successors by replacing the indirectbr
112 // with unreachable as there is no successor available.
113 if (IBr->getNumSuccessors() == 0) {
114 (void)new UnreachableInst(F.getContext(), IBr->getIterator());
115 IBr->eraseFromParent();
116 continue;
117 }
118
119 IndirectBrs.push_back(IBr);
120 IndirectBrSuccs.insert_range(IBr->successors());
121 }
122
123 if (IndirectBrs.empty())
124 return false;
125
126 // If we need to replace any indirectbrs we need to establish integer
127 // constants that will correspond to each of the basic blocks in the function
128 // whose address escapes. We do that here and rewrite all the blockaddress
129 // constants to just be those integer constants cast to a pointer type.
131
132 for (BasicBlock &BB : F) {
133 // Skip blocks that aren't successors to an indirectbr we're going to
134 // rewrite.
135 if (!IndirectBrSuccs.count(&BB))
136 continue;
137
138 auto *BA = BlockAddress::lookup(&BB);
139
140 // Skip if the constant was formed but ended up not being used (due to DCE
141 // or whatever).
142 if (!BA || !BA->isConstantUsed())
143 continue;
144
145 // Compute the index we want to use for this basic block. We can't use zero
146 // because null can be compared with block addresses.
147 int BBIndex = BBs.size() + 1;
148 BBs.push_back(&BB);
149
150 auto *ITy = cast<IntegerType>(DL.getIntPtrType(BA->getType()));
151 ConstantInt *BBIndexC = ConstantInt::get(ITy, BBIndex);
152
153 // Now rewrite the blockaddress to an integer constant based on the index.
154 // FIXME: This part doesn't properly recognize other uses of blockaddress
155 // expressions, for instance, where they are used to pass labels to
156 // asm-goto. This part of the pass needs a rework.
157 BA->replaceAllUsesWith(ConstantExpr::getIntToPtr(BBIndexC, BA->getType()));
158 }
159
160 if (BBs.empty()) {
161 // There are no blocks whose address is taken, so any indirectbr instruction
162 // cannot get a valid input and we can replace all of them with unreachable.
164 if (DTU)
165 Updates.reserve(IndirectBrSuccs.size());
166 for (auto *IBr : IndirectBrs) {
167 if (DTU) {
168 for (BasicBlock *SuccBB : IBr->successors())
169 Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
170 }
171 (void)new UnreachableInst(F.getContext(), IBr->getIterator());
172 IBr->eraseFromParent();
173 }
174 if (DTU) {
175 assert(Updates.size() == IndirectBrSuccs.size() &&
176 "Got unexpected update count.");
177 DTU->applyUpdates(Updates);
178 }
179 return true;
180 }
181
182 BasicBlock *SwitchBB;
183 Value *SwitchValue;
184
185 // Compute a common integer type across all the indirectbr instructions.
186 IntegerType *CommonITy = nullptr;
187 for (auto *IBr : IndirectBrs) {
188 auto *ITy =
189 cast<IntegerType>(DL.getIntPtrType(IBr->getAddress()->getType()));
190 if (!CommonITy || ITy->getBitWidth() > CommonITy->getBitWidth())
191 CommonITy = ITy;
192 }
193
194 auto GetSwitchValue = [CommonITy](IndirectBrInst *IBr) {
195 return CastInst::CreatePointerCast(IBr->getAddress(), CommonITy,
196 Twine(IBr->getAddress()->getName()) +
197 ".switch_cast",
198 IBr->getIterator());
199 };
200
202
203 if (IndirectBrs.size() == 1) {
204 // If we only have one indirectbr, we can just directly replace it within
205 // its block.
206 IndirectBrInst *IBr = IndirectBrs[0];
207 SwitchBB = IBr->getParent();
208 SwitchValue = GetSwitchValue(IBr);
209 if (DTU) {
210 Updates.reserve(IndirectBrSuccs.size());
211 for (BasicBlock *SuccBB : IBr->successors())
212 Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
213 assert(Updates.size() == IndirectBrSuccs.size() &&
214 "Got unexpected update count.");
215 }
216 IBr->eraseFromParent();
217 } else {
218 // Otherwise we need to create a new block to hold the switch across BBs,
219 // jump to that block instead of each indirectbr, and phi together the
220 // values for the switch.
221 SwitchBB = BasicBlock::Create(F.getContext(), "switch_bb", &F);
222 auto *SwitchPN = PHINode::Create(CommonITy, IndirectBrs.size(),
223 "switch_value_phi", SwitchBB);
224 SwitchValue = SwitchPN;
225
226 // Now replace the indirectbr instructions with direct branches to the
227 // switch block and fill out the PHI operands.
228 if (DTU)
229 Updates.reserve(IndirectBrs.size() + 2 * IndirectBrSuccs.size());
230 for (auto *IBr : IndirectBrs) {
231 SwitchPN->addIncoming(GetSwitchValue(IBr), IBr->getParent());
232 UncondBrInst::Create(SwitchBB, IBr->getIterator());
233 if (DTU) {
234 Updates.push_back({DominatorTree::Insert, IBr->getParent(), SwitchBB});
235 for (BasicBlock *SuccBB : IBr->successors())
236 Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
237 }
238 IBr->eraseFromParent();
239 }
240 }
241
242 // Now build the switch in the block. The block will have no terminator
243 // already.
244 auto *SI = SwitchInst::Create(SwitchValue, BBs[0], BBs.size(), SwitchBB);
245
246 // Add a case for each block.
247 for (int i : llvm::seq<int>(1, BBs.size()))
248 SI->addCase(ConstantInt::get(CommonITy, i + 1), BBs[i]);
249
250 if (DTU) {
251 // If there were multiple indirectbr's, they may have common successors,
252 // but in the dominator tree, we only track unique edges.
253 SmallPtrSet<BasicBlock *, 8> UniqueSuccessors;
254 Updates.reserve(Updates.size() + BBs.size());
255 for (BasicBlock *BB : BBs) {
256 if (UniqueSuccessors.insert(BB).second)
257 Updates.push_back({DominatorTree::Insert, SwitchBB, BB});
258 }
259 DTU->applyUpdates(Updates);
260 }
261
262 return true;
263}
264
265bool IndirectBrExpandLegacyPass::runOnFunction(Function &F) {
266 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
267 if (!TPC)
268 return false;
269
270 auto &TM = TPC->getTM<TargetMachine>();
271 auto &STI = *TM.getSubtargetImpl(F);
272 if (!STI.enableIndirectBrExpand())
273 return false;
274 auto *TLI = STI.getTargetLowering();
275
276 std::optional<DomTreeUpdater> DTU;
277 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
278 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
279
280 return runImpl(F, TLI, DTU ? &*DTU : nullptr);
281}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
static bool runImpl(Function &F, const TargetLowering &TLI, const LibcallLoweringInfo &Libcalls, AssumptionCache *AC)
#define DEBUG_TYPE
static bool runImpl(Function &F, const TargetLowering *TLI, DomTreeUpdater *DTU)
#define F(x, y, z)
Definition MD5.cpp:54
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file contains some templates that are useful if you are working with the STL at all.
Provides some synthesis utilities to produce sequences of values.
This file defines the SmallVector class.
Target-Independent Code Generator Pass Configuration Options pass.
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
static LLVM_ABI BlockAddress * lookup(const BasicBlock *BB)
Lookup an existing BlockAddress constant for the given BasicBlock.
static LLVM_ABI CastInst * CreatePointerCast(Value *S, Type *Ty, const Twine &Name="", InsertPosition InsertBefore=nullptr)
Create a BitCast, AddrSpaceCast or a PtrToInt cast instruction.
static LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
This is the shared class of boolean and integer constants.
Definition Constants.h:87
Analysis pass which computes a DominatorTree.
Definition Dominators.h:274
Legacy analysis pass which computes a DominatorTree.
Definition Dominators.h:310
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
Indirect Branch Instruction.
iterator_range< succ_iterator > successors()
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Class to represent integer types.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
size_type size() const
Definition SmallPtrSet.h:99
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void insert_range(Range &&R)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static SwitchInst * Create(Value *Value, BasicBlock *Default, unsigned NumCases, InsertPosition InsertBefore=nullptr)
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
This function has undefined behavior.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
const ParentTy * getParent() const
Definition ilist_node.h:34
self_iterator getIterator()
Definition ilist_node.h:123
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI FunctionPass * createIndirectBrExpandPass()
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:305
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.