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" 19*8a4dda33SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 20*8a4dda33SDimitry 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" 30*8a4dda33SDimitry 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 { 46*8a4dda33SDimitry 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 51*8a4dda33SDimitry Andric /// TargetLoweringInfo availability of the corresponding function. 5206c3fb27SDimitry Andric const bool UseMemIntrinsicLibFunc; 5306c3fb27SDimitry Andric 5406c3fb27SDimitry Andric explicit PreISelIntrinsicLowering( 55*8a4dda33SDimitry Andric const TargetMachine &TM_, 5606c3fb27SDimitry Andric function_ref<TargetTransformInfo &(Function &)> LookupTTI_, 5706c3fb27SDimitry Andric bool UseMemIntrinsicLibFunc_ = true) 58*8a4dda33SDimitry 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 *Int32PtrTy = Int32Ty->getPointerTo(); 760b57cec5SDimitry Andric Type *Int8Ty = Type::getInt8Ty(F.getContext()); 770b57cec5SDimitry Andric 78349cc55cSDimitry Andric for (Use &U : llvm::make_early_inc_range(F.uses())) { 79349cc55cSDimitry Andric auto CI = dyn_cast<CallInst>(U.getUser()); 805ffd83dbSDimitry Andric if (!CI || CI->getCalledOperand() != &F) 810b57cec5SDimitry Andric continue; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric IRBuilder<> B(CI); 840b57cec5SDimitry Andric Value *OffsetPtr = 850b57cec5SDimitry Andric B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1)); 860b57cec5SDimitry Andric Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy); 875ffd83dbSDimitry Andric Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, Align(4)); 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric CI->replaceAllUsesWith(ResultPtr); 920b57cec5SDimitry Andric CI->eraseFromParent(); 930b57cec5SDimitry Andric Changed = true; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric return Changed; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 99480093f4SDimitry Andric // ObjCARC has knowledge about whether an obj-c runtime function needs to be 100480093f4SDimitry Andric // always tail-called or never tail-called. 101480093f4SDimitry Andric static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) { 102480093f4SDimitry Andric objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F); 103480093f4SDimitry Andric if (objcarc::IsAlwaysTail(Kind)) 104480093f4SDimitry Andric return CallInst::TCK_Tail; 105480093f4SDimitry Andric else if (objcarc::IsNeverTail(Kind)) 106480093f4SDimitry Andric return CallInst::TCK_NoTail; 107480093f4SDimitry Andric return CallInst::TCK_None; 108480093f4SDimitry Andric } 109480093f4SDimitry Andric 1100b57cec5SDimitry Andric static bool lowerObjCCall(Function &F, const char *NewFn, 1110b57cec5SDimitry Andric bool setNonLazyBind = false) { 112972a253aSDimitry Andric assert(IntrinsicInst::mayLowerToFunctionCall(F.getIntrinsicID()) && 113972a253aSDimitry Andric "Pre-ISel intrinsics do lower into regular function calls"); 1140b57cec5SDimitry Andric if (F.use_empty()) 1150b57cec5SDimitry Andric return false; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // If we haven't already looked up this function, check to see if the 1180b57cec5SDimitry Andric // program already contains a function with this name. 1190b57cec5SDimitry Andric Module *M = F.getParent(); 1200b57cec5SDimitry Andric FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType()); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) { 1230b57cec5SDimitry Andric Fn->setLinkage(F.getLinkage()); 1240b57cec5SDimitry Andric if (setNonLazyBind && !Fn->isWeakForLinker()) { 1250b57cec5SDimitry Andric // If we have Native ARC, set nonlazybind attribute for these APIs for 1260b57cec5SDimitry Andric // performance. 1270b57cec5SDimitry Andric Fn->addFnAttr(Attribute::NonLazyBind); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 131480093f4SDimitry Andric CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F); 132480093f4SDimitry Andric 133349cc55cSDimitry Andric for (Use &U : llvm::make_early_inc_range(F.uses())) { 134349cc55cSDimitry Andric auto *CB = cast<CallBase>(U.getUser()); 135349cc55cSDimitry Andric 136349cc55cSDimitry Andric if (CB->getCalledFunction() != &F) { 137349cc55cSDimitry Andric objcarc::ARCInstKind Kind = objcarc::getAttachedARCFunctionKind(CB); 138349cc55cSDimitry Andric (void)Kind; 139349cc55cSDimitry Andric assert((Kind == objcarc::ARCInstKind::RetainRV || 14004eeddc0SDimitry Andric Kind == objcarc::ARCInstKind::UnsafeClaimRV) && 141349cc55cSDimitry Andric "use expected to be the argument of operand bundle " 142349cc55cSDimitry Andric "\"clang.arc.attachedcall\""); 143349cc55cSDimitry Andric U.set(FCache.getCallee()); 144349cc55cSDimitry Andric continue; 145349cc55cSDimitry Andric } 146349cc55cSDimitry Andric 147349cc55cSDimitry Andric auto *CI = cast<CallInst>(CB); 1480b57cec5SDimitry Andric assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric IRBuilder<> Builder(CI->getParent(), CI->getIterator()); 151e8d8bef9SDimitry Andric SmallVector<Value *, 8> Args(CI->args()); 152972a253aSDimitry Andric SmallVector<llvm::OperandBundleDef, 1> BundleList; 153972a253aSDimitry Andric CI->getOperandBundlesAsDefs(BundleList); 154972a253aSDimitry Andric CallInst *NewCI = Builder.CreateCall(FCache, Args, BundleList); 1550b57cec5SDimitry Andric NewCI->setName(CI->getName()); 156480093f4SDimitry Andric 157480093f4SDimitry Andric // Try to set the most appropriate TailCallKind based on both the current 158480093f4SDimitry Andric // attributes and the ones that we could get from ObjCARC's special 159480093f4SDimitry Andric // knowledge of the runtime functions. 160480093f4SDimitry Andric // 161480093f4SDimitry Andric // std::max respects both requirements of notail and tail here: 162480093f4SDimitry Andric // * notail on either the call or from ObjCARC becomes notail 163480093f4SDimitry Andric // * tail on either side is stronger than none, but not notail 164480093f4SDimitry Andric CallInst::TailCallKind TCK = CI->getTailCallKind(); 165480093f4SDimitry Andric NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); 166480093f4SDimitry Andric 1670b57cec5SDimitry Andric if (!CI->use_empty()) 1680b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCI); 1690b57cec5SDimitry Andric CI->eraseFromParent(); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric return true; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 17506c3fb27SDimitry Andric // TODO: Should refine based on estimated number of accesses (e.g. does it 17606c3fb27SDimitry Andric // require splitting based on alignment) 17706c3fb27SDimitry Andric bool PreISelIntrinsicLowering::shouldExpandMemIntrinsicWithSize( 17806c3fb27SDimitry Andric Value *Size, const TargetTransformInfo &TTI) { 17906c3fb27SDimitry Andric ConstantInt *CI = dyn_cast<ConstantInt>(Size); 18006c3fb27SDimitry Andric if (!CI) 18106c3fb27SDimitry Andric return true; 18206c3fb27SDimitry Andric uint64_t Threshold = MemIntrinsicExpandSizeThresholdOpt.getNumOccurrences() 18306c3fb27SDimitry Andric ? MemIntrinsicExpandSizeThresholdOpt 18406c3fb27SDimitry Andric : TTI.getMaxMemIntrinsicInlineSizeThreshold(); 18506c3fb27SDimitry Andric uint64_t SizeVal = CI->getZExtValue(); 18606c3fb27SDimitry Andric 18706c3fb27SDimitry Andric // Treat a threshold of 0 as a special case to force expansion of all 18806c3fb27SDimitry Andric // intrinsics, including size 0. 18906c3fb27SDimitry Andric return SizeVal > Threshold || Threshold == 0; 19006c3fb27SDimitry Andric } 19106c3fb27SDimitry Andric 192*8a4dda33SDimitry Andric static bool canEmitLibcall(const TargetMachine &TM, Function *F, 193*8a4dda33SDimitry Andric RTLIB::Libcall LC) { 194*8a4dda33SDimitry Andric // TODO: Should this consider the address space of the memcpy? 195*8a4dda33SDimitry Andric const TargetLowering *TLI = TM.getSubtargetImpl(*F)->getTargetLowering(); 196*8a4dda33SDimitry Andric return TLI->getLibcallName(LC) != nullptr; 197*8a4dda33SDimitry Andric } 198*8a4dda33SDimitry Andric 19906c3fb27SDimitry Andric // TODO: Handle atomic memcpy and memcpy.inline 20006c3fb27SDimitry Andric // TODO: Pass ScalarEvolution 20106c3fb27SDimitry Andric bool PreISelIntrinsicLowering::expandMemIntrinsicUses(Function &F) const { 20206c3fb27SDimitry Andric Intrinsic::ID ID = F.getIntrinsicID(); 20306c3fb27SDimitry Andric bool Changed = false; 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric for (User *U : llvm::make_early_inc_range(F.users())) { 20606c3fb27SDimitry Andric Instruction *Inst = cast<Instruction>(U); 20706c3fb27SDimitry Andric 20806c3fb27SDimitry Andric switch (ID) { 20906c3fb27SDimitry Andric case Intrinsic::memcpy: { 21006c3fb27SDimitry Andric auto *Memcpy = cast<MemCpyInst>(Inst); 21106c3fb27SDimitry Andric Function *ParentFunc = Memcpy->getFunction(); 21206c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 21306c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memcpy->getLength(), TTI)) { 21406c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 215*8a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMCPY)) 21606c3fb27SDimitry Andric break; 21706c3fb27SDimitry Andric 218*8a4dda33SDimitry Andric // TODO: For optsize, emit the loop into a separate function 21906c3fb27SDimitry Andric expandMemCpyAsLoop(Memcpy, TTI); 22006c3fb27SDimitry Andric Changed = true; 22106c3fb27SDimitry Andric Memcpy->eraseFromParent(); 22206c3fb27SDimitry Andric } 22306c3fb27SDimitry Andric 22406c3fb27SDimitry Andric break; 22506c3fb27SDimitry Andric } 22606c3fb27SDimitry Andric case Intrinsic::memmove: { 22706c3fb27SDimitry Andric auto *Memmove = cast<MemMoveInst>(Inst); 22806c3fb27SDimitry Andric Function *ParentFunc = Memmove->getFunction(); 22906c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 23006c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memmove->getLength(), TTI)) { 23106c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 232*8a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMMOVE)) 23306c3fb27SDimitry Andric break; 23406c3fb27SDimitry Andric 23506c3fb27SDimitry Andric if (expandMemMoveAsLoop(Memmove, TTI)) { 23606c3fb27SDimitry Andric Changed = true; 23706c3fb27SDimitry Andric Memmove->eraseFromParent(); 23806c3fb27SDimitry Andric } 23906c3fb27SDimitry Andric } 24006c3fb27SDimitry Andric 24106c3fb27SDimitry Andric break; 24206c3fb27SDimitry Andric } 24306c3fb27SDimitry Andric case Intrinsic::memset: { 24406c3fb27SDimitry Andric auto *Memset = cast<MemSetInst>(Inst); 24506c3fb27SDimitry Andric Function *ParentFunc = Memset->getFunction(); 24606c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 24706c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memset->getLength(), TTI)) { 24806c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 249*8a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMSET)) 25006c3fb27SDimitry Andric break; 25106c3fb27SDimitry Andric 25206c3fb27SDimitry Andric expandMemSetAsLoop(Memset); 25306c3fb27SDimitry Andric Changed = true; 25406c3fb27SDimitry Andric Memset->eraseFromParent(); 25506c3fb27SDimitry Andric } 25606c3fb27SDimitry Andric 25706c3fb27SDimitry Andric break; 25806c3fb27SDimitry Andric } 25906c3fb27SDimitry Andric default: 26006c3fb27SDimitry Andric llvm_unreachable("unhandled intrinsic"); 26106c3fb27SDimitry Andric } 26206c3fb27SDimitry Andric } 26306c3fb27SDimitry Andric 26406c3fb27SDimitry Andric return Changed; 26506c3fb27SDimitry Andric } 26606c3fb27SDimitry Andric 26706c3fb27SDimitry Andric bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const { 2680b57cec5SDimitry Andric bool Changed = false; 2690b57cec5SDimitry Andric for (Function &F : M) { 2700b57cec5SDimitry Andric switch (F.getIntrinsicID()) { 2710b57cec5SDimitry Andric default: 2720b57cec5SDimitry Andric break; 27306c3fb27SDimitry Andric case Intrinsic::memcpy: 27406c3fb27SDimitry Andric case Intrinsic::memmove: 27506c3fb27SDimitry Andric case Intrinsic::memset: 27606c3fb27SDimitry Andric Changed |= expandMemIntrinsicUses(F); 27706c3fb27SDimitry Andric break; 27806c3fb27SDimitry Andric case Intrinsic::load_relative: 27906c3fb27SDimitry Andric Changed |= lowerLoadRelative(F); 28006c3fb27SDimitry Andric break; 2810b57cec5SDimitry Andric case Intrinsic::objc_autorelease: 2820b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autorelease"); 2830b57cec5SDimitry Andric break; 2840b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPop: 2850b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); 2860b57cec5SDimitry Andric break; 2870b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPush: 2880b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); 2890b57cec5SDimitry Andric break; 2900b57cec5SDimitry Andric case Intrinsic::objc_autoreleaseReturnValue: 2910b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); 2920b57cec5SDimitry Andric break; 2930b57cec5SDimitry Andric case Intrinsic::objc_copyWeak: 2940b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_copyWeak"); 2950b57cec5SDimitry Andric break; 2960b57cec5SDimitry Andric case Intrinsic::objc_destroyWeak: 2970b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_destroyWeak"); 2980b57cec5SDimitry Andric break; 2990b57cec5SDimitry Andric case Intrinsic::objc_initWeak: 3000b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_initWeak"); 3010b57cec5SDimitry Andric break; 3020b57cec5SDimitry Andric case Intrinsic::objc_loadWeak: 3030b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeak"); 3040b57cec5SDimitry Andric break; 3050b57cec5SDimitry Andric case Intrinsic::objc_loadWeakRetained: 3060b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); 3070b57cec5SDimitry Andric break; 3080b57cec5SDimitry Andric case Intrinsic::objc_moveWeak: 3090b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_moveWeak"); 3100b57cec5SDimitry Andric break; 3110b57cec5SDimitry Andric case Intrinsic::objc_release: 3120b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_release", true); 3130b57cec5SDimitry Andric break; 3140b57cec5SDimitry Andric case Intrinsic::objc_retain: 3150b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain", true); 3160b57cec5SDimitry Andric break; 3170b57cec5SDimitry Andric case Intrinsic::objc_retainAutorelease: 3180b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutorelease"); 3190b57cec5SDimitry Andric break; 3200b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleaseReturnValue: 3210b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); 3220b57cec5SDimitry Andric break; 3230b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleasedReturnValue: 3240b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); 3250b57cec5SDimitry Andric break; 3260b57cec5SDimitry Andric case Intrinsic::objc_retainBlock: 3270b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainBlock"); 3280b57cec5SDimitry Andric break; 3290b57cec5SDimitry Andric case Intrinsic::objc_storeStrong: 3300b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeStrong"); 3310b57cec5SDimitry Andric break; 3320b57cec5SDimitry Andric case Intrinsic::objc_storeWeak: 3330b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeWeak"); 3340b57cec5SDimitry Andric break; 3350b57cec5SDimitry Andric case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: 3360b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); 3370b57cec5SDimitry Andric break; 3380b57cec5SDimitry Andric case Intrinsic::objc_retainedObject: 3390b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainedObject"); 3400b57cec5SDimitry Andric break; 3410b57cec5SDimitry Andric case Intrinsic::objc_unretainedObject: 3420b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedObject"); 3430b57cec5SDimitry Andric break; 3440b57cec5SDimitry Andric case Intrinsic::objc_unretainedPointer: 3450b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedPointer"); 3460b57cec5SDimitry Andric break; 3470b57cec5SDimitry Andric case Intrinsic::objc_retain_autorelease: 3480b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain_autorelease"); 3490b57cec5SDimitry Andric break; 3500b57cec5SDimitry Andric case Intrinsic::objc_sync_enter: 3510b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_enter"); 3520b57cec5SDimitry Andric break; 3530b57cec5SDimitry Andric case Intrinsic::objc_sync_exit: 3540b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_exit"); 3550b57cec5SDimitry Andric break; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric return Changed; 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric namespace { 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass { 3640b57cec5SDimitry Andric public: 3650b57cec5SDimitry Andric static char ID; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} 3680b57cec5SDimitry Andric 36906c3fb27SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 37006c3fb27SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 371*8a4dda33SDimitry Andric AU.addRequired<TargetPassConfig>(); 37206c3fb27SDimitry Andric } 37306c3fb27SDimitry Andric 37406c3fb27SDimitry Andric bool runOnModule(Module &M) override { 37506c3fb27SDimitry Andric auto LookupTTI = [this](Function &F) -> TargetTransformInfo & { 37606c3fb27SDimitry Andric return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 37706c3fb27SDimitry Andric }; 37806c3fb27SDimitry Andric 379*8a4dda33SDimitry Andric const auto &TM = getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 380*8a4dda33SDimitry Andric PreISelIntrinsicLowering Lowering(TM, LookupTTI); 38106c3fb27SDimitry Andric return Lowering.lowerIntrinsics(M); 38206c3fb27SDimitry Andric } 3830b57cec5SDimitry Andric }; 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric } // end anonymous namespace 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID; 3880b57cec5SDimitry Andric 389*8a4dda33SDimitry Andric INITIALIZE_PASS_BEGIN(PreISelIntrinsicLoweringLegacyPass, 390*8a4dda33SDimitry Andric "pre-isel-intrinsic-lowering", 391*8a4dda33SDimitry Andric "Pre-ISel Intrinsic Lowering", false, false) 392*8a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 393*8a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 394*8a4dda33SDimitry Andric INITIALIZE_PASS_END(PreISelIntrinsicLoweringLegacyPass, 395*8a4dda33SDimitry Andric "pre-isel-intrinsic-lowering", 396*8a4dda33SDimitry Andric "Pre-ISel Intrinsic Lowering", false, false) 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() { 399*8a4dda33SDimitry Andric return new PreISelIntrinsicLoweringLegacyPass(); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, 4030b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 40406c3fb27SDimitry Andric auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 40506c3fb27SDimitry Andric 40606c3fb27SDimitry Andric auto LookupTTI = [&FAM](Function &F) -> TargetTransformInfo & { 40706c3fb27SDimitry Andric return FAM.getResult<TargetIRAnalysis>(F); 40806c3fb27SDimitry Andric }; 40906c3fb27SDimitry Andric 410*8a4dda33SDimitry Andric PreISelIntrinsicLowering Lowering(TM, LookupTTI); 41106c3fb27SDimitry Andric if (!Lowering.lowerIntrinsics(M)) 4120b57cec5SDimitry Andric return PreservedAnalyses::all(); 4130b57cec5SDimitry Andric else 4140b57cec5SDimitry Andric return PreservedAnalyses::none(); 4150b57cec5SDimitry Andric } 416