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