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