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 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 = 837a6dacacSDimitry Andric B.CreatePtrAdd(CI->getArgOperand(0), CI->getArgOperand(1)); 845f757f3fSDimitry Andric Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtr, Align(4)); 850b57cec5SDimitry Andric 867a6dacacSDimitry Andric Value *ResultPtr = B.CreatePtrAdd(CI->getArgOperand(0), OffsetI32); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric CI->replaceAllUsesWith(ResultPtr); 890b57cec5SDimitry Andric CI->eraseFromParent(); 900b57cec5SDimitry Andric Changed = true; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric return Changed; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 96480093f4SDimitry Andric // ObjCARC has knowledge about whether an obj-c runtime function needs to be 97480093f4SDimitry Andric // always tail-called or never tail-called. 98480093f4SDimitry Andric static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) { 99480093f4SDimitry Andric objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F); 100480093f4SDimitry Andric if (objcarc::IsAlwaysTail(Kind)) 101480093f4SDimitry Andric return CallInst::TCK_Tail; 102480093f4SDimitry Andric else if (objcarc::IsNeverTail(Kind)) 103480093f4SDimitry Andric return CallInst::TCK_NoTail; 104480093f4SDimitry Andric return CallInst::TCK_None; 105480093f4SDimitry Andric } 106480093f4SDimitry Andric 1070b57cec5SDimitry Andric static bool lowerObjCCall(Function &F, const char *NewFn, 1080b57cec5SDimitry Andric bool setNonLazyBind = false) { 109972a253aSDimitry Andric assert(IntrinsicInst::mayLowerToFunctionCall(F.getIntrinsicID()) && 110972a253aSDimitry Andric "Pre-ISel intrinsics do lower into regular function calls"); 1110b57cec5SDimitry Andric if (F.use_empty()) 1120b57cec5SDimitry Andric return false; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // If we haven't already looked up this function, check to see if the 1150b57cec5SDimitry Andric // program already contains a function with this name. 1160b57cec5SDimitry Andric Module *M = F.getParent(); 1170b57cec5SDimitry Andric FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType()); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) { 1200b57cec5SDimitry Andric Fn->setLinkage(F.getLinkage()); 1210b57cec5SDimitry Andric if (setNonLazyBind && !Fn->isWeakForLinker()) { 1220b57cec5SDimitry Andric // If we have Native ARC, set nonlazybind attribute for these APIs for 1230b57cec5SDimitry Andric // performance. 1240b57cec5SDimitry Andric Fn->addFnAttr(Attribute::NonLazyBind); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 128480093f4SDimitry Andric CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F); 129480093f4SDimitry Andric 130349cc55cSDimitry Andric for (Use &U : llvm::make_early_inc_range(F.uses())) { 131349cc55cSDimitry Andric auto *CB = cast<CallBase>(U.getUser()); 132349cc55cSDimitry Andric 133349cc55cSDimitry Andric if (CB->getCalledFunction() != &F) { 134349cc55cSDimitry Andric objcarc::ARCInstKind Kind = objcarc::getAttachedARCFunctionKind(CB); 135349cc55cSDimitry Andric (void)Kind; 136349cc55cSDimitry Andric assert((Kind == objcarc::ARCInstKind::RetainRV || 13704eeddc0SDimitry Andric Kind == objcarc::ARCInstKind::UnsafeClaimRV) && 138349cc55cSDimitry Andric "use expected to be the argument of operand bundle " 139349cc55cSDimitry Andric "\"clang.arc.attachedcall\""); 140349cc55cSDimitry Andric U.set(FCache.getCallee()); 141349cc55cSDimitry Andric continue; 142349cc55cSDimitry Andric } 143349cc55cSDimitry Andric 144349cc55cSDimitry Andric auto *CI = cast<CallInst>(CB); 1450b57cec5SDimitry Andric assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric IRBuilder<> Builder(CI->getParent(), CI->getIterator()); 148e8d8bef9SDimitry Andric SmallVector<Value *, 8> Args(CI->args()); 149972a253aSDimitry Andric SmallVector<llvm::OperandBundleDef, 1> BundleList; 150972a253aSDimitry Andric CI->getOperandBundlesAsDefs(BundleList); 151972a253aSDimitry Andric CallInst *NewCI = Builder.CreateCall(FCache, Args, BundleList); 1520b57cec5SDimitry Andric NewCI->setName(CI->getName()); 153480093f4SDimitry Andric 154480093f4SDimitry Andric // Try to set the most appropriate TailCallKind based on both the current 155480093f4SDimitry Andric // attributes and the ones that we could get from ObjCARC's special 156480093f4SDimitry Andric // knowledge of the runtime functions. 157480093f4SDimitry Andric // 158480093f4SDimitry Andric // std::max respects both requirements of notail and tail here: 159480093f4SDimitry Andric // * notail on either the call or from ObjCARC becomes notail 160480093f4SDimitry Andric // * tail on either side is stronger than none, but not notail 161480093f4SDimitry Andric CallInst::TailCallKind TCK = CI->getTailCallKind(); 162480093f4SDimitry Andric NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); 163480093f4SDimitry Andric 1645f757f3fSDimitry Andric // Transfer the 'returned' attribute from the intrinsic to the call site. 1655f757f3fSDimitry Andric // By applying this only to intrinsic call sites, we avoid applying it to 1665f757f3fSDimitry Andric // non-ARC explicit calls to things like objc_retain which have not been 1675f757f3fSDimitry Andric // auto-upgraded to use the intrinsics. 1685f757f3fSDimitry Andric unsigned Index; 1695f757f3fSDimitry Andric if (F.getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) && 1705f757f3fSDimitry Andric Index) 1715f757f3fSDimitry Andric NewCI->addParamAttr(Index - AttributeList::FirstArgIndex, 1725f757f3fSDimitry Andric Attribute::Returned); 1735f757f3fSDimitry Andric 1740b57cec5SDimitry Andric if (!CI->use_empty()) 1750b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCI); 1760b57cec5SDimitry Andric CI->eraseFromParent(); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric return true; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 18206c3fb27SDimitry Andric // TODO: Should refine based on estimated number of accesses (e.g. does it 18306c3fb27SDimitry Andric // require splitting based on alignment) 18406c3fb27SDimitry Andric bool PreISelIntrinsicLowering::shouldExpandMemIntrinsicWithSize( 18506c3fb27SDimitry Andric Value *Size, const TargetTransformInfo &TTI) { 18606c3fb27SDimitry Andric ConstantInt *CI = dyn_cast<ConstantInt>(Size); 18706c3fb27SDimitry Andric if (!CI) 18806c3fb27SDimitry Andric return true; 18906c3fb27SDimitry Andric uint64_t Threshold = MemIntrinsicExpandSizeThresholdOpt.getNumOccurrences() 19006c3fb27SDimitry Andric ? MemIntrinsicExpandSizeThresholdOpt 19106c3fb27SDimitry Andric : TTI.getMaxMemIntrinsicInlineSizeThreshold(); 19206c3fb27SDimitry Andric uint64_t SizeVal = CI->getZExtValue(); 19306c3fb27SDimitry Andric 19406c3fb27SDimitry Andric // Treat a threshold of 0 as a special case to force expansion of all 19506c3fb27SDimitry Andric // intrinsics, including size 0. 19606c3fb27SDimitry Andric return SizeVal > Threshold || Threshold == 0; 19706c3fb27SDimitry Andric } 19806c3fb27SDimitry Andric 1998a4dda33SDimitry Andric static bool canEmitLibcall(const TargetMachine &TM, Function *F, 2008a4dda33SDimitry Andric RTLIB::Libcall LC) { 2018a4dda33SDimitry Andric // TODO: Should this consider the address space of the memcpy? 2028a4dda33SDimitry Andric const TargetLowering *TLI = TM.getSubtargetImpl(*F)->getTargetLowering(); 2038a4dda33SDimitry Andric return TLI->getLibcallName(LC) != nullptr; 2048a4dda33SDimitry Andric } 2058a4dda33SDimitry Andric 20606c3fb27SDimitry Andric // TODO: Handle atomic memcpy and memcpy.inline 20706c3fb27SDimitry Andric // TODO: Pass ScalarEvolution 20806c3fb27SDimitry Andric bool PreISelIntrinsicLowering::expandMemIntrinsicUses(Function &F) const { 20906c3fb27SDimitry Andric Intrinsic::ID ID = F.getIntrinsicID(); 21006c3fb27SDimitry Andric bool Changed = false; 21106c3fb27SDimitry Andric 21206c3fb27SDimitry Andric for (User *U : llvm::make_early_inc_range(F.users())) { 21306c3fb27SDimitry Andric Instruction *Inst = cast<Instruction>(U); 21406c3fb27SDimitry Andric 21506c3fb27SDimitry Andric switch (ID) { 21606c3fb27SDimitry Andric case Intrinsic::memcpy: { 21706c3fb27SDimitry Andric auto *Memcpy = cast<MemCpyInst>(Inst); 21806c3fb27SDimitry Andric Function *ParentFunc = Memcpy->getFunction(); 21906c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 22006c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memcpy->getLength(), TTI)) { 22106c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 2228a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMCPY)) 22306c3fb27SDimitry Andric break; 22406c3fb27SDimitry Andric 2258a4dda33SDimitry Andric // TODO: For optsize, emit the loop into a separate function 22606c3fb27SDimitry Andric expandMemCpyAsLoop(Memcpy, TTI); 22706c3fb27SDimitry Andric Changed = true; 22806c3fb27SDimitry Andric Memcpy->eraseFromParent(); 22906c3fb27SDimitry Andric } 23006c3fb27SDimitry Andric 23106c3fb27SDimitry Andric break; 23206c3fb27SDimitry Andric } 233*0fca6ea1SDimitry Andric case Intrinsic::memcpy_inline: { 234*0fca6ea1SDimitry Andric // Only expand llvm.memcpy.inline with non-constant length in this 235*0fca6ea1SDimitry Andric // codepath, leaving the current SelectionDAG expansion for constant 236*0fca6ea1SDimitry Andric // length memcpy intrinsics undisturbed. 237*0fca6ea1SDimitry Andric auto *Memcpy = cast<MemCpyInlineInst>(Inst); 238*0fca6ea1SDimitry Andric if (isa<ConstantInt>(Memcpy->getLength())) 239*0fca6ea1SDimitry Andric break; 240*0fca6ea1SDimitry Andric 241*0fca6ea1SDimitry Andric Function *ParentFunc = Memcpy->getFunction(); 242*0fca6ea1SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 243*0fca6ea1SDimitry Andric expandMemCpyAsLoop(Memcpy, TTI); 244*0fca6ea1SDimitry Andric Changed = true; 245*0fca6ea1SDimitry Andric Memcpy->eraseFromParent(); 246*0fca6ea1SDimitry Andric break; 247*0fca6ea1SDimitry Andric } 24806c3fb27SDimitry Andric case Intrinsic::memmove: { 24906c3fb27SDimitry Andric auto *Memmove = cast<MemMoveInst>(Inst); 25006c3fb27SDimitry Andric Function *ParentFunc = Memmove->getFunction(); 25106c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 25206c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memmove->getLength(), TTI)) { 25306c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 2548a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMMOVE)) 25506c3fb27SDimitry Andric break; 25606c3fb27SDimitry Andric 25706c3fb27SDimitry Andric if (expandMemMoveAsLoop(Memmove, TTI)) { 25806c3fb27SDimitry Andric Changed = true; 25906c3fb27SDimitry Andric Memmove->eraseFromParent(); 26006c3fb27SDimitry Andric } 26106c3fb27SDimitry Andric } 26206c3fb27SDimitry Andric 26306c3fb27SDimitry Andric break; 26406c3fb27SDimitry Andric } 26506c3fb27SDimitry Andric case Intrinsic::memset: { 26606c3fb27SDimitry Andric auto *Memset = cast<MemSetInst>(Inst); 26706c3fb27SDimitry Andric Function *ParentFunc = Memset->getFunction(); 26806c3fb27SDimitry Andric const TargetTransformInfo &TTI = LookupTTI(*ParentFunc); 26906c3fb27SDimitry Andric if (shouldExpandMemIntrinsicWithSize(Memset->getLength(), TTI)) { 27006c3fb27SDimitry Andric if (UseMemIntrinsicLibFunc && 2718a4dda33SDimitry Andric canEmitLibcall(TM, ParentFunc, RTLIB::MEMSET)) 27206c3fb27SDimitry Andric break; 27306c3fb27SDimitry Andric 27406c3fb27SDimitry Andric expandMemSetAsLoop(Memset); 27506c3fb27SDimitry Andric Changed = true; 27606c3fb27SDimitry Andric Memset->eraseFromParent(); 27706c3fb27SDimitry Andric } 27806c3fb27SDimitry Andric 27906c3fb27SDimitry Andric break; 28006c3fb27SDimitry Andric } 281*0fca6ea1SDimitry Andric case Intrinsic::memset_inline: { 282*0fca6ea1SDimitry Andric // Only expand llvm.memset.inline with non-constant length in this 283*0fca6ea1SDimitry Andric // codepath, leaving the current SelectionDAG expansion for constant 284*0fca6ea1SDimitry Andric // length memset intrinsics undisturbed. 285*0fca6ea1SDimitry Andric auto *Memset = cast<MemSetInlineInst>(Inst); 286*0fca6ea1SDimitry Andric if (isa<ConstantInt>(Memset->getLength())) 287*0fca6ea1SDimitry Andric break; 288*0fca6ea1SDimitry Andric 289*0fca6ea1SDimitry Andric expandMemSetAsLoop(Memset); 290*0fca6ea1SDimitry Andric Changed = true; 291*0fca6ea1SDimitry Andric Memset->eraseFromParent(); 292*0fca6ea1SDimitry Andric break; 293*0fca6ea1SDimitry Andric } 29406c3fb27SDimitry Andric default: 29506c3fb27SDimitry Andric llvm_unreachable("unhandled intrinsic"); 29606c3fb27SDimitry Andric } 29706c3fb27SDimitry Andric } 29806c3fb27SDimitry Andric 29906c3fb27SDimitry Andric return Changed; 30006c3fb27SDimitry Andric } 30106c3fb27SDimitry Andric 30206c3fb27SDimitry Andric bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const { 3030b57cec5SDimitry Andric bool Changed = false; 3040b57cec5SDimitry Andric for (Function &F : M) { 3050b57cec5SDimitry Andric switch (F.getIntrinsicID()) { 3060b57cec5SDimitry Andric default: 3070b57cec5SDimitry Andric break; 30806c3fb27SDimitry Andric case Intrinsic::memcpy: 309*0fca6ea1SDimitry Andric case Intrinsic::memcpy_inline: 31006c3fb27SDimitry Andric case Intrinsic::memmove: 31106c3fb27SDimitry Andric case Intrinsic::memset: 312*0fca6ea1SDimitry Andric case Intrinsic::memset_inline: 31306c3fb27SDimitry Andric Changed |= expandMemIntrinsicUses(F); 31406c3fb27SDimitry Andric break; 31506c3fb27SDimitry Andric case Intrinsic::load_relative: 31606c3fb27SDimitry Andric Changed |= lowerLoadRelative(F); 31706c3fb27SDimitry Andric break; 3180b57cec5SDimitry Andric case Intrinsic::objc_autorelease: 3190b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autorelease"); 3200b57cec5SDimitry Andric break; 3210b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPop: 3220b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); 3230b57cec5SDimitry Andric break; 3240b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPush: 3250b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); 3260b57cec5SDimitry Andric break; 3270b57cec5SDimitry Andric case Intrinsic::objc_autoreleaseReturnValue: 3280b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); 3290b57cec5SDimitry Andric break; 3300b57cec5SDimitry Andric case Intrinsic::objc_copyWeak: 3310b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_copyWeak"); 3320b57cec5SDimitry Andric break; 3330b57cec5SDimitry Andric case Intrinsic::objc_destroyWeak: 3340b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_destroyWeak"); 3350b57cec5SDimitry Andric break; 3360b57cec5SDimitry Andric case Intrinsic::objc_initWeak: 3370b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_initWeak"); 3380b57cec5SDimitry Andric break; 3390b57cec5SDimitry Andric case Intrinsic::objc_loadWeak: 3400b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeak"); 3410b57cec5SDimitry Andric break; 3420b57cec5SDimitry Andric case Intrinsic::objc_loadWeakRetained: 3430b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); 3440b57cec5SDimitry Andric break; 3450b57cec5SDimitry Andric case Intrinsic::objc_moveWeak: 3460b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_moveWeak"); 3470b57cec5SDimitry Andric break; 3480b57cec5SDimitry Andric case Intrinsic::objc_release: 3490b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_release", true); 3500b57cec5SDimitry Andric break; 3510b57cec5SDimitry Andric case Intrinsic::objc_retain: 3520b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain", true); 3530b57cec5SDimitry Andric break; 3540b57cec5SDimitry Andric case Intrinsic::objc_retainAutorelease: 3550b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutorelease"); 3560b57cec5SDimitry Andric break; 3570b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleaseReturnValue: 3580b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); 3590b57cec5SDimitry Andric break; 3600b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleasedReturnValue: 3610b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); 3620b57cec5SDimitry Andric break; 3630b57cec5SDimitry Andric case Intrinsic::objc_retainBlock: 3640b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainBlock"); 3650b57cec5SDimitry Andric break; 3660b57cec5SDimitry Andric case Intrinsic::objc_storeStrong: 3670b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeStrong"); 3680b57cec5SDimitry Andric break; 3690b57cec5SDimitry Andric case Intrinsic::objc_storeWeak: 3700b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeWeak"); 3710b57cec5SDimitry Andric break; 3720b57cec5SDimitry Andric case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: 3730b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); 3740b57cec5SDimitry Andric break; 3750b57cec5SDimitry Andric case Intrinsic::objc_retainedObject: 3760b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainedObject"); 3770b57cec5SDimitry Andric break; 3780b57cec5SDimitry Andric case Intrinsic::objc_unretainedObject: 3790b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedObject"); 3800b57cec5SDimitry Andric break; 3810b57cec5SDimitry Andric case Intrinsic::objc_unretainedPointer: 3820b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedPointer"); 3830b57cec5SDimitry Andric break; 3840b57cec5SDimitry Andric case Intrinsic::objc_retain_autorelease: 3850b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain_autorelease"); 3860b57cec5SDimitry Andric break; 3870b57cec5SDimitry Andric case Intrinsic::objc_sync_enter: 3880b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_enter"); 3890b57cec5SDimitry Andric break; 3900b57cec5SDimitry Andric case Intrinsic::objc_sync_exit: 3910b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_exit"); 3920b57cec5SDimitry Andric break; 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric } 3950b57cec5SDimitry Andric return Changed; 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric namespace { 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass { 4010b57cec5SDimitry Andric public: 4020b57cec5SDimitry Andric static char ID; 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} 4050b57cec5SDimitry Andric 40606c3fb27SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 40706c3fb27SDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>(); 4088a4dda33SDimitry Andric AU.addRequired<TargetPassConfig>(); 40906c3fb27SDimitry Andric } 41006c3fb27SDimitry Andric 41106c3fb27SDimitry Andric bool runOnModule(Module &M) override { 41206c3fb27SDimitry Andric auto LookupTTI = [this](Function &F) -> TargetTransformInfo & { 41306c3fb27SDimitry Andric return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); 41406c3fb27SDimitry Andric }; 41506c3fb27SDimitry Andric 4168a4dda33SDimitry Andric const auto &TM = getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 4178a4dda33SDimitry Andric PreISelIntrinsicLowering Lowering(TM, LookupTTI); 41806c3fb27SDimitry Andric return Lowering.lowerIntrinsics(M); 41906c3fb27SDimitry Andric } 4200b57cec5SDimitry Andric }; 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric } // end anonymous namespace 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID; 4250b57cec5SDimitry Andric 4268a4dda33SDimitry Andric INITIALIZE_PASS_BEGIN(PreISelIntrinsicLoweringLegacyPass, 4278a4dda33SDimitry Andric "pre-isel-intrinsic-lowering", 4288a4dda33SDimitry Andric "Pre-ISel Intrinsic Lowering", false, false) 4298a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 4308a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) 4318a4dda33SDimitry Andric INITIALIZE_PASS_END(PreISelIntrinsicLoweringLegacyPass, 4328a4dda33SDimitry Andric "pre-isel-intrinsic-lowering", 4338a4dda33SDimitry Andric "Pre-ISel Intrinsic Lowering", false, false) 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() { 4368a4dda33SDimitry Andric return new PreISelIntrinsicLoweringLegacyPass(); 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, 4400b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 44106c3fb27SDimitry Andric auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 44206c3fb27SDimitry Andric 44306c3fb27SDimitry Andric auto LookupTTI = [&FAM](Function &F) -> TargetTransformInfo & { 44406c3fb27SDimitry Andric return FAM.getResult<TargetIRAnalysis>(F); 44506c3fb27SDimitry Andric }; 44606c3fb27SDimitry Andric 4478a4dda33SDimitry Andric PreISelIntrinsicLowering Lowering(TM, LookupTTI); 44806c3fb27SDimitry Andric if (!Lowering.lowerIntrinsics(M)) 4490b57cec5SDimitry Andric return PreservedAnalyses::all(); 4500b57cec5SDimitry Andric else 4510b57cec5SDimitry Andric return PreservedAnalyses::none(); 4520b57cec5SDimitry Andric } 453