xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- DependencyAnalysis.cpp - ObjC ARC Optimization ---------------------===//
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 ///
100b57cec5SDimitry Andric /// This file defines special dependency analysis routines used in Objective C
110b57cec5SDimitry Andric /// ARC Optimizations.
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 #include "DependencyAnalysis.h"
230b57cec5SDimitry Andric #include "ObjCARC.h"
240b57cec5SDimitry Andric #include "ProvenanceAnalysis.h"
25e8d8bef9SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
260b57cec5SDimitry Andric #include "llvm/IR/CFG.h"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric using namespace llvm::objcarc;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric #define DEBUG_TYPE "objc-arc-dependency"
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric /// Test whether the given instruction can result in a reference count
340b57cec5SDimitry Andric /// modification (positive or negative) for the pointer's object.
350b57cec5SDimitry Andric bool llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr,
360b57cec5SDimitry Andric                                      ProvenanceAnalysis &PA,
370b57cec5SDimitry Andric                                      ARCInstKind Class) {
380b57cec5SDimitry Andric   switch (Class) {
390b57cec5SDimitry Andric   case ARCInstKind::Autorelease:
400b57cec5SDimitry Andric   case ARCInstKind::AutoreleaseRV:
410b57cec5SDimitry Andric   case ARCInstKind::IntrinsicUser:
420b57cec5SDimitry Andric   case ARCInstKind::User:
430b57cec5SDimitry Andric     // These operations never directly modify a reference count.
440b57cec5SDimitry Andric     return false;
450b57cec5SDimitry Andric   default: break;
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   const auto *Call = cast<CallBase>(Inst);
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   // See if AliasAnalysis can help us with the call.
51bdd1243dSDimitry Andric   MemoryEffects ME = PA.getAA()->getMemoryEffects(Call);
52bdd1243dSDimitry Andric   if (ME.onlyReadsMemory())
530b57cec5SDimitry Andric     return false;
54bdd1243dSDimitry Andric   if (ME.onlyAccessesArgPointees()) {
550b57cec5SDimitry Andric     for (const Value *Op : Call->args()) {
56e8d8bef9SDimitry Andric       if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))
570b57cec5SDimitry Andric         return true;
580b57cec5SDimitry Andric     }
590b57cec5SDimitry Andric     return false;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   // Assume the worst.
630b57cec5SDimitry Andric   return true;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric bool llvm::objcarc::CanDecrementRefCount(const Instruction *Inst,
670b57cec5SDimitry Andric                                          const Value *Ptr,
680b57cec5SDimitry Andric                                          ProvenanceAnalysis &PA,
690b57cec5SDimitry Andric                                          ARCInstKind Class) {
700b57cec5SDimitry Andric   // First perform a quick check if Class can not touch ref counts.
710b57cec5SDimitry Andric   if (!CanDecrementRefCount(Class))
720b57cec5SDimitry Andric     return false;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   // Otherwise, just use CanAlterRefCount for now.
750b57cec5SDimitry Andric   return CanAlterRefCount(Inst, Ptr, PA, Class);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric /// Test whether the given instruction can "use" the given pointer's object in a
790b57cec5SDimitry Andric /// way that requires the reference count to be positive.
800b57cec5SDimitry Andric bool llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr,
810b57cec5SDimitry Andric                            ProvenanceAnalysis &PA, ARCInstKind Class) {
820b57cec5SDimitry Andric   // ARCInstKind::Call operations (as opposed to
830b57cec5SDimitry Andric   // ARCInstKind::CallOrUser) never "use" objc pointers.
840b57cec5SDimitry Andric   if (Class == ARCInstKind::Call)
850b57cec5SDimitry Andric     return false;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   // Consider various instructions which may have pointer arguments which are
880b57cec5SDimitry Andric   // not "uses".
890b57cec5SDimitry Andric   if (const ICmpInst *ICI = dyn_cast<ICmpInst>(Inst)) {
900b57cec5SDimitry Andric     // Comparing a pointer with null, or any other constant, isn't really a use,
910b57cec5SDimitry Andric     // because we don't care what the pointer points to, or about the values
920b57cec5SDimitry Andric     // of any other dynamic reference-counted pointers.
930b57cec5SDimitry Andric     if (!IsPotentialRetainableObjPtr(ICI->getOperand(1), *PA.getAA()))
940b57cec5SDimitry Andric       return false;
955ffd83dbSDimitry Andric   } else if (const auto *CS = dyn_cast<CallBase>(Inst)) {
960b57cec5SDimitry Andric     // For calls, just check the arguments (and not the callee operand).
974824e7fdSDimitry Andric     for (const Value *Op : CS->args())
98e8d8bef9SDimitry Andric       if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))
990b57cec5SDimitry Andric         return true;
1000b57cec5SDimitry Andric     return false;
1010b57cec5SDimitry Andric   } else if (const StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
1020b57cec5SDimitry Andric     // Special-case stores, because we don't care about the stored value, just
1030b57cec5SDimitry Andric     // the store address.
104e8d8bef9SDimitry Andric     const Value *Op = GetUnderlyingObjCPtr(SI->getPointerOperand());
1050b57cec5SDimitry Andric     // If we can't tell what the underlying object was, assume there is a
1060b57cec5SDimitry Andric     // dependence.
107e8d8bef9SDimitry Andric     return IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Op, Ptr);
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // Check each operand for a match.
111fe6060f1SDimitry Andric   for (const Use &U : Inst->operands()) {
112fe6060f1SDimitry Andric     const Value *Op = U;
113e8d8bef9SDimitry Andric     if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))
1140b57cec5SDimitry Andric       return true;
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric   return false;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric /// Test if there can be dependencies on Inst through Arg. This function only
1200b57cec5SDimitry Andric /// tests dependencies relevant for removing pairs of calls.
1210b57cec5SDimitry Andric bool
1220b57cec5SDimitry Andric llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
1230b57cec5SDimitry Andric                        const Value *Arg, ProvenanceAnalysis &PA) {
1240b57cec5SDimitry Andric   // If we've reached the definition of Arg, stop.
1250b57cec5SDimitry Andric   if (Inst == Arg)
1260b57cec5SDimitry Andric     return true;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   switch (Flavor) {
1290b57cec5SDimitry Andric   case NeedsPositiveRetainCount: {
1300b57cec5SDimitry Andric     ARCInstKind Class = GetARCInstKind(Inst);
1310b57cec5SDimitry Andric     switch (Class) {
1320b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPop:
1330b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPush:
1340b57cec5SDimitry Andric     case ARCInstKind::None:
1350b57cec5SDimitry Andric       return false;
1360b57cec5SDimitry Andric     default:
1370b57cec5SDimitry Andric       return CanUse(Inst, Arg, PA, Class);
1380b57cec5SDimitry Andric     }
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   case AutoreleasePoolBoundary: {
1420b57cec5SDimitry Andric     ARCInstKind Class = GetARCInstKind(Inst);
1430b57cec5SDimitry Andric     switch (Class) {
1440b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPop:
1450b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPush:
1460b57cec5SDimitry Andric       // These mark the end and begin of an autorelease pool scope.
1470b57cec5SDimitry Andric       return true;
1480b57cec5SDimitry Andric     default:
1490b57cec5SDimitry Andric       // Nothing else does this.
1500b57cec5SDimitry Andric       return false;
1510b57cec5SDimitry Andric     }
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   case CanChangeRetainCount: {
1550b57cec5SDimitry Andric     ARCInstKind Class = GetARCInstKind(Inst);
1560b57cec5SDimitry Andric     switch (Class) {
1570b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPop:
1580b57cec5SDimitry Andric       // Conservatively assume this can decrement any count.
1590b57cec5SDimitry Andric       return true;
1600b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPush:
1610b57cec5SDimitry Andric     case ARCInstKind::None:
1620b57cec5SDimitry Andric       return false;
1630b57cec5SDimitry Andric     default:
1640b57cec5SDimitry Andric       return CanAlterRefCount(Inst, Arg, PA, Class);
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   case RetainAutoreleaseDep:
1690b57cec5SDimitry Andric     switch (GetBasicARCInstKind(Inst)) {
1700b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPop:
1710b57cec5SDimitry Andric     case ARCInstKind::AutoreleasepoolPush:
1720b57cec5SDimitry Andric       // Don't merge an objc_autorelease with an objc_retain inside a different
1730b57cec5SDimitry Andric       // autoreleasepool scope.
1740b57cec5SDimitry Andric       return true;
1750b57cec5SDimitry Andric     case ARCInstKind::Retain:
1760b57cec5SDimitry Andric     case ARCInstKind::RetainRV:
1770b57cec5SDimitry Andric       // Check for a retain of the same pointer for merging.
1780b57cec5SDimitry Andric       return GetArgRCIdentityRoot(Inst) == Arg;
1790b57cec5SDimitry Andric     default:
1800b57cec5SDimitry Andric       // Nothing else matters for objc_retainAutorelease formation.
1810b57cec5SDimitry Andric       return false;
1820b57cec5SDimitry Andric     }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   case RetainAutoreleaseRVDep: {
1850b57cec5SDimitry Andric     ARCInstKind Class = GetBasicARCInstKind(Inst);
1860b57cec5SDimitry Andric     switch (Class) {
1870b57cec5SDimitry Andric     case ARCInstKind::Retain:
1880b57cec5SDimitry Andric     case ARCInstKind::RetainRV:
1890b57cec5SDimitry Andric       // Check for a retain of the same pointer for merging.
1900b57cec5SDimitry Andric       return GetArgRCIdentityRoot(Inst) == Arg;
1910b57cec5SDimitry Andric     default:
1920b57cec5SDimitry Andric       // Anything that can autorelease interrupts
1930b57cec5SDimitry Andric       // retainAutoreleaseReturnValue formation.
1940b57cec5SDimitry Andric       return CanInterruptRV(Class);
1950b57cec5SDimitry Andric     }
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric   }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   llvm_unreachable("Invalid dependence flavor");
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric /// Walk up the CFG from StartPos (which is in StartBB) and find local and
2030b57cec5SDimitry Andric /// non-local dependencies on Arg.
2040b57cec5SDimitry Andric ///
2050b57cec5SDimitry Andric /// TODO: Cache results?
206e8d8bef9SDimitry Andric static bool findDependencies(DependenceKind Flavor, const Value *Arg,
2070b57cec5SDimitry Andric                              BasicBlock *StartBB, Instruction *StartInst,
2080b57cec5SDimitry Andric                              SmallPtrSetImpl<Instruction *> &DependingInsts,
2090b57cec5SDimitry Andric                              ProvenanceAnalysis &PA) {
2100b57cec5SDimitry Andric   BasicBlock::iterator StartPos = StartInst->getIterator();
2110b57cec5SDimitry Andric 
212e8d8bef9SDimitry Andric   SmallPtrSet<const BasicBlock *, 4> Visited;
2130b57cec5SDimitry Andric   SmallVector<std::pair<BasicBlock *, BasicBlock::iterator>, 4> Worklist;
2140b57cec5SDimitry Andric   Worklist.push_back(std::make_pair(StartBB, StartPos));
2150b57cec5SDimitry Andric   do {
2160b57cec5SDimitry Andric     std::pair<BasicBlock *, BasicBlock::iterator> Pair =
2170b57cec5SDimitry Andric       Worklist.pop_back_val();
2180b57cec5SDimitry Andric     BasicBlock *LocalStartBB = Pair.first;
2190b57cec5SDimitry Andric     BasicBlock::iterator LocalStartPos = Pair.second;
2200b57cec5SDimitry Andric     BasicBlock::iterator StartBBBegin = LocalStartBB->begin();
2210b57cec5SDimitry Andric     for (;;) {
2220b57cec5SDimitry Andric       if (LocalStartPos == StartBBBegin) {
223*0fca6ea1SDimitry Andric         if (pred_empty(LocalStartBB))
224e8d8bef9SDimitry Andric           // Return if we've reached the function entry.
225e8d8bef9SDimitry Andric           return false;
2260b57cec5SDimitry Andric         // Add the predecessors to the worklist.
227*0fca6ea1SDimitry Andric         for (BasicBlock *PredBB : predecessors(LocalStartBB))
2280b57cec5SDimitry Andric           if (Visited.insert(PredBB).second)
2290b57cec5SDimitry Andric             Worklist.push_back(std::make_pair(PredBB, PredBB->end()));
2300b57cec5SDimitry Andric         break;
2310b57cec5SDimitry Andric       }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric       Instruction *Inst = &*--LocalStartPos;
2340b57cec5SDimitry Andric       if (Depends(Flavor, Inst, Arg, PA)) {
2350b57cec5SDimitry Andric         DependingInsts.insert(Inst);
2360b57cec5SDimitry Andric         break;
2370b57cec5SDimitry Andric       }
2380b57cec5SDimitry Andric     }
2390b57cec5SDimitry Andric   } while (!Worklist.empty());
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric   // Determine whether the original StartBB post-dominates all of the blocks we
2427a6dacacSDimitry Andric   // visited. If not, insert a sentinel indicating that most optimizations are
2430b57cec5SDimitry Andric   // not safe.
2440b57cec5SDimitry Andric   for (const BasicBlock *BB : Visited) {
2450b57cec5SDimitry Andric     if (BB == StartBB)
2460b57cec5SDimitry Andric       continue;
2470b57cec5SDimitry Andric     for (const BasicBlock *Succ : successors(BB))
248e8d8bef9SDimitry Andric       if (Succ != StartBB && !Visited.count(Succ))
249e8d8bef9SDimitry Andric         return false;
2500b57cec5SDimitry Andric   }
251e8d8bef9SDimitry Andric 
252e8d8bef9SDimitry Andric   return true;
2530b57cec5SDimitry Andric }
254e8d8bef9SDimitry Andric 
255e8d8bef9SDimitry Andric llvm::Instruction *llvm::objcarc::findSingleDependency(DependenceKind Flavor,
256e8d8bef9SDimitry Andric                                                        const Value *Arg,
257e8d8bef9SDimitry Andric                                                        BasicBlock *StartBB,
258e8d8bef9SDimitry Andric                                                        Instruction *StartInst,
259e8d8bef9SDimitry Andric                                                        ProvenanceAnalysis &PA) {
260e8d8bef9SDimitry Andric   SmallPtrSet<Instruction *, 4> DependingInsts;
261e8d8bef9SDimitry Andric 
262e8d8bef9SDimitry Andric   if (!findDependencies(Flavor, Arg, StartBB, StartInst, DependingInsts, PA) ||
263e8d8bef9SDimitry Andric       DependingInsts.size() != 1)
264e8d8bef9SDimitry Andric     return nullptr;
265e8d8bef9SDimitry Andric   return *DependingInsts.begin();
2660b57cec5SDimitry Andric }
267