LLVM 24.0.0git
JumpTableToSwitch.cpp
Go to the documentation of this file.
1//===- JumpTableToSwitch.cpp ----------------------------------------------===//
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
10#include "ScalarOptions.h"
11#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/Statistic.h"
18#include "llvm/IR/IRBuilder.h"
19#include "llvm/IR/LLVMContext.h"
23#include <limits>
24
25using namespace llvm;
26
27#define DEBUG_TYPE "jump-table-to-switch"
28
29STATISTIC(NumEligibleJumpTables, "The number of jump tables seen by the pass "
30 "that can be converted if deemed profitable.");
31STATISTIC(NumJumpTablesConverted,
32 "The number of jump tables converted into switches.");
33
34namespace {
35struct JumpTable {
36 Value *Index;
38};
39} // anonymous namespace
40
41static Function *getExpandableCallee(const ScalarOptions &Opts, Value *V,
42 FunctionType *CallFTy) {
43 auto *Func = dyn_cast<Function>(V);
44 if (!Func || Func->isDeclaration() || Func->getFunctionType() != CallFTy ||
45 Func->getInstructionCount() >
46 Opts.jump_table_to_switch_function_size_threshold)
47 return nullptr;
48 return Func;
49}
50
51static std::optional<JumpTable> parseJumpTable(const ScalarOptions &Opts,
53 PointerType *PtrTy,
54 FunctionType *CallFTy) {
55 Constant *Ptr = dyn_cast<Constant>(GEP->getPointerOperand());
56 if (!Ptr)
57 return std::nullopt;
58
60 if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer())
61 return std::nullopt;
62
63 Function &F = *GEP->getParent()->getParent();
64 const DataLayout &DL = F.getDataLayout();
65 const unsigned BitWidth =
66 DL.getIndexSizeInBits(GEP->getPointerAddressSpace());
68 APInt ConstantOffset(BitWidth, 0);
69 if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset))
70 return std::nullopt;
71 if (VariableOffsets.size() != 1)
72 return std::nullopt;
73 // TODO: consider supporting more general patterns
74 if (!ConstantOffset.isZero())
75 return std::nullopt;
76 APInt StrideBytes = VariableOffsets.front().second;
77 const uint64_t JumpTableSizeBytes = GV->getGlobalSize(DL);
78 if (JumpTableSizeBytes % StrideBytes.getZExtValue() != 0)
79 return std::nullopt;
80 ++NumEligibleJumpTables;
81 const uint64_t N = JumpTableSizeBytes / StrideBytes.getZExtValue();
82 if (N > Opts.jump_table_to_switch_size_threshold)
83 return std::nullopt;
84
85 JumpTable JT;
86 JT.Index = VariableOffsets.front().first;
87 JT.Funcs.reserve(N);
88 for (uint64_t Index = 0; Index < N; ++Index) {
89 // ConstantOffset is zero.
90 APInt Offset = Index * StrideBytes;
91 Constant *C =
93 if (!C)
94 return std::nullopt;
96 !NullPointerIsDefined(&F, PtrTy->getAddressSpace())) ||
98 continue;
99 Function *Func = getExpandableCallee(Opts, C, CallFTy);
100 if (!Func)
101 return std::nullopt;
102 JT.Funcs.push_back({Index, Func});
103 }
104 // Empty table, or only values that are UB when called
105 if (JT.Funcs.empty())
106 return std::nullopt;
107 return JT;
108}
109
110static BasicBlock *
114 GetGuidForFunction) {
115 ++NumJumpTablesConverted;
116 const bool IsVoid = CB->getType() == Type::getVoidTy(CB->getContext());
117
119 BasicBlock *BB = CB->getParent();
120 BasicBlock *Tail = SplitBlock(BB, CB, &DTU, nullptr, nullptr,
121 BB->getName() + Twine(".tail"));
122 DTUpdates.push_back({DominatorTree::Delete, BB, Tail});
124
125 Function &F = *BB->getParent();
126 BasicBlock *BBUnreachable = BasicBlock::Create(
127 F.getContext(), "default.switch.case.unreachable", &F, Tail);
128 IRBuilder<> BuilderUnreachable(BBUnreachable);
129 BuilderUnreachable.CreateUnreachable();
130
131 IRBuilder<> Builder(BB);
132 SwitchInst *Switch = Builder.CreateSwitch(JT.Index, BBUnreachable);
133 DTUpdates.push_back({DominatorTree::Insert, BB, BBUnreachable});
134
135 IRBuilder<> BuilderTail(CB);
136 PHINode *PHI =
137 IsVoid ? nullptr : BuilderTail.CreatePHI(CB->getType(), JT.Funcs.size());
138 const auto *ProfMD = CB->getMetadata(LLVMContext::MD_prof);
139
140 SmallVector<uint64_t> BranchWeights;
142 const bool HadProfile = isValueProfileMD(ProfMD);
143 if (HadProfile) {
144 // The assumptions, coming in, are that the functions in JT.Funcs are
145 // defined in this module (from parseJumpTable).
146 assert(llvm::all_of(JT.Funcs, [](auto &F) {
147 return F.second && !F.second->isDeclaration();
148 }));
149 BranchWeights.reserve(JT.Funcs.size() + 1);
150 // The first is the default target, which is the unreachable block created
151 // above.
152 BranchWeights.push_back(0U);
153 uint64_t TotalCount = 0;
154 auto Targets = getValueProfDataFromInst(
155 *CB, InstrProfValueKind::IPVK_IndirectCallTarget,
156 std::numeric_limits<uint32_t>::max(), TotalCount);
157
158 for (const auto &[G, C] : Targets) {
159 [[maybe_unused]] auto It = GuidToCounter.insert({G, C});
160 // We should always be inserting as it is verifier-enforced IR invariant
161 // that VP metadata does not have duplicate values.
162 assert(It.second);
163 }
164 }
165 for (auto [Index, Func] : JT.Funcs) {
166 BasicBlock *B = BasicBlock::Create(Func->getContext(),
167 "call." + Twine(Index), &F, Tail);
168 DTUpdates.push_back({DominatorTree::Insert, BB, B});
169 DTUpdates.push_back({DominatorTree::Insert, B, Tail});
170
172 // The MD_prof metadata (VP kind), if it existed, can be dropped, it doesn't
173 // make sense on a direct call. Note that the values are used for the branch
174 // weights of the switch.
175 Call->setMetadata(LLVMContext::MD_prof, nullptr);
176 Call->setCalledFunction(Func);
177 Call->insertInto(B, B->end());
178 Switch->addCase(
179 cast<ConstantInt>(ConstantInt::get(JT.Index->getType(), Index)), B);
180 GlobalValue::GUID FctID = GetGuidForFunction(*Func);
181 // It'd be OK to _not_ find target functions in GuidToCounter, e.g. suppose
182 // just some of the jump targets are taken (for the given profile).
183 BranchWeights.push_back(FctID == 0U ? 0U
184 : GuidToCounter.lookup_or(FctID, 0U));
185 UncondBrInst::Create(Tail, B);
186 if (PHI)
187 PHI->addIncoming(Call, B);
188 }
189 DTU.applyUpdates(DTUpdates);
190 ORE.emit([&]() {
191 return OptimizationRemark(DEBUG_TYPE, "ReplacedJumpTableWithSwitch", CB)
192 << "expanded indirect call into switch";
193 });
195 SmallVector<uint32_t, 2> SelectWeights;
196 // Only set branch weights on the switch if we have non-zero branch weights.
197 // We can have no non-zero branch weights while having VP metadata if for
198 // example, all of the functions are external and not instrumented.
199 if (HadProfile && llvm::any_of(BranchWeights, not_equal_to(0))) {
200 setBranchWeights(*Switch, downscaleWeights(BranchWeights),
201 /*IsExpected=*/false);
202 } else if (Select && extractBranchWeights(*Select, SelectWeights) &&
203 llvm::any_of(SelectWeights, not_equal_to(0))) {
204 // Switch branches:
205 // - default (never taken)
206 // - 0: false case (branch 1) of select
207 // - 1: true case (branch 0) of select
208 setBranchWeights(*Switch, {0, SelectWeights[1], SelectWeights[0]},
209 /*IsExpected=*/false);
210 } else
212 if (PHI)
214 CB->eraseFromParent();
215 return Tail;
216}
217
224 DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
225 const ScalarOptions &Opts = getScalarOptions(F);
226 bool Changed = false;
227 auto FuncToGuid = [&](const Function &Fct) {
228 if (const auto MaybeGUID = Fct.getGUIDIfAssigned(); MaybeGUID)
229 return *MaybeGUID;
230
232 getIRPGOObjectName(Fct, InLTO));
233 };
234
235 for (BasicBlock &BB : make_early_inc_range(F)) {
236 BasicBlock *CurrentBB = &BB;
237 while (CurrentBB) {
238 BasicBlock *SplittedOutTail = nullptr;
239 for (Instruction &I : make_early_inc_range(*CurrentBB)) {
240 auto *Call = dyn_cast<CallInst>(&I);
241 if (!Call || Call->getCalledFunction() || Call->isMustTailCall())
242 continue;
243 std::optional<JumpTable> JT;
244 if (auto *S = dyn_cast<SelectInst>(Call->getCalledOperand())) {
245 Function *F0 = getExpandableCallee(Opts, S->getFalseValue(),
246 Call->getFunctionType());
247 if (!F0)
248 continue;
249 Function *F1 = getExpandableCallee(Opts, S->getTrueValue(),
250 Call->getFunctionType());
251 if (!F1)
252 continue;
253 JT = JumpTable();
254 JT->Index = S->getCondition();
255 JT->Funcs.push_back({0, F0});
256 JT->Funcs.push_back({1, F1});
257 } else if (auto *L = dyn_cast<LoadInst>(Call->getCalledOperand())) {
258 // Skip atomic or volatile loads.
259 if (!L || !L->isSimple())
260 continue;
261 auto *GEP = dyn_cast<GetElementPtrInst>(L->getPointerOperand());
262 if (!GEP ||
263 (!GEP->hasNoUnsignedWrap() && !GEP->hasNoUnsignedSignedWrap()))
264 continue;
265 auto *PtrTy = dyn_cast<PointerType>(L->getType());
266 assert(PtrTy && "call operand must be a pointer");
267 JT = parseJumpTable(Opts, GEP, PtrTy, Call->getFunctionType());
268 }
269 if (!JT)
270 continue;
271 SplittedOutTail = expandToSwitch(Call, *JT, DTU, ORE, FuncToGuid);
272 Changed = true;
273 break;
274 }
275 CurrentBB = SplittedOutTail ? SplittedOutTail : nullptr;
276 }
277 }
278
279 if (!Changed)
280 return PreservedAnalyses::all();
281
283 if (DT)
285 if (PDT)
287 return PA;
288}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
AMDGPU Register Bank Select
Rewrite undef for PHI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define DEBUG_TYPE
Hexagon Common GEP
static Function * getExpandableCallee(const ScalarOptions &Opts, Value *V, FunctionType *CallFTy)
static std::optional< JumpTable > parseJumpTable(const ScalarOptions &Opts, GetElementPtrInst *GEP, PointerType *PtrTy, FunctionType *CallFTy)
static BasicBlock * expandToSwitch(CallBase *CB, const JumpTable &JT, DomTreeUpdater &DTU, OptimizationRemarkEmitter &ORE, llvm::function_ref< GlobalValue::GUID(const Function &)> GetGuidForFunction)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
This file contains the declarations for profiling metadata utility functions.
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Value * getCalledOperand() const
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
Definition DenseMap.h:803
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:827
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
Definition Globals.cpp:80
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
LLVM_ABI uint64_t getGlobalSize(const DataLayout &DL) const
Get the size of this global variable in bytes.
Definition Globals.cpp:640
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
bool hasDefinitiveInitializer() const
hasDefinitiveInitializer - Whether the global variable has an initializer, and any other instances of...
UnreachableInst * CreateUnreachable()
Definition IRBuilder.h:1354
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition IRBuilder.h:2547
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2909
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Run the pass over the function.
size_type size() const
Definition MapVector.h:58
std::pair< KeyT, ValueT > & front()
Definition MapVector.h:81
The optimization diagnostic interface.
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for applied optimization remarks.
Analysis pass which computes a PostDominatorTree.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
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
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.
Multiway switch.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
CallInst * Call
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
constexpr auto not_equal_to(T &&Arg)
Functor variant of std::not_equal_to that can be used as a UnaryPredicate in functional algorithms li...
Definition STLExtras.h:2196
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
LLVM_ABI std::string getIRPGOObjectName(const GlobalObject &GO, bool InLTO=false)
const ScalarOptions & getScalarOptions(const LLVMContext &C)
LLVM_ABI void setExplicitlyUnknownBranchWeights(Instruction &I, StringRef PassName)
Specify that the branch weights for this terminator cannot be known at compile time.
LLVM_ABI void setBranchWeights(Instruction &I, ArrayRef< uint32_t > Weights, bool IsExpected, bool ElideAllZero=false)
Create a new branch_weights metadata node and add or overwrite a prof metadata reference to instructi...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
LLVM_ABI bool NullPointerIsDefined(const Function *F, unsigned AS=0)
Check whether null pointer dereferencing is considered undefined behavior for a given function or an ...
LLVM_ABI Constant * ConstantFoldLoadFromConst(Constant *C, Type *Ty, const APInt &Offset, const DataLayout &DL)
Extract value of C at the given Offset reinterpreted as Ty.
LLVM_ABI SmallVector< InstrProfValueData, 4 > getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind, uint32_t MaxNumValueData, uint64_t &TotalC, bool GetNoICPValue=false)
Extract the value profile data from Inst and returns them if Inst is annotated with value profile dat...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI bool isValueProfileMD(const MDNode *ProfileData)
Checks if an MDNode contains value profiling Metadata.
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
constexpr unsigned BitWidth
LLVM_ABI bool extractBranchWeights(const MDNode *ProfileData, SmallVectorImpl< uint32_t > &Weights)
Extract branch weights from MD_prof metadata.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI SmallVector< uint32_t > downscaleWeights(ArrayRef< uint64_t > Weights, std::optional< uint64_t > KnownMaxCount=std::nullopt)
downscale the given weights preserving the ratio.
#define N
A MapVector that performs no allocations if smaller than a certain size.
Definition MapVector.h:342