LLVM 24.0.0git
RelLookupTableConverter.cpp
Go to the documentation of this file.
1//===- RelLookupTableConverterPass - Rel Table Conv -----------------------===//
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//
9// This file implements relative lookup table converter that converts
10// lookup tables to relative lookup tables to make them PIC-friendly.
11//
12//===----------------------------------------------------------------------===//
13
17#include "llvm/IR/BasicBlock.h"
18#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/Module.h"
21
22using namespace llvm;
23
28
30 GlobalVariable &GV) {
31 // If lookup table has more than one user,
32 // do not generate a relative lookup table.
33 // This is to simplify the analysis that needs to be done for this pass.
34 // TODO: Add support for lookup tables with multiple uses.
35 // For ex, this can happen when a function that uses a lookup table gets
36 // inlined into multiple call sites.
37 //
38 // If the original lookup table does not have local linkage and is
39 // not dso_local, do not generate a relative lookup table.
40 // This optimization creates a relative lookup table that consists of
41 // offsets between the start of the lookup table and its elements.
42 // To be able to generate these offsets, relative lookup table and
43 // its elements should have internal linkage and be dso_local, which means
44 // that they should resolve to symbols within the same linkage unit.
45 if (!GV.hasInitializer() || !GV.isConstant() || !GV.hasOneUse() ||
46 !GV.hasLocalLinkage() || !GV.isDSOLocal() || !GV.isImplicitDSOLocal())
47 return false;
48
50 if (!GEP || !GEP->hasOneUse())
51 return false;
52
53 auto *Load = dyn_cast<LoadInst>(GEP->use_begin()->getUser());
54 if (!Load || !Load->hasOneUse())
55 return false;
56
57 // If values are not 64-bit pointers, do not generate a relative lookup table.
58 const DataLayout &DL = M.getDataLayout();
59 Type *ElemType = Load->getType();
60 if (!ElemType->isPointerTy() || DL.getPointerTypeSizeInBits(ElemType) != 64)
61 return false;
62
63 // Make sure this is a gep of the form GV + scale*var.
64 unsigned IndexWidth =
65 DL.getIndexTypeSizeInBits(Load->getPointerOperand()->getType());
67 APInt ConstOffset(IndexWidth, 0);
68 if (!GEP->collectOffset(DL, IndexWidth, VarOffsets, ConstOffset) ||
69 !ConstOffset.isZero() || VarOffsets.size() != 1)
70 return false;
71
72 // This can't be a pointer lookup table if the stride is smaller than a
73 // pointer.
74 Info.Index = VarOffsets.front().first;
75 const APInt &Stride = VarOffsets.front().second;
76 if (Stride.ult(DL.getTypeStoreSize(ElemType)))
77 return false;
78
80 Triple TT = M.getTargetTriple();
81 // FIXME: This should be removed in the future.
82 bool ShouldDropUnnamedAddr =
83 // Drop unnamed_addr to avoid matching pattern in
84 // `handleIndirectSymViaGOTPCRel`, which generates GOTPCREL relocations
85 // not supported by the GNU linker and LLD versions below 18 on aarch64.
86 TT.isAArch64()
87 // Apple's ld64 (and ld-prime on Xcode 15.2) miscompile something on
88 // x86_64-apple-darwin. See
89 // https://github.com/rust-lang/rust/issues/140686 and
90 // https://github.com/rust-lang/rust/issues/141306.
91 || (TT.isX86() && TT.isOSDarwin());
92
93 APInt Offset(IndexWidth, 0);
94 uint64_t GVSize = GV.getGlobalSize(DL);
95 for (; Offset.ult(GVSize); Offset += Stride) {
96 Constant *C =
98 if (!C)
99 return false;
100
101 GlobalValue *GVOp;
102 APInt GVOffset;
103
104 // If an operand is not a constant offset from a lookup table,
105 // do not generate a relative lookup table.
106 if (!IsConstantOffsetFromGlobal(C, GVOp, GVOffset, DL))
107 return false;
108
109 // If operand is mutable, do not generate a relative lookup table.
110 auto *GlovalVarOp = dyn_cast<GlobalVariable>(GVOp);
111 if (!GlovalVarOp || !GlovalVarOp->isConstant())
112 return false;
113
114 if (!GlovalVarOp->hasLocalLinkage() ||
115 !GlovalVarOp->isDSOLocal() ||
116 !GlovalVarOp->isImplicitDSOLocal())
117 return false;
118
119 // On AArch64 small code model, the text-to-data span can be up to 4GB,
120 // which exceeds 32-bit signed relative offsets. Avoid converting if the
121 // target operand requires dynamic relocations (placing it in .data.rel.ro
122 // in the data segment rather than .rodata in the text segment).
123 if (TT.isAArch64() &&
124 (!GlovalVarOp->hasInitializer() ||
125 GlovalVarOp->getInitializer()->needsDynamicRelocation()))
126 return false;
127
128 if (ShouldDropUnnamedAddr)
129 GVOps.push_back(GlovalVarOp);
130
131 Info.Ptrs.push_back(C);
132 }
133
134 if (ShouldDropUnnamedAddr)
135 for (auto *GVOp : GVOps)
136 GVOp->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
137
138 return true;
139}
140
142 Function &Func,
143 GlobalVariable &LookupTable) {
144 Module &M = *Func.getParent();
145 ArrayType *IntArrayTy =
146 ArrayType::get(Type::getInt32Ty(M.getContext()), Info.Ptrs.size());
147
148 GlobalVariable *RelLookupTable = new GlobalVariable(
149 M, IntArrayTy, LookupTable.isConstant(), LookupTable.getLinkage(),
150 nullptr, LookupTable.getName() + ".rel", &LookupTable,
151 LookupTable.getThreadLocalMode(), LookupTable.getAddressSpace(),
152 LookupTable.isExternallyInitialized());
153
154 uint64_t Idx = 0;
155 SmallVector<Constant *, 64> RelLookupTableContents(Info.Ptrs.size());
156
157 for (Constant *Element : Info.Ptrs) {
158 Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
162 Constant *RelOffset =
164 RelLookupTableContents[Idx++] = RelOffset;
165 }
166
167 Constant *Initializer =
168 ConstantArray::get(IntArrayTy, RelLookupTableContents);
169 RelLookupTable->setInitializer(Initializer);
171 RelLookupTable->setAlignment(llvm::Align(4));
172 return RelLookupTable;
173}
174
176 GlobalVariable &LookupTable) {
178 cast<GetElementPtrInst>(LookupTable.use_begin()->getUser());
179 LoadInst *Load = cast<LoadInst>(GEP->use_begin()->getUser());
180
181 Module &M = *LookupTable.getParent();
182 BasicBlock *BB = GEP->getParent();
183 IRBuilder<> Builder(BB);
184 Function &Func = *BB->getParent();
185
186 // Generate an array that consists of relative offsets.
187 GlobalVariable *RelLookupTable =
188 createRelLookupTable(Info, Func, LookupTable);
189
190 // Place new instruction sequence before GEP.
191 Builder.SetInsertPoint(GEP);
192 IntegerType *IntTy = cast<IntegerType>(Info.Index->getType());
193 Value *Offset = Builder.CreateShl(Info.Index, ConstantInt::get(IntTy, 2),
194 "reltable.shift");
195
196 // Insert the call to load.relative intrinsic before LOAD.
197 // GEP might not be immediately followed by a LOAD, like it can be hoisted
198 // outside the loop or another instruction might be inserted them in between.
199 Builder.SetInsertPoint(Load);
201 &M, Intrinsic::load_relative, {Info.Index->getType()});
202
203 // Create a call to load.relative intrinsic that computes the target address
204 // by adding base address (lookup table address) and relative offset.
205 Value *Result = Builder.CreateCall(LoadRelIntrinsic, {RelLookupTable, Offset},
206 "reltable.intrinsic");
207
208 // Replace load instruction with the new generated instruction sequence.
209 Load->replaceAllUsesWith(Result);
210 // Remove Load and GEP instructions.
211 Load->eraseFromParent();
212 GEP->eraseFromParent();
213}
214
215// Convert lookup tables to relative lookup tables in the module.
218 for (Function &F : M) {
219 if (F.isDeclaration())
220 continue;
221
222 // Check if we have a target that supports relative lookup tables.
223 if (!GetTTI(F).shouldBuildRelLookupTables())
224 return false;
225
226 // We assume that the result is independent of the checked function.
227 break;
228 }
229
230 bool Changed = false;
231
232 for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {
233 LookupTableInfo Info;
234 if (!shouldConvertToRelLookupTable(Info, M, GV))
235 continue;
236
237 convertToRelLookupTable(Info, GV);
238
239 // Remove the original lookup table.
240 GV.eraseFromParent();
241
242 Changed = true;
243 }
244
245 return Changed;
246}
247
252
253 auto GetTTI = [&](Function &F) -> TargetTransformInfo & {
254 return FAM.getResult<TargetIRAnalysis>(F);
255 };
256
257 if (!convertToRelativeLookupTables(M, GetTTI))
258 return PreservedAnalyses::all();
259
262 return PA;
263}
unsigned uint64_t
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
FunctionAnalysisManager FAM
static bool convertToRelativeLookupTables(Module &M, function_ref< TargetTransformInfo &(Function &)> GetTTI)
static bool shouldConvertToRelLookupTable(LookupTableInfo &Info, Module &M, GlobalVariable &GV)
static GlobalVariable * createRelLookupTable(LookupTableInfo &Info, Function &Func, GlobalVariable &LookupTable)
static void convertToRelLookupTable(LookupTableInfo &Info, GlobalVariable &LookupTable)
This file implements relative lookup table converter that converts lookup tables to relative lookup t...
This pass exposes codegen information to IR-level passes.
Class for arbitrary precision integers.
Definition APInt.h:78
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:377
bool ult(const APInt &RHS) const
Unsigned less than comparison.
Definition APInt.h:1116
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static LLVM_ABI Constant * getSub(Constant *C1, Constant *C2, bool HasNUW=false, bool HasNSW=false)
static LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_ABI Constant * getTrunc(Constant *C, Type *Ty, bool OnlyIfReduced=false)
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:64
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
bool isDSOLocal() const
bool isImplicitDSOLocal() const
void setUnnamedAddr(UnnamedAddr Val)
bool hasLocalLinkage() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
LLVM_ABI void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
Definition Globals.cpp:613
bool hasInitializer() const
Definitions have initializers, declarations don't.
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...
void setAlignment(Align Align)
Sets the alignment attribute of the GlobalVariable.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2908
Class to represent integer types.
An instruction for reading from memory.
size_type size() const
Definition MapVector.h:58
std::pair< KeyT, ValueT > & front()
Definition MapVector.h:81
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
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 & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
User * getUser() const
Returns the User that contains this Use.
Definition Use.h:61
LLVM Value Representation.
Definition Value.h:75
bool hasOneUse() const
Return true if there is exactly one use of this value.
Definition Value.h:441
use_iterator use_begin()
Definition Value.h:366
An efficient, type-erasing, non-owning reference to a callable.
Changed
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
LLVM_ABI bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset, const DataLayout &DL, DSOLocalEquivalent **DSOEquiv=nullptr)
If this constant is a constant offset from a global, return the global and the constant.
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:633
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
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.
@ Sub
Subtraction of integers.
IntPtrTy
Definition InstrProf.h:82
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.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
SmallVector< Constant * > Ptrs
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
A MapVector that performs no allocations if smaller than a certain size.
Definition MapVector.h:342