LLVM 22.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
25 // If lookup table has more than one user,
26 // do not generate a relative lookup table.
27 // This is to simplify the analysis that needs to be done for this pass.
28 // TODO: Add support for lookup tables with multiple uses.
29 // For ex, this can happen when a function that uses a lookup table gets
30 // inlined into multiple call sites.
31 if (!GV.hasInitializer() ||
32 !GV.isConstant() ||
33 !GV.hasOneUse())
34 return false;
35
37 dyn_cast<GetElementPtrInst>(GV.use_begin()->getUser());
38 if (!GEP || !GEP->hasOneUse() ||
39 GV.getValueType() != GEP->getSourceElementType())
40 return false;
41
42 LoadInst *Load = dyn_cast<LoadInst>(GEP->use_begin()->getUser());
43 if (!Load || !Load->hasOneUse() ||
44 Load->getType() != GEP->getResultElementType())
45 return false;
46
47 // If the original lookup table does not have local linkage and is
48 // not dso_local, do not generate a relative lookup table.
49 // This optimization creates a relative lookup table that consists of
50 // offsets between the start of the lookup table and its elements.
51 // To be able to generate these offsets, relative lookup table and
52 // its elements should have internal linkage and be dso_local, which means
53 // that they should resolve to symbols within the same linkage unit.
54 if (!GV.hasLocalLinkage() ||
55 !GV.isDSOLocal() ||
57 return false;
58
59 ConstantArray *Array = dyn_cast<ConstantArray>(GV.getInitializer());
60 if (!Array)
61 return false;
62
63 // If values are not 64-bit pointers, do not generate a relative lookup table.
64 const DataLayout &DL = M.getDataLayout();
65 Type *ElemType = Array->getType()->getElementType();
66 if (!ElemType->isPointerTy() || DL.getPointerTypeSizeInBits(ElemType) != 64)
67 return false;
68
70 Triple TT = M.getTargetTriple();
71 // FIXME: This should be removed in the future.
72 bool ShouldDropUnnamedAddr =
73 // Drop unnamed_addr to avoid matching pattern in
74 // `handleIndirectSymViaGOTPCRel`, which generates GOTPCREL relocations
75 // not supported by the GNU linker and LLD versions below 18 on aarch64.
76 TT.isAArch64()
77 // Apple's ld64 (and ld-prime on Xcode 15.2) miscompile something on
78 // x86_64-apple-darwin. See
79 // https://github.com/rust-lang/rust/issues/140686 and
80 // https://github.com/rust-lang/rust/issues/141306.
81 || (TT.isX86() && TT.isOSDarwin());
82
83 for (const Use &Op : Array->operands()) {
84 Constant *ConstOp = cast<Constant>(&Op);
85 GlobalValue *GVOp;
87
88 // If an operand is not a constant offset from a lookup table,
89 // do not generate a relative lookup table.
90 if (!IsConstantOffsetFromGlobal(ConstOp, GVOp, Offset, DL))
91 return false;
92
93 // If operand is mutable, do not generate a relative lookup table.
94 auto *GlovalVarOp = dyn_cast<GlobalVariable>(GVOp);
95 if (!GlovalVarOp || !GlovalVarOp->isConstant())
96 return false;
97
98 if (!GlovalVarOp->hasLocalLinkage() ||
99 !GlovalVarOp->isDSOLocal() ||
100 !GlovalVarOp->isImplicitDSOLocal())
101 return false;
102
103 if (ShouldDropUnnamedAddr)
104 GVOps.push_back(GlovalVarOp);
105 }
106
107 if (ShouldDropUnnamedAddr)
108 for (auto *GVOp : GVOps)
109 GVOp->setUnnamedAddr(GlobalValue::UnnamedAddr::None);
110
111 return true;
112}
113
115 GlobalVariable &LookupTable) {
116 Module &M = *Func.getParent();
117 ConstantArray *LookupTableArr =
118 cast<ConstantArray>(LookupTable.getInitializer());
119 unsigned NumElts = LookupTableArr->getType()->getNumElements();
120 ArrayType *IntArrayTy =
121 ArrayType::get(Type::getInt32Ty(M.getContext()), NumElts);
122
123 GlobalVariable *RelLookupTable = new GlobalVariable(
124 M, IntArrayTy, LookupTable.isConstant(), LookupTable.getLinkage(),
125 nullptr, LookupTable.getName() + ".rel", &LookupTable,
126 LookupTable.getThreadLocalMode(), LookupTable.getAddressSpace(),
127 LookupTable.isExternallyInitialized());
128
129 uint64_t Idx = 0;
130 SmallVector<Constant *, 64> RelLookupTableContents(NumElts);
131
132 for (Use &Operand : LookupTableArr->operands()) {
133 Constant *Element = cast<Constant>(Operand);
134 Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
135 Constant *Base = llvm::ConstantExpr::getPtrToInt(RelLookupTable, IntPtrTy);
136 Constant *Target = llvm::ConstantExpr::getPtrToInt(Element, IntPtrTy);
138 Constant *RelOffset =
140 RelLookupTableContents[Idx++] = RelOffset;
141 }
142
143 Constant *Initializer =
144 ConstantArray::get(IntArrayTy, RelLookupTableContents);
145 RelLookupTable->setInitializer(Initializer);
146 RelLookupTable->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
147 RelLookupTable->setAlignment(llvm::Align(4));
148 return RelLookupTable;
149}
150
151static void convertToRelLookupTable(GlobalVariable &LookupTable) {
153 cast<GetElementPtrInst>(LookupTable.use_begin()->getUser());
154 LoadInst *Load = cast<LoadInst>(GEP->use_begin()->getUser());
155
156 Module &M = *LookupTable.getParent();
157 BasicBlock *BB = GEP->getParent();
158 IRBuilder<> Builder(BB);
159 Function &Func = *BB->getParent();
160
161 // Generate an array that consists of relative offsets.
162 GlobalVariable *RelLookupTable = createRelLookupTable(Func, LookupTable);
163
164 // Place new instruction sequence before GEP.
165 Builder.SetInsertPoint(GEP);
166 Value *Index = GEP->getOperand(2);
167 IntegerType *IntTy = cast<IntegerType>(Index->getType());
168 Value *Offset =
169 Builder.CreateShl(Index, ConstantInt::get(IntTy, 2), "reltable.shift");
170
171 // Insert the call to load.relative intrinsic before LOAD.
172 // GEP might not be immediately followed by a LOAD, like it can be hoisted
173 // outside the loop or another instruction might be inserted them in between.
174 Builder.SetInsertPoint(Load);
176 &M, Intrinsic::load_relative, {Index->getType()});
177
178 // Create a call to load.relative intrinsic that computes the target address
179 // by adding base address (lookup table address) and relative offset.
180 Value *Result = Builder.CreateCall(LoadRelIntrinsic, {RelLookupTable, Offset},
181 "reltable.intrinsic");
182
183 // Replace load instruction with the new generated instruction sequence.
184 Load->replaceAllUsesWith(Result);
185 // Remove Load and GEP instructions.
186 Load->eraseFromParent();
187 GEP->eraseFromParent();
188}
189
190// Convert lookup tables to relative lookup tables in the module.
193 for (Function &F : M) {
194 if (F.isDeclaration())
195 continue;
196
197 // Check if we have a target that supports relative lookup tables.
198 if (!GetTTI(F).shouldBuildRelLookupTables())
199 return false;
200
201 // We assume that the result is independent of the checked function.
202 break;
203 }
204
205 bool Changed = false;
206
207 for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {
209 continue;
210
212
213 // Remove the original lookup table.
214 GV.eraseFromParent();
215
216 Changed = true;
217 }
218
219 return Changed;
220}
221
226
227 auto GetTTI = [&](Function &F) -> TargetTransformInfo & {
229 };
230
231 if (!convertToRelativeLookupTables(M, GetTTI))
232 return PreservedAnalyses::all();
233
236 return PA;
237}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition: MD5.cpp:55
FunctionAnalysisManager FAM
static bool shouldConvertToRelLookupTable(Module &M, GlobalVariable &GV)
static void convertToRelLookupTable(GlobalVariable &LookupTable)
static bool convertToRelativeLookupTables(Module &M, function_ref< TargetTransformInfo &(Function &)> GetTTI)
static GlobalVariable * createRelLookupTable(Function &Func, 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
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
uint64_t getNumElements() const
Definition: DerivedTypes.h:410
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
ConstantArray - Constant Array Declarations.
Definition: Constants.h:433
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
Definition: Constants.cpp:1314
ArrayType * getType() const
Specialize the getType() method to always return an ArrayType, which reduces the amount of casting ne...
Definition: Constants.h:452
static LLVM_ABI Constant * getSub(Constant *C1, Constant *C2, bool HasNUW=false, bool HasNSW=false)
Definition: Constants.cpp:2654
static LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
Definition: Constants.cpp:2300
static LLVM_ABI Constant * getTrunc(Constant *C, Type *Ty, bool OnlyIfReduced=false)
Definition: Constants.cpp:2272
This is an important base class in LLVM.
Definition: Constant.h:43
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
Definition: Instructions.h:949
bool isDSOLocal() const
Definition: GlobalValue.h:307
bool isImplicitDSOLocal() const
Definition: GlobalValue.h:300
void setUnnamedAddr(UnnamedAddr Val)
Definition: GlobalValue.h:233
bool hasLocalLinkage() const
Definition: GlobalValue.h:530
Type * getValueType() const
Definition: GlobalValue.h:298
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:511
bool hasInitializer() const
Definitions have initializers, declarations don't.
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.
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1492
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2508
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition: IRBuilder.h:207
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2780
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
Definition: PassManager.h:585
Class to represent integer types.
Definition: DerivedTypes.h:42
An instruction for reading from memory.
Definition: Instructions.h:180
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
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
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
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:47
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:267
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
Definition: Use.h:35
op_range operands()
Definition: User.h:292
LLVM Value Representation.
Definition: Value.h:75
bool hasOneUse() const
Return true if there is exactly one use of this value.
Definition: Value.h:439
use_iterator use_begin()
Definition: Value.h:364
An efficient, type-erasing, non-owning reference to a callable.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
Definition: Intrinsics.cpp:751
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
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:663
@ Sub
Subtraction of integers.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39