Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
35266 views
//===- DependencyAnalysis.cpp - ObjC ARC Optimization ---------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8///9/// This file defines special dependency analysis routines used in Objective C10/// ARC Optimizations.11///12/// WARNING: This file knows about certain library functions. It recognizes them13/// by name, and hardwires knowledge of their semantics.14///15/// WARNING: This file knows about how certain Objective-C library functions are16/// used. Naive LLVM IR transformations which would otherwise be17/// behavior-preserving may break these assumptions.18///19//===----------------------------------------------------------------------===//2021#include "DependencyAnalysis.h"22#include "ObjCARC.h"23#include "ProvenanceAnalysis.h"24#include "llvm/Analysis/AliasAnalysis.h"25#include "llvm/IR/CFG.h"2627using namespace llvm;28using namespace llvm::objcarc;2930#define DEBUG_TYPE "objc-arc-dependency"3132/// Test whether the given instruction can result in a reference count33/// modification (positive or negative) for the pointer's object.34bool llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr,35ProvenanceAnalysis &PA,36ARCInstKind Class) {37switch (Class) {38case ARCInstKind::Autorelease:39case ARCInstKind::AutoreleaseRV:40case ARCInstKind::IntrinsicUser:41case ARCInstKind::User:42// These operations never directly modify a reference count.43return false;44default: break;45}4647const auto *Call = cast<CallBase>(Inst);4849// See if AliasAnalysis can help us with the call.50MemoryEffects ME = PA.getAA()->getMemoryEffects(Call);51if (ME.onlyReadsMemory())52return false;53if (ME.onlyAccessesArgPointees()) {54for (const Value *Op : Call->args()) {55if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))56return true;57}58return false;59}6061// Assume the worst.62return true;63}6465bool llvm::objcarc::CanDecrementRefCount(const Instruction *Inst,66const Value *Ptr,67ProvenanceAnalysis &PA,68ARCInstKind Class) {69// First perform a quick check if Class can not touch ref counts.70if (!CanDecrementRefCount(Class))71return false;7273// Otherwise, just use CanAlterRefCount for now.74return CanAlterRefCount(Inst, Ptr, PA, Class);75}7677/// Test whether the given instruction can "use" the given pointer's object in a78/// way that requires the reference count to be positive.79bool llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr,80ProvenanceAnalysis &PA, ARCInstKind Class) {81// ARCInstKind::Call operations (as opposed to82// ARCInstKind::CallOrUser) never "use" objc pointers.83if (Class == ARCInstKind::Call)84return false;8586// Consider various instructions which may have pointer arguments which are87// not "uses".88if (const ICmpInst *ICI = dyn_cast<ICmpInst>(Inst)) {89// Comparing a pointer with null, or any other constant, isn't really a use,90// because we don't care what the pointer points to, or about the values91// of any other dynamic reference-counted pointers.92if (!IsPotentialRetainableObjPtr(ICI->getOperand(1), *PA.getAA()))93return false;94} else if (const auto *CS = dyn_cast<CallBase>(Inst)) {95// For calls, just check the arguments (and not the callee operand).96for (const Value *Op : CS->args())97if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))98return true;99return false;100} else if (const StoreInst *SI = dyn_cast<StoreInst>(Inst)) {101// Special-case stores, because we don't care about the stored value, just102// the store address.103const Value *Op = GetUnderlyingObjCPtr(SI->getPointerOperand());104// If we can't tell what the underlying object was, assume there is a105// dependence.106return IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Op, Ptr);107}108109// Check each operand for a match.110for (const Use &U : Inst->operands()) {111const Value *Op = U;112if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op))113return true;114}115return false;116}117118/// Test if there can be dependencies on Inst through Arg. This function only119/// tests dependencies relevant for removing pairs of calls.120bool121llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,122const Value *Arg, ProvenanceAnalysis &PA) {123// If we've reached the definition of Arg, stop.124if (Inst == Arg)125return true;126127switch (Flavor) {128case NeedsPositiveRetainCount: {129ARCInstKind Class = GetARCInstKind(Inst);130switch (Class) {131case ARCInstKind::AutoreleasepoolPop:132case ARCInstKind::AutoreleasepoolPush:133case ARCInstKind::None:134return false;135default:136return CanUse(Inst, Arg, PA, Class);137}138}139140case AutoreleasePoolBoundary: {141ARCInstKind Class = GetARCInstKind(Inst);142switch (Class) {143case ARCInstKind::AutoreleasepoolPop:144case ARCInstKind::AutoreleasepoolPush:145// These mark the end and begin of an autorelease pool scope.146return true;147default:148// Nothing else does this.149return false;150}151}152153case CanChangeRetainCount: {154ARCInstKind Class = GetARCInstKind(Inst);155switch (Class) {156case ARCInstKind::AutoreleasepoolPop:157// Conservatively assume this can decrement any count.158return true;159case ARCInstKind::AutoreleasepoolPush:160case ARCInstKind::None:161return false;162default:163return CanAlterRefCount(Inst, Arg, PA, Class);164}165}166167case RetainAutoreleaseDep:168switch (GetBasicARCInstKind(Inst)) {169case ARCInstKind::AutoreleasepoolPop:170case ARCInstKind::AutoreleasepoolPush:171// Don't merge an objc_autorelease with an objc_retain inside a different172// autoreleasepool scope.173return true;174case ARCInstKind::Retain:175case ARCInstKind::RetainRV:176// Check for a retain of the same pointer for merging.177return GetArgRCIdentityRoot(Inst) == Arg;178default:179// Nothing else matters for objc_retainAutorelease formation.180return false;181}182183case RetainAutoreleaseRVDep: {184ARCInstKind Class = GetBasicARCInstKind(Inst);185switch (Class) {186case ARCInstKind::Retain:187case ARCInstKind::RetainRV:188// Check for a retain of the same pointer for merging.189return GetArgRCIdentityRoot(Inst) == Arg;190default:191// Anything that can autorelease interrupts192// retainAutoreleaseReturnValue formation.193return CanInterruptRV(Class);194}195}196}197198llvm_unreachable("Invalid dependence flavor");199}200201/// Walk up the CFG from StartPos (which is in StartBB) and find local and202/// non-local dependencies on Arg.203///204/// TODO: Cache results?205static bool findDependencies(DependenceKind Flavor, const Value *Arg,206BasicBlock *StartBB, Instruction *StartInst,207SmallPtrSetImpl<Instruction *> &DependingInsts,208ProvenanceAnalysis &PA) {209BasicBlock::iterator StartPos = StartInst->getIterator();210211SmallPtrSet<const BasicBlock *, 4> Visited;212SmallVector<std::pair<BasicBlock *, BasicBlock::iterator>, 4> Worklist;213Worklist.push_back(std::make_pair(StartBB, StartPos));214do {215std::pair<BasicBlock *, BasicBlock::iterator> Pair =216Worklist.pop_back_val();217BasicBlock *LocalStartBB = Pair.first;218BasicBlock::iterator LocalStartPos = Pair.second;219BasicBlock::iterator StartBBBegin = LocalStartBB->begin();220for (;;) {221if (LocalStartPos == StartBBBegin) {222if (pred_empty(LocalStartBB))223// Return if we've reached the function entry.224return false;225// Add the predecessors to the worklist.226for (BasicBlock *PredBB : predecessors(LocalStartBB))227if (Visited.insert(PredBB).second)228Worklist.push_back(std::make_pair(PredBB, PredBB->end()));229break;230}231232Instruction *Inst = &*--LocalStartPos;233if (Depends(Flavor, Inst, Arg, PA)) {234DependingInsts.insert(Inst);235break;236}237}238} while (!Worklist.empty());239240// Determine whether the original StartBB post-dominates all of the blocks we241// visited. If not, insert a sentinel indicating that most optimizations are242// not safe.243for (const BasicBlock *BB : Visited) {244if (BB == StartBB)245continue;246for (const BasicBlock *Succ : successors(BB))247if (Succ != StartBB && !Visited.count(Succ))248return false;249}250251return true;252}253254llvm::Instruction *llvm::objcarc::findSingleDependency(DependenceKind Flavor,255const Value *Arg,256BasicBlock *StartBB,257Instruction *StartInst,258ProvenanceAnalysis &PA) {259SmallPtrSet<Instruction *, 4> DependingInsts;260261if (!findDependencies(Flavor, Arg, StartBB, StartInst, DependingInsts, PA) ||262DependingInsts.size() != 1)263return nullptr;264return *DependingInsts.begin();265}266267268