RelLookupTableConverter.cpp 7.9 KB

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