| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 1 | //===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===// | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 9 | // This pass implements IR lowering for the llvm.load.relative and llvm.objc.* | 
|  | 10 | // intrinsics. | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 11 | // | 
|  | 12 | //===----------------------------------------------------------------------===// | 
|  | 13 |  | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 14 | #include "llvm/CodeGen/PreISelIntrinsicLowering.h" | 
| Francis Visoiu Mistrih | a9a3781 | 2019-11-06 17:09:55 -0800 | [diff] [blame] | 15 | #include "llvm/Analysis/ObjCARCInstKind.h" | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 16 | #include "llvm/CodeGen/Passes.h" | 
|  | 17 | #include "llvm/IR/Function.h" | 
|  | 18 | #include "llvm/IR/IRBuilder.h" | 
|  | 19 | #include "llvm/IR/Instructions.h" | 
| Reid Kleckner | 05da2fe | 2019-11-13 13:15:01 -0800 | [diff] [blame] | 20 | #include "llvm/IR/Intrinsics.h" | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 21 | #include "llvm/IR/Module.h" | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 22 | #include "llvm/IR/Type.h" | 
|  | 23 | #include "llvm/IR/User.h" | 
| Reid Kleckner | 05da2fe | 2019-11-13 13:15:01 -0800 | [diff] [blame] | 24 | #include "llvm/InitializePasses.h" | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 25 | #include "llvm/Pass.h" | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 26 | #include "llvm/Support/Casting.h" | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 27 |  | 
|  | 28 | using namespace llvm; | 
|  | 29 |  | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 30 | static bool lowerLoadRelative(Function &F) { | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 31 | if (F.use_empty()) | 
|  | 32 | return false; | 
|  | 33 |  | 
|  | 34 | bool Changed = false; | 
|  | 35 | Type *Int32Ty = Type::getInt32Ty(F.getContext()); | 
|  | 36 | Type *Int32PtrTy = Int32Ty->getPointerTo(); | 
|  | 37 | Type *Int8Ty = Type::getInt8Ty(F.getContext()); | 
|  | 38 |  | 
|  | 39 | for (auto I = F.use_begin(), E = F.use_end(); I != E;) { | 
|  | 40 | auto CI = dyn_cast<CallInst>(I->getUser()); | 
|  | 41 | ++I; | 
|  | 42 | if (!CI || CI->getCalledValue() != &F) | 
|  | 43 | continue; | 
|  | 44 |  | 
|  | 45 | IRBuilder<> B(CI); | 
|  | 46 | Value *OffsetPtr = | 
|  | 47 | B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1)); | 
|  | 48 | Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy); | 
| James Y Knight | 14359ef | 2019-02-01 20:44:24 +0000 | [diff] [blame] | 49 | Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, 4); | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 50 |  | 
|  | 51 | Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32); | 
|  | 52 |  | 
|  | 53 | CI->replaceAllUsesWith(ResultPtr); | 
|  | 54 | CI->eraseFromParent(); | 
|  | 55 | Changed = true; | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | return Changed; | 
|  | 59 | } | 
|  | 60 |  | 
| Francis Visoiu Mistrih | a9a3781 | 2019-11-06 17:09:55 -0800 | [diff] [blame] | 61 | // ObjCARC has knowledge about whether an obj-c runtime function needs to be | 
|  | 62 | // always tail-called or never tail-called. | 
|  | 63 | static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) { | 
|  | 64 | objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F); | 
|  | 65 | if (objcarc::IsAlwaysTail(Kind)) | 
|  | 66 | return CallInst::TCK_Tail; | 
|  | 67 | else if (objcarc::IsNeverTail(Kind)) | 
|  | 68 | return CallInst::TCK_NoTail; | 
|  | 69 | return CallInst::TCK_None; | 
|  | 70 | } | 
|  | 71 |  | 
| Pete Cooper | d0ffdf8 | 2018-12-18 22:31:34 +0000 | [diff] [blame] | 72 | static bool lowerObjCCall(Function &F, const char *NewFn, | 
|  | 73 | bool setNonLazyBind = false) { | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 74 | if (F.use_empty()) | 
|  | 75 | return false; | 
|  | 76 |  | 
|  | 77 | // If we haven't already looked up this function, check to see if the | 
|  | 78 | // program already contains a function with this name. | 
|  | 79 | Module *M = F.getParent(); | 
| James Y Knight | 1368022 | 2019-02-01 02:28:03 +0000 | [diff] [blame] | 80 | FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType()); | 
| Pete Cooper | a3e0be1 | 2018-12-18 22:42:08 +0000 | [diff] [blame] | 81 |  | 
| James Y Knight | 1368022 | 2019-02-01 02:28:03 +0000 | [diff] [blame] | 82 | if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) { | 
| Pete Cooper | a3e0be1 | 2018-12-18 22:42:08 +0000 | [diff] [blame] | 83 | Fn->setLinkage(F.getLinkage()); | 
|  | 84 | if (setNonLazyBind && !Fn->isWeakForLinker()) { | 
|  | 85 | // If we have Native ARC, set nonlazybind attribute for these APIs for | 
|  | 86 | // performance. | 
| Pete Cooper | d0ffdf8 | 2018-12-18 22:31:34 +0000 | [diff] [blame] | 87 | Fn->addFnAttr(Attribute::NonLazyBind); | 
| Pete Cooper | a3e0be1 | 2018-12-18 22:42:08 +0000 | [diff] [blame] | 88 | } | 
|  | 89 | } | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 90 |  | 
| Francis Visoiu Mistrih | a9a3781 | 2019-11-06 17:09:55 -0800 | [diff] [blame] | 91 | CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F); | 
|  | 92 |  | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 93 | for (auto I = F.use_begin(), E = F.use_end(); I != E;) { | 
| Simon Pilgrim | c81f8e4 | 2019-09-24 10:46:30 +0000 | [diff] [blame] | 94 | auto *CI = cast<CallInst>(I->getUser()); | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 95 | assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); | 
|  | 96 | ++I; | 
|  | 97 |  | 
|  | 98 | IRBuilder<> Builder(CI->getParent(), CI->getIterator()); | 
|  | 99 | SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end()); | 
|  | 100 | CallInst *NewCI = Builder.CreateCall(FCache, Args); | 
|  | 101 | NewCI->setName(CI->getName()); | 
| Francis Visoiu Mistrih | a9a3781 | 2019-11-06 17:09:55 -0800 | [diff] [blame] | 102 |  | 
|  | 103 | // Try to set the most appropriate TailCallKind based on both the current | 
|  | 104 | // attributes and the ones that we could get from ObjCARC's special | 
|  | 105 | // knowledge of the runtime functions. | 
|  | 106 | // | 
|  | 107 | // std::max respects both requirements of notail and tail here: | 
|  | 108 | // * notail on either the call or from ObjCARC becomes notail | 
|  | 109 | // * tail on either side is stronger than none, but not notail | 
|  | 110 | CallInst::TailCallKind TCK = CI->getTailCallKind(); | 
|  | 111 | NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); | 
|  | 112 |  | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 113 | if (!CI->use_empty()) | 
|  | 114 | CI->replaceAllUsesWith(NewCI); | 
|  | 115 | CI->eraseFromParent(); | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | return true; | 
|  | 119 | } | 
|  | 120 |  | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 121 | static bool lowerIntrinsics(Module &M) { | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 122 | bool Changed = false; | 
|  | 123 | for (Function &F : M) { | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 124 | if (F.getName().startswith("llvm.load.relative.")) { | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 125 | Changed |= lowerLoadRelative(F); | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 126 | continue; | 
|  | 127 | } | 
|  | 128 | switch (F.getIntrinsicID()) { | 
|  | 129 | default: | 
|  | 130 | break; | 
|  | 131 | case Intrinsic::objc_autorelease: | 
|  | 132 | Changed |= lowerObjCCall(F, "objc_autorelease"); | 
|  | 133 | break; | 
|  | 134 | case Intrinsic::objc_autoreleasePoolPop: | 
|  | 135 | Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); | 
|  | 136 | break; | 
|  | 137 | case Intrinsic::objc_autoreleasePoolPush: | 
|  | 138 | Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); | 
|  | 139 | break; | 
|  | 140 | case Intrinsic::objc_autoreleaseReturnValue: | 
|  | 141 | Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); | 
|  | 142 | break; | 
|  | 143 | case Intrinsic::objc_copyWeak: | 
|  | 144 | Changed |= lowerObjCCall(F, "objc_copyWeak"); | 
|  | 145 | break; | 
|  | 146 | case Intrinsic::objc_destroyWeak: | 
|  | 147 | Changed |= lowerObjCCall(F, "objc_destroyWeak"); | 
|  | 148 | break; | 
|  | 149 | case Intrinsic::objc_initWeak: | 
|  | 150 | Changed |= lowerObjCCall(F, "objc_initWeak"); | 
|  | 151 | break; | 
|  | 152 | case Intrinsic::objc_loadWeak: | 
|  | 153 | Changed |= lowerObjCCall(F, "objc_loadWeak"); | 
|  | 154 | break; | 
|  | 155 | case Intrinsic::objc_loadWeakRetained: | 
|  | 156 | Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); | 
|  | 157 | break; | 
|  | 158 | case Intrinsic::objc_moveWeak: | 
|  | 159 | Changed |= lowerObjCCall(F, "objc_moveWeak"); | 
|  | 160 | break; | 
|  | 161 | case Intrinsic::objc_release: | 
| Pete Cooper | d0ffdf8 | 2018-12-18 22:31:34 +0000 | [diff] [blame] | 162 | Changed |= lowerObjCCall(F, "objc_release", true); | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 163 | break; | 
|  | 164 | case Intrinsic::objc_retain: | 
| Pete Cooper | d0ffdf8 | 2018-12-18 22:31:34 +0000 | [diff] [blame] | 165 | Changed |= lowerObjCCall(F, "objc_retain", true); | 
| Pete Cooper | f86db5c | 2018-12-18 22:20:03 +0000 | [diff] [blame] | 166 | break; | 
|  | 167 | case Intrinsic::objc_retainAutorelease: | 
|  | 168 | Changed |= lowerObjCCall(F, "objc_retainAutorelease"); | 
|  | 169 | break; | 
|  | 170 | case Intrinsic::objc_retainAutoreleaseReturnValue: | 
|  | 171 | Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); | 
|  | 172 | break; | 
|  | 173 | case Intrinsic::objc_retainAutoreleasedReturnValue: | 
|  | 174 | Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); | 
|  | 175 | break; | 
|  | 176 | case Intrinsic::objc_retainBlock: | 
|  | 177 | Changed |= lowerObjCCall(F, "objc_retainBlock"); | 
|  | 178 | break; | 
|  | 179 | case Intrinsic::objc_storeStrong: | 
|  | 180 | Changed |= lowerObjCCall(F, "objc_storeStrong"); | 
|  | 181 | break; | 
|  | 182 | case Intrinsic::objc_storeWeak: | 
|  | 183 | Changed |= lowerObjCCall(F, "objc_storeWeak"); | 
|  | 184 | break; | 
|  | 185 | case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: | 
|  | 186 | Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); | 
|  | 187 | break; | 
|  | 188 | case Intrinsic::objc_retainedObject: | 
|  | 189 | Changed |= lowerObjCCall(F, "objc_retainedObject"); | 
|  | 190 | break; | 
|  | 191 | case Intrinsic::objc_unretainedObject: | 
|  | 192 | Changed |= lowerObjCCall(F, "objc_unretainedObject"); | 
|  | 193 | break; | 
|  | 194 | case Intrinsic::objc_unretainedPointer: | 
|  | 195 | Changed |= lowerObjCCall(F, "objc_unretainedPointer"); | 
|  | 196 | break; | 
|  | 197 | case Intrinsic::objc_retain_autorelease: | 
|  | 198 | Changed |= lowerObjCCall(F, "objc_retain_autorelease"); | 
|  | 199 | break; | 
|  | 200 | case Intrinsic::objc_sync_enter: | 
|  | 201 | Changed |= lowerObjCCall(F, "objc_sync_enter"); | 
|  | 202 | break; | 
|  | 203 | case Intrinsic::objc_sync_exit: | 
|  | 204 | Changed |= lowerObjCCall(F, "objc_sync_exit"); | 
|  | 205 | break; | 
|  | 206 | } | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 207 | } | 
|  | 208 | return Changed; | 
|  | 209 | } | 
|  | 210 |  | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 211 | namespace { | 
|  | 212 |  | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 213 | class PreISelIntrinsicLoweringLegacyPass : public ModulePass { | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 214 | public: | 
|  | 215 | static char ID; | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 216 |  | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 217 | PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 218 |  | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 219 | bool runOnModule(Module &M) override { return lowerIntrinsics(M); } | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 220 | }; | 
|  | 221 |  | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 222 | } // end anonymous namespace | 
|  | 223 |  | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 224 | char PreISelIntrinsicLoweringLegacyPass::ID; | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 225 |  | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 226 | INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, | 
|  | 227 | "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", | 
|  | 228 | false, false) | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 229 |  | 
| Eugene Zelenko | 618c555 | 2017-09-13 21:15:20 +0000 | [diff] [blame] | 230 | ModulePass *llvm::createPreISelIntrinsicLoweringPass() { | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 231 | return new PreISelIntrinsicLoweringLegacyPass; | 
| Peter Collingbourne | 7dd8dbf | 2016-04-22 21:18:02 +0000 | [diff] [blame] | 232 | } | 
| Michael Kuperstein | 82d5da5 | 2016-06-24 20:13:42 +0000 | [diff] [blame] | 233 |  | 
|  | 234 | PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, | 
|  | 235 | ModuleAnalysisManager &AM) { | 
|  | 236 | if (!lowerIntrinsics(M)) | 
|  | 237 | return PreservedAnalyses::all(); | 
|  | 238 | else | 
|  | 239 | return PreservedAnalyses::none(); | 
|  | 240 | } |