PreISelIntrinsicLowering.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===//
  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 pass implements IR lowering for the llvm.load.relative and llvm.objc.*
  10. // intrinsics.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/CodeGen/PreISelIntrinsicLowering.h"
  14. #include "llvm/CodeGen/Passes.h"
  15. #include "llvm/IR/Function.h"
  16. #include "llvm/IR/Intrinsics.h"
  17. #include "llvm/IR/IRBuilder.h"
  18. #include "llvm/IR/Instructions.h"
  19. #include "llvm/IR/Module.h"
  20. #include "llvm/IR/Type.h"
  21. #include "llvm/IR/User.h"
  22. #include "llvm/Pass.h"
  23. #include "llvm/Support/Casting.h"
  24. using namespace llvm;
  25. static bool lowerLoadRelative(Function &F) {
  26. if (F.use_empty())
  27. return false;
  28. bool Changed = false;
  29. Type *Int32Ty = Type::getInt32Ty(F.getContext());
  30. Type *Int32PtrTy = Int32Ty->getPointerTo();
  31. Type *Int8Ty = Type::getInt8Ty(F.getContext());
  32. for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
  33. auto CI = dyn_cast<CallInst>(I->getUser());
  34. ++I;
  35. if (!CI || CI->getCalledValue() != &F)
  36. continue;
  37. IRBuilder<> B(CI);
  38. Value *OffsetPtr =
  39. B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1));
  40. Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy);
  41. Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, 4);
  42. Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32);
  43. CI->replaceAllUsesWith(ResultPtr);
  44. CI->eraseFromParent();
  45. Changed = true;
  46. }
  47. return Changed;
  48. }
  49. static bool lowerObjCCall(Function &F, const char *NewFn,
  50. bool setNonLazyBind = false) {
  51. if (F.use_empty())
  52. return false;
  53. // If we haven't already looked up this function, check to see if the
  54. // program already contains a function with this name.
  55. Module *M = F.getParent();
  56. FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
  57. if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) {
  58. Fn->setLinkage(F.getLinkage());
  59. if (setNonLazyBind && !Fn->isWeakForLinker()) {
  60. // If we have Native ARC, set nonlazybind attribute for these APIs for
  61. // performance.
  62. Fn->addFnAttr(Attribute::NonLazyBind);
  63. }
  64. }
  65. for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
  66. auto *CI = dyn_cast<CallInst>(I->getUser());
  67. assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
  68. ++I;
  69. IRBuilder<> Builder(CI->getParent(), CI->getIterator());
  70. SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end());
  71. CallInst *NewCI = Builder.CreateCall(FCache, Args);
  72. NewCI->setName(CI->getName());
  73. NewCI->setTailCallKind(CI->getTailCallKind());
  74. if (!CI->use_empty())
  75. CI->replaceAllUsesWith(NewCI);
  76. CI->eraseFromParent();
  77. }
  78. return true;
  79. }
  80. static bool lowerIntrinsics(Module &M) {
  81. bool Changed = false;
  82. for (Function &F : M) {
  83. if (F.getName().startswith("llvm.load.relative.")) {
  84. Changed |= lowerLoadRelative(F);
  85. continue;
  86. }
  87. switch (F.getIntrinsicID()) {
  88. default:
  89. break;
  90. case Intrinsic::objc_autorelease:
  91. Changed |= lowerObjCCall(F, "objc_autorelease");
  92. break;
  93. case Intrinsic::objc_autoreleasePoolPop:
  94. Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
  95. break;
  96. case Intrinsic::objc_autoreleasePoolPush:
  97. Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
  98. break;
  99. case Intrinsic::objc_autoreleaseReturnValue:
  100. Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
  101. break;
  102. case Intrinsic::objc_copyWeak:
  103. Changed |= lowerObjCCall(F, "objc_copyWeak");
  104. break;
  105. case Intrinsic::objc_destroyWeak:
  106. Changed |= lowerObjCCall(F, "objc_destroyWeak");
  107. break;
  108. case Intrinsic::objc_initWeak:
  109. Changed |= lowerObjCCall(F, "objc_initWeak");
  110. break;
  111. case Intrinsic::objc_loadWeak:
  112. Changed |= lowerObjCCall(F, "objc_loadWeak");
  113. break;
  114. case Intrinsic::objc_loadWeakRetained:
  115. Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
  116. break;
  117. case Intrinsic::objc_moveWeak:
  118. Changed |= lowerObjCCall(F, "objc_moveWeak");
  119. break;
  120. case Intrinsic::objc_release:
  121. Changed |= lowerObjCCall(F, "objc_release", true);
  122. break;
  123. case Intrinsic::objc_retain:
  124. Changed |= lowerObjCCall(F, "objc_retain", true);
  125. break;
  126. case Intrinsic::objc_retainAutorelease:
  127. Changed |= lowerObjCCall(F, "objc_retainAutorelease");
  128. break;
  129. case Intrinsic::objc_retainAutoreleaseReturnValue:
  130. Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
  131. break;
  132. case Intrinsic::objc_retainAutoreleasedReturnValue:
  133. Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
  134. break;
  135. case Intrinsic::objc_retainBlock:
  136. Changed |= lowerObjCCall(F, "objc_retainBlock");
  137. break;
  138. case Intrinsic::objc_storeStrong:
  139. Changed |= lowerObjCCall(F, "objc_storeStrong");
  140. break;
  141. case Intrinsic::objc_storeWeak:
  142. Changed |= lowerObjCCall(F, "objc_storeWeak");
  143. break;
  144. case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
  145. Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
  146. break;
  147. case Intrinsic::objc_retainedObject:
  148. Changed |= lowerObjCCall(F, "objc_retainedObject");
  149. break;
  150. case Intrinsic::objc_unretainedObject:
  151. Changed |= lowerObjCCall(F, "objc_unretainedObject");
  152. break;
  153. case Intrinsic::objc_unretainedPointer:
  154. Changed |= lowerObjCCall(F, "objc_unretainedPointer");
  155. break;
  156. case Intrinsic::objc_retain_autorelease:
  157. Changed |= lowerObjCCall(F, "objc_retain_autorelease");
  158. break;
  159. case Intrinsic::objc_sync_enter:
  160. Changed |= lowerObjCCall(F, "objc_sync_enter");
  161. break;
  162. case Intrinsic::objc_sync_exit:
  163. Changed |= lowerObjCCall(F, "objc_sync_exit");
  164. break;
  165. }
  166. }
  167. return Changed;
  168. }
  169. namespace {
  170. class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
  171. public:
  172. static char ID;
  173. PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
  174. bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
  175. };
  176. } // end anonymous namespace
  177. char PreISelIntrinsicLoweringLegacyPass::ID;
  178. INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
  179. "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
  180. false, false)
  181. ModulePass *llvm::createPreISelIntrinsicLoweringPass() {
  182. return new PreISelIntrinsicLoweringLegacyPass;
  183. }
  184. PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
  185. ModuleAnalysisManager &AM) {
  186. if (!lowerIntrinsics(M))
  187. return PreservedAnalyses::all();
  188. else
  189. return PreservedAnalyses::none();
  190. }