| 1 | //===- ObjCARC.h - ObjC ARC Optimization --------------*- C++ -*-----------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | /// \file |
| 9 | /// This file defines common definitions/declarations used by the ObjC ARC |
| 10 | /// Optimizer. ARC stands for Automatic Reference Counting and is a system for |
| 11 | /// managing reference counts for objects in Objective C. |
| 12 | /// |
| 13 | /// WARNING: This file knows about certain library functions. It recognizes them |
| 14 | /// by name, and hardwires knowledge of their semantics. |
| 15 | /// |
| 16 | /// WARNING: This file knows about how certain Objective-C library functions are |
| 17 | /// used. Naive LLVM IR transformations which would otherwise be |
| 18 | /// behavior-preserving may break these assumptions. |
| 19 | /// |
| 20 | //===----------------------------------------------------------------------===// |
| 21 | |
| 22 | #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H |
| 23 | #define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H |
| 24 | |
| 25 | #include "ARCRuntimeEntryPoints.h" |
| 26 | #include "llvm/Analysis/ObjCARCAnalysisUtils.h" |
| 27 | #include "llvm/Analysis/ObjCARCUtil.h" |
| 28 | #include "llvm/IR/EHPersonalities.h" |
| 29 | #include "llvm/Transforms/Utils/Local.h" |
| 30 | |
| 31 | namespace llvm { |
| 32 | namespace objcarc { |
| 33 | |
| 34 | /// Erase the given instruction. |
| 35 | /// |
| 36 | /// Many ObjC calls return their argument verbatim, |
| 37 | /// so if it's such a call and the return value has users, replace them with the |
| 38 | /// argument value. |
| 39 | /// |
| 40 | static inline void EraseInstruction(Instruction *CI) { |
| 41 | Value *OldArg = cast<CallInst>(Val: CI)->getArgOperand(i: 0); |
| 42 | |
| 43 | bool Unused = CI->use_empty(); |
| 44 | |
| 45 | if (!Unused) { |
| 46 | // Replace the return value with the argument. |
| 47 | assert((IsForwarding(GetBasicARCInstKind(CI)) || |
| 48 | (IsNoopOnNull(GetBasicARCInstKind(CI)) && |
| 49 | IsNullOrUndef(OldArg->stripPointerCasts()))) && |
| 50 | "Can't delete non-forwarding instruction with users!" ); |
| 51 | CI->replaceAllUsesWith(V: OldArg); |
| 52 | } |
| 53 | |
| 54 | CI->eraseFromParent(); |
| 55 | |
| 56 | if (Unused) |
| 57 | RecursivelyDeleteTriviallyDeadInstructions(V: OldArg); |
| 58 | } |
| 59 | |
| 60 | /// If Inst is a ReturnRV and its operand is a call or invoke, return the |
| 61 | /// operand. Otherwise return null. |
| 62 | static inline const Instruction *getreturnRVOperand(const Instruction &Inst, |
| 63 | ARCInstKind Class) { |
| 64 | if (Class != ARCInstKind::RetainRV) |
| 65 | return nullptr; |
| 66 | |
| 67 | const auto *Opnd = Inst.getOperand(i: 0)->stripPointerCasts(); |
| 68 | if (const auto *C = dyn_cast<CallInst>(Val: Opnd)) |
| 69 | return C; |
| 70 | return dyn_cast<InvokeInst>(Val: Opnd); |
| 71 | } |
| 72 | |
| 73 | /// Return the list of PHI nodes that are equivalent to PN. |
| 74 | template<class PHINodeTy, class VectorTy> |
| 75 | void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList) { |
| 76 | auto *BB = PN.getParent(); |
| 77 | for (auto &P : BB->phis()) { |
| 78 | if (&P == &PN) // Do not add PN to the list. |
| 79 | continue; |
| 80 | unsigned I = 0, E = PN.getNumIncomingValues(); |
| 81 | for (; I < E; ++I) { |
| 82 | auto *BB = PN.getIncomingBlock(I); |
| 83 | auto *PNOpnd = PN.getIncomingValue(I)->stripPointerCasts(); |
| 84 | auto *POpnd = P.getIncomingValueForBlock(BB)->stripPointerCasts(); |
| 85 | if (PNOpnd != POpnd) |
| 86 | break; |
| 87 | } |
| 88 | if (I == E) |
| 89 | PHIList.push_back(&P); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | static inline MDString *getRVInstMarker(Module &M) { |
| 94 | const char *MarkerKey = getRVMarkerModuleFlagStr(); |
| 95 | return dyn_cast_or_null<MDString>(Val: M.getModuleFlag(Key: MarkerKey)); |
| 96 | } |
| 97 | |
| 98 | /// Create a call instruction with the correct funclet token. This should be |
| 99 | /// called instead of calling CallInst::Create directly unless the call is |
| 100 | /// going to be removed from the IR before WinEHPrepare. |
| 101 | CallInst *createCallInstWithColors( |
| 102 | FunctionCallee Func, ArrayRef<Value *> Args, const Twine &NameStr, |
| 103 | BasicBlock::iterator InsertBefore, |
| 104 | const DenseMap<BasicBlock *, ColorVector> &BlockColors); |
| 105 | |
| 106 | class BundledRetainClaimRVs { |
| 107 | public: |
| 108 | BundledRetainClaimRVs(ARCRuntimeEntryPoints &EP, bool ContractPass, |
| 109 | bool UseClaimRV) |
| 110 | : EP(EP), ContractPass(ContractPass), UseClaimRV(UseClaimRV) {} |
| 111 | ~BundledRetainClaimRVs(); |
| 112 | |
| 113 | /// Insert a retainRV/claimRV call to the normal destination blocks of invokes |
| 114 | /// with operand bundle "clang.arc.attachedcall". If the edge to the normal |
| 115 | /// destination block is a critical edge, split it. |
| 116 | std::pair<bool, bool> insertAfterInvokes(Function &F, DominatorTree *DT); |
| 117 | |
| 118 | /// Insert a retainRV/claimRV call. |
| 119 | CallInst *insertRVCall(BasicBlock::iterator InsertPt, |
| 120 | CallBase *AnnotatedCall); |
| 121 | |
| 122 | /// Insert a retainRV/claimRV call with colors. |
| 123 | CallInst *insertRVCallWithColors( |
| 124 | BasicBlock::iterator InsertPt, CallBase *AnnotatedCall, |
| 125 | const DenseMap<BasicBlock *, ColorVector> &BlockColors); |
| 126 | |
| 127 | /// See if an instruction is a bundled retainRV/claimRV call. |
| 128 | bool contains(const Instruction *I) const { |
| 129 | if (auto *CI = dyn_cast<CallInst>(Val: I)) |
| 130 | return RVCalls.count(Val: CI); |
| 131 | return false; |
| 132 | } |
| 133 | |
| 134 | /// Remove a retainRV/claimRV call entirely. |
| 135 | void eraseInst(CallInst *CI) { |
| 136 | auto It = RVCalls.find(Val: CI); |
| 137 | if (It != RVCalls.end()) { |
| 138 | // Remove call to @llvm.objc.clang.arc.noop.use. |
| 139 | for (User *U : It->second->users()) |
| 140 | if (auto *CI = dyn_cast<CallInst>(Val: U)) |
| 141 | if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) { |
| 142 | CI->eraseFromParent(); |
| 143 | break; |
| 144 | } |
| 145 | |
| 146 | auto *NewCall = CallBase::removeOperandBundle( |
| 147 | CB: It->second, ID: LLVMContext::OB_clang_arc_attachedcall, |
| 148 | InsertPt: It->second->getIterator()); |
| 149 | NewCall->copyMetadata(SrcInst: *It->second); |
| 150 | It->second->replaceAllUsesWith(V: NewCall); |
| 151 | It->second->eraseFromParent(); |
| 152 | RVCalls.erase(I: It); |
| 153 | } |
| 154 | EraseInstruction(CI); |
| 155 | } |
| 156 | |
| 157 | private: |
| 158 | /// A map of inserted retainRV/claimRV calls to annotated calls/invokes. |
| 159 | DenseMap<CallInst *, CallBase *> RVCalls; |
| 160 | |
| 161 | ARCRuntimeEntryPoints &EP; |
| 162 | bool ContractPass; |
| 163 | bool UseClaimRV; |
| 164 | }; |
| 165 | |
| 166 | } // end namespace objcarc |
| 167 | } // end namespace llvm |
| 168 | |
| 169 | #endif |
| 170 | |