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" 15*480093f4SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 170b57cec5SDimitry Andric #include "llvm/IR/Function.h" 180b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 190b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 20*480093f4SDimitry Andric #include "llvm/IR/Intrinsics.h" 210b57cec5SDimitry Andric #include "llvm/IR/Module.h" 220b57cec5SDimitry Andric #include "llvm/IR/Type.h" 230b57cec5SDimitry Andric #include "llvm/IR/User.h" 24*480093f4SDimitry Andric #include "llvm/InitializePasses.h" 250b57cec5SDimitry Andric #include "llvm/Pass.h" 260b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric using namespace llvm; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric static bool lowerLoadRelative(Function &F) { 310b57cec5SDimitry Andric if (F.use_empty()) 320b57cec5SDimitry Andric return false; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric bool Changed = false; 350b57cec5SDimitry Andric Type *Int32Ty = Type::getInt32Ty(F.getContext()); 360b57cec5SDimitry Andric Type *Int32PtrTy = Int32Ty->getPointerTo(); 370b57cec5SDimitry Andric Type *Int8Ty = Type::getInt8Ty(F.getContext()); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric for (auto I = F.use_begin(), E = F.use_end(); I != E;) { 400b57cec5SDimitry Andric auto CI = dyn_cast<CallInst>(I->getUser()); 410b57cec5SDimitry Andric ++I; 420b57cec5SDimitry Andric if (!CI || CI->getCalledValue() != &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); 490b57cec5SDimitry Andric Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, 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 61*480093f4SDimitry Andric // ObjCARC has knowledge about whether an obj-c runtime function needs to be 62*480093f4SDimitry Andric // always tail-called or never tail-called. 63*480093f4SDimitry Andric static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) { 64*480093f4SDimitry Andric objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F); 65*480093f4SDimitry Andric if (objcarc::IsAlwaysTail(Kind)) 66*480093f4SDimitry Andric return CallInst::TCK_Tail; 67*480093f4SDimitry Andric else if (objcarc::IsNeverTail(Kind)) 68*480093f4SDimitry Andric return CallInst::TCK_NoTail; 69*480093f4SDimitry Andric return CallInst::TCK_None; 70*480093f4SDimitry Andric } 71*480093f4SDimitry 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 91*480093f4SDimitry Andric CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F); 92*480093f4SDimitry Andric 930b57cec5SDimitry Andric for (auto I = F.use_begin(), E = F.use_end(); I != E;) { 948bcb0991SDimitry Andric auto *CI = cast<CallInst>(I->getUser()); 950b57cec5SDimitry Andric assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); 960b57cec5SDimitry Andric ++I; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric IRBuilder<> Builder(CI->getParent(), CI->getIterator()); 990b57cec5SDimitry Andric SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end()); 1000b57cec5SDimitry Andric CallInst *NewCI = Builder.CreateCall(FCache, Args); 1010b57cec5SDimitry Andric NewCI->setName(CI->getName()); 102*480093f4SDimitry Andric 103*480093f4SDimitry Andric // Try to set the most appropriate TailCallKind based on both the current 104*480093f4SDimitry Andric // attributes and the ones that we could get from ObjCARC's special 105*480093f4SDimitry Andric // knowledge of the runtime functions. 106*480093f4SDimitry Andric // 107*480093f4SDimitry Andric // std::max respects both requirements of notail and tail here: 108*480093f4SDimitry Andric // * notail on either the call or from ObjCARC becomes notail 109*480093f4SDimitry Andric // * tail on either side is stronger than none, but not notail 110*480093f4SDimitry Andric CallInst::TailCallKind TCK = CI->getTailCallKind(); 111*480093f4SDimitry Andric NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); 112*480093f4SDimitry Andric 1130b57cec5SDimitry Andric if (!CI->use_empty()) 1140b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCI); 1150b57cec5SDimitry Andric CI->eraseFromParent(); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric return true; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric static bool lowerIntrinsics(Module &M) { 1220b57cec5SDimitry Andric bool Changed = false; 1230b57cec5SDimitry Andric for (Function &F : M) { 1240b57cec5SDimitry Andric if (F.getName().startswith("llvm.load.relative.")) { 1250b57cec5SDimitry Andric Changed |= lowerLoadRelative(F); 1260b57cec5SDimitry Andric continue; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric switch (F.getIntrinsicID()) { 1290b57cec5SDimitry Andric default: 1300b57cec5SDimitry Andric break; 1310b57cec5SDimitry Andric case Intrinsic::objc_autorelease: 1320b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autorelease"); 1330b57cec5SDimitry Andric break; 1340b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPop: 1350b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); 1360b57cec5SDimitry Andric break; 1370b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPush: 1380b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); 1390b57cec5SDimitry Andric break; 1400b57cec5SDimitry Andric case Intrinsic::objc_autoreleaseReturnValue: 1410b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); 1420b57cec5SDimitry Andric break; 1430b57cec5SDimitry Andric case Intrinsic::objc_copyWeak: 1440b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_copyWeak"); 1450b57cec5SDimitry Andric break; 1460b57cec5SDimitry Andric case Intrinsic::objc_destroyWeak: 1470b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_destroyWeak"); 1480b57cec5SDimitry Andric break; 1490b57cec5SDimitry Andric case Intrinsic::objc_initWeak: 1500b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_initWeak"); 1510b57cec5SDimitry Andric break; 1520b57cec5SDimitry Andric case Intrinsic::objc_loadWeak: 1530b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeak"); 1540b57cec5SDimitry Andric break; 1550b57cec5SDimitry Andric case Intrinsic::objc_loadWeakRetained: 1560b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); 1570b57cec5SDimitry Andric break; 1580b57cec5SDimitry Andric case Intrinsic::objc_moveWeak: 1590b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_moveWeak"); 1600b57cec5SDimitry Andric break; 1610b57cec5SDimitry Andric case Intrinsic::objc_release: 1620b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_release", true); 1630b57cec5SDimitry Andric break; 1640b57cec5SDimitry Andric case Intrinsic::objc_retain: 1650b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain", true); 1660b57cec5SDimitry Andric break; 1670b57cec5SDimitry Andric case Intrinsic::objc_retainAutorelease: 1680b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutorelease"); 1690b57cec5SDimitry Andric break; 1700b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleaseReturnValue: 1710b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); 1720b57cec5SDimitry Andric break; 1730b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleasedReturnValue: 1740b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); 1750b57cec5SDimitry Andric break; 1760b57cec5SDimitry Andric case Intrinsic::objc_retainBlock: 1770b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainBlock"); 1780b57cec5SDimitry Andric break; 1790b57cec5SDimitry Andric case Intrinsic::objc_storeStrong: 1800b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeStrong"); 1810b57cec5SDimitry Andric break; 1820b57cec5SDimitry Andric case Intrinsic::objc_storeWeak: 1830b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeWeak"); 1840b57cec5SDimitry Andric break; 1850b57cec5SDimitry Andric case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: 1860b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); 1870b57cec5SDimitry Andric break; 1880b57cec5SDimitry Andric case Intrinsic::objc_retainedObject: 1890b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainedObject"); 1900b57cec5SDimitry Andric break; 1910b57cec5SDimitry Andric case Intrinsic::objc_unretainedObject: 1920b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedObject"); 1930b57cec5SDimitry Andric break; 1940b57cec5SDimitry Andric case Intrinsic::objc_unretainedPointer: 1950b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedPointer"); 1960b57cec5SDimitry Andric break; 1970b57cec5SDimitry Andric case Intrinsic::objc_retain_autorelease: 1980b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain_autorelease"); 1990b57cec5SDimitry Andric break; 2000b57cec5SDimitry Andric case Intrinsic::objc_sync_enter: 2010b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_enter"); 2020b57cec5SDimitry Andric break; 2030b57cec5SDimitry Andric case Intrinsic::objc_sync_exit: 2040b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_exit"); 2050b57cec5SDimitry Andric break; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric return Changed; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric namespace { 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass { 2140b57cec5SDimitry Andric public: 2150b57cec5SDimitry Andric static char ID; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric bool runOnModule(Module &M) override { return lowerIntrinsics(M); } 2200b57cec5SDimitry Andric }; 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric } // end anonymous namespace 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, 2270b57cec5SDimitry Andric "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", 2280b57cec5SDimitry Andric false, false) 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() { 2310b57cec5SDimitry Andric return new PreISelIntrinsicLoweringLegacyPass; 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, 2350b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 2360b57cec5SDimitry Andric if (!lowerIntrinsics(M)) 2370b57cec5SDimitry Andric return PreservedAnalyses::all(); 2380b57cec5SDimitry Andric else 2390b57cec5SDimitry Andric return PreservedAnalyses::none(); 2400b57cec5SDimitry Andric } 241