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 // 906c3fb27SDimitry Andric // This pass implements IR lowering for the llvm.memcpy, llvm.memmove, 1006c3fb27SDimitry 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" 1706c3fb27SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 198a4dda33SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 208a4dda33SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 210b57cec5SDimitry Andric #include "llvm/IR/Function.h" 220b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 230b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 24972a253aSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 250b57cec5SDimitry Andric #include "llvm/IR/Module.h" 260b57cec5SDimitry Andric #include "llvm/IR/Type.h" 27480093f4SDimitry Andric #include "llvm/InitializePasses.h" 280b57cec5SDimitry Andric #include "llvm/Pass.h" 290b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 308a4dda33SDimitry Andric #include "llvm/Target/TargetMachine.h" 3106c3fb27SDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h" 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric using namespace llvm; 340b57cec5SDimitry Andric 3506c3fb27SDimitry Andric /// Threshold to leave statically sized memory intrinsic calls. Calls of known 3606c3fb27SDimitry Andric /// size larger than this will be expanded by the pass. Calls of unknown or 3706c3fb27SDimitry Andric /// lower size will be left for expansion in codegen. 3806c3fb27SDimitry Andric static cl::opt<int64_t> MemIntrinsicExpandSizeThresholdOpt( 3906c3fb27SDimitry Andric "mem-intrinsic-expand-size", 4006c3fb27SDimitry Andric cl::desc("Set minimum mem intrinsic size to expand in IR"), cl::init(-1), 4106c3fb27SDimitry Andric cl::Hidden); 4206c3fb27SDimitry Andric 4306c3fb27SDimitry Andric namespace { 4406c3fb27SDimitry Andric 4506c3fb27SDimitry Andric struct PreISelIntrinsicLowering { 468a4dda33SDimitry Andric const TargetMachine &TM; 4706c3fb27SDimitry Andric const function_ref<TargetTransformInfo &(Function &)> LookupTTI; 4806c3fb27SDimitry Andric 4906c3fb27SDimitry Andric /// If this is true, assume it's preferably to leave memory intrinsic calls 5006c3fb27SDimitry Andric /// for replacement with a library call later. Otherwise this depends on 518a4dda33SDimitry Andric /// TargetLoweringInfo availability of the corresponding function. 5206c3fb27SDimitry Andric const bool UseMemIntrinsicLibFunc; 5306c3fb27SDimitry Andric 5406c3fb27SDimitry Andric explicit PreISelIntrinsicLowering( 558a4dda33SDimitry Andric const TargetMachine &TM_, 5606c3fb27SDimitry Andric function_ref<TargetTransformInfo &(Function &)> LookupTTI_, 5706c3fb27SDimitry Andric bool UseMemIntrinsicLibFunc_ = true) 588a4dda33SDimitry Andric : TM(TM_), LookupTTI(LookupTTI_), 5906c3fb27SDimitry Andric UseMemIntrinsicLibFunc(UseMemIntrinsicLibFunc_) {} 6006c3fb27SDimitry Andric 6106c3fb27SDimitry Andric static bool shouldExpandMemIntrinsicWithSize(Value *Size, 6206c3fb27SDimitry Andric const TargetTransformInfo &TTI); 6306c3fb27SDimitry Andric bool expandMemIntrinsicUses(Function &F) const; 6406c3fb27SDimitry Andric bool lowerIntrinsics(Module &M) const; 6506c3fb27SDimitry Andric }; 6606c3fb27SDimitry Andric 6706c3fb27SDimitry Andric } // namespace 6806c3fb27SDimitry Andric 690b57cec5SDimitry Andric static bool lowerLoadRelative(Function &F) { 700b57cec5SDimitry Andric if (F.use_empty()) 710b57cec5SDimitry Andric return false; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric bool Changed = false; 740b57cec5SDimitry Andric Type *Int32Ty = Type::getInt32Ty(F.getContext()); 750b57cec5SDimitry Andric Type *Int8Ty = Type::getInt8Ty(F.getContext()); 760b57cec5SDimitry Andric 77349cc55cSDimitry Andric for (Use &U : llvm::make_early_inc_range(F.uses())) { 78349cc55cSDimitry Andric auto CI = dyn_cast<CallInst>(U.getUser()); 795ffd83dbSDimitry Andric if (!CI || CI->getCalledOperand() != &F) 800b57cec5SDimitry Andric continue; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric IRBuilder<> B(CI); 830b57cec5SDimitry Andric Value *OffsetPtr = 840b57cec5SDimitry Andric B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1)); 85*5f757f3fSDimitry Andric Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtr, 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 165*5f757f3fSDimitry Andric // Transfer the 'returned' attribute from the intrinsic to the call site. 166*5f757f3fSDimitry Andric // By applying this only to intrinsic call sites, we avoid applying it to 167*5f757f3fSDimitry Andric // non-ARC explicit calls to things like objc_retain which have not been 168*5f757f3fSDimitry Andric // auto-upgraded to use the intrinsics. 169*5f757f3fSDimitry Andric unsigned Index; 170*5f757f3fSDimitry Andric if (F.getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) && 171*5f757f3fSDimitry Andric Index) 172*5f757f3fSDimitry Andric NewCI->addParamAttr(Index - AttributeList::FirstArgIndex, 173*5f757f3fSDimitry Andric Attribute::Returned); 174*5f757f3fSDimitry Andric 1750b57cec5SDimitry Andric if (!CI->use_empty()) 1760b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCI); 1770b57cec5SDimitry Andric CI->eraseFromParent(); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric return true; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 18306c3fb27SDimitry Andric // TODO: Should refine based on estimated number of accesses (e.g. does it 18406c3fb27SDimitry Andric // require splitting based on alignment) 18506c3fb27SDimitry Andric bool PreISelIntrinsicLowering::shouldExpandMemIntrinsicWithSize( 18606c3fb27SDimitry Andric Value *Size, const TargetTransformInfo &TTI) { 18706c3fb27SDimitry Andric ConstantInt *CI = dyn_cast<ConstantInt>(Size); 18806c3fb27SDimitry Andric if (!CI) 18906c3fb27SDimitry Andric return true; 19006c3fb27SDimitry Andric uint64_t Threshold = MemIntrinsicExpandSizeThresholdOpt.getNumOccurrences() 19106c3fb27SDimitry Andric ? MemIntrinsicExpandSizeThresholdOpt 19206c3fb27SDimitry Andric : TTI.getMaxMemIntrinsicInlineSizeThreshold(); 19306c3fb27SDimitry Andric uint64_t SizeVal = CI->getZExtValue(); 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric // Treat a threshold of 0 as a special case to force expansion of all 19606c3fb27SDimitry Andric // intrinsics, including size 0. 19706c3fb27SDimitry Andric return SizeVal > Threshold || Threshold == 0; 19806c3fb27SDimitry Andric } 19906c3fb27SDimitry Andric 2008a4dda33SDimitry Andric static bool canEmitLibcall(const TargetMachine &TM, Function *F, 2018a4dda33SDimitry Andric RTLIB::Libcall LC) { 2028a4dda33SDimitry Andric // TODO: Should this consider the address space of the memcpy? 2038a4dda33SDimitry Andric const TargetLowering *TLI = TM.getSubtargetImpl(*F)->getTargetLowering(); 2048a4dda33SDimitry Andric return TLI->getLibcallName(LC) != nullptr; 2058a4dda33SDimitry Andric } 2068a4dda33SDimitry Andric 20706c3fb27SDimitry Andric // TODO: Handle atomic memcpy and memcpy.inline 20806c3fb27SDimitry Andric // TODO: Pass ScalarEvolution 20906c3fb27SDimitry Andric bool PreISelIntrinsicLowering::expandMemIntrinsicUses(Function &F) const { 21006c3fb27SDimitry Andric Intrinsic::ID ID = F.getIntrinsicID(); 21106c3fb27SDimitry Andric bool Changed = false; 21206c3fb27SDimitry Andric 21306c3fb27SDimitry Andric for (User *U : llvm::make_early_inc_range(F.users())) { 21406c3fb27SDimitry Andric Instruction *Inst = cast<Instruction>(U); 21506c3fb27SDimitry Andric 21606c3fb27SDimitry Andric switch (ID) { 21706c3fb27SDimitry Andric case Intrinsic::memcpy: { 21806c3fb27SDimitry Andric auto *Memcpy = cast<MemCpyInst>(Inst); 21906c3fb27SDimitry Andric Function *ParentFunc = Memcpy->getFunction(); 22006c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 22106c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memcpy->getLength(), TTI)) { 22206c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 2238a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMCPY)) 22406c3fb27SDimitry Andric break; 22506c3fb27SDimitry Andric 2268a4dda33SDimitry Andric // TODO: For optsize, emit the loop into a separate function 22706c3fb27SDimitry Andric expandMemCpyAsLoop(Memcpy, TTI); 22806c3fb27SDimitry Andric Changed = true; 22906c3fb27SDimitry Andric Memcpy->eraseFromParent(); 23006c3fb27SDimitry Andric } 23106c3fb27SDimitry Andric 23206c3fb27SDimitry Andric break; 23306c3fb27SDimitry Andric } 23406c3fb27SDimitry Andric case Intrinsic::memmove: { 23506c3fb27SDimitry Andric auto *Memmove = cast<MemMoveInst>(Inst); 23606c3fb27SDimitry Andric Function *ParentFunc = Memmove->getFunction(); 23706c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 23806c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memmove->getLength(), TTI)) { 23906c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 2408a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMMOVE)) 24106c3fb27SDimitry Andric break; 24206c3fb27SDimitry Andric 24306c3fb27SDimitry Andric if (expandMemMoveAsLoop(Memmove, TTI)) { 24406c3fb27SDimitry Andric Changed = true; 24506c3fb27SDimitry Andric Memmove->eraseFromParent(); 24606c3fb27SDimitry Andric } 24706c3fb27SDimitry Andric } 24806c3fb27SDimitry Andric 24906c3fb27SDimitry Andric break; 25006c3fb27SDimitry Andric } 25106c3fb27SDimitry Andric case Intrinsic::memset: { 25206c3fb27SDimitry Andric auto *Memset = cast<MemSetInst>(Inst); 25306c3fb27SDimitry Andric Function *ParentFunc = Memset->getFunction(); 25406c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 25506c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memset->getLength(), TTI)) { 25606c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 2578a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMSET)) 25806c3fb27SDimitry Andric break; 25906c3fb27SDimitry Andric 26006c3fb27SDimitry Andric expandMemSetAsLoop(Memset); 26106c3fb27SDimitry Andric Changed = true; 26206c3fb27SDimitry Andric Memset->eraseFromParent(); 26306c3fb27SDimitry Andric } 26406c3fb27SDimitry Andric 26506c3fb27SDimitry Andric break; 26606c3fb27SDimitry Andric } 26706c3fb27SDimitry Andric default: 26806c3fb27SDimitry Andric llvm_unreachable("unhandled intrinsic"); 26906c3fb27SDimitry Andric } 27006c3fb27SDimitry Andric } 27106c3fb27SDimitry Andric 27206c3fb27SDimitry Andric return Changed; 27306c3fb27SDimitry Andric } 27406c3fb27SDimitry Andric 27506c3fb27SDimitry Andric bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const { 2760b57cec5SDimitry Andric bool Changed = false; 2770b57cec5SDimitry Andric for (Function &F : M) { 2780b57cec5SDimitry Andric switch (F.getIntrinsicID()) { 2790b57cec5SDimitry Andric default: 2800b57cec5SDimitry Andric break; 28106c3fb27SDimitry Andric case Intrinsic::memcpy: 28206c3fb27SDimitry Andric case Intrinsic::memmove: 28306c3fb27SDimitry Andric case Intrinsic::memset: 28406c3fb27SDimitry Andric Changed |= expandMemIntrinsicUses(F); 28506c3fb27SDimitry Andric break; 28606c3fb27SDimitry Andric case Intrinsic::load_relative: 28706c3fb27SDimitry Andric Changed |= lowerLoadRelative(F); 28806c3fb27SDimitry Andric break; 2890b57cec5SDimitry Andric case Intrinsic::objc_autorelease: 2900b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autorelease"); 2910b57cec5SDimitry Andric break; 2920b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPop: 2930b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); 2940b57cec5SDimitry Andric break; 2950b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPush: 2960b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric case Intrinsic::objc_autoreleaseReturnValue: 2990b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); 3000b57cec5SDimitry Andric break; 3010b57cec5SDimitry Andric case Intrinsic::objc_copyWeak: 3020b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_copyWeak"); 3030b57cec5SDimitry Andric break; 3040b57cec5SDimitry Andric case Intrinsic::objc_destroyWeak: 3050b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_destroyWeak"); 3060b57cec5SDimitry Andric break; 3070b57cec5SDimitry Andric case Intrinsic::objc_initWeak: 3080b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_initWeak"); 3090b57cec5SDimitry Andric break; 3100b57cec5SDimitry Andric case Intrinsic::objc_loadWeak: 3110b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeak"); 3120b57cec5SDimitry Andric break; 3130b57cec5SDimitry Andric case Intrinsic::objc_loadWeakRetained: 3140b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); 3150b57cec5SDimitry Andric break; 3160b57cec5SDimitry Andric case Intrinsic::objc_moveWeak: 3170b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_moveWeak"); 3180b57cec5SDimitry Andric break; 3190b57cec5SDimitry Andric case Intrinsic::objc_release: 3200b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_release", true); 3210b57cec5SDimitry Andric break; 3220b57cec5SDimitry Andric case Intrinsic::objc_retain: 3230b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain", true); 3240b57cec5SDimitry Andric break; 3250b57cec5SDimitry Andric case Intrinsic::objc_retainAutorelease: 3260b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutorelease"); 3270b57cec5SDimitry Andric break; 3280b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleaseReturnValue: 3290b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); 3300b57cec5SDimitry Andric break; 3310b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleasedReturnValue: 3320b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); 3330b57cec5SDimitry Andric break; 3340b57cec5SDimitry Andric case Intrinsic::objc_retainBlock: 3350b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainBlock"); 3360b57cec5SDimitry Andric break; 3370b57cec5SDimitry Andric case Intrinsic::objc_storeStrong: 3380b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeStrong"); 3390b57cec5SDimitry Andric break; 3400b57cec5SDimitry Andric case Intrinsic::objc_storeWeak: 3410b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeWeak"); 3420b57cec5SDimitry Andric break; 3430b57cec5SDimitry Andric case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: 3440b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); 3450b57cec5SDimitry Andric break; 3460b57cec5SDimitry Andric case Intrinsic::objc_retainedObject: 3470b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainedObject"); 3480b57cec5SDimitry Andric break; 3490b57cec5SDimitry Andric case Intrinsic::objc_unretainedObject: 3500b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedObject"); 3510b57cec5SDimitry Andric break; 3520b57cec5SDimitry Andric case Intrinsic::objc_unretainedPointer: 3530b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedPointer"); 3540b57cec5SDimitry Andric break; 3550b57cec5SDimitry Andric case Intrinsic::objc_retain_autorelease: 3560b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain_autorelease"); 3570b57cec5SDimitry Andric break; 3580b57cec5SDimitry Andric case Intrinsic::objc_sync_enter: 3590b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_enter"); 3600b57cec5SDimitry Andric break; 3610b57cec5SDimitry Andric case Intrinsic::objc_sync_exit: 3620b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_exit"); 3630b57cec5SDimitry Andric break; 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric return Changed; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric namespace { 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass { 3720b57cec5SDimitry Andric public: 3730b57cec5SDimitry Andric static char ID; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} 3760b57cec5SDimitry Andric 37706c3fb27SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 37806c3fb27SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 3798a4dda33SDimitry Andric AU.addRequired<TargetPassConfig>(); 38006c3fb27SDimitry Andric } 38106c3fb27SDimitry Andric 38206c3fb27SDimitry Andric bool runOnModule(Module &M) override { 38306c3fb27SDimitry Andric auto LookupTTI = [this](Function &F) -> TargetTransformInfo & { 38406c3fb27SDimitry Andric return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 38506c3fb27SDimitry Andric }; 38606c3fb27SDimitry Andric 3878a4dda33SDimitry Andric const auto &TM = getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 3888a4dda33SDimitry Andric PreISelIntrinsicLowering Lowering(TM, LookupTTI); 38906c3fb27SDimitry Andric return Lowering.lowerIntrinsics(M); 39006c3fb27SDimitry Andric } 3910b57cec5SDimitry Andric }; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric } // end anonymous namespace 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID; 3960b57cec5SDimitry Andric 3978a4dda33SDimitry Andric INITIALIZE_PASS_BEGIN(PreISelIntrinsicLoweringLegacyPass, 3988a4dda33SDimitry Andric "pre-isel-intrinsic-lowering", 3998a4dda33SDimitry Andric "Pre-ISel Intrinsic Lowering", false, false) 4008a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 4018a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 4028a4dda33SDimitry Andric INITIALIZE_PASS_END(PreISelIntrinsicLoweringLegacyPass, 4038a4dda33SDimitry Andric "pre-isel-intrinsic-lowering", 4048a4dda33SDimitry Andric "Pre-ISel Intrinsic Lowering", false, false) 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() { 4078a4dda33SDimitry Andric return new PreISelIntrinsicLoweringLegacyPass(); 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, 4110b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 41206c3fb27SDimitry Andric auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 41306c3fb27SDimitry Andric 41406c3fb27SDimitry Andric auto LookupTTI = [&FAM](Function &F) -> TargetTransformInfo & { 41506c3fb27SDimitry Andric return FAM.getResult<TargetIRAnalysis>(F); 41606c3fb27SDimitry Andric }; 41706c3fb27SDimitry Andric 4188a4dda33SDimitry Andric PreISelIntrinsicLowering Lowering(TM, LookupTTI); 41906c3fb27SDimitry Andric if (!Lowering.lowerIntrinsics(M)) 4200b57cec5SDimitry Andric return PreservedAnalyses::all(); 4210b57cec5SDimitry Andric else 4220b57cec5SDimitry Andric return PreservedAnalyses::none(); 4230b57cec5SDimitry Andric } 424