LLVM  15.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/Module.h"
22 #include "llvm/IR/Type.h"
23 #include "llvm/InitializePasses.h"
24 #include "llvm/Pass.h"
25 #include "llvm/Support/Casting.h"
26 
27 using namespace llvm;
28 
29 static bool lowerLoadRelative(Function &F) {
30  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 (Use &U : llvm::make_early_inc_range(F.uses())) {
39  auto CI = dyn_cast<CallInst>(U.getUser());
40  if (!CI || CI->getCalledOperand() != &F)
41  continue;
42 
43  IRBuilder<> B(CI);
44  Value *OffsetPtr =
45  B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1));
46  Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy);
47  Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, Align(4));
48 
49  Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32);
50 
51  CI->replaceAllUsesWith(ResultPtr);
52  CI->eraseFromParent();
53  Changed = true;
54  }
55 
56  return Changed;
57 }
58 
59 // ObjCARC has knowledge about whether an obj-c runtime function needs to be
60 // always tail-called or never tail-called.
64  return CallInst::TCK_Tail;
65  else if (objcarc::IsNeverTail(Kind))
66  return CallInst::TCK_NoTail;
67  return CallInst::TCK_None;
68 }
69 
70 static bool lowerObjCCall(Function &F, const char *NewFn,
71  bool setNonLazyBind = false) {
72  if (F.use_empty())
73  return false;
74 
75  // If we haven't already looked up this function, check to see if the
76  // program already contains a function with this name.
77  Module *M = F.getParent();
78  FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
79 
80  if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) {
81  Fn->setLinkage(F.getLinkage());
82  if (setNonLazyBind && !Fn->isWeakForLinker()) {
83  // If we have Native ARC, set nonlazybind attribute for these APIs for
84  // performance.
85  Fn->addFnAttr(Attribute::NonLazyBind);
86  }
87  }
88 
90 
91  for (Use &U : llvm::make_early_inc_range(F.uses())) {
92  auto *CB = cast<CallBase>(U.getUser());
93 
94  if (CB->getCalledFunction() != &F) {
96  (void)Kind;
99  "use expected to be the argument of operand bundle "
100  "\"clang.arc.attachedcall\"");
101  U.set(FCache.getCallee());
102  continue;
103  }
104 
105  auto *CI = cast<CallInst>(CB);
106  assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
107 
108  IRBuilder<> Builder(CI->getParent(), CI->getIterator());
109  SmallVector<Value *, 8> Args(CI->args());
110  CallInst *NewCI = Builder.CreateCall(FCache, Args);
111  NewCI->setName(CI->getName());
112 
113  // Try to set the most appropriate TailCallKind based on both the current
114  // attributes and the ones that we could get from ObjCARC's special
115  // knowledge of the runtime functions.
116  //
117  // std::max respects both requirements of notail and tail here:
118  // * notail on either the call or from ObjCARC becomes notail
119  // * tail on either side is stronger than none, but not notail
120  CallInst::TailCallKind TCK = CI->getTailCallKind();
121  NewCI->setTailCallKind(std::max(TCK, OverridingTCK));
122 
123  if (!CI->use_empty())
124  CI->replaceAllUsesWith(NewCI);
125  CI->eraseFromParent();
126  }
127 
128  return true;
129 }
130 
131 static bool lowerIntrinsics(Module &M) {
132  bool Changed = false;
133  for (Function &F : M) {
134  if (F.getName().startswith("llvm.load.relative.")) {
135  Changed |= lowerLoadRelative(F);
136  continue;
137  }
138  switch (F.getIntrinsicID()) {
139  default:
140  break;
141  case Intrinsic::objc_autorelease:
142  Changed |= lowerObjCCall(F, "objc_autorelease");
143  break;
144  case Intrinsic::objc_autoreleasePoolPop:
145  Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
146  break;
147  case Intrinsic::objc_autoreleasePoolPush:
148  Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
149  break;
150  case Intrinsic::objc_autoreleaseReturnValue:
151  Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
152  break;
153  case Intrinsic::objc_copyWeak:
154  Changed |= lowerObjCCall(F, "objc_copyWeak");
155  break;
156  case Intrinsic::objc_destroyWeak:
157  Changed |= lowerObjCCall(F, "objc_destroyWeak");
158  break;
159  case Intrinsic::objc_initWeak:
160  Changed |= lowerObjCCall(F, "objc_initWeak");
161  break;
162  case Intrinsic::objc_loadWeak:
163  Changed |= lowerObjCCall(F, "objc_loadWeak");
164  break;
165  case Intrinsic::objc_loadWeakRetained:
166  Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
167  break;
168  case Intrinsic::objc_moveWeak:
169  Changed |= lowerObjCCall(F, "objc_moveWeak");
170  break;
171  case Intrinsic::objc_release:
172  Changed |= lowerObjCCall(F, "objc_release", true);
173  break;
174  case Intrinsic::objc_retain:
175  Changed |= lowerObjCCall(F, "objc_retain", true);
176  break;
177  case Intrinsic::objc_retainAutorelease:
178  Changed |= lowerObjCCall(F, "objc_retainAutorelease");
179  break;
180  case Intrinsic::objc_retainAutoreleaseReturnValue:
181  Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
182  break;
183  case Intrinsic::objc_retainAutoreleasedReturnValue:
184  Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
185  break;
186  case Intrinsic::objc_retainBlock:
187  Changed |= lowerObjCCall(F, "objc_retainBlock");
188  break;
189  case Intrinsic::objc_storeStrong:
190  Changed |= lowerObjCCall(F, "objc_storeStrong");
191  break;
192  case Intrinsic::objc_storeWeak:
193  Changed |= lowerObjCCall(F, "objc_storeWeak");
194  break;
195  case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
196  Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
197  break;
198  case Intrinsic::objc_retainedObject:
199  Changed |= lowerObjCCall(F, "objc_retainedObject");
200  break;
201  case Intrinsic::objc_unretainedObject:
202  Changed |= lowerObjCCall(F, "objc_unretainedObject");
203  break;
204  case Intrinsic::objc_unretainedPointer:
205  Changed |= lowerObjCCall(F, "objc_unretainedPointer");
206  break;
207  case Intrinsic::objc_retain_autorelease:
208  Changed |= lowerObjCCall(F, "objc_retain_autorelease");
209  break;
210  case Intrinsic::objc_sync_enter:
211  Changed |= lowerObjCCall(F, "objc_sync_enter");
212  break;
213  case Intrinsic::objc_sync_exit:
214  Changed |= lowerObjCCall(F, "objc_sync_exit");
215  break;
216  }
217  }
218  return Changed;
219 }
220 
221 namespace {
222 
223 class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
224 public:
225  static char ID;
226 
227  PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
228 
229  bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
230 };
231 
232 } // end anonymous namespace
233 
235 
236 INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
237  "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
238  false, false)
239 
241  return new PreISelIntrinsicLoweringLegacyPass;
242 }
243 
245  ModuleAnalysisManager &AM) {
246  if (!lowerIntrinsics(M))
247  return PreservedAnalyses::all();
248  else
249  return PreservedAnalyses::none();
250 }
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:29
Int32Ty
IntegerType * Int32Ty
Definition: NVVMIntrRange.cpp:67
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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:248
lowerIntrinsics
static bool lowerIntrinsics(Module &M)
Definition: PreISelIntrinsicLowering.cpp:131
llvm::Function
Definition: Function.h:60
Pass.h
llvm::SmallVector< Value *, 8 >
llvm::CallInst::setTailCallKind
void setTailCallKind(TailCallKind TCK)
Definition: Instructions.h:1664
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:1639
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:61
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:372
Align
uint64_t Align
Definition: ELFObjHandler.cpp:81
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
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:244
llvm::CallInst::TailCallKind
TailCallKind
Definition: Instructions.h:1638
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:618
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:236
llvm::CallInst::TCK_Tail
@ TCK_Tail
Definition: Instructions.h:1640
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
lowerObjCCall
static bool lowerObjCCall(Function &F, const char *NewFn, bool setNonLazyBind=false)
Definition: PreISelIntrinsicLowering.cpp:70
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:1461
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:197
llvm::CallInst::TCK_NoTail
@ TCK_NoTail
Definition: Instructions.h:1642
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
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38