xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
9*06c3fb27SDimitry Andric // This pass implements IR lowering for the llvm.memcpy, llvm.memmove,
10*06c3fb27SDimitry Andric // llvm.memset, llvm.load.relative and llvm.objc.* intrinsics.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/CodeGen/PreISelIntrinsicLowering.h"
15480093f4SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h"
16349cc55cSDimitry Andric #include "llvm/Analysis/ObjCARCUtil.h"
17*06c3fb27SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
18*06c3fb27SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
200b57cec5SDimitry Andric #include "llvm/IR/Function.h"
210b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
220b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
23972a253aSDimitry Andric #include "llvm/IR/IntrinsicInst.h"
240b57cec5SDimitry Andric #include "llvm/IR/Module.h"
250b57cec5SDimitry Andric #include "llvm/IR/Type.h"
26480093f4SDimitry Andric #include "llvm/InitializePasses.h"
270b57cec5SDimitry Andric #include "llvm/Pass.h"
280b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
29*06c3fb27SDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric 
33*06c3fb27SDimitry Andric /// Threshold to leave statically sized memory intrinsic calls. Calls of known
34*06c3fb27SDimitry Andric /// size larger than this will be expanded by the pass. Calls of unknown or
35*06c3fb27SDimitry Andric /// lower size will be left for expansion in codegen.
36*06c3fb27SDimitry Andric static cl::opt<int64_t> MemIntrinsicExpandSizeThresholdOpt(
37*06c3fb27SDimitry Andric     "mem-intrinsic-expand-size",
38*06c3fb27SDimitry Andric     cl::desc("Set minimum mem intrinsic size to expand in IR"), cl::init(-1),
39*06c3fb27SDimitry Andric     cl::Hidden);
40*06c3fb27SDimitry Andric 
41*06c3fb27SDimitry Andric namespace {
42*06c3fb27SDimitry Andric 
43*06c3fb27SDimitry Andric struct PreISelIntrinsicLowering {
44*06c3fb27SDimitry Andric   const function_ref<TargetTransformInfo &(Function &)> LookupTTI;
45*06c3fb27SDimitry Andric   const function_ref<TargetLibraryInfo &(Function &)> LookupLibInfo;
46*06c3fb27SDimitry Andric 
47*06c3fb27SDimitry Andric   /// If this is true, assume it's preferably to leave memory intrinsic calls
48*06c3fb27SDimitry Andric   /// for replacement with a library call later. Otherwise this depends on
49*06c3fb27SDimitry Andric   /// TargetLibraryInfo availability of the corresponding function.
50*06c3fb27SDimitry Andric   const bool UseMemIntrinsicLibFunc;
51*06c3fb27SDimitry Andric 
52*06c3fb27SDimitry Andric   explicit PreISelIntrinsicLowering(
53*06c3fb27SDimitry Andric       function_ref<TargetTransformInfo &(Function &)> LookupTTI_,
54*06c3fb27SDimitry Andric       function_ref<TargetLibraryInfo &(Function &)> LookupLibInfo_,
55*06c3fb27SDimitry Andric       bool UseMemIntrinsicLibFunc_ = true)
56*06c3fb27SDimitry Andric       : LookupTTI(LookupTTI_), LookupLibInfo(LookupLibInfo_),
57*06c3fb27SDimitry Andric         UseMemIntrinsicLibFunc(UseMemIntrinsicLibFunc_) {}
58*06c3fb27SDimitry Andric 
59*06c3fb27SDimitry Andric   static bool shouldExpandMemIntrinsicWithSize(Value *Size,
60*06c3fb27SDimitry Andric                                                const TargetTransformInfo &TTI);
61*06c3fb27SDimitry Andric   bool expandMemIntrinsicUses(Function &F) const;
62*06c3fb27SDimitry Andric   bool lowerIntrinsics(Module &M) const;
63*06c3fb27SDimitry Andric };
64*06c3fb27SDimitry Andric 
65*06c3fb27SDimitry Andric } // namespace
66*06c3fb27SDimitry Andric 
670b57cec5SDimitry Andric static bool lowerLoadRelative(Function &F) {
680b57cec5SDimitry Andric   if (F.use_empty())
690b57cec5SDimitry Andric     return false;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   bool Changed = false;
720b57cec5SDimitry Andric   Type *Int32Ty = Type::getInt32Ty(F.getContext());
730b57cec5SDimitry Andric   Type *Int32PtrTy = Int32Ty->getPointerTo();
740b57cec5SDimitry Andric   Type *Int8Ty = Type::getInt8Ty(F.getContext());
750b57cec5SDimitry Andric 
76349cc55cSDimitry Andric   for (Use &U : llvm::make_early_inc_range(F.uses())) {
77349cc55cSDimitry Andric     auto CI = dyn_cast<CallInst>(U.getUser());
785ffd83dbSDimitry Andric     if (!CI || CI->getCalledOperand() != &F)
790b57cec5SDimitry Andric       continue;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric     IRBuilder<> B(CI);
820b57cec5SDimitry Andric     Value *OffsetPtr =
830b57cec5SDimitry Andric         B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1));
840b57cec5SDimitry Andric     Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy);
855ffd83dbSDimitry Andric     Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, Align(4));
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric     Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32);
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric     CI->replaceAllUsesWith(ResultPtr);
900b57cec5SDimitry Andric     CI->eraseFromParent();
910b57cec5SDimitry Andric     Changed = true;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   return Changed;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
97480093f4SDimitry Andric // ObjCARC has knowledge about whether an obj-c runtime function needs to be
98480093f4SDimitry Andric // always tail-called or never tail-called.
99480093f4SDimitry Andric static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) {
100480093f4SDimitry Andric   objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F);
101480093f4SDimitry Andric   if (objcarc::IsAlwaysTail(Kind))
102480093f4SDimitry Andric     return CallInst::TCK_Tail;
103480093f4SDimitry Andric   else if (objcarc::IsNeverTail(Kind))
104480093f4SDimitry Andric     return CallInst::TCK_NoTail;
105480093f4SDimitry Andric   return CallInst::TCK_None;
106480093f4SDimitry Andric }
107480093f4SDimitry Andric 
1080b57cec5SDimitry Andric static bool lowerObjCCall(Function &F, const char *NewFn,
1090b57cec5SDimitry Andric                           bool setNonLazyBind = false) {
110972a253aSDimitry Andric   assert(IntrinsicInst::mayLowerToFunctionCall(F.getIntrinsicID()) &&
111972a253aSDimitry Andric          "Pre-ISel intrinsics do lower into regular function calls");
1120b57cec5SDimitry Andric   if (F.use_empty())
1130b57cec5SDimitry Andric     return false;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   // If we haven't already looked up this function, check to see if the
1160b57cec5SDimitry Andric   // program already contains a function with this name.
1170b57cec5SDimitry Andric   Module *M = F.getParent();
1180b57cec5SDimitry Andric   FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) {
1210b57cec5SDimitry Andric     Fn->setLinkage(F.getLinkage());
1220b57cec5SDimitry Andric     if (setNonLazyBind && !Fn->isWeakForLinker()) {
1230b57cec5SDimitry Andric       // If we have Native ARC, set nonlazybind attribute for these APIs for
1240b57cec5SDimitry Andric       // performance.
1250b57cec5SDimitry Andric       Fn->addFnAttr(Attribute::NonLazyBind);
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric   }
1280b57cec5SDimitry Andric 
129480093f4SDimitry Andric   CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F);
130480093f4SDimitry Andric 
131349cc55cSDimitry Andric   for (Use &U : llvm::make_early_inc_range(F.uses())) {
132349cc55cSDimitry Andric     auto *CB = cast<CallBase>(U.getUser());
133349cc55cSDimitry Andric 
134349cc55cSDimitry Andric     if (CB->getCalledFunction() != &F) {
135349cc55cSDimitry Andric       objcarc::ARCInstKind Kind = objcarc::getAttachedARCFunctionKind(CB);
136349cc55cSDimitry Andric       (void)Kind;
137349cc55cSDimitry Andric       assert((Kind == objcarc::ARCInstKind::RetainRV ||
13804eeddc0SDimitry Andric               Kind == objcarc::ARCInstKind::UnsafeClaimRV) &&
139349cc55cSDimitry Andric              "use expected to be the argument of operand bundle "
140349cc55cSDimitry Andric              "\"clang.arc.attachedcall\"");
141349cc55cSDimitry Andric       U.set(FCache.getCallee());
142349cc55cSDimitry Andric       continue;
143349cc55cSDimitry Andric     }
144349cc55cSDimitry Andric 
145349cc55cSDimitry Andric     auto *CI = cast<CallInst>(CB);
1460b57cec5SDimitry Andric     assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric     IRBuilder<> Builder(CI->getParent(), CI->getIterator());
149e8d8bef9SDimitry Andric     SmallVector<Value *, 8> Args(CI->args());
150972a253aSDimitry Andric     SmallVector<llvm::OperandBundleDef, 1> BundleList;
151972a253aSDimitry Andric     CI->getOperandBundlesAsDefs(BundleList);
152972a253aSDimitry Andric     CallInst *NewCI = Builder.CreateCall(FCache, Args, BundleList);
1530b57cec5SDimitry Andric     NewCI->setName(CI->getName());
154480093f4SDimitry Andric 
155480093f4SDimitry Andric     // Try to set the most appropriate TailCallKind based on both the current
156480093f4SDimitry Andric     // attributes and the ones that we could get from ObjCARC's special
157480093f4SDimitry Andric     // knowledge of the runtime functions.
158480093f4SDimitry Andric     //
159480093f4SDimitry Andric     // std::max respects both requirements of notail and tail here:
160480093f4SDimitry Andric     // * notail on either the call or from ObjCARC becomes notail
161480093f4SDimitry Andric     // * tail on either side is stronger than none, but not notail
162480093f4SDimitry Andric     CallInst::TailCallKind TCK = CI->getTailCallKind();
163480093f4SDimitry Andric     NewCI->setTailCallKind(std::max(TCK, OverridingTCK));
164480093f4SDimitry Andric 
1650b57cec5SDimitry Andric     if (!CI->use_empty())
1660b57cec5SDimitry Andric       CI->replaceAllUsesWith(NewCI);
1670b57cec5SDimitry Andric     CI->eraseFromParent();
1680b57cec5SDimitry Andric   }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   return true;
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
173*06c3fb27SDimitry Andric // TODO: Should refine based on estimated number of accesses (e.g. does it
174*06c3fb27SDimitry Andric // require splitting based on alignment)
175*06c3fb27SDimitry Andric bool PreISelIntrinsicLowering::shouldExpandMemIntrinsicWithSize(
176*06c3fb27SDimitry Andric     Value *Size, const TargetTransformInfo &TTI) {
177*06c3fb27SDimitry Andric   ConstantInt *CI = dyn_cast<ConstantInt>(Size);
178*06c3fb27SDimitry Andric   if (!CI)
179*06c3fb27SDimitry Andric     return true;
180*06c3fb27SDimitry Andric   uint64_t Threshold = MemIntrinsicExpandSizeThresholdOpt.getNumOccurrences()
181*06c3fb27SDimitry Andric                            ? MemIntrinsicExpandSizeThresholdOpt
182*06c3fb27SDimitry Andric                            : TTI.getMaxMemIntrinsicInlineSizeThreshold();
183*06c3fb27SDimitry Andric   uint64_t SizeVal = CI->getZExtValue();
184*06c3fb27SDimitry Andric 
185*06c3fb27SDimitry Andric   // Treat a threshold of 0 as a special case to force expansion of all
186*06c3fb27SDimitry Andric   // intrinsics, including size 0.
187*06c3fb27SDimitry Andric   return SizeVal > Threshold || Threshold == 0;
188*06c3fb27SDimitry Andric }
189*06c3fb27SDimitry Andric 
190*06c3fb27SDimitry Andric // TODO: Handle atomic memcpy and memcpy.inline
191*06c3fb27SDimitry Andric // TODO: Pass ScalarEvolution
192*06c3fb27SDimitry Andric bool PreISelIntrinsicLowering::expandMemIntrinsicUses(Function &F) const {
193*06c3fb27SDimitry Andric   Intrinsic::ID ID = F.getIntrinsicID();
194*06c3fb27SDimitry Andric   bool Changed = false;
195*06c3fb27SDimitry Andric 
196*06c3fb27SDimitry Andric   for (User *U : llvm::make_early_inc_range(F.users())) {
197*06c3fb27SDimitry Andric     Instruction *Inst = cast<Instruction>(U);
198*06c3fb27SDimitry Andric 
199*06c3fb27SDimitry Andric     switch (ID) {
200*06c3fb27SDimitry Andric     case Intrinsic::memcpy: {
201*06c3fb27SDimitry Andric       auto *Memcpy = cast<MemCpyInst>(Inst);
202*06c3fb27SDimitry Andric       Function *ParentFunc = Memcpy->getFunction();
203*06c3fb27SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
204*06c3fb27SDimitry Andric       if (shouldExpandMemIntrinsicWithSize(Memcpy->getLength(), TTI)) {
205*06c3fb27SDimitry Andric         if (UseMemIntrinsicLibFunc &&
206*06c3fb27SDimitry Andric             LookupLibInfo(*ParentFunc).has(LibFunc_memcpy))
207*06c3fb27SDimitry Andric           break;
208*06c3fb27SDimitry Andric 
209*06c3fb27SDimitry Andric         expandMemCpyAsLoop(Memcpy, TTI);
210*06c3fb27SDimitry Andric         Changed = true;
211*06c3fb27SDimitry Andric         Memcpy->eraseFromParent();
212*06c3fb27SDimitry Andric       }
213*06c3fb27SDimitry Andric 
214*06c3fb27SDimitry Andric       break;
215*06c3fb27SDimitry Andric     }
216*06c3fb27SDimitry Andric     case Intrinsic::memmove: {
217*06c3fb27SDimitry Andric       auto *Memmove = cast<MemMoveInst>(Inst);
218*06c3fb27SDimitry Andric       Function *ParentFunc = Memmove->getFunction();
219*06c3fb27SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
220*06c3fb27SDimitry Andric       if (shouldExpandMemIntrinsicWithSize(Memmove->getLength(), TTI)) {
221*06c3fb27SDimitry Andric         if (UseMemIntrinsicLibFunc &&
222*06c3fb27SDimitry Andric             LookupLibInfo(*ParentFunc).has(LibFunc_memmove))
223*06c3fb27SDimitry Andric           break;
224*06c3fb27SDimitry Andric 
225*06c3fb27SDimitry Andric         if (expandMemMoveAsLoop(Memmove, TTI)) {
226*06c3fb27SDimitry Andric           Changed = true;
227*06c3fb27SDimitry Andric           Memmove->eraseFromParent();
228*06c3fb27SDimitry Andric         }
229*06c3fb27SDimitry Andric       }
230*06c3fb27SDimitry Andric 
231*06c3fb27SDimitry Andric       break;
232*06c3fb27SDimitry Andric     }
233*06c3fb27SDimitry Andric     case Intrinsic::memset: {
234*06c3fb27SDimitry Andric       auto *Memset = cast<MemSetInst>(Inst);
235*06c3fb27SDimitry Andric       Function *ParentFunc = Memset->getFunction();
236*06c3fb27SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
237*06c3fb27SDimitry Andric       if (shouldExpandMemIntrinsicWithSize(Memset->getLength(), TTI)) {
238*06c3fb27SDimitry Andric         if (UseMemIntrinsicLibFunc &&
239*06c3fb27SDimitry Andric             LookupLibInfo(*Memset->getFunction()).has(LibFunc_memset))
240*06c3fb27SDimitry Andric           break;
241*06c3fb27SDimitry Andric 
242*06c3fb27SDimitry Andric         expandMemSetAsLoop(Memset);
243*06c3fb27SDimitry Andric         Changed = true;
244*06c3fb27SDimitry Andric         Memset->eraseFromParent();
245*06c3fb27SDimitry Andric       }
246*06c3fb27SDimitry Andric 
247*06c3fb27SDimitry Andric       break;
248*06c3fb27SDimitry Andric     }
249*06c3fb27SDimitry Andric     default:
250*06c3fb27SDimitry Andric       llvm_unreachable("unhandled intrinsic");
251*06c3fb27SDimitry Andric     }
252*06c3fb27SDimitry Andric   }
253*06c3fb27SDimitry Andric 
254*06c3fb27SDimitry Andric   return Changed;
255*06c3fb27SDimitry Andric }
256*06c3fb27SDimitry Andric 
257*06c3fb27SDimitry Andric bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {
2580b57cec5SDimitry Andric   bool Changed = false;
2590b57cec5SDimitry Andric   for (Function &F : M) {
2600b57cec5SDimitry Andric     switch (F.getIntrinsicID()) {
2610b57cec5SDimitry Andric     default:
2620b57cec5SDimitry Andric       break;
263*06c3fb27SDimitry Andric     case Intrinsic::memcpy:
264*06c3fb27SDimitry Andric     case Intrinsic::memmove:
265*06c3fb27SDimitry Andric     case Intrinsic::memset:
266*06c3fb27SDimitry Andric       Changed |= expandMemIntrinsicUses(F);
267*06c3fb27SDimitry Andric       break;
268*06c3fb27SDimitry Andric     case Intrinsic::load_relative:
269*06c3fb27SDimitry Andric       Changed |= lowerLoadRelative(F);
270*06c3fb27SDimitry Andric       break;
2710b57cec5SDimitry Andric     case Intrinsic::objc_autorelease:
2720b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autorelease");
2730b57cec5SDimitry Andric       break;
2740b57cec5SDimitry Andric     case Intrinsic::objc_autoreleasePoolPop:
2750b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
2760b57cec5SDimitry Andric       break;
2770b57cec5SDimitry Andric     case Intrinsic::objc_autoreleasePoolPush:
2780b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
2790b57cec5SDimitry Andric       break;
2800b57cec5SDimitry Andric     case Intrinsic::objc_autoreleaseReturnValue:
2810b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
2820b57cec5SDimitry Andric       break;
2830b57cec5SDimitry Andric     case Intrinsic::objc_copyWeak:
2840b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_copyWeak");
2850b57cec5SDimitry Andric       break;
2860b57cec5SDimitry Andric     case Intrinsic::objc_destroyWeak:
2870b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_destroyWeak");
2880b57cec5SDimitry Andric       break;
2890b57cec5SDimitry Andric     case Intrinsic::objc_initWeak:
2900b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_initWeak");
2910b57cec5SDimitry Andric       break;
2920b57cec5SDimitry Andric     case Intrinsic::objc_loadWeak:
2930b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_loadWeak");
2940b57cec5SDimitry Andric       break;
2950b57cec5SDimitry Andric     case Intrinsic::objc_loadWeakRetained:
2960b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
2970b57cec5SDimitry Andric       break;
2980b57cec5SDimitry Andric     case Intrinsic::objc_moveWeak:
2990b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_moveWeak");
3000b57cec5SDimitry Andric       break;
3010b57cec5SDimitry Andric     case Intrinsic::objc_release:
3020b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_release", true);
3030b57cec5SDimitry Andric       break;
3040b57cec5SDimitry Andric     case Intrinsic::objc_retain:
3050b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retain", true);
3060b57cec5SDimitry Andric       break;
3070b57cec5SDimitry Andric     case Intrinsic::objc_retainAutorelease:
3080b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainAutorelease");
3090b57cec5SDimitry Andric       break;
3100b57cec5SDimitry Andric     case Intrinsic::objc_retainAutoreleaseReturnValue:
3110b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
3120b57cec5SDimitry Andric       break;
3130b57cec5SDimitry Andric     case Intrinsic::objc_retainAutoreleasedReturnValue:
3140b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
3150b57cec5SDimitry Andric       break;
3160b57cec5SDimitry Andric     case Intrinsic::objc_retainBlock:
3170b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainBlock");
3180b57cec5SDimitry Andric       break;
3190b57cec5SDimitry Andric     case Intrinsic::objc_storeStrong:
3200b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_storeStrong");
3210b57cec5SDimitry Andric       break;
3220b57cec5SDimitry Andric     case Intrinsic::objc_storeWeak:
3230b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_storeWeak");
3240b57cec5SDimitry Andric       break;
3250b57cec5SDimitry Andric     case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
3260b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
3270b57cec5SDimitry Andric       break;
3280b57cec5SDimitry Andric     case Intrinsic::objc_retainedObject:
3290b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainedObject");
3300b57cec5SDimitry Andric       break;
3310b57cec5SDimitry Andric     case Intrinsic::objc_unretainedObject:
3320b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_unretainedObject");
3330b57cec5SDimitry Andric       break;
3340b57cec5SDimitry Andric     case Intrinsic::objc_unretainedPointer:
3350b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_unretainedPointer");
3360b57cec5SDimitry Andric       break;
3370b57cec5SDimitry Andric     case Intrinsic::objc_retain_autorelease:
3380b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retain_autorelease");
3390b57cec5SDimitry Andric       break;
3400b57cec5SDimitry Andric     case Intrinsic::objc_sync_enter:
3410b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_sync_enter");
3420b57cec5SDimitry Andric       break;
3430b57cec5SDimitry Andric     case Intrinsic::objc_sync_exit:
3440b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_sync_exit");
3450b57cec5SDimitry Andric       break;
3460b57cec5SDimitry Andric     }
3470b57cec5SDimitry Andric   }
3480b57cec5SDimitry Andric   return Changed;
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric namespace {
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
3540b57cec5SDimitry Andric public:
3550b57cec5SDimitry Andric   static char ID;
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
3580b57cec5SDimitry Andric 
359*06c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
360*06c3fb27SDimitry Andric     AU.addRequired<TargetLibraryInfoWrapperPass>();
361*06c3fb27SDimitry Andric     AU.addRequired<TargetTransformInfoWrapperPass>();
362*06c3fb27SDimitry Andric   }
363*06c3fb27SDimitry Andric 
364*06c3fb27SDimitry Andric   bool runOnModule(Module &M) override {
365*06c3fb27SDimitry Andric     auto LookupTTI = [this](Function &F) -> TargetTransformInfo & {
366*06c3fb27SDimitry Andric       return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
367*06c3fb27SDimitry Andric     };
368*06c3fb27SDimitry Andric 
369*06c3fb27SDimitry Andric     auto LookupTLI = [this](Function &F) -> TargetLibraryInfo & {
370*06c3fb27SDimitry Andric       return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
371*06c3fb27SDimitry Andric     };
372*06c3fb27SDimitry Andric 
373*06c3fb27SDimitry Andric     PreISelIntrinsicLowering Lowering(LookupTTI, LookupTLI);
374*06c3fb27SDimitry Andric     return Lowering.lowerIntrinsics(M);
375*06c3fb27SDimitry Andric   }
3760b57cec5SDimitry Andric };
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric } // end anonymous namespace
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID;
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
3830b57cec5SDimitry Andric                 "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
3840b57cec5SDimitry Andric                 false, false)
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() {
3870b57cec5SDimitry Andric   return new PreISelIntrinsicLoweringLegacyPass;
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
3910b57cec5SDimitry Andric                                                     ModuleAnalysisManager &AM) {
392*06c3fb27SDimitry Andric   auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
393*06c3fb27SDimitry Andric 
394*06c3fb27SDimitry Andric   auto LookupTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
395*06c3fb27SDimitry Andric     return FAM.getResult<TargetLibraryAnalysis>(F);
396*06c3fb27SDimitry Andric   };
397*06c3fb27SDimitry Andric 
398*06c3fb27SDimitry Andric   auto LookupTTI = [&FAM](Function &F) -> TargetTransformInfo & {
399*06c3fb27SDimitry Andric     return FAM.getResult<TargetIRAnalysis>(F);
400*06c3fb27SDimitry Andric   };
401*06c3fb27SDimitry Andric 
402*06c3fb27SDimitry Andric   PreISelIntrinsicLowering Lowering(LookupTTI, LookupTLI);
403*06c3fb27SDimitry Andric   if (!Lowering.lowerIntrinsics(M))
4040b57cec5SDimitry Andric     return PreservedAnalyses::all();
4050b57cec5SDimitry Andric   else
4060b57cec5SDimitry Andric     return PreservedAnalyses::none();
4070b57cec5SDimitry Andric }
408