LLVM  12.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 
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"
27 
28 using namespace llvm;
29 
30 static bool lowerLoadRelative(Function &F) {
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 (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->getCalledOperand() != &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);
49  Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, Align(4));
50 
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 
61 // ObjCARC has knowledge about whether an obj-c runtime function needs to be
62 // always tail-called or never tail-called.
66  return CallInst::TCK_Tail;
67  else if (objcarc::IsNeverTail(Kind))
68  return CallInst::TCK_NoTail;
69  return CallInst::TCK_None;
70 }
71 
72 static bool lowerObjCCall(Function &F, const char *NewFn,
73  bool setNonLazyBind = false) {
74  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();
80  FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
81 
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
86  // performance.
87  Fn->addFnAttr(Attribute::NonLazyBind);
88  }
89  }
90 
92 
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!");
96  ++I;
97 
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());
102 
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 
113  if (!CI->use_empty())
114  CI->replaceAllUsesWith(NewCI);
115  CI->eraseFromParent();
116  }
117 
118  return true;
119 }
120 
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);
126  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:
162  Changed |= lowerObjCCall(F, "objc_release", true);
163  break;
164  case Intrinsic::objc_retain:
165  Changed |= lowerObjCCall(F, "objc_retain", true);
166  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  }
207  }
208  return Changed;
209 }
210 
211 namespace {
212 
213 class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
214 public:
215  static char ID;
216 
217  PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
218 
219  bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
220 };
221 
222 } // end anonymous namespace
223 
225 
226 INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
227  "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
228  false, false)
229 
231  return new PreISelIntrinsicLoweringLegacyPass;
232 }
233 
235  ModuleAnalysisManager &AM) {
236  if (!lowerIntrinsics(M))
237  return PreservedAnalyses::all();
238  else
239  return PreservedAnalyses::none();
240 }
This class represents lattice values for constants.
Definition: AllocatorList.h:23
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:164
This class represents a function call, abstracting a target machine's calling convention.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
F(f)
static bool setNonLazyBind(Function &F)
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
Definition: Type.cpp:691
static bool lowerLoadRelative(Function &F)
bool IsAlwaysTail(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the "tail" keyword...
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: PassManager.h:158
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:155
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:46
INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", false, false) ModulePass *llvm
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind=false)
ARCInstKind GetFunctionClass(const Function *F)
Determine if F is one of the special known Functions.
static CallInst::TailCallKind getOverridingTailCallKind(const Function &F)
assume Assume Builder
uint64_t Align
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:161
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:350
ARCInstKind
Equivalence classes of instructions in the ARC Model.
Module.h This file contains the declarations for the Module class.
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:197
#define I(x, y, z)
Definition: MD5.cpp:59
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:238
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
Definition: Value.h:75
ModulePass * createPreISelIntrinsicLoweringPass()
This pass lowers the @llvm.load.relative and @llvm.objc.
A container for analyses that lazily runs them and caches their results.
static bool lowerIntrinsics(Module &M)
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:195
bool IsNeverTail(ARCInstKind Class)
Test if the given class represents instructions which are never safe to mark with the "tail" keyword.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
IntegerType * Int32Ty