RelLookupTableConverter.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. #include "llvm/Transforms/Utils/RelLookupTableConverter.h"
  14. #include "llvm/Analysis/ConstantFolding.h"
  15. #include "llvm/Analysis/TargetTransformInfo.h"
  16. #include "llvm/IR/BasicBlock.h"
  17. #include "llvm/IR/IRBuilder.h"
  18. #include "llvm/IR/Instructions.h"
  19. #include "llvm/IR/Module.h"
  20. using namespace llvm;
  21. static bool shouldConvertToRelLookupTable(Module &M, GlobalVariable &GV) {
  22. // If lookup table has more than one user,
  23. // do not generate a relative lookup table.
  24. // This is to simplify the analysis that needs to be done for this pass.
  25. // TODO: Add support for lookup tables with multiple uses.
  26. // For ex, this can happen when a function that uses a lookup table gets
  27. // inlined into multiple call sites.
  28. if (!GV.hasInitializer() ||
  29. !GV.isConstant() ||
  30. !GV.hasOneUse())
  31. return false;
  32. GetElementPtrInst *GEP =
  33. dyn_cast<GetElementPtrInst>(GV.use_begin()->getUser());
  34. if (!GEP || !GEP->hasOneUse() ||
  35. GV.getValueType() != GEP->getSourceElementType())
  36. return false;
  37. LoadInst *Load = dyn_cast<LoadInst>(GEP->use_begin()->getUser());
  38. if (!Load || !Load->hasOneUse() ||
  39. Load->getType() != GEP->getResultElementType())
  40. return false;
  41. // If the original lookup table does not have local linkage and is
  42. // not dso_local, do not generate a relative lookup table.
  43. // This optimization creates a relative lookup table that consists of
  44. // offsets between the start of the lookup table and its elements.
  45. // To be able to generate these offsets, relative lookup table and
  46. // its elements should have internal linkage and be dso_local, which means
  47. // that they should resolve to symbols within the same linkage unit.
  48. if (!GV.hasLocalLinkage() ||
  49. !GV.isDSOLocal() ||
  50. !GV.isImplicitDSOLocal())
  51. return false;
  52. ConstantArray *Array = dyn_cast<ConstantArray>(GV.getInitializer());
  53. if (!Array)
  54. return false;
  55. // If values are not 64-bit pointers, do not generate a relative lookup table.
  56. const DataLayout &DL = M.getDataLayout();
  57. Type *ElemType = Array->getType()->getElementType();
  58. if (!ElemType->isPointerTy() || DL.getPointerTypeSizeInBits(ElemType) != 64)
  59. return false;
  60. for (const Use &Op : Array->operands()) {
  61. Constant *ConstOp = cast<Constant>(&Op);
  62. GlobalValue *GVOp;
  63. APInt Offset;
  64. // If an operand is not a constant offset from a lookup table,
  65. // do not generate a relative lookup table.
  66. if (!IsConstantOffsetFromGlobal(ConstOp, GVOp, Offset, DL))
  67. return false;
  68. // If operand is mutable, do not generate a relative lookup table.
  69. auto *GlovalVarOp = dyn_cast<GlobalVariable>(GVOp);
  70. if (!GlovalVarOp || !GlovalVarOp->isConstant())
  71. return false;
  72. if (!GlovalVarOp->hasLocalLinkage() ||
  73. !GlovalVarOp->isDSOLocal() ||
  74. !GlovalVarOp->isImplicitDSOLocal())
  75. return false;
  76. }
  77. return true;
  78. }
  79. static GlobalVariable *createRelLookupTable(Function &Func,
  80. GlobalVariable &LookupTable) {
  81. Module &M = *Func.getParent();
  82. ConstantArray *LookupTableArr =
  83. cast<ConstantArray>(LookupTable.getInitializer());
  84. unsigned NumElts = LookupTableArr->getType()->getNumElements();
  85. ArrayType *IntArrayTy =
  86. ArrayType::get(Type::getInt32Ty(M.getContext()), NumElts);
  87. GlobalVariable *RelLookupTable = new GlobalVariable(
  88. M, IntArrayTy, LookupTable.isConstant(), LookupTable.getLinkage(),
  89. nullptr, "reltable." + Func.getName(), &LookupTable,
  90. LookupTable.getThreadLocalMode(), LookupTable.getAddressSpace(),
  91. LookupTable.isExternallyInitialized());
  92. uint64_t Idx = 0;
  93. SmallVector<Constant *, 64> RelLookupTableContents(NumElts);
  94. for (Use &Operand : LookupTableArr->operands()) {
  95. Constant *Element = cast<Constant>(Operand);
  96. Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
  97. Constant *Base = llvm::ConstantExpr::getPtrToInt(RelLookupTable, IntPtrTy);
  98. Constant *Target = llvm::ConstantExpr::getPtrToInt(Element, IntPtrTy);
  99. Constant *Sub = llvm::ConstantExpr::getSub(Target, Base);
  100. Constant *RelOffset =
  101. llvm::ConstantExpr::getTrunc(Sub, Type::getInt32Ty(M.getContext()));
  102. RelLookupTableContents[Idx++] = RelOffset;
  103. }
  104. Constant *Initializer =
  105. ConstantArray::get(IntArrayTy, RelLookupTableContents);
  106. RelLookupTable->setInitializer(Initializer);
  107. RelLookupTable->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
  108. RelLookupTable->setAlignment(llvm::Align(4));
  109. return RelLookupTable;
  110. }
  111. static void convertToRelLookupTable(GlobalVariable &LookupTable) {
  112. GetElementPtrInst *GEP =
  113. cast<GetElementPtrInst>(LookupTable.use_begin()->getUser());
  114. LoadInst *Load = cast<LoadInst>(GEP->use_begin()->getUser());
  115. Module &M = *LookupTable.getParent();
  116. BasicBlock *BB = GEP->getParent();
  117. IRBuilder<> Builder(BB);
  118. Function &Func = *BB->getParent();
  119. // Generate an array that consists of relative offsets.
  120. GlobalVariable *RelLookupTable = createRelLookupTable(Func, LookupTable);
  121. // Place new instruction sequence before GEP.
  122. Builder.SetInsertPoint(GEP);
  123. Value *Index = GEP->getOperand(2);
  124. IntegerType *IntTy = cast<IntegerType>(Index->getType());
  125. Value *Offset =
  126. Builder.CreateShl(Index, ConstantInt::get(IntTy, 2), "reltable.shift");
  127. // Insert the call to load.relative intrinsic before LOAD.
  128. // GEP might not be immediately followed by a LOAD, like it can be hoisted
  129. // outside the loop or another instruction might be inserted them in between.
  130. Builder.SetInsertPoint(Load);
  131. Function *LoadRelIntrinsic = llvm::Intrinsic::getDeclaration(
  132. &M, Intrinsic::load_relative, {Index->getType()});
  133. Value *Base = Builder.CreateBitCast(RelLookupTable, Builder.getInt8PtrTy());
  134. // Create a call to load.relative intrinsic that computes the target address
  135. // by adding base address (lookup table address) and relative offset.
  136. Value *Result = Builder.CreateCall(LoadRelIntrinsic, {Base, Offset},
  137. "reltable.intrinsic");
  138. // Create a bitcast instruction if necessary.
  139. if (Load->getType() != Builder.getInt8PtrTy())
  140. Result = Builder.CreateBitCast(Result, Load->getType(), "reltable.bitcast");
  141. // Replace load instruction with the new generated instruction sequence.
  142. Load->replaceAllUsesWith(Result);
  143. // Remove Load and GEP instructions.
  144. Load->eraseFromParent();
  145. GEP->eraseFromParent();
  146. }
  147. // Convert lookup tables to relative lookup tables in the module.
  148. static bool convertToRelativeLookupTables(
  149. Module &M, function_ref<TargetTransformInfo &(Function &)> GetTTI) {
  150. for (Function &F : M) {
  151. if (F.isDeclaration())
  152. continue;
  153. // Check if we have a target that supports relative lookup tables.
  154. if (!GetTTI(F).shouldBuildRelLookupTables())
  155. return false;
  156. // We assume that the result is independent of the checked function.
  157. break;
  158. }
  159. bool Changed = false;
  160. for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {
  161. if (!shouldConvertToRelLookupTable(M, GV))
  162. continue;
  163. convertToRelLookupTable(GV);
  164. // Remove the original lookup table.
  165. GV.eraseFromParent();
  166. Changed = true;
  167. }
  168. return Changed;
  169. }
  170. PreservedAnalyses RelLookupTableConverterPass::run(Module &M,
  171. ModuleAnalysisManager &AM) {
  172. FunctionAnalysisManager &FAM =
  173. AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
  174. auto GetTTI = [&](Function &F) -> TargetTransformInfo & {
  175. return FAM.getResult<TargetIRAnalysis>(F);
  176. };
  177. if (!convertToRelativeLookupTables(M, GetTTI))
  178. return PreservedAnalyses::all();
  179. PreservedAnalyses PA;
  180. PA.preserveSet<CFGAnalyses>();
  181. return PA;
  182. }