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/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"
28 static bool lowerLoadRelative(Function
&F
) {
33 Type
*Int32Ty
= Type::getInt32Ty(F
.getContext());
34 Type
*Int32PtrTy
= Int32Ty
->getPointerTo();
35 Type
*Int8Ty
= Type::getInt8Ty(F
.getContext());
37 for (auto I
= F
.use_begin(), E
= F
.use_end(); I
!= E
;) {
38 auto CI
= dyn_cast
<CallInst
>(I
->getUser());
40 if (!CI
|| CI
->getCalledValue() != &F
)
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);
49 Value
*ResultPtr
= B
.CreateGEP(Int8Ty
, CI
->getArgOperand(0), OffsetI32
);
51 CI
->replaceAllUsesWith(ResultPtr
);
52 CI
->eraseFromParent();
59 static bool lowerObjCCall(Function
&F
, const char *NewFn
,
60 bool setNonLazyBind
= false) {
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());
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
74 Fn
->addFnAttr(Attribute::NonLazyBind
);
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!");
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());
89 CI
->replaceAllUsesWith(NewCI
);
90 CI
->eraseFromParent();
96 static bool lowerIntrinsics(Module
&M
) {
98 for (Function
&F
: M
) {
99 if (F
.getName().startswith("llvm.load.relative.")) {
100 Changed
|= lowerLoadRelative(F
);
103 switch (F
.getIntrinsicID()) {
106 case Intrinsic::objc_autorelease
:
107 Changed
|= lowerObjCCall(F
, "objc_autorelease");
109 case Intrinsic::objc_autoreleasePoolPop
:
110 Changed
|= lowerObjCCall(F
, "objc_autoreleasePoolPop");
112 case Intrinsic::objc_autoreleasePoolPush
:
113 Changed
|= lowerObjCCall(F
, "objc_autoreleasePoolPush");
115 case Intrinsic::objc_autoreleaseReturnValue
:
116 Changed
|= lowerObjCCall(F
, "objc_autoreleaseReturnValue");
118 case Intrinsic::objc_copyWeak
:
119 Changed
|= lowerObjCCall(F
, "objc_copyWeak");
121 case Intrinsic::objc_destroyWeak
:
122 Changed
|= lowerObjCCall(F
, "objc_destroyWeak");
124 case Intrinsic::objc_initWeak
:
125 Changed
|= lowerObjCCall(F
, "objc_initWeak");
127 case Intrinsic::objc_loadWeak
:
128 Changed
|= lowerObjCCall(F
, "objc_loadWeak");
130 case Intrinsic::objc_loadWeakRetained
:
131 Changed
|= lowerObjCCall(F
, "objc_loadWeakRetained");
133 case Intrinsic::objc_moveWeak
:
134 Changed
|= lowerObjCCall(F
, "objc_moveWeak");
136 case Intrinsic::objc_release
:
137 Changed
|= lowerObjCCall(F
, "objc_release", true);
139 case Intrinsic::objc_retain
:
140 Changed
|= lowerObjCCall(F
, "objc_retain", true);
142 case Intrinsic::objc_retainAutorelease
:
143 Changed
|= lowerObjCCall(F
, "objc_retainAutorelease");
145 case Intrinsic::objc_retainAutoreleaseReturnValue
:
146 Changed
|= lowerObjCCall(F
, "objc_retainAutoreleaseReturnValue");
148 case Intrinsic::objc_retainAutoreleasedReturnValue
:
149 Changed
|= lowerObjCCall(F
, "objc_retainAutoreleasedReturnValue");
151 case Intrinsic::objc_retainBlock
:
152 Changed
|= lowerObjCCall(F
, "objc_retainBlock");
154 case Intrinsic::objc_storeStrong
:
155 Changed
|= lowerObjCCall(F
, "objc_storeStrong");
157 case Intrinsic::objc_storeWeak
:
158 Changed
|= lowerObjCCall(F
, "objc_storeWeak");
160 case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue
:
161 Changed
|= lowerObjCCall(F
, "objc_unsafeClaimAutoreleasedReturnValue");
163 case Intrinsic::objc_retainedObject
:
164 Changed
|= lowerObjCCall(F
, "objc_retainedObject");
166 case Intrinsic::objc_unretainedObject
:
167 Changed
|= lowerObjCCall(F
, "objc_unretainedObject");
169 case Intrinsic::objc_unretainedPointer
:
170 Changed
|= lowerObjCCall(F
, "objc_unretainedPointer");
172 case Intrinsic::objc_retain_autorelease
:
173 Changed
|= lowerObjCCall(F
, "objc_retain_autorelease");
175 case Intrinsic::objc_sync_enter
:
176 Changed
|= lowerObjCCall(F
, "objc_sync_enter");
178 case Intrinsic::objc_sync_exit
:
179 Changed
|= lowerObjCCall(F
, "objc_sync_exit");
188 class PreISelIntrinsicLoweringLegacyPass
: public ModulePass
{
192 PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID
) {}
194 bool runOnModule(Module
&M
) override
{ return lowerIntrinsics(M
); }
197 } // end anonymous namespace
199 char PreISelIntrinsicLoweringLegacyPass::ID
;
201 INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass
,
202 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
205 ModulePass
*llvm::createPreISelIntrinsicLoweringPass() {
206 return new PreISelIntrinsicLoweringLegacyPass
;
209 PreservedAnalyses
PreISelIntrinsicLoweringPass::run(Module
&M
,
210 ModuleAnalysisManager
&AM
) {
211 if (!lowerIntrinsics(M
))
212 return PreservedAnalyses::all();
214 return PreservedAnalyses::none();