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" 150b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 160b57cec5SDimitry Andric #include "llvm/IR/Function.h" 170b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 180b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 190b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 200b57cec5SDimitry Andric #include "llvm/IR/Module.h" 210b57cec5SDimitry Andric #include "llvm/IR/Type.h" 220b57cec5SDimitry Andric #include "llvm/IR/User.h" 230b57cec5SDimitry Andric #include "llvm/Pass.h" 240b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric static bool lowerLoadRelative(Function &F) { 290b57cec5SDimitry Andric if (F.use_empty()) 300b57cec5SDimitry Andric return false; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric bool Changed = false; 330b57cec5SDimitry Andric Type *Int32Ty = Type::getInt32Ty(F.getContext()); 340b57cec5SDimitry Andric Type *Int32PtrTy = Int32Ty->getPointerTo(); 350b57cec5SDimitry Andric Type *Int8Ty = Type::getInt8Ty(F.getContext()); 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric for (auto I = F.use_begin(), E = F.use_end(); I != E;) { 380b57cec5SDimitry Andric auto CI = dyn_cast<CallInst>(I->getUser()); 390b57cec5SDimitry Andric ++I; 400b57cec5SDimitry Andric if (!CI || CI->getCalledValue() != &F) 410b57cec5SDimitry Andric continue; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric IRBuilder<> B(CI); 440b57cec5SDimitry Andric Value *OffsetPtr = 450b57cec5SDimitry Andric B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1)); 460b57cec5SDimitry Andric Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy); 470b57cec5SDimitry Andric Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtrI32, 4); 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric CI->replaceAllUsesWith(ResultPtr); 520b57cec5SDimitry Andric CI->eraseFromParent(); 530b57cec5SDimitry Andric Changed = true; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric return Changed; 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric static bool lowerObjCCall(Function &F, const char *NewFn, 600b57cec5SDimitry Andric bool setNonLazyBind = false) { 610b57cec5SDimitry Andric if (F.use_empty()) 620b57cec5SDimitry Andric return false; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric // If we haven't already looked up this function, check to see if the 650b57cec5SDimitry Andric // program already contains a function with this name. 660b57cec5SDimitry Andric Module *M = F.getParent(); 670b57cec5SDimitry Andric FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType()); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) { 700b57cec5SDimitry Andric Fn->setLinkage(F.getLinkage()); 710b57cec5SDimitry Andric if (setNonLazyBind && !Fn->isWeakForLinker()) { 720b57cec5SDimitry Andric // If we have Native ARC, set nonlazybind attribute for these APIs for 730b57cec5SDimitry Andric // performance. 740b57cec5SDimitry Andric Fn->addFnAttr(Attribute::NonLazyBind); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric for (auto I = F.use_begin(), E = F.use_end(); I != E;) { 79*8bcb0991SDimitry Andric auto *CI = cast<CallInst>(I->getUser()); 800b57cec5SDimitry Andric assert(CI->getCalledFunction() && "Cannot lower an indirect call!"); 810b57cec5SDimitry Andric ++I; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric IRBuilder<> Builder(CI->getParent(), CI->getIterator()); 840b57cec5SDimitry Andric SmallVector<Value *, 8> Args(CI->arg_begin(), CI->arg_end()); 850b57cec5SDimitry Andric CallInst *NewCI = Builder.CreateCall(FCache, Args); 860b57cec5SDimitry Andric NewCI->setName(CI->getName()); 870b57cec5SDimitry Andric NewCI->setTailCallKind(CI->getTailCallKind()); 880b57cec5SDimitry Andric if (!CI->use_empty()) 890b57cec5SDimitry Andric CI->replaceAllUsesWith(NewCI); 900b57cec5SDimitry Andric CI->eraseFromParent(); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric return true; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric static bool lowerIntrinsics(Module &M) { 970b57cec5SDimitry Andric bool Changed = false; 980b57cec5SDimitry Andric for (Function &F : M) { 990b57cec5SDimitry Andric if (F.getName().startswith("llvm.load.relative.")) { 1000b57cec5SDimitry Andric Changed |= lowerLoadRelative(F); 1010b57cec5SDimitry Andric continue; 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric switch (F.getIntrinsicID()) { 1040b57cec5SDimitry Andric default: 1050b57cec5SDimitry Andric break; 1060b57cec5SDimitry Andric case Intrinsic::objc_autorelease: 1070b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autorelease"); 1080b57cec5SDimitry Andric break; 1090b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPop: 1100b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop"); 1110b57cec5SDimitry Andric break; 1120b57cec5SDimitry Andric case Intrinsic::objc_autoreleasePoolPush: 1130b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush"); 1140b57cec5SDimitry Andric break; 1150b57cec5SDimitry Andric case Intrinsic::objc_autoreleaseReturnValue: 1160b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue"); 1170b57cec5SDimitry Andric break; 1180b57cec5SDimitry Andric case Intrinsic::objc_copyWeak: 1190b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_copyWeak"); 1200b57cec5SDimitry Andric break; 1210b57cec5SDimitry Andric case Intrinsic::objc_destroyWeak: 1220b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_destroyWeak"); 1230b57cec5SDimitry Andric break; 1240b57cec5SDimitry Andric case Intrinsic::objc_initWeak: 1250b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_initWeak"); 1260b57cec5SDimitry Andric break; 1270b57cec5SDimitry Andric case Intrinsic::objc_loadWeak: 1280b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeak"); 1290b57cec5SDimitry Andric break; 1300b57cec5SDimitry Andric case Intrinsic::objc_loadWeakRetained: 1310b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_loadWeakRetained"); 1320b57cec5SDimitry Andric break; 1330b57cec5SDimitry Andric case Intrinsic::objc_moveWeak: 1340b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_moveWeak"); 1350b57cec5SDimitry Andric break; 1360b57cec5SDimitry Andric case Intrinsic::objc_release: 1370b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_release", true); 1380b57cec5SDimitry Andric break; 1390b57cec5SDimitry Andric case Intrinsic::objc_retain: 1400b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain", true); 1410b57cec5SDimitry Andric break; 1420b57cec5SDimitry Andric case Intrinsic::objc_retainAutorelease: 1430b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutorelease"); 1440b57cec5SDimitry Andric break; 1450b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleaseReturnValue: 1460b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue"); 1470b57cec5SDimitry Andric break; 1480b57cec5SDimitry Andric case Intrinsic::objc_retainAutoreleasedReturnValue: 1490b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue"); 1500b57cec5SDimitry Andric break; 1510b57cec5SDimitry Andric case Intrinsic::objc_retainBlock: 1520b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainBlock"); 1530b57cec5SDimitry Andric break; 1540b57cec5SDimitry Andric case Intrinsic::objc_storeStrong: 1550b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeStrong"); 1560b57cec5SDimitry Andric break; 1570b57cec5SDimitry Andric case Intrinsic::objc_storeWeak: 1580b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_storeWeak"); 1590b57cec5SDimitry Andric break; 1600b57cec5SDimitry Andric case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue: 1610b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue"); 1620b57cec5SDimitry Andric break; 1630b57cec5SDimitry Andric case Intrinsic::objc_retainedObject: 1640b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retainedObject"); 1650b57cec5SDimitry Andric break; 1660b57cec5SDimitry Andric case Intrinsic::objc_unretainedObject: 1670b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedObject"); 1680b57cec5SDimitry Andric break; 1690b57cec5SDimitry Andric case Intrinsic::objc_unretainedPointer: 1700b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_unretainedPointer"); 1710b57cec5SDimitry Andric break; 1720b57cec5SDimitry Andric case Intrinsic::objc_retain_autorelease: 1730b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_retain_autorelease"); 1740b57cec5SDimitry Andric break; 1750b57cec5SDimitry Andric case Intrinsic::objc_sync_enter: 1760b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_enter"); 1770b57cec5SDimitry Andric break; 1780b57cec5SDimitry Andric case Intrinsic::objc_sync_exit: 1790b57cec5SDimitry Andric Changed |= lowerObjCCall(F, "objc_sync_exit"); 1800b57cec5SDimitry Andric break; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric return Changed; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric namespace { 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass { 1890b57cec5SDimitry Andric public: 1900b57cec5SDimitry Andric static char ID; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {} 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric bool runOnModule(Module &M) override { return lowerIntrinsics(M); } 1950b57cec5SDimitry Andric }; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric } // end anonymous namespace 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID; 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass, 2020b57cec5SDimitry Andric "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering", 2030b57cec5SDimitry Andric false, false) 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() { 2060b57cec5SDimitry Andric return new PreISelIntrinsicLoweringLegacyPass; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M, 2100b57cec5SDimitry Andric ModuleAnalysisManager &AM) { 2110b57cec5SDimitry Andric if (!lowerIntrinsics(M)) 2120b57cec5SDimitry Andric return PreservedAnalyses::all(); 2130b57cec5SDimitry Andric else 2140b57cec5SDimitry Andric return PreservedAnalyses::none(); 2150b57cec5SDimitry Andric } 216