//===-- ObjCARC.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements common infrastructure for libLLVMObjCARCOpts.a, which // implements several scalar transformations over the LLVM intermediate // representation, including the C bindings for that library. // //===----------------------------------------------------------------------===// #include "ObjCARC.h" #include "llvm/Analysis/ObjCARCUtil.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" using namespace llvm; using namespace llvm::objcarc; CallInst *objcarc::createCallInstWithColors( FunctionCallee Func, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore, const DenseMap &BlockColors) { FunctionType *FTy = Func.getFunctionType(); Value *Callee = Func.getCallee(); SmallVector OpBundles; if (!BlockColors.empty()) { const ColorVector &CV = BlockColors.find(InsertBefore->getParent())->second; assert(CV.size() == 1 && "non-unique color for block!"); Instruction *EHPad = CV.front()->getFirstNonPHI(); if (EHPad->isEHPad()) OpBundles.emplace_back("funclet", EHPad); } return CallInst::Create(FTy, Callee, Args, OpBundles, NameStr, InsertBefore); } std::pair BundledRetainClaimRVs::insertAfterInvokes(Function &F, DominatorTree *DT) { bool Changed = false, CFGChanged = false; for (BasicBlock &BB : F) { auto *I = dyn_cast(BB.getTerminator()); if (!I) continue; if (!objcarc::hasAttachedCallOpBundle(I)) continue; BasicBlock *DestBB = I->getNormalDest(); if (!DestBB->getSinglePredecessor()) { assert(I->getSuccessor(0) == DestBB && "the normal dest is expected to be the first successor"); DestBB = SplitCriticalEdge(I, 0, CriticalEdgeSplittingOptions(DT)); CFGChanged = true; } // We don't have to call insertRVCallWithColors since DestBB is the normal // destination of the invoke. insertRVCall(&*DestBB->getFirstInsertionPt(), I); Changed = true; } return std::make_pair(Changed, CFGChanged); } CallInst *BundledRetainClaimRVs::insertRVCall(Instruction *InsertPt, CallBase *AnnotatedCall) { DenseMap BlockColors; return insertRVCallWithColors(InsertPt, AnnotatedCall, BlockColors); } CallInst *BundledRetainClaimRVs::insertRVCallWithColors( Instruction *InsertPt, CallBase *AnnotatedCall, const DenseMap &BlockColors) { IRBuilder<> Builder(InsertPt); Function *Func = *objcarc::getAttachedARCFunction(AnnotatedCall); assert(Func && "operand isn't a Function"); Type *ParamTy = Func->getArg(0)->getType(); Value *CallArg = Builder.CreateBitCast(AnnotatedCall, ParamTy); auto *Call = createCallInstWithColors(Func, CallArg, "", InsertPt, BlockColors); RVCalls[Call] = AnnotatedCall; return Call; } BundledRetainClaimRVs::~BundledRetainClaimRVs() { for (auto P : RVCalls) { if (ContractPass) { CallBase *CB = P.second; // At this point, we know that the annotated calls can't be tail calls // as they are followed by marker instructions and retainRV/claimRV // calls. Mark them as notail so that the backend knows these calls // can't be tail calls. if (auto *CI = dyn_cast(CB)) CI->setTailCallKind(CallInst::TCK_NoTail); } EraseInstruction(P.first); } RVCalls.clear(); }