blob: 3689dab2331064cb6b869f937b85cc7aadb79a01 [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//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Pete Cooperf86db5c2018-12-18 22:20:03 +000010// This pass implements IR lowering for the llvm.load.relative and llvm.objc.*
11// intrinsics.
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000012//
13//===----------------------------------------------------------------------===//
14
Michael Kuperstein82d5da52016-06-24 20:13:42 +000015#include "llvm/CodeGen/PreISelIntrinsicLowering.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000016#include "llvm/CodeGen/Passes.h"
17#include "llvm/IR/Function.h"
Pete Cooperf86db5c2018-12-18 22:20:03 +000018#include "llvm/IR/Intrinsics.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000019#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/Instructions.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"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000024#include "llvm/Pass.h"
Eugene Zelenko618c5552017-09-13 21:15:20 +000025#include "llvm/Support/Casting.h"
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000026
27using namespace llvm;
28
Eugene Zelenko618c5552017-09-13 21:15:20 +000029static bool lowerLoadRelative(Function &F) {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000030 if (F.use_empty())
31 return false;
32
33 bool Changed = false;
34 Type *Int32Ty = Type::getInt32Ty(F.getContext());
35 Type *Int32PtrTy = Int32Ty->getPointerTo();
36 Type *Int8Ty = Type::getInt8Ty(F.getContext());
37
38 for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
39 auto CI = dyn_cast<CallInst>(I->getUser());
40 ++I;
41 if (!CI || CI->getCalledValue() != &F)
42 continue;
43
44 IRBuilder<> B(CI);
45 Value *OffsetPtr =
46 B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1));
47 Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy);
48 Value *OffsetI32 = B.CreateAlignedLoad(OffsetPtrI32, 4);
49
50 Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32);
51
52 CI->replaceAllUsesWith(ResultPtr);
53 CI->eraseFromParent();
54 Changed = true;
55 }
56
57 return Changed;
58}
59
Pete Cooperd0ffdf82018-12-18 22:31:34 +000060static bool lowerObjCCall(Function &F, const char *NewFn,
61 bool setNonLazyBind = false) {
Pete Cooperf86db5c2018-12-18 22:20:03 +000062 if (F.use_empty())
63 return false;
64
65 // If we haven't already looked up this function, check to see if the
66 // program already contains a function with this name.
67 Module *M = F.getParent();
68 Constant* FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
Pete Cooperd0ffdf82018-12-18 22:31:34 +000069
70 // If we have Native ARC, set nonlazybind attribute for these APIs for
71 // performance.
72 if (setNonLazyBind)
73 if (Function* Fn = dyn_cast<Function>(FCache))
74 Fn->addFnAttr(Attribute::NonLazyBind);
Pete Cooperf86db5c2018-12-18 22:20:03 +000075
76 for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
77 auto *CI = dyn_cast<CallInst>(I->getUser());
78 assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
79 ++I;
80
81 IRBuilder<> Builder(CI->getParent(), CI->getIterator());
82 SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end());
83 CallInst *NewCI = Builder.CreateCall(FCache, Args);
84 NewCI->setName(CI->getName());
85 NewCI->setTailCallKind(CI->getTailCallKind());
86 if (!CI->use_empty())
87 CI->replaceAllUsesWith(NewCI);
88 CI->eraseFromParent();
89 }
90
91 return true;
92}
93
Eugene Zelenko618c5552017-09-13 21:15:20 +000094static bool lowerIntrinsics(Module &M) {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000095 bool Changed = false;
96 for (Function &F : M) {
Pete Cooperf86db5c2018-12-18 22:20:03 +000097 if (F.getName().startswith("llvm.load.relative.")) {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +000098 Changed |= lowerLoadRelative(F);
Pete Cooperf86db5c2018-12-18 22:20:03 +000099 continue;
100 }
101 switch (F.getIntrinsicID()) {
102 default:
103 break;
104 case Intrinsic::objc_autorelease:
105 Changed |= lowerObjCCall(F, "objc_autorelease");
106 break;
107 case Intrinsic::objc_autoreleasePoolPop:
108 Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
109 break;
110 case Intrinsic::objc_autoreleasePoolPush:
111 Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
112 break;
113 case Intrinsic::objc_autoreleaseReturnValue:
114 Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
115 break;
116 case Intrinsic::objc_copyWeak:
117 Changed |= lowerObjCCall(F, "objc_copyWeak");
118 break;
119 case Intrinsic::objc_destroyWeak:
120 Changed |= lowerObjCCall(F, "objc_destroyWeak");
121 break;
122 case Intrinsic::objc_initWeak:
123 Changed |= lowerObjCCall(F, "objc_initWeak");
124 break;
125 case Intrinsic::objc_loadWeak:
126 Changed |= lowerObjCCall(F, "objc_loadWeak");
127 break;
128 case Intrinsic::objc_loadWeakRetained:
129 Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
130 break;
131 case Intrinsic::objc_moveWeak:
132 Changed |= lowerObjCCall(F, "objc_moveWeak");
133 break;
134 case Intrinsic::objc_release:
Pete Cooperd0ffdf82018-12-18 22:31:34 +0000135 Changed |= lowerObjCCall(F, "objc_release", true);
Pete Cooperf86db5c2018-12-18 22:20:03 +0000136 break;
137 case Intrinsic::objc_retain:
Pete Cooperd0ffdf82018-12-18 22:31:34 +0000138 Changed |= lowerObjCCall(F, "objc_retain", true);
Pete Cooperf86db5c2018-12-18 22:20:03 +0000139 break;
140 case Intrinsic::objc_retainAutorelease:
141 Changed |= lowerObjCCall(F, "objc_retainAutorelease");
142 break;
143 case Intrinsic::objc_retainAutoreleaseReturnValue:
144 Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
145 break;
146 case Intrinsic::objc_retainAutoreleasedReturnValue:
147 Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
148 break;
149 case Intrinsic::objc_retainBlock:
150 Changed |= lowerObjCCall(F, "objc_retainBlock");
151 break;
152 case Intrinsic::objc_storeStrong:
153 Changed |= lowerObjCCall(F, "objc_storeStrong");
154 break;
155 case Intrinsic::objc_storeWeak:
156 Changed |= lowerObjCCall(F, "objc_storeWeak");
157 break;
158 case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
159 Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
160 break;
161 case Intrinsic::objc_retainedObject:
162 Changed |= lowerObjCCall(F, "objc_retainedObject");
163 break;
164 case Intrinsic::objc_unretainedObject:
165 Changed |= lowerObjCCall(F, "objc_unretainedObject");
166 break;
167 case Intrinsic::objc_unretainedPointer:
168 Changed |= lowerObjCCall(F, "objc_unretainedPointer");
169 break;
170 case Intrinsic::objc_retain_autorelease:
171 Changed |= lowerObjCCall(F, "objc_retain_autorelease");
172 break;
173 case Intrinsic::objc_sync_enter:
174 Changed |= lowerObjCCall(F, "objc_sync_enter");
175 break;
176 case Intrinsic::objc_sync_exit:
177 Changed |= lowerObjCCall(F, "objc_sync_exit");
178 break;
179 }
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000180 }
181 return Changed;
182}
183
Eugene Zelenko618c5552017-09-13 21:15:20 +0000184namespace {
185
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000186class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000187public:
188 static char ID;
Eugene Zelenko618c5552017-09-13 21:15:20 +0000189
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000190 PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000191
Eugene Zelenko618c5552017-09-13 21:15:20 +0000192 bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000193};
194
Eugene Zelenko618c5552017-09-13 21:15:20 +0000195} // end anonymous namespace
196
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000197char PreISelIntrinsicLoweringLegacyPass::ID;
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000198
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000199INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
200 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
201 false, false)
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000202
Eugene Zelenko618c5552017-09-13 21:15:20 +0000203ModulePass *llvm::createPreISelIntrinsicLoweringPass() {
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000204 return new PreISelIntrinsicLoweringLegacyPass;
Peter Collingbourne7dd8dbf2016-04-22 21:18:02 +0000205}
Michael Kuperstein82d5da52016-06-24 20:13:42 +0000206
207PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
208 ModuleAnalysisManager &AM) {
209 if (!lowerIntrinsics(M))
210 return PreservedAnalyses::all();
211 else
212 return PreservedAnalyses::none();
213}