LLVM 17.0.0git
PreISelIntrinsicLowering.cpp
Go to the documentation of this file.
1//===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass implements IR lowering for the llvm.load.relative and llvm.objc.*
10// intrinsics.
11//
12//===----------------------------------------------------------------------===//
13
17#include "llvm/CodeGen/Passes.h"
18#include "llvm/IR/Function.h"
19#include "llvm/IR/IRBuilder.h"
22#include "llvm/IR/Module.h"
23#include "llvm/IR/Type.h"
25#include "llvm/Pass.h"
27
28using namespace llvm;
29
31 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 (Use &U : llvm::make_early_inc_range(F.uses())) {
40 auto CI = dyn_cast<CallInst>(U.getUser());
41 if (!CI || CI->getCalledOperand() != &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(Int32Ty, OffsetPtrI32, Align(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
60// ObjCARC has knowledge about whether an obj-c runtime function needs to be
61// always tail-called or never tail-called.
64 if (objcarc::IsAlwaysTail(Kind))
65 return CallInst::TCK_Tail;
66 else if (objcarc::IsNeverTail(Kind))
68 return CallInst::TCK_None;
69}
70
71static bool lowerObjCCall(Function &F, const char *NewFn,
72 bool setNonLazyBind = false) {
74 "Pre-ISel intrinsics do lower into regular function calls");
75 if (F.use_empty())
76 return false;
77
78 // If we haven't already looked up this function, check to see if the
79 // program already contains a function with this name.
80 Module *M = F.getParent();
81 FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
82
83 if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) {
84 Fn->setLinkage(F.getLinkage());
85 if (setNonLazyBind && !Fn->isWeakForLinker()) {
86 // If we have Native ARC, set nonlazybind attribute for these APIs for
87 // performance.
88 Fn->addFnAttr(Attribute::NonLazyBind);
89 }
90 }
91
93
94 for (Use &U : llvm::make_early_inc_range(F.uses())) {
95 auto *CB = cast<CallBase>(U.getUser());
96
97 if (CB->getCalledFunction() != &F) {
99 (void)Kind;
100 assert((Kind == objcarc::ARCInstKind::RetainRV ||
101 Kind == objcarc::ARCInstKind::UnsafeClaimRV) &&
102 "use expected to be the argument of operand bundle "
103 "\"clang.arc.attachedcall\"");
104 U.set(FCache.getCallee());
105 continue;
106 }
107
108 auto *CI = cast<CallInst>(CB);
109 assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
110
111 IRBuilder<> Builder(CI->getParent(), CI->getIterator());
112 SmallVector<Value *, 8> Args(CI->args());
114 CI->getOperandBundlesAsDefs(BundleList);
115 CallInst *NewCI = Builder.CreateCall(FCache, Args, BundleList);
116 NewCI->setName(CI->getName());
117
118 // Try to set the most appropriate TailCallKind based on both the current
119 // attributes and the ones that we could get from ObjCARC's special
120 // knowledge of the runtime functions.
121 //
122 // std::max respects both requirements of notail and tail here:
123 // * notail on either the call or from ObjCARC becomes notail
124 // * tail on either side is stronger than none, but not notail
125 CallInst::TailCallKind TCK = CI->getTailCallKind();
126 NewCI->setTailCallKind(std::max(TCK, OverridingTCK));
127
128 if (!CI->use_empty())
129 CI->replaceAllUsesWith(NewCI);
130 CI->eraseFromParent();
131 }
132
133 return true;
134}
135
136static bool lowerIntrinsics(Module &M) {
137 bool Changed = false;
138 for (Function &F : M) {
139 if (F.getName().startswith("llvm.load.relative.")) {
140 Changed |= lowerLoadRelative(F);
141 continue;
142 }
143 switch (F.getIntrinsicID()) {
144 default:
145 break;
146 case Intrinsic::objc_autorelease:
147 Changed |= lowerObjCCall(F, "objc_autorelease");
148 break;
149 case Intrinsic::objc_autoreleasePoolPop:
150 Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
151 break;
152 case Intrinsic::objc_autoreleasePoolPush:
153 Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
154 break;
155 case Intrinsic::objc_autoreleaseReturnValue:
156 Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
157 break;
158 case Intrinsic::objc_copyWeak:
159 Changed |= lowerObjCCall(F, "objc_copyWeak");
160 break;
161 case Intrinsic::objc_destroyWeak:
162 Changed |= lowerObjCCall(F, "objc_destroyWeak");
163 break;
164 case Intrinsic::objc_initWeak:
165 Changed |= lowerObjCCall(F, "objc_initWeak");
166 break;
167 case Intrinsic::objc_loadWeak:
168 Changed |= lowerObjCCall(F, "objc_loadWeak");
169 break;
170 case Intrinsic::objc_loadWeakRetained:
171 Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
172 break;
173 case Intrinsic::objc_moveWeak:
174 Changed |= lowerObjCCall(F, "objc_moveWeak");
175 break;
176 case Intrinsic::objc_release:
177 Changed |= lowerObjCCall(F, "objc_release", true);
178 break;
179 case Intrinsic::objc_retain:
180 Changed |= lowerObjCCall(F, "objc_retain", true);
181 break;
182 case Intrinsic::objc_retainAutorelease:
183 Changed |= lowerObjCCall(F, "objc_retainAutorelease");
184 break;
185 case Intrinsic::objc_retainAutoreleaseReturnValue:
186 Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
187 break;
188 case Intrinsic::objc_retainAutoreleasedReturnValue:
189 Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
190 break;
191 case Intrinsic::objc_retainBlock:
192 Changed |= lowerObjCCall(F, "objc_retainBlock");
193 break;
194 case Intrinsic::objc_storeStrong:
195 Changed |= lowerObjCCall(F, "objc_storeStrong");
196 break;
197 case Intrinsic::objc_storeWeak:
198 Changed |= lowerObjCCall(F, "objc_storeWeak");
199 break;
200 case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
201 Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
202 break;
203 case Intrinsic::objc_retainedObject:
204 Changed |= lowerObjCCall(F, "objc_retainedObject");
205 break;
206 case Intrinsic::objc_unretainedObject:
207 Changed |= lowerObjCCall(F, "objc_unretainedObject");
208 break;
209 case Intrinsic::objc_unretainedPointer:
210 Changed |= lowerObjCCall(F, "objc_unretainedPointer");
211 break;
212 case Intrinsic::objc_retain_autorelease:
213 Changed |= lowerObjCCall(F, "objc_retain_autorelease");
214 break;
215 case Intrinsic::objc_sync_enter:
216 Changed |= lowerObjCCall(F, "objc_sync_enter");
217 break;
218 case Intrinsic::objc_sync_exit:
219 Changed |= lowerObjCCall(F, "objc_sync_exit");
220 break;
221 }
222 }
223 return Changed;
224}
225
226namespace {
227
228class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
229public:
230 static char ID;
231
232 PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
233
234 bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
235};
236
237} // end anonymous namespace
238
239char PreISelIntrinsicLoweringLegacyPass::ID;
240
241INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
242 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
243 false, false)
244
246 return new PreISelIntrinsicLoweringLegacyPass;
247}
248
251 if (!lowerIntrinsics(M))
252 return PreservedAnalyses::all();
253 else
255}
assume Assume Builder
static bool setNonLazyBind(Function &F)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define F(x, y, z)
Definition: MD5.cpp:55
Module.h This file contains the declarations for the Module class.
IntegerType * Int32Ty
This file defines ARC utility functions which are used by various parts of the compiler.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
static bool lowerIntrinsics(Module &M)
static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind=false)
static CallInst::TailCallKind getOverridingTailCallKind(const Function &F)
static bool lowerLoadRelative(Function &F)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:620
This class represents a function call, abstracting a target machine's calling convention.
void setTailCallKind(TailCallKind TCK)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:165
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2558
static bool mayLowerToFunctionCall(Intrinsic::ID IID)
Check if the intrinsic might lower into a regular function call in the course of IR transformations.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:248
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: PassManager.h:155
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
static IntegerType * getInt8Ty(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
LLVM Value Representation.
Definition: Value.h:74
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:375
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
ARCInstKind getAttachedARCFunctionKind(const CallBase *CB)
This function returns the ARCInstKind of the function attached to operand bundle clang_arc_attachedca...
Definition: ObjCARCUtil.h:60
bool IsNeverTail(ARCInstKind Class)
Test if the given class represents instructions which are never safe to mark with the "tail" keyword.
bool IsAlwaysTail(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the "tail" keyword...
ARCInstKind
Equivalence classes of instructions in the ARC Model.
ARCInstKind GetFunctionClass(const Function *F)
Determine if F is one of the special known Functions.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ModulePass * createPreISelIntrinsicLoweringPass()
This pass lowers the @llvm.load.relative and @llvm.objc.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:732
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)