]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / CodeGen / PreISelIntrinsicLowering.cpp
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 (Function* Fn = dyn_cast<Function>(FCache)) {
71     Fn->setLinkage(F.getLinkage());
72     if (setNonLazyBind && !Fn->isWeakForLinker()) {
73       // If we have Native ARC, set nonlazybind attribute for these APIs for
74       // performance.
75       Fn->addFnAttr(Attribute::NonLazyBind);
76     }
77   }
78
79   for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
80     auto *CI = dyn_cast<CallInst>(I->getUser());
81     assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
82     ++I;
83
84     IRBuilder<> Builder(CI->getParent(), CI->getIterator());
85     SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end());
86     CallInst *NewCI = Builder.CreateCall(FCache, Args);
87     NewCI->setName(CI->getName());
88     NewCI->setTailCallKind(CI->getTailCallKind());
89     if (!CI->use_empty())
90       CI->replaceAllUsesWith(NewCI);
91     CI->eraseFromParent();
92   }
93
94   return true;
95 }
96
97 static bool lowerIntrinsics(Module &M) {
98   bool Changed = false;
99   for (Function &F : M) {
100     if (F.getName().startswith("llvm.load.relative.")) {
101       Changed |= lowerLoadRelative(F);
102       continue;
103     }
104     switch (F.getIntrinsicID()) {
105     default:
106       break;
107     case Intrinsic::objc_autorelease:
108       Changed |= lowerObjCCall(F, "objc_autorelease");
109       break;
110     case Intrinsic::objc_autoreleasePoolPop:
111       Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
112       break;
113     case Intrinsic::objc_autoreleasePoolPush:
114       Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
115       break;
116     case Intrinsic::objc_autoreleaseReturnValue:
117       Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
118       break;
119     case Intrinsic::objc_copyWeak:
120       Changed |= lowerObjCCall(F, "objc_copyWeak");
121       break;
122     case Intrinsic::objc_destroyWeak:
123       Changed |= lowerObjCCall(F, "objc_destroyWeak");
124       break;
125     case Intrinsic::objc_initWeak:
126       Changed |= lowerObjCCall(F, "objc_initWeak");
127       break;
128     case Intrinsic::objc_loadWeak:
129       Changed |= lowerObjCCall(F, "objc_loadWeak");
130       break;
131     case Intrinsic::objc_loadWeakRetained:
132       Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
133       break;
134     case Intrinsic::objc_moveWeak:
135       Changed |= lowerObjCCall(F, "objc_moveWeak");
136       break;
137     case Intrinsic::objc_release:
138       Changed |= lowerObjCCall(F, "objc_release", true);
139       break;
140     case Intrinsic::objc_retain:
141       Changed |= lowerObjCCall(F, "objc_retain", true);
142       break;
143     case Intrinsic::objc_retainAutorelease:
144       Changed |= lowerObjCCall(F, "objc_retainAutorelease");
145       break;
146     case Intrinsic::objc_retainAutoreleaseReturnValue:
147       Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
148       break;
149     case Intrinsic::objc_retainAutoreleasedReturnValue:
150       Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
151       break;
152     case Intrinsic::objc_retainBlock:
153       Changed |= lowerObjCCall(F, "objc_retainBlock");
154       break;
155     case Intrinsic::objc_storeStrong:
156       Changed |= lowerObjCCall(F, "objc_storeStrong");
157       break;
158     case Intrinsic::objc_storeWeak:
159       Changed |= lowerObjCCall(F, "objc_storeWeak");
160       break;
161     case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
162       Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
163       break;
164     case Intrinsic::objc_retainedObject:
165       Changed |= lowerObjCCall(F, "objc_retainedObject");
166       break;
167     case Intrinsic::objc_unretainedObject:
168       Changed |= lowerObjCCall(F, "objc_unretainedObject");
169       break;
170     case Intrinsic::objc_unretainedPointer:
171       Changed |= lowerObjCCall(F, "objc_unretainedPointer");
172       break;
173     case Intrinsic::objc_retain_autorelease:
174       Changed |= lowerObjCCall(F, "objc_retain_autorelease");
175       break;
176     case Intrinsic::objc_sync_enter:
177       Changed |= lowerObjCCall(F, "objc_sync_enter");
178       break;
179     case Intrinsic::objc_sync_exit:
180       Changed |= lowerObjCCall(F, "objc_sync_exit");
181       break;
182     }
183   }
184   return Changed;
185 }
186
187 namespace {
188
189 class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
190 public:
191   static char ID;
192
193   PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
194
195   bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
196 };
197
198 } // end anonymous namespace
199
200 char PreISelIntrinsicLoweringLegacyPass::ID;
201
202 INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
203                 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
204                 false, false)
205
206 ModulePass *llvm::createPreISelIntrinsicLoweringPass() {
207   return new PreISelIntrinsicLoweringLegacyPass;
208 }
209
210 PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
211                                                     ModuleAnalysisManager &AM) {
212   if (!lowerIntrinsics(M))
213     return PreservedAnalyses::all();
214   else
215     return PreservedAnalyses::none();
216 }