1//===- RelLookupTableConverterPass - Rel Table Conv -----------------------===//
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
7//===----------------------------------------------------------------------===//
9// This file implements relative lookup table converter that converts
10// lookup tables to relative lookup tables to make them PIC-friendly.
12//===----------------------------------------------------------------------===//
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.
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.
50 if (!
GEP || !
GEP->hasOneUse())
54 if (!Load || !Load->hasOneUse())
57 // If values are not 64-bit pointers, do not generate a relative lookup table.
59 Type *ElemType = Load->getType();
60 if (!ElemType->
isPointerTy() ||
DL.getPointerTypeSizeInBits(ElemType) != 64)
63 // Make sure this is a gep of the form GV + scale*var.
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)
72 // This can't be a pointer lookup table if the stride is smaller than a
75 const APInt &Stride = VarOffsets.
front().second;
76 if (Stride.
ult(
DL.getTypeStoreSize(ElemType)))
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.
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());
104 // If an operand is not a constant offset from a lookup table,
105 // do not generate a relative lookup table.
109 // If operand is mutable, do not generate a relative lookup table.
111 if (!GlovalVarOp || !GlovalVarOp->isConstant())
114 if (!GlovalVarOp->hasLocalLinkage() ||
115 !GlovalVarOp->isDSOLocal() ||
116 !GlovalVarOp->isImplicitDSOLocal())
119 if (ShouldDropUnnamedAddr)
122 Info.Ptrs.push_back(
C);
125 if (ShouldDropUnnamedAddr)
126 for (
auto *GVOp : GVOps)
135 Module &M = *Func.getParent();
140 M, IntArrayTy, LookupTable.isConstant(), LookupTable.getLinkage(),
141 nullptr, LookupTable.getName() +
".rel", &LookupTable,
142 LookupTable.getThreadLocalMode(), LookupTable.getAddressSpace(),
143 LookupTable.isExternallyInitialized());
149 Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
155 RelLookupTableContents[Idx++] = RelOffset;
163 return RelLookupTable;
172 Module &M = *LookupTable.getParent();
177 // Generate an array that consists of relative offsets.
181 // Place new instruction sequence before GEP.
182 Builder.SetInsertPoint(
GEP);
184 Value *
Offset = Builder.CreateShl(
Info.Index, ConstantInt::get(IntTy, 2),
187 // Insert the call to load.relative intrinsic before LOAD.
188 // GEP might not be immediately followed by a LOAD, like it can be hoisted
189 // outside the loop or another instruction might be inserted them in between.
190 Builder.SetInsertPoint(Load);
192 &M, Intrinsic::load_relative, {
Info.Index->getType()});
194 // Create a call to load.relative intrinsic that computes the target address
195 // by adding base address (lookup table address) and relative offset.
196 Value *Result = Builder.CreateCall(LoadRelIntrinsic, {RelLookupTable,
Offset},
197 "reltable.intrinsic");
199 // Replace load instruction with the new generated instruction sequence.
200 Load->replaceAllUsesWith(Result);
201 // Remove Load and GEP instructions.
202 Load->eraseFromParent();
203 GEP->eraseFromParent();
206// Convert lookup tables to relative lookup tables in the module.
210 if (
F.isDeclaration())
213 // Check if we have a target that supports relative lookup tables.
214 if (!GetTTI(
F).shouldBuildRelLookupTables())
217 // We assume that the result is independent of the checked function.
230 // Remove the original lookup table.
231 GV.eraseFromParent();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Analysis containing CSE Info
Module.h This file contains the declarations for the Module class.
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...
Class for arbitrary precision integers.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
bool ult(const APInt &RHS) const
Unsigned less than comparison.
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.
const Function * getParent() const
Return the enclosing method, or null if none.
Represents analyses that only rely on functions' control flow.
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.
A parsed version of the target data layout string in and methods for querying it.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
bool isImplicitDSOLocal() const
void setUnnamedAddr(UnnamedAddr Val)
bool hasLocalLinkage() const
Type * getValueType() 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 ...
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.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Class to represent integer types.
An instruction for reading from memory.
std::pair< KeyT, ValueT > & front()
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
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.
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
User * getUser() const
Returns the User that contains this Use.
LLVM Value Representation.
bool hasOneUse() const
Return true if there is exactly one use of this value.
An efficient, type-erasing, non-owning reference to a callable.
@ C
The default llvm calling convention, compatible with C.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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...
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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
SmallVector< Constant * > Ptrs
This struct is a compact representation of a valid (non-zero power of two) alignment.
A MapVector that performs no allocations if smaller than a certain size.