blob: 21076047f77d4a25d624b700bebdef633a083db8 [file] [log] [blame]
Eugene Zelenko618c5552017-09-13 21:15:20 +00001//===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===//
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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 Collingbourne7dd8dbf2016-04-22 21:18:02 +00006//
7//===----------------------------------------------------------------------===//
8//
Pete Cooperf86db5c2018-12-18 22:20:03 +00009// This pass implements IR lowering for the llvm.load.relative and llvm.objc.*
10// intrinsics.
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000011//
12//===----------------------------------------------------------------------===//
13
Michael Kuperstein82d5da52016-06-24 20:13:42 +000014#include "llvm/CodeGen/PreISelIntrinsicLowering.h"
Francis Visoiu Mistriha9a37812019-11-06 17:09:55 -080015#include "llvm/Analysis/ObjCARCInstKind.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000016#include "llvm/CodeGen/Passes.h"
17#include "llvm/IR/Function.h"
18#include "llvm/IR/IRBuilder.h"
19#include "llvm/IR/Instructions.h"
Reid Kleckner05da2fe2019-11-13 13:15:01 -080020#include "llvm/IR/Intrinsics.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000021#include "llvm/IR/Module.h"
Eugene Zelenko618c5552017-09-13 21:15:20 +000022#include "llvm/IR/Type.h"
23#include "llvm/IR/User.h"
Reid Kleckner05da2fe2019-11-13 13:15:01 -080024#include "llvm/InitializePasses.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000025#include "llvm/Pass.h"
Eugene Zelenko618c5552017-09-13 21:15:20 +000026#include "llvm/Support/Casting.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000027
28using namespace llvm;
29
Eugene Zelenko618c5552017-09-13 21:15:20 +000030static bool lowerLoadRelative(Function &F) {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000031 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);
Guillaume Chatelet279fa8e2020-01-23 11:33:12 +010049 Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, Align(4));
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000050
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 Mistriha9a37812019-11-06 17:09:55 -080061// ObjCARC has knowledge about whether an obj-c runtime function needs to be
62// always tail-called or never tail-called.
63static 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 Cooperd0ffdf82018-12-18 22:31:34 +000072static bool lowerObjCCall(Function &F, const char *NewFn,
73 bool setNonLazyBind = false) {
Pete Cooperf86db5c2018-12-18 22:20:03 +000074 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 Knight13680222019-02-01 02:28:03 +000080 FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
Pete Coopera3e0be12018-12-18 22:42:08 +000081
James Y Knight13680222019-02-01 02:28:03 +000082 if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) {
Pete Coopera3e0be12018-12-18 22:42:08 +000083 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 Cooperd0ffdf82018-12-18 22:31:34 +000087 Fn->addFnAttr(Attribute::NonLazyBind);
Pete Coopera3e0be12018-12-18 22:42:08 +000088 }
89 }
Pete Cooperf86db5c2018-12-18 22:20:03 +000090
Francis Visoiu Mistriha9a37812019-11-06 17:09:55 -080091 CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F);
92
Pete Cooperf86db5c2018-12-18 22:20:03 +000093 for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
Simon Pilgrimc81f8e42019-09-24 10:46:30 +000094 auto *CI = cast<CallInst>(I->getUser());
Pete Cooperf86db5c2018-12-18 22:20:03 +000095 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 Mistriha9a37812019-11-06 17:09:55 -0800102
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 Cooperf86db5c2018-12-18 22:20:03 +0000113 if (!CI->use_empty())
114 CI->replaceAllUsesWith(NewCI);
115 CI->eraseFromParent();
116 }
117
118 return true;
119}
120
Eugene Zelenko618c5552017-09-13 21:15:20 +0000121static bool lowerIntrinsics(Module &M) {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000122 bool Changed = false;
123 for (Function &F : M) {
Pete Cooperf86db5c2018-12-18 22:20:03 +0000124 if (F.getName().startswith("llvm.load.relative.")) {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000125 Changed |= lowerLoadRelative(F);
Pete Cooperf86db5c2018-12-18 22:20:03 +0000126 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 Cooperd0ffdf82018-12-18 22:31:34 +0000162 Changed |= lowerObjCCall(F, "objc_release", true);
Pete Cooperf86db5c2018-12-18 22:20:03 +0000163 break;
164 case Intrinsic::objc_retain:
Pete Cooperd0ffdf82018-12-18 22:31:34 +0000165 Changed |= lowerObjCCall(F, "objc_retain", true);
Pete Cooperf86db5c2018-12-18 22:20:03 +0000166 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 Collingbourne7dd8dbf2016-04-22 21:18:02 +0000207 }
208 return Changed;
209}
210
Eugene Zelenko618c5552017-09-13 21:15:20 +0000211namespace {
212
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000213class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000214public:
215 static char ID;
Eugene Zelenko618c5552017-09-13 21:15:20 +0000216
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000217 PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000218
Eugene Zelenko618c5552017-09-13 21:15:20 +0000219 bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000220};
221
Eugene Zelenko618c5552017-09-13 21:15:20 +0000222} // end anonymous namespace
223
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000224char PreISelIntrinsicLoweringLegacyPass::ID;
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000225
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000226INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
227 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
228 false, false)
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000229
Eugene Zelenko618c5552017-09-13 21:15:20 +0000230ModulePass *llvm::createPreISelIntrinsicLoweringPass() {
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000231 return new PreISelIntrinsicLoweringLegacyPass;
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000232}
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000233
234PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
235 ModuleAnalysisManager &AM) {
236 if (!lowerIntrinsics(M))
237 return PreservedAnalyses::all();
238 else
239 return PreservedAnalyses::none();
240}