LLVM  16.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"
20 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/IntrinsicInst.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/IR/Type.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 (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))
67  return CallInst::TCK_NoTail;
68  return CallInst::TCK_None;
69 }
70 
71 static 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;
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 
136 static 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 
226 namespace {
227 
228 class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
229 public:
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 
240 
241 INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
242  "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
243  false, false)
244 
246  return new PreISelIntrinsicLoweringLegacyPass;
247 }
248 
250  ModuleAnalysisManager &AM) {
251  if (!lowerIntrinsics(M))
252  return PreservedAnalyses::all();
253  else
254  return PreservedAnalyses::none();
255 }
llvm::PreservedAnalyses
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
lowerLoadRelative
static bool lowerLoadRelative(Function &F)
Definition: PreISelIntrinsicLowering.cpp:30
Int32Ty
IntegerType * Int32Ty
Definition: NVVMIntrRange.cpp:67
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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::AArch64PACKey::ID
ID
Definition: AArch64BaseInfo.h:818
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:248
IntrinsicInst.h
lowerIntrinsics
static bool lowerIntrinsics(Module &M)
Definition: PreISelIntrinsicLowering.cpp:136
llvm::Function
Definition: Function.h:60
Pass.h
llvm::SmallVector< Value *, 8 >
llvm::CallInst::setTailCallKind
void setTailCallKind(TailCallKind TCK)
Definition: Instructions.h:1677
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:155
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
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:556
llvm::max
Expected< ExpressionValue > max(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:337
llvm::CallInst::TCK_None
@ TCK_None
Definition: Instructions.h:1652
llvm::Type::getInt8Ty
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:237
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:239
F
#define F(x, y, z)
Definition: MD5.cpp:55
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:62
llvm::objcarc::ARCInstKind::RetainRV
@ RetainRV
objc_retainAutoreleasedReturnValue
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:375
Align
uint64_t Align
Definition: ELFObjHandler.cpp:82
llvm::objcarc::ARCInstKind
ARCInstKind
Definition: ObjCARCInstKind.h:28
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
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:520
Passes.h
llvm::PreISelIntrinsicLoweringPass::run
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Definition: PreISelIntrinsicLowering.cpp:249
llvm::CallInst::TailCallKind
TailCallKind
Definition: Instructions.h:1651
llvm::make_early_inc_range
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:716
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:65
Builder
assume Assume Builder
Definition: AssumeBundleBuilder.cpp:651
INITIALIZE_PASS
INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", false, false) ModulePass *llvm
Definition: PreISelIntrinsicLowering.cpp:241
llvm::CallInst::TCK_Tail
@ TCK_Tail
Definition: Instructions.h:1653
llvm::objcarc::getAttachedARCFunctionKind
ARCInstKind getAttachedARCFunctionKind(const CallBase *CB)
This function returns the ARCInstKind of the function attached to operand bundle clang_arc_attachedca...
Definition: ObjCARCUtil.h:60
llvm::IntrinsicInst::mayLowerToFunctionCall
static bool mayLowerToFunctionCall(Intrinsic::ID IID)
Check if the intrinsic might lower into a regular function call in the course of IR transformations.
Definition: IntrinsicInst.cpp:36
lowerObjCCall
static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind=false)
Definition: PreISelIntrinsicLowering.cpp:71
llvm::FunctionCallee::getCallee
Value * getCallee()
Definition: DerivedTypes.h:184
ObjCARCUtil.h
llvm::PreservedAnalyses::all
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
Casting.h
Function.h
llvm::Type::getPointerTo
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
Definition: Type.cpp:774
Instructions.h
llvm::FunctionCallee
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:165
llvm::AnalysisManager
A container for analyses that lazily runs them and caches their results.
Definition: InstructionSimplify.h:42
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1474
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:394
setNonLazyBind
static bool setNonLazyBind(Function &F)
Definition: BuildLibCalls.cpp:192
llvm::CallInst::TCK_NoTail
@ TCK_NoTail
Definition: Instructions.h:1655
InitializePasses.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
PreISelIntrinsicLowering.h
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
llvm::objcarc::ARCInstKind::UnsafeClaimRV
@ UnsafeClaimRV
objc_unsafeClaimAutoreleasedReturnValue