1 //===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===//
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
7 //===----------------------------------------------------------------------===//
9 // This pass implements IR lowering for the llvm.load.relative and llvm.objc.*
12 //===----------------------------------------------------------------------===//
14 #include "llvm/CodeGen/PreISelIntrinsicLowering.h"
15 #include "llvm/Analysis/ObjCARCInstKind.h"
16 #include "llvm/CodeGen/Passes.h"
17 #include "llvm/IR/Function.h"
18 #include "llvm/IR/IRBuilder.h"
19 #include "llvm/IR/Instructions.h"
20 #include "llvm/IR/Intrinsics.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/IR/Type.h"
23 #include "llvm/IR/User.h"
24 #include "llvm/InitializePasses.h"
25 #include "llvm/Pass.h"
26 #include "llvm/Support/Casting.h"
30 static bool lowerLoadRelative(Function
&F
) {
35 Type
*Int32Ty
= Type::getInt32Ty(F
.getContext());
36 Type
*Int32PtrTy
= Int32Ty
->getPointerTo();
37 Type
*Int8Ty
= Type::getInt8Ty(F
.getContext());
39 for (auto I
= F
.use_begin(), E
= F
.use_end(); I
!= E
;) {
40 auto CI
= dyn_cast
<CallInst
>(I
->getUser());
42 if (!CI
|| CI
->getCalledOperand() != &F
)
47 B
.CreateGEP(Int8Ty
, CI
->getArgOperand(0), CI
->getArgOperand(1));
48 Value
*OffsetPtrI32
= B
.CreateBitCast(OffsetPtr
, Int32PtrTy
);
49 Value
*OffsetI32
= B
.CreateAlignedLoad(Int32Ty
, OffsetPtrI32
, Align(4));
51 Value
*ResultPtr
= B
.CreateGEP(Int8Ty
, CI
->getArgOperand(0), OffsetI32
);
53 CI
->replaceAllUsesWith(ResultPtr
);
54 CI
->eraseFromParent();
61 // ObjCARC has knowledge about whether an obj-c runtime function needs to be
62 // always tail-called or never tail-called.
63 static 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
;
72 static bool lowerObjCCall(Function
&F
, const char *NewFn
,
73 bool setNonLazyBind
= false) {
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();
80 FunctionCallee FCache
= M
->getOrInsertFunction(NewFn
, F
.getFunctionType());
82 if (Function
*Fn
= dyn_cast
<Function
>(FCache
.getCallee())) {
83 Fn
->setLinkage(F
.getLinkage());
84 if (setNonLazyBind
&& !Fn
->isWeakForLinker()) {
85 // If we have Native ARC, set nonlazybind attribute for these APIs for
87 Fn
->addFnAttr(Attribute::NonLazyBind
);
91 CallInst::TailCallKind OverridingTCK
= getOverridingTailCallKind(F
);
93 for (auto I
= F
.use_begin(), E
= F
.use_end(); I
!= E
;) {
94 auto *CI
= cast
<CallInst
>(I
->getUser());
95 assert(CI
->getCalledFunction() && "Cannot lower an indirect call!");
98 IRBuilder
<> Builder(CI
->getParent(), CI
->getIterator());
99 SmallVector
<Value
*, 8> Args(CI
->args());
100 CallInst
*NewCI
= Builder
.CreateCall(FCache
, Args
);
101 NewCI
->setName(CI
->getName());
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.
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
));
113 if (!CI
->use_empty())
114 CI
->replaceAllUsesWith(NewCI
);
115 CI
->eraseFromParent();
121 static bool lowerIntrinsics(Module
&M
) {
122 bool Changed
= false;
123 for (Function
&F
: M
) {
124 if (F
.getName().startswith("llvm.load.relative.")) {
125 Changed
|= lowerLoadRelative(F
);
128 switch (F
.getIntrinsicID()) {
131 case Intrinsic::objc_autorelease
:
132 Changed
|= lowerObjCCall(F
, "objc_autorelease");
134 case Intrinsic::objc_autoreleasePoolPop
:
135 Changed
|= lowerObjCCall(F
, "objc_autoreleasePoolPop");
137 case Intrinsic::objc_autoreleasePoolPush
:
138 Changed
|= lowerObjCCall(F
, "objc_autoreleasePoolPush");
140 case Intrinsic::objc_autoreleaseReturnValue
:
141 Changed
|= lowerObjCCall(F
, "objc_autoreleaseReturnValue");
143 case Intrinsic::objc_copyWeak
:
144 Changed
|= lowerObjCCall(F
, "objc_copyWeak");
146 case Intrinsic::objc_destroyWeak
:
147 Changed
|= lowerObjCCall(F
, "objc_destroyWeak");
149 case Intrinsic::objc_initWeak
:
150 Changed
|= lowerObjCCall(F
, "objc_initWeak");
152 case Intrinsic::objc_loadWeak
:
153 Changed
|= lowerObjCCall(F
, "objc_loadWeak");
155 case Intrinsic::objc_loadWeakRetained
:
156 Changed
|= lowerObjCCall(F
, "objc_loadWeakRetained");
158 case Intrinsic::objc_moveWeak
:
159 Changed
|= lowerObjCCall(F
, "objc_moveWeak");
161 case Intrinsic::objc_release
:
162 Changed
|= lowerObjCCall(F
, "objc_release", true);
164 case Intrinsic::objc_retain
:
165 Changed
|= lowerObjCCall(F
, "objc_retain", true);
167 case Intrinsic::objc_retainAutorelease
:
168 Changed
|= lowerObjCCall(F
, "objc_retainAutorelease");
170 case Intrinsic::objc_retainAutoreleaseReturnValue
:
171 Changed
|= lowerObjCCall(F
, "objc_retainAutoreleaseReturnValue");
173 case Intrinsic::objc_retainAutoreleasedReturnValue
:
174 Changed
|= lowerObjCCall(F
, "objc_retainAutoreleasedReturnValue");
176 case Intrinsic::objc_retainBlock
:
177 Changed
|= lowerObjCCall(F
, "objc_retainBlock");
179 case Intrinsic::objc_storeStrong
:
180 Changed
|= lowerObjCCall(F
, "objc_storeStrong");
182 case Intrinsic::objc_storeWeak
:
183 Changed
|= lowerObjCCall(F
, "objc_storeWeak");
185 case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue
:
186 Changed
|= lowerObjCCall(F
, "objc_unsafeClaimAutoreleasedReturnValue");
188 case Intrinsic::objc_retainedObject
:
189 Changed
|= lowerObjCCall(F
, "objc_retainedObject");
191 case Intrinsic::objc_unretainedObject
:
192 Changed
|= lowerObjCCall(F
, "objc_unretainedObject");
194 case Intrinsic::objc_unretainedPointer
:
195 Changed
|= lowerObjCCall(F
, "objc_unretainedPointer");
197 case Intrinsic::objc_retain_autorelease
:
198 Changed
|= lowerObjCCall(F
, "objc_retain_autorelease");
200 case Intrinsic::objc_sync_enter
:
201 Changed
|= lowerObjCCall(F
, "objc_sync_enter");
203 case Intrinsic::objc_sync_exit
:
204 Changed
|= lowerObjCCall(F
, "objc_sync_exit");
213 class PreISelIntrinsicLoweringLegacyPass
: public ModulePass
{
217 PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID
) {}
219 bool runOnModule(Module
&M
) override
{ return lowerIntrinsics(M
); }
222 } // end anonymous namespace
224 char PreISelIntrinsicLoweringLegacyPass::ID
;
226 INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass
,
227 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
230 ModulePass
*llvm::createPreISelIntrinsicLoweringPass() {
231 return new PreISelIntrinsicLoweringLegacyPass
;
234 PreservedAnalyses
PreISelIntrinsicLoweringPass::run(Module
&M
,
235 ModuleAnalysisManager
&AM
) {
236 if (!lowerIntrinsics(M
))
237 return PreservedAnalyses::all();
239 return PreservedAnalyses::none();