]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / CodeGen / PreISelIntrinsicLowering.cpp
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 }