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 // 90b57cec5SDimitry Andric // This pass implements IR lowering for the llvm.load.relative and llvm.objc.* 100b57cec5SDimitry Andric // 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" 170b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 180b57cec5SDimitry Andric #include "llvm/IR/Function.h" 190b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 200b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 21480093f4SDimitry Andric #include "llvm/IR/Intrinsics.h" 220b57cec5SDimitry Andric #include "llvm/IR/Module.h" 230b57cec5SDimitry Andric #include "llvm/IR/Type.h" 240b57cec5SDimitry Andric #include "llvm/IR/User.h" 25480093f4SDimitry Andric #include "llvm/InitializePasses.h" 260b57cec5SDimitry Andric #include "llvm/Pass.h" 270b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric static bool lowerLoadRelative(Function &F) { 320b57cec5SDimitry Andric if (F.use_empty()) 330b57cec5SDimitry Andric return false; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric bool Changed = false; 360b57cec5SDimitry Andric Type *Int32Ty = Type::getInt32Ty(F.getContext()); 370b57cec5SDimitry Andric Type *Int32PtrTy = Int32Ty->getPointerTo(); 380b57cec5SDimitry Andric Type *Int8Ty = Type::getInt8Ty(F.getContext()); 390b57cec5SDimitry Andric 40349cc55cSDimitry Andric for (Use &U : llvm::make_early_inc_range(F.uses())) { 41349cc55cSDimitry Andric auto CI = dyn_cast<CallInst>(U.getUser()); 425ffd83dbSDimitry Andric if (!CI || CI->getCalledOperand() != &F) 430b57cec5SDimitry Andric continue; 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric IRBuilder<> B(CI); 460b57cec5SDimitry Andric Value *OffsetPtr = 470b57cec5SDimitry Andric B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1)); 480b57cec5SDimitry Andric Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy); 495ffd83dbSDimitry Andric Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, Align(4)); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32); 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric CI->replaceAllUsesWith(ResultPtr); 540b57cec5SDimitry Andric CI->eraseFromParent(); 550b57cec5SDimitry Andric Changed = true; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric return Changed; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 61480093f4SDimitry Andric // ObjCARC has knowledge about whether an obj-c runtime function needs to be 62480093f4SDimitry Andric // always tail-called or never tail-called. 63480093f4SDimitry Andric static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) { 64480093f4SDimitry Andric objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F); 65480093f4SDimitry Andric if (objcarc::IsAlwaysTail(Kind)) 66480093f4SDimitry Andric return CallInst::TCK_Tail; 67480093f4SDimitry Andric else if (objcarc::IsNeverTail(Kind)) 68480093f4SDimitry Andric return CallInst::TCK_NoTail; 69480093f4SDimitry Andric return CallInst::TCK_None; 70480093f4SDimitry Andric } 71480093f4SDimitry Andric 720b57cec5SDimitry Andric static bool lowerObjCCall(Function &F, const char *NewFn, 730b57cec5SDimitry Andric bool setNonLazyBind = false) { 740b57cec5SDimitry Andric if (F.use_empty()) 750b57cec5SDimitry Andric return false; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // If we haven't already looked up this function, check to see if the 780b57cec5SDimitry Andric // program already contains a function with this name. 790b57cec5SDimitry Andric Module *M = F.getParent(); 800b57cec5SDimitry Andric FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType()); 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) { 830b57cec5SDimitry Andric Fn->setLinkage(F.getLinkage()); 840b57cec5SDimitry Andric if (setNonLazyBind && !Fn->isWeakForLinker()) { 850b57cec5SDimitry Andric // If we have Native ARC, set nonlazybind attribute for these APIs for 860b57cec5SDimitry Andric // performance. 870b57cec5SDimitry Andric Fn->addFnAttr(Attribute::NonLazyBind); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 91480093f4SDimitry Andric CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F); 92480093f4SDimitry Andric 93349cc55cSDimitry Andric for (Use &U : llvm::make_early_inc_range(F.uses())) { 94349cc55cSDimitry Andric auto *CB = cast<CallBase>(U.getUser()); 95349cc55cSDimitry Andric 96349cc55cSDimitry Andric if (CB->getCalledFunction() != &F) { 97349cc55cSDimitry Andric objcarc::ARCInstKind Kind = objcarc::getAttachedARCFunctionKind(CB); 98349cc55cSDimitry Andric (void)Kind; 99349cc55cSDimitry Andric assert((Kind == objcarc::ARCInstKind::RetainRV || 100*04eeddc0SDimitry Andric Kind == objcarc::ARCInstKind::UnsafeClaimRV) && 101349cc55cSDimitry Andric "use expected to be the argument of operand bundle " 102349cc55cSDimitry Andric "\"clang.arc.attachedcall\""); 103349cc55cSDimitry Andric U.set(FCache.getCallee()); 104349cc55cSDimitry Andric continue; 105349cc55cSDimitry Andric } 106349cc55cSDimitry Andric 107349cc55cSDimitry Andric auto *CI = cast<CallInst>(CB); 1080b57cec5SDimitry Andric assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric IRBuilder<> Builder(CI->getParent(), CI->getIterator()); 111e8d8bef9SDimitry Andric SmallVector<Value *, 8> Args(CI->args()); 1120b57cec5SDimitry Andric CallInst *NewCI = Builder.CreateCall(FCache, Args); 1130b57cec5SDimitry Andric NewCI->setName(CI->getName()); 114480093f4SDimitry Andric 115480093f4SDimitry Andric // Try to set the most appropriate TailCallKind based on both the current 116480093f4SDimitry Andric // attributes and the ones that we could get from ObjCARC's special 117480093f4SDimitry Andric // knowledge of the runtime functions. 118480093f4SDimitry Andric // 119480093f4SDimitry Andric // std::max respects both requirements of notail and tail here: 120480093f4SDimitry Andric // * notail on either the call or from ObjCARC becomes notail 121480093f4SDimitry Andric // * tail on either side is stronger than none, but not notail 122480093f4SDimitry Andric CallInst::TailCallKind TCK = CI->getTailCallKind(); 123480093f4SDimitry Andric NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); 124480093f4SDimitry Andric 1250b57cec5SDimitry Andric if (!CI->use_empty()) 1260b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCI); 1270b57cec5SDimitry Andric CI->eraseFromParent(); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric return true; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric static bool lowerIntrinsics(Module &M) { 1340b57cec5SDimitry Andric bool Changed = false; 1350b57cec5SDimitry Andric for (Function &F : M) { 1360b57cec5SDimitry Andric if (F.getName().startswith("llvm.load.relative.")) { 1370b57cec5SDimitry Andric Changed |= lowerLoadRelative(F); 1380b57cec5SDimitry Andric continue; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric switch (F.getIntrinsicID()) { 1410b57cec5SDimitry Andric default: 1420b57cec5SDimitry Andric break; 1430b57cec5SDimitry Andric case Intrinsic::objc_autorelease: 1440b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autorelease"); 1450b57cec5SDimitry Andric break; 1460b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPop: 1470b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); 1480b57cec5SDimitry Andric break; 1490b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPush: 1500b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); 1510b57cec5SDimitry Andric break; 1520b57cec5SDimitry Andric case Intrinsic::objc_autoreleaseReturnValue: 1530b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); 1540b57cec5SDimitry Andric break; 1550b57cec5SDimitry Andric case Intrinsic::objc_copyWeak: 1560b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_copyWeak"); 1570b57cec5SDimitry Andric break; 1580b57cec5SDimitry Andric case Intrinsic::objc_destroyWeak: 1590b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_destroyWeak"); 1600b57cec5SDimitry Andric break; 1610b57cec5SDimitry Andric case Intrinsic::objc_initWeak: 1620b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_initWeak"); 1630b57cec5SDimitry Andric break; 1640b57cec5SDimitry Andric case Intrinsic::objc_loadWeak: 1650b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeak"); 1660b57cec5SDimitry Andric break; 1670b57cec5SDimitry Andric case Intrinsic::objc_loadWeakRetained: 1680b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); 1690b57cec5SDimitry Andric break; 1700b57cec5SDimitry Andric case Intrinsic::objc_moveWeak: 1710b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_moveWeak"); 1720b57cec5SDimitry Andric break; 1730b57cec5SDimitry Andric case Intrinsic::objc_release: 1740b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_release", true); 1750b57cec5SDimitry Andric break; 1760b57cec5SDimitry Andric case Intrinsic::objc_retain: 1770b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain", true); 1780b57cec5SDimitry Andric break; 1790b57cec5SDimitry Andric case Intrinsic::objc_retainAutorelease: 1800b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutorelease"); 1810b57cec5SDimitry Andric break; 1820b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleaseReturnValue: 1830b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); 1840b57cec5SDimitry Andric break; 1850b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleasedReturnValue: 1860b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); 1870b57cec5SDimitry Andric break; 1880b57cec5SDimitry Andric case Intrinsic::objc_retainBlock: 1890b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainBlock"); 1900b57cec5SDimitry Andric break; 1910b57cec5SDimitry Andric case Intrinsic::objc_storeStrong: 1920b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeStrong"); 1930b57cec5SDimitry Andric break; 1940b57cec5SDimitry Andric case Intrinsic::objc_storeWeak: 1950b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeWeak"); 1960b57cec5SDimitry Andric break; 1970b57cec5SDimitry Andric case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: 1980b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); 1990b57cec5SDimitry Andric break; 2000b57cec5SDimitry Andric case Intrinsic::objc_retainedObject: 2010b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainedObject"); 2020b57cec5SDimitry Andric break; 2030b57cec5SDimitry Andric case Intrinsic::objc_unretainedObject: 2040b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedObject"); 2050b57cec5SDimitry Andric break; 2060b57cec5SDimitry Andric case Intrinsic::objc_unretainedPointer: 2070b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedPointer"); 2080b57cec5SDimitry Andric break; 2090b57cec5SDimitry Andric case Intrinsic::objc_retain_autorelease: 2100b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain_autorelease"); 2110b57cec5SDimitry Andric break; 2120b57cec5SDimitry Andric case Intrinsic::objc_sync_enter: 2130b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_enter"); 2140b57cec5SDimitry Andric break; 2150b57cec5SDimitry Andric case Intrinsic::objc_sync_exit: 2160b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_exit"); 2170b57cec5SDimitry Andric break; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric return Changed; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric namespace { 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass { 2260b57cec5SDimitry Andric public: 2270b57cec5SDimitry Andric static char ID; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric bool runOnModule(Module &M) override { return lowerIntrinsics(M); } 2320b57cec5SDimitry Andric }; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric } // end anonymous namespace 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, 2390b57cec5SDimitry Andric "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", 2400b57cec5SDimitry Andric false, false) 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() { 2430b57cec5SDimitry Andric return new PreISelIntrinsicLoweringLegacyPass; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, 2470b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 2480b57cec5SDimitry Andric if (!lowerIntrinsics(M)) 2490b57cec5SDimitry Andric return PreservedAnalyses::all(); 2500b57cec5SDimitry Andric else 2510b57cec5SDimitry Andric return PreservedAnalyses::none(); 2520b57cec5SDimitry Andric } 253