xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/ObjCARC.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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