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.
CanAlterRefCount(const Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)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
CanDecrementRefCount(const Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)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.
CanUse(const Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)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
Depends(DependenceKind Flavor,Instruction * Inst,const Value * Arg,ProvenanceAnalysis & PA)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?
findDependencies(DependenceKind Flavor,const Value * Arg,BasicBlock * StartBB,Instruction * StartInst,SmallPtrSetImpl<Instruction * > & DependingInsts,ProvenanceAnalysis & PA)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
findSingleDependency(DependenceKind Flavor,const Value * Arg,BasicBlock * StartBB,Instruction * StartInst,ProvenanceAnalysis & PA)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