LLVM 24.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/Sequence.h"
34#include "llvm/IR/BasicBlock.h"
35#include "llvm/IR/Constants.h"
36#include "llvm/IR/Dominators.h"
37#include "llvm/IR/Function.h"
40#include "llvm/Pass.h"
43#include <optional>
44
45using namespace llvm;
46
47#define DEBUG_TYPE "indirectbr-expand"
48
49namespace {
50
51class IndirectBrExpandLegacyPass : public FunctionPass {
52public:
53 static char ID; // Pass identification, replacement for typeid
54
55 IndirectBrExpandLegacyPass() : FunctionPass(ID) {}
56
57 void getAnalysisUsage(AnalysisUsage &AU) const override {
59 }
60
61 bool runOnFunction(Function &F) override;
62};
63
64} // end anonymous namespace
65
66static bool runImpl(Function &F, const TargetLowering *TLI,
67 DomTreeUpdater *DTU);
68
71 auto *STI = TM->getSubtargetImpl(F);
72 if (!STI->enableIndirectBrExpand())
74
75 auto *TLI = STI->getTargetLowering();
76 auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
77 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
78
79 bool Changed = runImpl(F, TLI, DT ? &DTU : nullptr);
80 if (!Changed)
84 return PA;
85}
86
87char IndirectBrExpandLegacyPass::ID = 0;
88
89INITIALIZE_PASS_BEGIN(IndirectBrExpandLegacyPass, DEBUG_TYPE,
90 "Expand indirectbr instructions", false, false)
92INITIALIZE_PASS_END(IndirectBrExpandLegacyPass, DEBUG_TYPE,
93 "Expand indirectbr instructions", false, false)
94
96 return new IndirectBrExpandLegacyPass();
97}
98
100 auto &DL = F.getDataLayout();
101
103
104 // Set of all potential successors for indirectbr instructions.
105 SmallPtrSet<BasicBlock *, 4> IndirectBrSuccs;
106
107 // Build a list of indirectbrs that we want to rewrite.
108 for (BasicBlock &BB : F)
109 if (auto *IBr = dyn_cast<IndirectBrInst>(BB.getTerminator())) {
110 // Handle the degenerate case of no successors by replacing the indirectbr
111 // with unreachable as there is no successor available.
112 if (IBr->getNumSuccessors() == 0) {
113 (void)new UnreachableInst(F.getContext(), IBr->getIterator());
114 IBr->eraseFromParent();
115 continue;
116 }
117
118 IndirectBrs.push_back(IBr);
119 IndirectBrSuccs.insert_range(IBr->successors());
120 }
121
122 if (IndirectBrs.empty())
123 return false;
124
125 // If we need to replace any indirectbrs we need to establish integer
126 // constants that will correspond to each of the basic blocks in the function
127 // whose address escapes. We do that here and rewrite all the blockaddress
128 // constants to just be those integer constants cast to a pointer type.
130
131 for (BasicBlock &BB : F) {
132 // Skip blocks that aren't successors to an indirectbr we're going to
133 // rewrite.
134 if (!IndirectBrSuccs.count(&BB))
135 continue;
136
137 auto *BA = BlockAddress::lookup(&BB);
138
139 // Skip if the constant was formed but ended up not being used (due to DCE
140 // or whatever).
141 if (!BA || !BA->isConstantUsed())
142 continue;
143
144 // Compute the index we want to use for this basic block. We can't use zero
145 // because null can be compared with block addresses.
146 int BBIndex = BBs.size() + 1;
147 BBs.push_back(&BB);
148
149 auto *ITy = cast<IntegerType>(DL.getIntPtrType(BA->getType()));
150 ConstantInt *BBIndexC = ConstantInt::get(ITy, BBIndex);
151
152 // Now rewrite the blockaddress to an integer constant based on the index.
153 // FIXME: This part doesn't properly recognize other uses of blockaddress
154 // expressions, for instance, where they are used to pass labels to
155 // asm-goto. This part of the pass needs a rework.
156 BA->replaceAllUsesWith(ConstantExpr::getIntToPtr(BBIndexC, BA->getType()));
157 }
158
159 if (BBs.empty()) {
160 // There are no blocks whose address is taken, so any indirectbr instruction
161 // cannot get a valid input and we can replace all of them with unreachable.
163 if (DTU)
164 Updates.reserve(IndirectBrSuccs.size());
165 for (auto *IBr : IndirectBrs) {
166 if (DTU) {
167 for (BasicBlock *SuccBB : IBr->successors())
168 Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
169 }
170 (void)new UnreachableInst(F.getContext(), IBr->getIterator());
171 IBr->eraseFromParent();
172 }
173 if (DTU) {
174 assert(Updates.size() == IndirectBrSuccs.size() &&
175 "Got unexpected update count.");
176 DTU->applyUpdates(Updates);
177 }
178 return true;
179 }
180
181 BasicBlock *SwitchBB;
182 Value *SwitchValue;
183
184 // Compute a common integer type across all the indirectbr instructions.
185 IntegerType *CommonITy = nullptr;
186 for (auto *IBr : IndirectBrs) {
187 auto *ITy =
188 cast<IntegerType>(DL.getIntPtrType(IBr->getAddress()->getType()));
189 if (!CommonITy || ITy->getBitWidth() > CommonITy->getBitWidth())
190 CommonITy = ITy;
191 }
192
193 auto GetSwitchValue = [CommonITy](IndirectBrInst *IBr) {
194 return CastInst::CreatePointerCast(IBr->getAddress(), CommonITy,
195 Twine(IBr->getAddress()->getName()) +
196 ".switch_cast",
197 IBr->getIterator());
198 };
199
201
202 if (IndirectBrs.size() == 1) {
203 // If we only have one indirectbr, we can just directly replace it within
204 // its block.
205 IndirectBrInst *IBr = IndirectBrs[0];
206 SwitchBB = IBr->getParent();
207 SwitchValue = GetSwitchValue(IBr);
208 if (DTU) {
209 Updates.reserve(IndirectBrSuccs.size());
210 for (BasicBlock *SuccBB : IBr->successors())
211 Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
212 assert(Updates.size() == IndirectBrSuccs.size() &&
213 "Got unexpected update count.");
214 }
215 IBr->eraseFromParent();
216 } else {
217 // Otherwise we need to create a new block to hold the switch across BBs,
218 // jump to that block instead of each indirectbr, and phi together the
219 // values for the switch.
220 SwitchBB = BasicBlock::Create(F.getContext(), "switch_bb", &F);
221 auto *SwitchPN = PHINode::Create(CommonITy, IndirectBrs.size(),
222 "switch_value_phi", SwitchBB);
223 SwitchValue = SwitchPN;
224
225 // Now replace the indirectbr instructions with direct branches to the
226 // switch block and fill out the PHI operands.
227 if (DTU)
228 Updates.reserve(IndirectBrs.size() + 2 * IndirectBrSuccs.size());
229 for (auto *IBr : IndirectBrs) {
230 SwitchPN->addIncoming(GetSwitchValue(IBr), IBr->getParent());
231 UncondBrInst::Create(SwitchBB, IBr->getIterator());
232 if (DTU) {
233 Updates.push_back({DominatorTree::Insert, IBr->getParent(), SwitchBB});
234 for (BasicBlock *SuccBB : IBr->successors())
235 Updates.push_back({DominatorTree::Delete, IBr->getParent(), SuccBB});
236 }
237 IBr->eraseFromParent();
238 }
239 }
240
241 // Now build the switch in the block. The block will have no terminator
242 // already.
243 auto *SI = SwitchInst::Create(SwitchValue, BBs[0], BBs.size(), SwitchBB);
244
245 // Add a case for each block.
246 for (int i : llvm::seq<int>(1, BBs.size()))
247 SI->addCase(ConstantInt::get(CommonITy, i + 1), BBs[i]);
248
249 if (DTU) {
250 // If there were multiple indirectbr's, they may have common successors,
251 // but in the dominator tree, we only track unique edges.
252 SmallPtrSet<BasicBlock *, 8> UniqueSuccessors;
253 Updates.reserve(Updates.size() + BBs.size());
254 for (BasicBlock *BB : BBs) {
255 if (UniqueSuccessors.insert(BB).second)
256 Updates.push_back({DominatorTree::Insert, SwitchBB, BB});
257 }
258 DTU->applyUpdates(Updates);
259 }
260
261 return true;
262}
263
264bool IndirectBrExpandLegacyPass::runOnFunction(Function &F) {
265 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
266 if (!TPC)
267 return false;
268
269 auto &TM = TPC->getTM<TargetMachine>();
270 auto &STI = *TM.getSubtargetImpl(F);
271 if (!STI.enableIndirectBrExpand())
272 return false;
273 auto *TLI = STI.getTargetLowering();
274
275 std::optional<DomTreeUpdater> DTU;
276 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
277 DTU.emplace(DTWP->getDomTree(), DomTreeUpdater::UpdateStrategy::Lazy);
278
279 return runImpl(F, TLI, DTU ? &*DTU : nullptr);
280}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool runImpl(MachineFunction &MF)
Definition CFIFixup.cpp:304
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
#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
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:241
Legacy analysis pass which computes a DominatorTree.
Definition Dominators.h:277
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
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
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
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.