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