LLVM  13.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 }
llvm::PreservedAnalyses
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:155
llvm::EngineKind::Kind
Kind
Definition: ExecutionEngine.h:524
lowerLoadRelative
static bool lowerLoadRelative(Function &F)
Definition: PreISelIntrinsicLowering.cpp:30
Int32Ty
IntegerType * Int32Ty
Definition: NVVMIntrRange.cpp:67
llvm
Definition: AllocatorList.h:23
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:238
lowerIntrinsics
static bool lowerIntrinsics(Module &M)
Definition: PreISelIntrinsicLowering.cpp:121
llvm::Function
Definition: Function.h:61
Pass.h
llvm::SmallVector< Value *, 8 >
llvm::CallInst::setTailCallKind
void setTailCallKind(TailCallKind TCK)
Definition: Instructions.h:1653
llvm::objcarc::GetFunctionClass
ARCInstKind GetFunctionClass(const Function *F)
Determine if F is one of the special known Functions.
Definition: ObjCARCInstKind.cpp:85
llvm::IRBuilder<>
llvm::PreservedAnalyses::none
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: PassManager.h:158
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:46
Module.h
llvm::objcarc::IsNeverTail
bool IsNeverTail(ARCInstKind Class)
Test if the given class represents instructions which are never safe to mark with the "tail" keyword.
Definition: ObjCARCInstKind.cpp:557
llvm::CallInst::TCK_None
@ TCK_None
Definition: Instructions.h:1628
llvm::Type::getInt8Ty
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:202
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:204
F
#define F(x, y, z)
Definition: MD5.cpp:56
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::createPreISelIntrinsicLoweringPass
ModulePass * createPreISelIntrinsicLoweringPass()
This pass lowers the @llvm.load.relative and @llvm.objc.
getOverridingTailCallKind
static CallInst::TailCallKind getOverridingTailCallKind(const Function &F)
Definition: PreISelIntrinsicLowering.cpp:63
Intrinsics.h
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::Value::setName
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:370
Align
uint64_t Align
Definition: ELFObjHandler.cpp:83
llvm::objcarc::ARCInstKind
ARCInstKind
Definition: ObjCARCInstKind.h:28
Type.h
llvm::objcarc::IsAlwaysTail
bool IsAlwaysTail(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the "tail" keyword...
Definition: ObjCARCInstKind.cpp:521
Passes.h
llvm::PreISelIntrinsicLoweringPass::run
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Definition: PreISelIntrinsicLowering.cpp:234
llvm::CallInst::TailCallKind
TailCallKind
Definition: Instructions.h:1627
I
#define I(x, y, z)
Definition: MD5.cpp:59
ObjCARCInstKind.h
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
Builder
assume Assume Builder
Definition: AssumeBundleBuilder.cpp:649
INITIALIZE_PASS
INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", false, false) ModulePass *llvm
Definition: PreISelIntrinsicLowering.cpp:226
llvm::CallInst::TCK_Tail
@ TCK_Tail
Definition: Instructions.h:1629
lowerObjCCall
static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind=false)
Definition: PreISelIntrinsicLowering.cpp:72
llvm::FunctionCallee::getCallee
Value * getCallee()
Definition: DerivedTypes.h:183
llvm::PreservedAnalyses::all
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:161
Casting.h
Function.h
llvm::Type::getPointerTo
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
Definition: Type.cpp:715
Instructions.h
User.h
llvm::max
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:350
llvm::FunctionCallee
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:164
llvm::AnalysisManager
A container for analyses that lazily runs them and caches their results.
Definition: InstructionSimplify.h:44
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1450
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:389
setNonLazyBind
static bool setNonLazyBind(Function &F)
Definition: BuildLibCalls.cpp:189
llvm::CallInst::TCK_NoTail
@ TCK_NoTail
Definition: Instructions.h:1631
InitializePasses.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:75
PreISelIntrinsicLowering.h
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38