10b57cec5SDimitry Andric //===- ObjCARC.h - ObjC ARC Optimization --------------*- C++ -*-----------===// 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 /// \file 90b57cec5SDimitry Andric /// This file defines common definitions/declarations used by the ObjC ARC 100b57cec5SDimitry Andric /// Optimizer. ARC stands for Automatic Reference Counting and is a system for 110b57cec5SDimitry Andric /// managing reference counts for objects in Objective C. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric /// WARNING: This file knows about certain library functions. It recognizes them 140b57cec5SDimitry Andric /// by name, and hardwires knowledge of their semantics. 150b57cec5SDimitry Andric /// 160b57cec5SDimitry Andric /// WARNING: This file knows about how certain Objective-C library functions are 170b57cec5SDimitry Andric /// used. Naive LLVM IR transformations which would otherwise be 180b57cec5SDimitry Andric /// behavior-preserving may break these assumptions. 190b57cec5SDimitry Andric /// 200b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H 230b57cec5SDimitry Andric #define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCAnalysisUtils.h" 26fe6060f1SDimitry Andric #include "llvm/Analysis/ObjCARCUtil.h" 2706c3fb27SDimitry Andric #include "llvm/IR/EHPersonalities.h" 280b57cec5SDimitry Andric #include "llvm/Transforms/Utils/Local.h" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric namespace llvm { 310b57cec5SDimitry Andric namespace objcarc { 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric /// Erase the given instruction. 340b57cec5SDimitry Andric /// 350b57cec5SDimitry Andric /// Many ObjC calls return their argument verbatim, 360b57cec5SDimitry Andric /// so if it's such a call and the return value has users, replace them with the 370b57cec5SDimitry Andric /// argument value. 380b57cec5SDimitry Andric /// 390b57cec5SDimitry Andric static inline void EraseInstruction(Instruction *CI) { 400b57cec5SDimitry Andric Value *OldArg = cast<CallInst>(CI)->getArgOperand(0); 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric bool Unused = CI->use_empty(); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric if (!Unused) { 450b57cec5SDimitry Andric // Replace the return value with the argument. 460b57cec5SDimitry Andric assert((IsForwarding(GetBasicARCInstKind(CI)) || 470b57cec5SDimitry Andric (IsNoopOnNull(GetBasicARCInstKind(CI)) && 480b57cec5SDimitry Andric IsNullOrUndef(OldArg->stripPointerCasts()))) && 490b57cec5SDimitry Andric "Can't delete non-forwarding instruction with users!"); 500b57cec5SDimitry Andric CI->replaceAllUsesWith(OldArg); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric CI->eraseFromParent(); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric if (Unused) 560b57cec5SDimitry Andric RecursivelyDeleteTriviallyDeadInstructions(OldArg); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric /// If Inst is a ReturnRV and its operand is a call or invoke, return the 600b57cec5SDimitry Andric /// operand. Otherwise return null. 610b57cec5SDimitry Andric static inline const Instruction *getreturnRVOperand(const Instruction &Inst, 620b57cec5SDimitry Andric ARCInstKind Class) { 630b57cec5SDimitry Andric if (Class != ARCInstKind::RetainRV) 640b57cec5SDimitry Andric return nullptr; 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric const auto *Opnd = Inst.getOperand(0)->stripPointerCasts(); 670b57cec5SDimitry Andric if (const auto *C = dyn_cast<CallInst>(Opnd)) 680b57cec5SDimitry Andric return C; 690b57cec5SDimitry Andric return dyn_cast<InvokeInst>(Opnd); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric /// Return the list of PHI nodes that are equivalent to PN. 730b57cec5SDimitry Andric template<class PHINodeTy, class VectorTy> 740b57cec5SDimitry Andric void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList) { 750b57cec5SDimitry Andric auto *BB = PN.getParent(); 760b57cec5SDimitry Andric for (auto &P : BB->phis()) { 770b57cec5SDimitry Andric if (&P == &PN) // Do not add PN to the list. 780b57cec5SDimitry Andric continue; 790b57cec5SDimitry Andric unsigned I = 0, E = PN.getNumIncomingValues(); 800b57cec5SDimitry Andric for (; I < E; ++I) { 810b57cec5SDimitry Andric auto *BB = PN.getIncomingBlock(I); 820b57cec5SDimitry Andric auto *PNOpnd = PN.getIncomingValue(I)->stripPointerCasts(); 830b57cec5SDimitry Andric auto *POpnd = P.getIncomingValueForBlock(BB)->stripPointerCasts(); 840b57cec5SDimitry Andric if (PNOpnd != POpnd) 850b57cec5SDimitry Andric break; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric if (I == E) 880b57cec5SDimitry Andric PHIList.push_back(&P); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 92fe6060f1SDimitry Andric static inline MDString *getRVInstMarker(Module &M) { 93fe6060f1SDimitry Andric const char *MarkerKey = getRVMarkerModuleFlagStr(); 94fe6060f1SDimitry Andric return dyn_cast_or_null<MDString>(M.getModuleFlag(MarkerKey)); 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric /// Create a call instruction with the correct funclet token. This should be 98fe6060f1SDimitry Andric /// called instead of calling CallInst::Create directly unless the call is 99fe6060f1SDimitry Andric /// going to be removed from the IR before WinEHPrepare. 100fe6060f1SDimitry Andric CallInst *createCallInstWithColors( 101fe6060f1SDimitry Andric FunctionCallee Func, ArrayRef<Value *> Args, const Twine &NameStr, 102*0fca6ea1SDimitry Andric BasicBlock::iterator InsertBefore, 103fe6060f1SDimitry Andric const DenseMap<BasicBlock *, ColorVector> &BlockColors); 104fe6060f1SDimitry Andric 105fe6060f1SDimitry Andric class BundledRetainClaimRVs { 106fe6060f1SDimitry Andric public: 1071fd87a68SDimitry Andric BundledRetainClaimRVs(bool ContractPass) : ContractPass(ContractPass) {} 108fe6060f1SDimitry Andric ~BundledRetainClaimRVs(); 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric /// Insert a retainRV/claimRV call to the normal destination blocks of invokes 111fe6060f1SDimitry Andric /// with operand bundle "clang.arc.attachedcall". If the edge to the normal 112fe6060f1SDimitry Andric /// destination block is a critical edge, split it. 113fe6060f1SDimitry Andric std::pair<bool, bool> insertAfterInvokes(Function &F, DominatorTree *DT); 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric /// Insert a retainRV/claimRV call. 116*0fca6ea1SDimitry Andric CallInst *insertRVCall(BasicBlock::iterator InsertPt, 117*0fca6ea1SDimitry Andric CallBase *AnnotatedCall); 118fe6060f1SDimitry Andric 119fe6060f1SDimitry Andric /// Insert a retainRV/claimRV call with colors. 120fe6060f1SDimitry Andric CallInst *insertRVCallWithColors( 121*0fca6ea1SDimitry Andric BasicBlock::iterator InsertPt, CallBase *AnnotatedCall, 122fe6060f1SDimitry Andric const DenseMap<BasicBlock *, ColorVector> &BlockColors); 123fe6060f1SDimitry Andric 124fe6060f1SDimitry Andric /// See if an instruction is a bundled retainRV/claimRV call. 125fe6060f1SDimitry Andric bool contains(const Instruction *I) const { 126fe6060f1SDimitry Andric if (auto *CI = dyn_cast<CallInst>(I)) 127fe6060f1SDimitry Andric return RVCalls.count(CI); 128fe6060f1SDimitry Andric return false; 129fe6060f1SDimitry Andric } 130fe6060f1SDimitry Andric 131fe6060f1SDimitry Andric /// Remove a retainRV/claimRV call entirely. 132fe6060f1SDimitry Andric void eraseInst(CallInst *CI) { 133fe6060f1SDimitry Andric auto It = RVCalls.find(CI); 134fe6060f1SDimitry Andric if (It != RVCalls.end()) { 135fe6060f1SDimitry Andric // Remove call to @llvm.objc.clang.arc.noop.use. 136bdd1243dSDimitry Andric for (User *U : It->second->users()) 137bdd1243dSDimitry Andric if (auto *CI = dyn_cast<CallInst>(U)) 138fe6060f1SDimitry Andric if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) { 139fe6060f1SDimitry Andric CI->eraseFromParent(); 140fe6060f1SDimitry Andric break; 141fe6060f1SDimitry Andric } 142fe6060f1SDimitry Andric 143fe6060f1SDimitry Andric auto *NewCall = CallBase::removeOperandBundle( 144*0fca6ea1SDimitry Andric It->second, LLVMContext::OB_clang_arc_attachedcall, 145*0fca6ea1SDimitry Andric It->second->getIterator()); 146fe6060f1SDimitry Andric NewCall->copyMetadata(*It->second); 147fe6060f1SDimitry Andric It->second->replaceAllUsesWith(NewCall); 148fe6060f1SDimitry Andric It->second->eraseFromParent(); 149fe6060f1SDimitry Andric RVCalls.erase(It); 150fe6060f1SDimitry Andric } 151fe6060f1SDimitry Andric EraseInstruction(CI); 152fe6060f1SDimitry Andric } 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric private: 155fe6060f1SDimitry Andric /// A map of inserted retainRV/claimRV calls to annotated calls/invokes. 156fe6060f1SDimitry Andric DenseMap<CallInst *, CallBase *> RVCalls; 157fe6060f1SDimitry Andric 158fe6060f1SDimitry Andric bool ContractPass; 159fe6060f1SDimitry Andric }; 160fe6060f1SDimitry Andric 1610b57cec5SDimitry Andric } // end namespace objcarc 1620b57cec5SDimitry Andric } // end namespace llvm 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric #endif 165