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