LLVM 22.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 "llvm/ADT/DenseSet.h"
11#include "llvm/ADT/STLExtras.h"
18#include "llvm/IR/IRBuilder.h"
19#include "llvm/IR/LLVMContext.h"
23#include "llvm/Support/Error.h"
25#include <limits>
26
27using namespace llvm;
28
29namespace llvm {
30
32 JumpTableSizeThreshold("jump-table-to-switch-size-threshold", cl::Hidden,
33 cl::desc("Only split jump tables with size less or "
34 "equal than JumpTableSizeThreshold."),
35 cl::init(10));
36
37// TODO: Consider adding a cost model for profitability analysis of this
38// transformation. Currently we replace a jump table with a switch if all the
39// functions in the jump table are smaller than the provided threshold.
41 "jump-table-to-switch-function-size-threshold", cl::Hidden,
42 cl::desc("Only split jump tables containing functions whose sizes are less "
43 "or equal than this threshold."),
44 cl::init(50));
45
47
48} // end namespace llvm
49
50#define DEBUG_TYPE "jump-table-to-switch"
51
52namespace {
53struct JumpTableTy {
54 Value *Index;
56};
57} // anonymous namespace
58
59static std::optional<JumpTableTy> parseJumpTable(GetElementPtrInst *GEP,
60 PointerType *PtrTy) {
61 Constant *Ptr = dyn_cast<Constant>(GEP->getPointerOperand());
62 if (!Ptr)
63 return std::nullopt;
64
66 if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer())
67 return std::nullopt;
68
69 Function &F = *GEP->getParent()->getParent();
70 const DataLayout &DL = F.getDataLayout();
71 const unsigned BitWidth =
72 DL.getIndexSizeInBits(GEP->getPointerAddressSpace());
74 APInt ConstantOffset(BitWidth, 0);
75 if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset))
76 return std::nullopt;
77 if (VariableOffsets.size() != 1)
78 return std::nullopt;
79 // TODO: consider supporting more general patterns
80 if (!ConstantOffset.isZero())
81 return std::nullopt;
82 APInt StrideBytes = VariableOffsets.front().second;
83 const uint64_t JumpTableSizeBytes = DL.getTypeAllocSize(GV->getValueType());
84 if (JumpTableSizeBytes % StrideBytes.getZExtValue() != 0)
85 return std::nullopt;
86 const uint64_t N = JumpTableSizeBytes / StrideBytes.getZExtValue();
88 return std::nullopt;
89
90 JumpTableTy JumpTable;
91 JumpTable.Index = VariableOffsets.front().first;
92 JumpTable.Funcs.reserve(N);
93 for (uint64_t Index = 0; Index < N; ++Index) {
94 // ConstantOffset is zero.
95 APInt Offset = Index * StrideBytes;
96 Constant *C =
98 auto *Func = dyn_cast_or_null<Function>(C);
99 if (!Func || Func->isDeclaration() ||
100 Func->getInstructionCount() > FunctionSizeThreshold)
101 return std::nullopt;
102 JumpTable.Funcs.push_back(Func);
103 }
104 return JumpTable;
105}
106
107static BasicBlock *
108expandToSwitch(CallBase *CB, const JumpTableTy &JT, DomTreeUpdater &DTU,
111 GetGuidForFunction) {
112 const bool IsVoid = CB->getType() == Type::getVoidTy(CB->getContext());
113
115 BasicBlock *BB = CB->getParent();
116 BasicBlock *Tail = SplitBlock(BB, CB, &DTU, nullptr, nullptr,
117 BB->getName() + Twine(".tail"));
118 DTUpdates.push_back({DominatorTree::Delete, BB, Tail});
120
121 Function &F = *BB->getParent();
122 BasicBlock *BBUnreachable = BasicBlock::Create(
123 F.getContext(), "default.switch.case.unreachable", &F, Tail);
124 IRBuilder<> BuilderUnreachable(BBUnreachable);
125 BuilderUnreachable.CreateUnreachable();
126
127 IRBuilder<> Builder(BB);
128 SwitchInst *Switch = Builder.CreateSwitch(JT.Index, BBUnreachable);
129 DTUpdates.push_back({DominatorTree::Insert, BB, BBUnreachable});
130
131 IRBuilder<> BuilderTail(CB);
132 PHINode *PHI =
133 IsVoid ? nullptr : BuilderTail.CreatePHI(CB->getType(), JT.Funcs.size());
134 const auto *ProfMD = CB->getMetadata(LLVMContext::MD_prof);
135
136 SmallVector<uint64_t> BranchWeights;
138 const bool HadProfile = isValueProfileMD(ProfMD);
139 if (HadProfile) {
140 // The assumptions, coming in, are that the functions in JT.Funcs are
141 // defined in this module (from parseJumpTable).
143 JT.Funcs, [](const Function *F) { return F && !F->isDeclaration(); }));
144 BranchWeights.reserve(JT.Funcs.size() + 1);
145 // The first is the default target, which is the unreachable block created
146 // above.
147 BranchWeights.push_back(0U);
148 uint64_t TotalCount = 0;
149 auto Targets = getValueProfDataFromInst(
150 *CB, InstrProfValueKind::IPVK_IndirectCallTarget,
151 std::numeric_limits<uint32_t>::max(), TotalCount);
152
153 for (const auto &[G, C] : Targets) {
154 [[maybe_unused]] auto It = GuidToCounter.insert({G, C});
155 assert(It.second);
156 }
157 }
158 for (auto [Index, Func] : llvm::enumerate(JT.Funcs)) {
159 BasicBlock *B = BasicBlock::Create(Func->getContext(),
160 "call." + Twine(Index), &F, Tail);
161 DTUpdates.push_back({DominatorTree::Insert, BB, B});
162 DTUpdates.push_back({DominatorTree::Insert, B, Tail});
163
165 // The MD_prof metadata (VP kind), if it existed, can be dropped, it doesn't
166 // make sense on a direct call. Note that the values are used for the branch
167 // weights of the switch.
168 Call->setMetadata(LLVMContext::MD_prof, nullptr);
169 Call->setCalledFunction(Func);
170 Call->insertInto(B, B->end());
171 Switch->addCase(
172 cast<ConstantInt>(ConstantInt::get(JT.Index->getType(), Index)), B);
173 GlobalValue::GUID FctID = GetGuidForFunction(*Func);
174 // It'd be OK to _not_ find target functions in GuidToCounter, e.g. suppose
175 // just some of the jump targets are taken (for the given profile).
176 BranchWeights.push_back(FctID == 0U ? 0U
177 : GuidToCounter.lookup_or(FctID, 0U));
179 if (PHI)
180 PHI->addIncoming(Call, B);
181 }
182 DTU.applyUpdates(DTUpdates);
183 ORE.emit([&]() {
184 return OptimizationRemark(DEBUG_TYPE, "ReplacedJumpTableWithSwitch", CB)
185 << "expanded indirect call into switch";
186 });
187 if (HadProfile && !ProfcheckDisableMetadataFixes) {
188 // At least one of the targets must've been taken.
189 assert(llvm::any_of(BranchWeights, [](uint64_t V) { return V != 0; }));
190 setBranchWeights(*Switch, downscaleWeights(BranchWeights),
191 /*IsExpected=*/false);
192 } else
194 if (PHI)
196 CB->eraseFromParent();
197 return Tail;
198}
199
206 DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
207 bool Changed = false;
208 auto FuncToGuid = [&](const Function &Fct) {
209 if (Fct.getMetadata(AssignGUIDPass::GUIDMetadataName))
210 return AssignGUIDPass::getGUID(Fct);
211
213 };
214
215 for (BasicBlock &BB : make_early_inc_range(F)) {
216 BasicBlock *CurrentBB = &BB;
217 while (CurrentBB) {
218 BasicBlock *SplittedOutTail = nullptr;
219 for (Instruction &I : make_early_inc_range(*CurrentBB)) {
220 auto *Call = dyn_cast<CallInst>(&I);
221 if (!Call || Call->getCalledFunction() || Call->isMustTailCall())
222 continue;
223 auto *L = dyn_cast<LoadInst>(Call->getCalledOperand());
224 // Skip atomic or volatile loads.
225 if (!L || !L->isSimple())
226 continue;
227 auto *GEP = dyn_cast<GetElementPtrInst>(L->getPointerOperand());
228 if (!GEP)
229 continue;
230 auto *PtrTy = dyn_cast<PointerType>(L->getType());
231 assert(PtrTy && "call operand must be a pointer");
232 std::optional<JumpTableTy> JumpTable = parseJumpTable(GEP, PtrTy);
233 if (!JumpTable)
234 continue;
235 SplittedOutTail =
236 expandToSwitch(Call, *JumpTable, DTU, ORE, FuncToGuid);
237 Changed = true;
238 break;
239 }
240 CurrentBB = SplittedOutTail ? SplittedOutTail : nullptr;
241 }
242 }
243
244 if (!Changed)
245 return PreservedAnalyses::all();
246
248 if (DT)
250 if (PDT)
252 return PA;
253}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Rewrite undef for PHI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
#define DEBUG_TYPE
Hexagon Common GEP
static BasicBlock * expandToSwitch(CallBase *CB, const JumpTableTy &JT, DomTreeUpdater &DTU, OptimizationRemarkEmitter &ORE, llvm::function_ref< GlobalValue::GUID(const Function &)> GetGuidForFunction)
static std::optional< JumpTableTy > parseJumpTable(GetElementPtrInst *GEP, PointerType *PtrTy)
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
#define G(x, y, z)
Definition MD5.cpp:56
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.
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1540
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:380
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.
static LLVM_ABI uint64_t getGUID(const Function &F)
static LLVM_ABI const char * GUIDMetadataName
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 if the block is well formed or null if the block is not well forme...
Definition BasicBlock.h:233
static BranchInst * Create(BasicBlock *IfTrue, InsertPosition InsertBefore=nullptr)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
This is an important base class in LLVM.
Definition Constant.h:43
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:63
ValueT lookup_or(const_arg_type_t< KeyT > Val, U &&Default) const
Definition DenseMap.h:204
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:222
Analysis pass which computes a DominatorTree.
Definition Dominators.h:284
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:165
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:77
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
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:1339
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition IRBuilder.h:2494
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2780
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.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Run the pass over the function.
size_type size() const
Definition MapVector.h:56
std::pair< KeyT, ValueT > & front()
Definition MapVector.h:79
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:281
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:546
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.cpp:1099
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
CallInst * Call
Changed
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
Definition CallingConv.h:76
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
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:1705
LLVM_ABI std::string getIRPGOFuncName(const Function &F, bool InLTO=false)
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2452
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:644
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:634
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...
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:754
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:1712
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...
LLVM_ABI bool isValueProfileMD(const MDNode *ProfileData)
Checks if an MDNode contains value profiling Metadata.
static cl::opt< unsigned > FunctionSizeThreshold("jump-table-to-switch-function-size-threshold", cl::Hidden, cl::desc("Only split jump tables containing functions whose sizes are less " "or equal than this threshold."), cl::init(50))
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:560
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="", bool Before=false)
Split the specified block at the specified instruction.
static cl::opt< unsigned > JumpTableSizeThreshold("jump-table-to-switch-size-threshold", cl::Hidden, cl::desc("Only split jump tables with size less or " "equal than JumpTableSizeThreshold."), cl::init(10))
cl::opt< bool > ProfcheckDisableMetadataFixes("profcheck-disable-metadata-fixes", cl::Hidden, cl::init(false), cl::desc("Disable metadata propagation fixes discovered through Issue #147390"))
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:257