[objc-arc] Change the InstructionClass to be an enum class called ARCInstKind.

I also renamed ObjCARCUtil.cpp -> ARCInstKind.cpp. That file only contained
items related to ARCInstKind anyways.

llvm-svn: 229905
This commit is contained in:
Michael Gottesman 2015-02-19 19:51:32 +00:00
parent a747e5935d
commit 6f729fa675
12 changed files with 648 additions and 588 deletions

View File

@ -0,0 +1,293 @@
//===- ARCInstKind.cpp - ObjC ARC Optimization ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines several utility functions used by various ARC
/// optimizations which are IMHO too big to be in a header file.
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//
#include "ObjCARC.h"
#include "llvm/IR/Intrinsics.h"
using namespace llvm;
using namespace llvm::objcarc;
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS,
const ARCInstKind Class) {
switch (Class) {
case ARCInstKind::Retain:
return OS << "ARCInstKind::Retain";
case ARCInstKind::RetainRV:
return OS << "ARCInstKind::RetainRV";
case ARCInstKind::RetainBlock:
return OS << "ARCInstKind::RetainBlock";
case ARCInstKind::Release:
return OS << "ARCInstKind::Release";
case ARCInstKind::Autorelease:
return OS << "ARCInstKind::Autorelease";
case ARCInstKind::AutoreleaseRV:
return OS << "ARCInstKind::AutoreleaseRV";
case ARCInstKind::AutoreleasepoolPush:
return OS << "ARCInstKind::AutoreleasepoolPush";
case ARCInstKind::AutoreleasepoolPop:
return OS << "ARCInstKind::AutoreleasepoolPop";
case ARCInstKind::NoopCast:
return OS << "ARCInstKind::NoopCast";
case ARCInstKind::FusedRetainAutorelease:
return OS << "ARCInstKind::FusedRetainAutorelease";
case ARCInstKind::FusedRetainAutoreleaseRV:
return OS << "ARCInstKind::FusedRetainAutoreleaseRV";
case ARCInstKind::LoadWeakRetained:
return OS << "ARCInstKind::LoadWeakRetained";
case ARCInstKind::StoreWeak:
return OS << "ARCInstKind::StoreWeak";
case ARCInstKind::InitWeak:
return OS << "ARCInstKind::InitWeak";
case ARCInstKind::LoadWeak:
return OS << "ARCInstKind::LoadWeak";
case ARCInstKind::MoveWeak:
return OS << "ARCInstKind::MoveWeak";
case ARCInstKind::CopyWeak:
return OS << "ARCInstKind::CopyWeak";
case ARCInstKind::DestroyWeak:
return OS << "ARCInstKind::DestroyWeak";
case ARCInstKind::StoreStrong:
return OS << "ARCInstKind::StoreStrong";
case ARCInstKind::CallOrUser:
return OS << "ARCInstKind::CallOrUser";
case ARCInstKind::Call:
return OS << "ARCInstKind::Call";
case ARCInstKind::User:
return OS << "ARCInstKind::User";
case ARCInstKind::IntrinsicUser:
return OS << "ARCInstKind::IntrinsicUser";
case ARCInstKind::None:
return OS << "ARCInstKind::None";
}
llvm_unreachable("Unknown instruction class!");
}
ARCInstKind llvm::objcarc::GetFunctionClass(const Function *F) {
Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
// No (mandatory) arguments.
if (AI == AE)
return StringSwitch<ARCInstKind>(F->getName())
.Case("objc_autoreleasePoolPush", ARCInstKind::AutoreleasepoolPush)
.Case("clang.arc.use", ARCInstKind::IntrinsicUser)
.Default(ARCInstKind::CallOrUser);
// One argument.
const Argument *A0 = AI++;
if (AI == AE)
// Argument is a pointer.
if (PointerType *PTy = dyn_cast<PointerType>(A0->getType())) {
Type *ETy = PTy->getElementType();
// Argument is i8*.
if (ETy->isIntegerTy(8))
return StringSwitch<ARCInstKind>(F->getName())
.Case("objc_retain", ARCInstKind::Retain)
.Case("objc_retainAutoreleasedReturnValue", ARCInstKind::RetainRV)
.Case("objc_retainBlock", ARCInstKind::RetainBlock)
.Case("objc_release", ARCInstKind::Release)
.Case("objc_autorelease", ARCInstKind::Autorelease)
.Case("objc_autoreleaseReturnValue", ARCInstKind::AutoreleaseRV)
.Case("objc_autoreleasePoolPop", ARCInstKind::AutoreleasepoolPop)
.Case("objc_retainedObject", ARCInstKind::NoopCast)
.Case("objc_unretainedObject", ARCInstKind::NoopCast)
.Case("objc_unretainedPointer", ARCInstKind::NoopCast)
.Case("objc_retain_autorelease",
ARCInstKind::FusedRetainAutorelease)
.Case("objc_retainAutorelease", ARCInstKind::FusedRetainAutorelease)
.Case("objc_retainAutoreleaseReturnValue",
ARCInstKind::FusedRetainAutoreleaseRV)
.Case("objc_sync_enter", ARCInstKind::User)
.Case("objc_sync_exit", ARCInstKind::User)
.Default(ARCInstKind::CallOrUser);
// Argument is i8**
if (PointerType *Pte = dyn_cast<PointerType>(ETy))
if (Pte->getElementType()->isIntegerTy(8))
return StringSwitch<ARCInstKind>(F->getName())
.Case("objc_loadWeakRetained", ARCInstKind::LoadWeakRetained)
.Case("objc_loadWeak", ARCInstKind::LoadWeak)
.Case("objc_destroyWeak", ARCInstKind::DestroyWeak)
.Default(ARCInstKind::CallOrUser);
}
// Two arguments, first is i8**.
const Argument *A1 = AI++;
if (AI == AE)
if (PointerType *PTy = dyn_cast<PointerType>(A0->getType()))
if (PointerType *Pte = dyn_cast<PointerType>(PTy->getElementType()))
if (Pte->getElementType()->isIntegerTy(8))
if (PointerType *PTy1 = dyn_cast<PointerType>(A1->getType())) {
Type *ETy1 = PTy1->getElementType();
// Second argument is i8*
if (ETy1->isIntegerTy(8))
return StringSwitch<ARCInstKind>(F->getName())
.Case("objc_storeWeak", ARCInstKind::StoreWeak)
.Case("objc_initWeak", ARCInstKind::InitWeak)
.Case("objc_storeStrong", ARCInstKind::StoreStrong)
.Default(ARCInstKind::CallOrUser);
// Second argument is i8**.
if (PointerType *Pte1 = dyn_cast<PointerType>(ETy1))
if (Pte1->getElementType()->isIntegerTy(8))
return StringSwitch<ARCInstKind>(F->getName())
.Case("objc_moveWeak", ARCInstKind::MoveWeak)
.Case("objc_copyWeak", ARCInstKind::CopyWeak)
// Ignore annotation calls. This is important to stop the
// optimizer from treating annotations as uses which would
// make the state of the pointers they are attempting to
// elucidate to be incorrect.
.Case("llvm.arc.annotation.topdown.bbstart",
ARCInstKind::None)
.Case("llvm.arc.annotation.topdown.bbend",
ARCInstKind::None)
.Case("llvm.arc.annotation.bottomup.bbstart",
ARCInstKind::None)
.Case("llvm.arc.annotation.bottomup.bbend",
ARCInstKind::None)
.Default(ARCInstKind::CallOrUser);
}
// Anything else.
return ARCInstKind::CallOrUser;
}
/// \brief Determine what kind of construct V is.
ARCInstKind llvm::objcarc::GetARCInstKind(const Value *V) {
if (const Instruction *I = dyn_cast<Instruction>(V)) {
// Any instruction other than bitcast and gep with a pointer operand have a
// use of an objc pointer. Bitcasts, GEPs, Selects, PHIs transfer a pointer
// to a subsequent use, rather than using it themselves, in this sense.
// As a short cut, several other opcodes are known to have no pointer
// operands of interest. And ret is never followed by a release, so it's
// not interesting to examine.
switch (I->getOpcode()) {
case Instruction::Call: {
const CallInst *CI = cast<CallInst>(I);
// Check for calls to special functions.
if (const Function *F = CI->getCalledFunction()) {
ARCInstKind Class = GetFunctionClass(F);
if (Class != ARCInstKind::CallOrUser)
return Class;
// None of the intrinsic functions do objc_release. For intrinsics, the
// only question is whether or not they may be users.
switch (F->getIntrinsicID()) {
case Intrinsic::returnaddress:
case Intrinsic::frameaddress:
case Intrinsic::stacksave:
case Intrinsic::stackrestore:
case Intrinsic::vastart:
case Intrinsic::vacopy:
case Intrinsic::vaend:
case Intrinsic::objectsize:
case Intrinsic::prefetch:
case Intrinsic::stackprotector:
case Intrinsic::eh_return_i32:
case Intrinsic::eh_return_i64:
case Intrinsic::eh_typeid_for:
case Intrinsic::eh_dwarf_cfa:
case Intrinsic::eh_sjlj_lsda:
case Intrinsic::eh_sjlj_functioncontext:
case Intrinsic::init_trampoline:
case Intrinsic::adjust_trampoline:
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
case Intrinsic::invariant_start:
case Intrinsic::invariant_end:
// Don't let dbg info affect our results.
case Intrinsic::dbg_declare:
case Intrinsic::dbg_value:
// Short cut: Some intrinsics obviously don't use ObjC pointers.
return ARCInstKind::None;
default:
break;
}
}
return GetCallSiteClass(CI);
}
case Instruction::Invoke:
return GetCallSiteClass(cast<InvokeInst>(I));
case Instruction::BitCast:
case Instruction::GetElementPtr:
case Instruction::Select:
case Instruction::PHI:
case Instruction::Ret:
case Instruction::Br:
case Instruction::Switch:
case Instruction::IndirectBr:
case Instruction::Alloca:
case Instruction::VAArg:
case Instruction::Add:
case Instruction::FAdd:
case Instruction::Sub:
case Instruction::FSub:
case Instruction::Mul:
case Instruction::FMul:
case Instruction::SDiv:
case Instruction::UDiv:
case Instruction::FDiv:
case Instruction::SRem:
case Instruction::URem:
case Instruction::FRem:
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
case Instruction::Xor:
case Instruction::SExt:
case Instruction::ZExt:
case Instruction::Trunc:
case Instruction::IntToPtr:
case Instruction::FCmp:
case Instruction::FPTrunc:
case Instruction::FPExt:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::UIToFP:
case Instruction::SIToFP:
case Instruction::InsertElement:
case Instruction::ExtractElement:
case Instruction::ShuffleVector:
case Instruction::ExtractValue:
break;
case Instruction::ICmp:
// Comparing a pointer with null, or any other constant, isn't an
// interesting use, because we don't care what the pointer points to, or
// about the values of any other dynamic reference-counted pointers.
if (IsPotentialRetainableObjPtr(I->getOperand(1)))
return ARCInstKind::User;
break;
default:
// For anything else, check all the operands.
// Note that this includes both operands of a Store: while the first
// operand isn't actually being dereferenced, it is being stored to
// memory where we can no longer track who might read it and dereference
// it, so we have to consider it potentially used.
for (User::const_op_iterator OI = I->op_begin(), OE = I->op_end();
OI != OE; ++OI)
if (IsPotentialRetainableObjPtr(*OI))
return ARCInstKind::User;
}
}
// Otherwise, it's totally inert for ARC purposes.
return ARCInstKind::None;
}

View File

@ -0,0 +1,168 @@
//===--- ARCInstKind.h - ARC instruction equivalence classes -*- C++ -*----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TRANSFORMS_OBJCARC_ARCINSTKIND_H
#define LLVM_LIB_TRANSFORMS_OBJCARC_ARCINSTKIND_H
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Function.h"
namespace llvm {
namespace objcarc {
/// \enum ARCInstKind
///
/// \brief Equivalence classes of instructions in the ARC Model.
///
/// Since we do not have "instructions" to represent ARC concepts in LLVM IR,
/// we instead operate on equivalence classes of instructions.
///
/// TODO: This should be split into two enums: a runtime entry point enum
/// (possibly united with the ARCRuntimeEntrypoint class) and an enum that deals
/// with effects of instructions in the ARC model (which would handle the notion
/// of a User or CallOrUser).
enum class ARCInstKind {
Retain, ///< objc_retain
RetainRV, ///< objc_retainAutoreleasedReturnValue
RetainBlock, ///< objc_retainBlock
Release, ///< objc_release
Autorelease, ///< objc_autorelease
AutoreleaseRV, ///< objc_autoreleaseReturnValue
AutoreleasepoolPush, ///< objc_autoreleasePoolPush
AutoreleasepoolPop, ///< objc_autoreleasePoolPop
NoopCast, ///< objc_retainedObject, etc.
FusedRetainAutorelease, ///< objc_retainAutorelease
FusedRetainAutoreleaseRV, ///< objc_retainAutoreleaseReturnValue
LoadWeakRetained, ///< objc_loadWeakRetained (primitive)
StoreWeak, ///< objc_storeWeak (primitive)
InitWeak, ///< objc_initWeak (derived)
LoadWeak, ///< objc_loadWeak (derived)
MoveWeak, ///< objc_moveWeak (derived)
CopyWeak, ///< objc_copyWeak (derived)
DestroyWeak, ///< objc_destroyWeak (derived)
StoreStrong, ///< objc_storeStrong (derived)
IntrinsicUser, ///< clang.arc.use
CallOrUser, ///< could call objc_release and/or "use" pointers
Call, ///< could call objc_release
User, ///< could "use" a pointer
None ///< anything else
};
raw_ostream &operator<<(raw_ostream &OS, const ARCInstKind Class);
/// \brief Test if the given class is a kind of user.
inline static bool IsUser(ARCInstKind Class) {
return Class == ARCInstKind::User || Class == ARCInstKind::CallOrUser ||
Class == ARCInstKind::IntrinsicUser;
}
/// \brief Test if the given class is objc_retain or equivalent.
static inline bool IsRetain(ARCInstKind Class) {
return Class == ARCInstKind::Retain || Class == ARCInstKind::RetainRV;
}
/// \brief Test if the given class is objc_autorelease or equivalent.
static inline bool IsAutorelease(ARCInstKind Class) {
return Class == ARCInstKind::Autorelease ||
Class == ARCInstKind::AutoreleaseRV;
}
/// \brief Test if the given class represents instructions which return their
/// argument verbatim.
static inline bool IsForwarding(ARCInstKind Class) {
return Class == ARCInstKind::Retain || Class == ARCInstKind::RetainRV ||
Class == ARCInstKind::Autorelease ||
Class == ARCInstKind::AutoreleaseRV || Class == ARCInstKind::NoopCast;
}
/// \brief Test if the given class represents instructions which do nothing if
/// passed a null pointer.
static inline bool IsNoopOnNull(ARCInstKind Class) {
return Class == ARCInstKind::Retain || Class == ARCInstKind::RetainRV ||
Class == ARCInstKind::Release || Class == ARCInstKind::Autorelease ||
Class == ARCInstKind::AutoreleaseRV ||
Class == ARCInstKind::RetainBlock;
}
/// \brief Test if the given class represents instructions which are always safe
/// to mark with the "tail" keyword.
static inline bool IsAlwaysTail(ARCInstKind Class) {
// ARCInstKind::RetainBlock may be given a stack argument.
return Class == ARCInstKind::Retain || Class == ARCInstKind::RetainRV ||
Class == ARCInstKind::AutoreleaseRV;
}
/// \brief Test if the given class represents instructions which are never safe
/// to mark with the "tail" keyword.
static inline bool IsNeverTail(ARCInstKind Class) {
/// It is never safe to tail call objc_autorelease since by tail calling
/// objc_autorelease, we also tail call -[NSObject autorelease] which supports
/// fast autoreleasing causing our object to be potentially reclaimed from the
/// autorelease pool which violates the semantics of __autoreleasing types in
/// ARC.
return Class == ARCInstKind::Autorelease;
}
/// \brief Test if the given class represents instructions which are always safe
/// to mark with the nounwind attribute.
static inline bool IsNoThrow(ARCInstKind Class) {
// objc_retainBlock is not nounwind because it calls user copy constructors
// which could theoretically throw.
return Class == ARCInstKind::Retain || Class == ARCInstKind::RetainRV ||
Class == ARCInstKind::Release || Class == ARCInstKind::Autorelease ||
Class == ARCInstKind::AutoreleaseRV ||
Class == ARCInstKind::AutoreleasepoolPush ||
Class == ARCInstKind::AutoreleasepoolPop;
}
/// Test whether the given instruction can autorelease any pointer or cause an
/// autoreleasepool pop.
static inline bool CanInterruptRV(ARCInstKind Class) {
switch (Class) {
case ARCInstKind::AutoreleasepoolPop:
case ARCInstKind::CallOrUser:
case ARCInstKind::Call:
case ARCInstKind::Autorelease:
case ARCInstKind::AutoreleaseRV:
case ARCInstKind::FusedRetainAutorelease:
case ARCInstKind::FusedRetainAutoreleaseRV:
return true;
default:
return false;
}
}
/// \brief Determine if F is one of the special known Functions. If it isn't,
/// return ARCInstKind::CallOrUser.
ARCInstKind GetFunctionClass(const Function *F);
/// \brief Determine which objc runtime call instruction class V belongs to.
///
/// This is similar to GetARCInstKind except that it only detects objc
/// runtime calls. This allows it to be faster.
///
static inline ARCInstKind GetBasicARCInstKind(const Value *V) {
if (const CallInst *CI = dyn_cast<CallInst>(V)) {
if (const Function *F = CI->getCalledFunction())
return GetFunctionClass(F);
// Otherwise, be conservative.
return ARCInstKind::CallOrUser;
}
// Otherwise, be conservative.
return isa<InvokeInst>(V) ? ARCInstKind::CallOrUser : ARCInstKind::User;
}
/// \brief Determine what kind of construct V is.
ARCInstKind GetARCInstKind(const Value *V);
} // end namespace objcarc
} // end namespace llvm
#endif

View File

@ -4,7 +4,7 @@ add_llvm_library(LLVMObjCARCOpts
ObjCARCExpand.cpp
ObjCARCAPElim.cpp
ObjCARCAliasAnalysis.cpp
ObjCARCUtil.cpp
ARCInstKind.cpp
ObjCARCContract.cpp
DependencyAnalysis.cpp
ProvenanceAnalysis.cpp

View File

@ -32,15 +32,14 @@ using namespace llvm::objcarc;
/// Test whether the given instruction can result in a reference count
/// modification (positive or negative) for the pointer's object.
bool
llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr,
bool llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr,
ProvenanceAnalysis &PA,
InstructionClass Class) {
ARCInstKind Class) {
switch (Class) {
case IC_Autorelease:
case IC_AutoreleaseRV:
case IC_IntrinsicUser:
case IC_User:
case ARCInstKind::Autorelease:
case ARCInstKind::AutoreleaseRV:
case ARCInstKind::IntrinsicUser:
case ARCInstKind::User:
// These operations never directly modify a reference count.
return false;
default: break;
@ -69,11 +68,11 @@ llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr,
/// Test whether the given instruction can "use" the given pointer's object in a
/// way that requires the reference count to be positive.
bool
llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr,
ProvenanceAnalysis &PA, InstructionClass Class) {
// IC_Call operations (as opposed to IC_CallOrUser) never "use" objc pointers.
if (Class == IC_Call)
bool llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr,
ProvenanceAnalysis &PA, ARCInstKind Class) {
// ARCInstKind::Call operations (as opposed to
// ARCInstKind::CallOrUser) never "use" objc pointers.
if (Class == ARCInstKind::Call)
return false;
// Consider various instructions which may have pointer arguments which are
@ -123,11 +122,11 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
switch (Flavor) {
case NeedsPositiveRetainCount: {
InstructionClass Class = GetInstructionClass(Inst);
ARCInstKind Class = GetARCInstKind(Inst);
switch (Class) {
case IC_AutoreleasepoolPop:
case IC_AutoreleasepoolPush:
case IC_None:
case ARCInstKind::AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::None:
return false;
default:
return CanUse(Inst, Arg, PA, Class);
@ -135,10 +134,10 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
}
case AutoreleasePoolBoundary: {
InstructionClass Class = GetInstructionClass(Inst);
ARCInstKind Class = GetARCInstKind(Inst);
switch (Class) {
case IC_AutoreleasepoolPop:
case IC_AutoreleasepoolPush:
case ARCInstKind::AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPush:
// These mark the end and begin of an autorelease pool scope.
return true;
default:
@ -148,13 +147,13 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
}
case CanChangeRetainCount: {
InstructionClass Class = GetInstructionClass(Inst);
ARCInstKind Class = GetARCInstKind(Inst);
switch (Class) {
case IC_AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPop:
// Conservatively assume this can decrement any count.
return true;
case IC_AutoreleasepoolPush:
case IC_None:
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::None:
return false;
default:
return CanAlterRefCount(Inst, Arg, PA, Class);
@ -162,14 +161,14 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
}
case RetainAutoreleaseDep:
switch (GetBasicInstructionClass(Inst)) {
case IC_AutoreleasepoolPop:
case IC_AutoreleasepoolPush:
switch (GetBasicARCInstKind(Inst)) {
case ARCInstKind::AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPush:
// Don't merge an objc_autorelease with an objc_retain inside a different
// autoreleasepool scope.
return true;
case IC_Retain:
case IC_RetainRV:
case ARCInstKind::Retain:
case ARCInstKind::RetainRV:
// Check for a retain of the same pointer for merging.
return GetArgRCIdentityRoot(Inst) == Arg;
default:
@ -178,10 +177,10 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
}
case RetainAutoreleaseRVDep: {
InstructionClass Class = GetBasicInstructionClass(Inst);
ARCInstKind Class = GetBasicARCInstKind(Inst);
switch (Class) {
case IC_Retain:
case IC_RetainRV:
case ARCInstKind::Retain:
case ARCInstKind::RetainRV:
// Check for a retain of the same pointer for merging.
return GetArgRCIdentityRoot(Inst) == Arg;
default:
@ -192,7 +191,7 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst,
}
case RetainRVDep:
return CanInterruptRV(GetBasicInstructionClass(Inst));
return CanInterruptRV(GetBasicARCInstKind(Inst));
}
llvm_unreachable("Invalid dependence flavor");

View File

@ -63,15 +63,13 @@ Depends(DependenceKind Flavor, Instruction *Inst, const Value *Arg,
/// Test whether the given instruction can "use" the given pointer's object in a
/// way that requires the reference count to be positive.
bool
CanUse(const Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA,
InstructionClass Class);
bool CanUse(const Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA,
ARCInstKind Class);
/// Test whether the given instruction can result in a reference count
/// modification (positive or negative) for the pointer's object.
bool
CanAlterRefCount(const Instruction *Inst, const Value *Ptr,
ProvenanceAnalysis &PA, InstructionClass Class);
bool CanAlterRefCount(const Instruction *Inst, const Value *Ptr,
ProvenanceAnalysis &PA, ARCInstKind Class);
} // namespace objcarc
} // namespace llvm

View File

@ -33,6 +33,7 @@
#include "llvm/Pass.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Utils/Local.h"
#include "ARCInstKind.h"
namespace llvm {
class raw_ostream;
@ -68,160 +69,13 @@ static inline bool ModuleHasARC(const Module &M) {
M.getNamedValue("clang.arc.use");
}
/// \enum InstructionClass
/// \brief A simple classification for instructions.
enum InstructionClass {
IC_Retain, ///< objc_retain
IC_RetainRV, ///< objc_retainAutoreleasedReturnValue
IC_RetainBlock, ///< objc_retainBlock
IC_Release, ///< objc_release
IC_Autorelease, ///< objc_autorelease
IC_AutoreleaseRV, ///< objc_autoreleaseReturnValue
IC_AutoreleasepoolPush, ///< objc_autoreleasePoolPush
IC_AutoreleasepoolPop, ///< objc_autoreleasePoolPop
IC_NoopCast, ///< objc_retainedObject, etc.
IC_FusedRetainAutorelease, ///< objc_retainAutorelease
IC_FusedRetainAutoreleaseRV, ///< objc_retainAutoreleaseReturnValue
IC_LoadWeakRetained, ///< objc_loadWeakRetained (primitive)
IC_StoreWeak, ///< objc_storeWeak (primitive)
IC_InitWeak, ///< objc_initWeak (derived)
IC_LoadWeak, ///< objc_loadWeak (derived)
IC_MoveWeak, ///< objc_moveWeak (derived)
IC_CopyWeak, ///< objc_copyWeak (derived)
IC_DestroyWeak, ///< objc_destroyWeak (derived)
IC_StoreStrong, ///< objc_storeStrong (derived)
IC_IntrinsicUser, ///< clang.arc.use
IC_CallOrUser, ///< could call objc_release and/or "use" pointers
IC_Call, ///< could call objc_release
IC_User, ///< could "use" a pointer
IC_None ///< anything else
};
raw_ostream &operator<<(raw_ostream &OS, const InstructionClass Class);
/// \brief Test if the given class is a kind of user.
inline static bool IsUser(InstructionClass Class) {
return Class == IC_User ||
Class == IC_CallOrUser ||
Class == IC_IntrinsicUser;
}
/// \brief Test if the given class is objc_retain or equivalent.
static inline bool IsRetain(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV;
}
/// \brief Test if the given class is objc_autorelease or equivalent.
static inline bool IsAutorelease(InstructionClass Class) {
return Class == IC_Autorelease ||
Class == IC_AutoreleaseRV;
}
/// \brief Test if the given class represents instructions which return their
/// argument verbatim.
static inline bool IsForwarding(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_Autorelease ||
Class == IC_AutoreleaseRV ||
Class == IC_NoopCast;
}
/// \brief Test if the given class represents instructions which do nothing if
/// passed a null pointer.
static inline bool IsNoopOnNull(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_Release ||
Class == IC_Autorelease ||
Class == IC_AutoreleaseRV ||
Class == IC_RetainBlock;
}
/// \brief Test if the given class represents instructions which are always safe
/// to mark with the "tail" keyword.
static inline bool IsAlwaysTail(InstructionClass Class) {
// IC_RetainBlock may be given a stack argument.
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_AutoreleaseRV;
}
/// \brief Test if the given class represents instructions which are never safe
/// to mark with the "tail" keyword.
static inline bool IsNeverTail(InstructionClass Class) {
/// It is never safe to tail call objc_autorelease since by tail calling
/// objc_autorelease, we also tail call -[NSObject autorelease] which supports
/// fast autoreleasing causing our object to be potentially reclaimed from the
/// autorelease pool which violates the semantics of __autoreleasing types in
/// ARC.
return Class == IC_Autorelease;
}
/// \brief Test if the given class represents instructions which are always safe
/// to mark with the nounwind attribute.
static inline bool IsNoThrow(InstructionClass Class) {
// objc_retainBlock is not nounwind because it calls user copy constructors
// which could theoretically throw.
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_Release ||
Class == IC_Autorelease ||
Class == IC_AutoreleaseRV ||
Class == IC_AutoreleasepoolPush ||
Class == IC_AutoreleasepoolPop;
}
/// Test whether the given instruction can autorelease any pointer or cause an
/// autoreleasepool pop.
static inline bool
CanInterruptRV(InstructionClass Class) {
switch (Class) {
case IC_AutoreleasepoolPop:
case IC_CallOrUser:
case IC_Call:
case IC_Autorelease:
case IC_AutoreleaseRV:
case IC_FusedRetainAutorelease:
case IC_FusedRetainAutoreleaseRV:
return true;
default:
return false;
}
}
/// \brief Determine if F is one of the special known Functions. If it isn't,
/// return IC_CallOrUser.
InstructionClass GetFunctionClass(const Function *F);
/// \brief Determine which objc runtime call instruction class V belongs to.
///
/// This is similar to GetInstructionClass except that it only detects objc
/// runtime calls. This allows it to be faster.
///
static inline InstructionClass GetBasicInstructionClass(const Value *V) {
if (const CallInst *CI = dyn_cast<CallInst>(V)) {
if (const Function *F = CI->getCalledFunction())
return GetFunctionClass(F);
// Otherwise, be conservative.
return IC_CallOrUser;
}
// Otherwise, be conservative.
return isa<InvokeInst>(V) ? IC_CallOrUser : IC_User;
}
/// \brief Determine what kind of construct V is.
InstructionClass GetInstructionClass(const Value *V);
/// \brief This is a wrapper around getUnderlyingObject which also knows how to
/// look through objc_retain and objc_autorelease calls, which we know to return
/// their argument verbatim.
static inline const Value *GetUnderlyingObjCPtr(const Value *V) {
for (;;) {
V = GetUnderlyingObject(V);
if (!IsForwarding(GetBasicInstructionClass(V)))
if (!IsForwarding(GetBasicARCInstKind(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
@ -247,7 +101,7 @@ static inline const Value *GetUnderlyingObjCPtr(const Value *V) {
static inline const Value *GetRCIdentityRoot(const Value *V) {
for (;;) {
V = V->stripPointerCasts();
if (!IsForwarding(GetBasicInstructionClass(V)))
if (!IsForwarding(GetBasicARCInstKind(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
@ -293,8 +147,8 @@ static inline void EraseInstruction(Instruction *CI) {
if (!Unused) {
// Replace the return value with the argument.
assert((IsForwarding(GetBasicInstructionClass(CI)) ||
(IsNoopOnNull(GetBasicInstructionClass(CI)) &&
assert((IsForwarding(GetBasicARCInstKind(CI)) ||
(IsNoopOnNull(GetBasicARCInstKind(CI)) &&
isa<ConstantPointerNull>(OldArg))) &&
"Can't delete non-forwarding instruction with users!");
CI->replaceAllUsesWith(OldArg);
@ -351,15 +205,15 @@ static inline bool IsPotentialRetainableObjPtr(const Value *Op,
return true;
}
/// \brief Helper for GetInstructionClass. Determines what kind of construct CS
/// \brief Helper for GetARCInstKind. Determines what kind of construct CS
/// is.
static inline InstructionClass GetCallSiteClass(ImmutableCallSite CS) {
static inline ARCInstKind GetCallSiteClass(ImmutableCallSite CS) {
for (ImmutableCallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
I != E; ++I)
if (IsPotentialRetainableObjPtr(*I))
return CS.onlyReadsMemory() ? IC_User : IC_CallOrUser;
return CS.onlyReadsMemory() ? ARCInstKind::User : ARCInstKind::CallOrUser;
return CS.onlyReadsMemory() ? IC_None : IC_Call;
return CS.onlyReadsMemory() ? ARCInstKind::None : ARCInstKind::Call;
}
/// \brief Return true if this value refers to a distinct and identifiable

View File

@ -97,11 +97,11 @@ bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) {
Instruction *Push = nullptr;
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
Instruction *Inst = I++;
switch (GetBasicInstructionClass(Inst)) {
case IC_AutoreleasepoolPush:
switch (GetBasicARCInstKind(Inst)) {
case ARCInstKind::AutoreleasepoolPush:
Push = Inst;
break;
case IC_AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPop:
// If this pop matches a push and nothing in between can autorelease,
// zap the pair.
if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push) {
@ -115,7 +115,7 @@ bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) {
}
Push = nullptr;
break;
case IC_CallOrUser:
case ARCInstKind::CallOrUser:
if (MayAutorelease(ImmutableCallSite(Inst)))
Push = nullptr;
break;

View File

@ -120,7 +120,7 @@ ObjCARCAliasAnalysis::getModRefBehavior(const Function *F) {
return AliasAnalysis::getModRefBehavior(F);
switch (GetFunctionClass(F)) {
case IC_NoopCast:
case ARCInstKind::NoopCast:
return DoesNotAccessMemory;
default:
break;
@ -134,15 +134,15 @@ ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS, const Location &Loc) {
if (!EnableARCOpts)
return AliasAnalysis::getModRefInfo(CS, Loc);
switch (GetBasicInstructionClass(CS.getInstruction())) {
case IC_Retain:
case IC_RetainRV:
case IC_Autorelease:
case IC_AutoreleaseRV:
case IC_NoopCast:
case IC_AutoreleasepoolPush:
case IC_FusedRetainAutorelease:
case IC_FusedRetainAutoreleaseRV:
switch (GetBasicARCInstKind(CS.getInstruction())) {
case ARCInstKind::Retain:
case ARCInstKind::RetainRV:
case ARCInstKind::Autorelease:
case ARCInstKind::AutoreleaseRV:
case ARCInstKind::NoopCast:
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::FusedRetainAutorelease:
case ARCInstKind::FusedRetainAutoreleaseRV:
// These functions don't access any memory visible to the compiler.
// Note that this doesn't include objc_retainBlock, because it updates
// pointers when it copies block data.

View File

@ -83,7 +83,7 @@ namespace {
bool
contractAutorelease(Function &F, Instruction *Autorelease,
InstructionClass Class,
ARCInstKind Class,
SmallPtrSetImpl<Instruction *> &DependingInstructions,
SmallPtrSetImpl<const BasicBlock *> &Visited);
@ -143,7 +143,7 @@ bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) {
/// Merge an autorelease with a retain into a fused call.
bool ObjCARCContract::contractAutorelease(
Function &F, Instruction *Autorelease, InstructionClass Class,
Function &F, Instruction *Autorelease, ARCInstKind Class,
SmallPtrSetImpl<Instruction *> &DependingInstructions,
SmallPtrSetImpl<const BasicBlock *> &Visited) {
const Value *Arg = GetArgRCIdentityRoot(Autorelease);
@ -151,7 +151,7 @@ bool ObjCARCContract::contractAutorelease(
// Check that there are no instructions between the retain and the autorelease
// (such as an autorelease_pop) which may change the count.
CallInst *Retain = nullptr;
if (Class == IC_AutoreleaseRV)
if (Class == ARCInstKind::AutoreleaseRV)
FindDependencies(RetainAutoreleaseRVDep, Arg,
Autorelease->getParent(), Autorelease,
DependingInstructions, Visited, PA);
@ -169,8 +169,7 @@ bool ObjCARCContract::contractAutorelease(
Retain = dyn_cast_or_null<CallInst>(*DependingInstructions.begin());
DependingInstructions.clear();
if (!Retain ||
GetBasicInstructionClass(Retain) != IC_Retain ||
if (!Retain || GetBasicARCInstKind(Retain) != ARCInstKind::Retain ||
GetArgRCIdentityRoot(Retain) != Arg)
return false;
@ -181,9 +180,9 @@ bool ObjCARCContract::contractAutorelease(
" Autorelease:" << *Autorelease << "\n"
" Retain: " << *Retain << "\n");
Constant *Decl = EP.get(Class == IC_AutoreleaseRV ?
ARCRuntimeEntryPoints::EPT_RetainAutoreleaseRV :
ARCRuntimeEntryPoints::EPT_RetainAutorelease);
Constant *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV
? ARCRuntimeEntryPoints::EPT_RetainAutoreleaseRV
: ARCRuntimeEntryPoints::EPT_RetainAutorelease);
Retain->setCalledFunction(Decl);
DEBUG(dbgs() << " New RetainAutorelease: " << *Retain << "\n");
@ -222,7 +221,7 @@ tryToContractReleaseIntoStoreStrong(Instruction *Release, inst_iterator &Iter) {
continue;
}
InstructionClass Class = GetBasicInstructionClass(Inst);
ARCInstKind Class = GetBasicARCInstKind(Inst);
// Unrelated retains are harmless.
if (IsRetain(Class))
@ -247,10 +246,11 @@ tryToContractReleaseIntoStoreStrong(Instruction *Release, inst_iterator &Iter) {
// Walk up to find the retain.
I = Store;
BasicBlock::iterator Begin = BB->begin();
while (I != Begin && GetBasicInstructionClass(I) != IC_Retain)
while (I != Begin && GetBasicARCInstKind(I) != ARCInstKind::Retain)
--I;
Instruction *Retain = I;
if (GetBasicInstructionClass(Retain) != IC_Retain) return;
if (GetBasicARCInstKind(Retain) != ARCInstKind::Retain)
return;
if (GetArgRCIdentityRoot(Retain) != New) return;
Changed = true;
@ -300,22 +300,22 @@ bool ObjCARCContract::tryToPeepholeInstruction(
bool &TailOkForStoreStrongs) {
// Only these library routines return their argument. In particular,
// objc_retainBlock does not necessarily return its argument.
InstructionClass Class = GetBasicInstructionClass(Inst);
ARCInstKind Class = GetBasicARCInstKind(Inst);
switch (Class) {
case IC_FusedRetainAutorelease:
case IC_FusedRetainAutoreleaseRV:
case ARCInstKind::FusedRetainAutorelease:
case ARCInstKind::FusedRetainAutoreleaseRV:
return false;
case IC_Autorelease:
case IC_AutoreleaseRV:
case ARCInstKind::Autorelease:
case ARCInstKind::AutoreleaseRV:
return contractAutorelease(F, Inst, Class, DependingInsts, Visited);
case IC_Retain:
case ARCInstKind::Retain:
// Attempt to convert retains to retainrvs if they are next to function
// calls.
if (!optimizeRetainCall(F, Inst))
return false;
// If we succeed in our optimization, fall through.
// FALLTHROUGH
case IC_RetainRV: {
case ARCInstKind::RetainRV: {
// If we're compiling for a target which needs a special inline-asm
// marker to do the retainAutoreleasedReturnValue optimization,
// insert it now.
@ -352,7 +352,7 @@ bool ObjCARCContract::tryToPeepholeInstruction(
decline_rv_optimization:
return false;
}
case IC_InitWeak: {
case ARCInstKind::InitWeak: {
// objc_initWeak(p, null) => *p = null
CallInst *CI = cast<CallInst>(Inst);
if (IsNullOrUndef(CI->getArgOperand(1))) {
@ -369,19 +369,19 @@ bool ObjCARCContract::tryToPeepholeInstruction(
}
return true;
}
case IC_Release:
case ARCInstKind::Release:
// Try to form an objc store strong from our release. If we fail, there is
// nothing further to do below, so continue.
tryToContractReleaseIntoStoreStrong(Inst, Iter);
return true;
case IC_User:
case ARCInstKind::User:
// Be conservative if the function has any alloca instructions.
// Technically we only care about escaping alloca instructions,
// but this is sufficient to handle some interesting cases.
if (isa<AllocaInst>(Inst))
TailOkForStoreStrongs = false;
return true;
case IC_IntrinsicUser:
case ARCInstKind::IntrinsicUser:
// Remove calls to @clang.arc.use(...).
Inst->eraseFromParent();
return true;

View File

@ -99,13 +99,13 @@ bool ObjCARCExpand::runOnFunction(Function &F) {
DEBUG(dbgs() << "ObjCARCExpand: Visiting: " << *Inst << "\n");
switch (GetBasicInstructionClass(Inst)) {
case IC_Retain:
case IC_RetainRV:
case IC_Autorelease:
case IC_AutoreleaseRV:
case IC_FusedRetainAutorelease:
case IC_FusedRetainAutoreleaseRV: {
switch (GetBasicARCInstKind(Inst)) {
case ARCInstKind::Retain:
case ARCInstKind::RetainRV:
case ARCInstKind::Autorelease:
case ARCInstKind::AutoreleaseRV:
case ARCInstKind::FusedRetainAutorelease:
case ARCInstKind::FusedRetainAutoreleaseRV: {
// These calls return their argument verbatim, as a low-level
// optimization. However, this makes high-level optimizations
// harder. Undo any uses of this optimization that the front-end

View File

@ -153,7 +153,7 @@ static const Value *FindSingleUseIdentifiedObject(const Value *Arg) {
if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Arg))
if (GEP->hasAllZeroIndices())
return FindSingleUseIdentifiedObject(GEP->getPointerOperand());
if (IsForwarding(GetBasicInstructionClass(Arg)))
if (IsForwarding(GetBasicARCInstKind(Arg)))
return FindSingleUseIdentifiedObject(
cast<CallInst>(Arg)->getArgOperand(0));
if (!IsObjCIdentifiedObject(Arg))
@ -1096,7 +1096,7 @@ namespace {
bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV);
void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
InstructionClass &Class);
ARCInstKind &Class);
void OptimizeIndividualCalls(Function &F);
void CheckForCFGHazards(const BasicBlock *BB,
@ -1216,7 +1216,7 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
BasicBlock::iterator I = RetainRV, Begin = RetainRV->getParent()->begin();
if (I != Begin) {
do --I; while (I != Begin && IsNoopInstruction(I));
if (GetBasicInstructionClass(I) == IC_AutoreleaseRV &&
if (GetBasicARCInstKind(I) == ARCInstKind::AutoreleaseRV &&
GetArgRCIdentityRoot(I) == Arg) {
Changed = true;
++NumPeeps;
@ -1248,9 +1248,9 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
/// Turn objc_autoreleaseReturnValue into objc_autorelease if the result is not
/// used as a return value.
void
ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
InstructionClass &Class) {
void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F,
Instruction *AutoreleaseRV,
ARCInstKind &Class) {
// Check for a return of the pointer value.
const Value *Ptr = GetArgRCIdentityRoot(AutoreleaseRV);
SmallVector<const Value *, 2> Users;
@ -1258,7 +1258,7 @@ ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
do {
Ptr = Users.pop_back_val();
for (const User *U : Ptr->users()) {
if (isa<ReturnInst>(U) || GetBasicInstructionClass(U) == IC_RetainRV)
if (isa<ReturnInst>(U) || GetBasicARCInstKind(U) == ARCInstKind::RetainRV)
return;
if (isa<BitCastInst>(U))
Users.push_back(U);
@ -1277,7 +1277,7 @@ ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
Constant *NewDecl = EP.get(ARCRuntimeEntryPoints::EPT_Autorelease);
AutoreleaseRVCI->setCalledFunction(NewDecl);
AutoreleaseRVCI->setTailCall(false); // Never tail call objc_autorelease.
Class = IC_Autorelease;
Class = ARCInstKind::Autorelease;
DEBUG(dbgs() << "New: " << *AutoreleaseRV << "\n");
@ -1294,7 +1294,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;
InstructionClass Class = GetBasicInstructionClass(Inst);
ARCInstKind Class = GetBasicARCInstKind(Inst);
DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n");
@ -1309,7 +1309,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
// There are gray areas here, as the ability to cast reference-counted
// pointers to raw void* and back allows code to break ARC assumptions,
// however these are currently considered to be unimportant.
case IC_NoopCast:
case ARCInstKind::NoopCast:
Changed = true;
++NumNoops;
DEBUG(dbgs() << "Erasing no-op cast: " << *Inst << "\n");
@ -1317,11 +1317,11 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
continue;
// If the pointer-to-weak-pointer is null, it's undefined behavior.
case IC_StoreWeak:
case IC_LoadWeak:
case IC_LoadWeakRetained:
case IC_InitWeak:
case IC_DestroyWeak: {
case ARCInstKind::StoreWeak:
case ARCInstKind::LoadWeak:
case ARCInstKind::LoadWeakRetained:
case ARCInstKind::InitWeak:
case ARCInstKind::DestroyWeak: {
CallInst *CI = cast<CallInst>(Inst);
if (IsNullOrUndef(CI->getArgOperand(0))) {
Changed = true;
@ -1338,8 +1338,8 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
}
break;
}
case IC_CopyWeak:
case IC_MoveWeak: {
case ARCInstKind::CopyWeak:
case ARCInstKind::MoveWeak: {
CallInst *CI = cast<CallInst>(Inst);
if (IsNullOrUndef(CI->getArgOperand(0)) ||
IsNullOrUndef(CI->getArgOperand(1))) {
@ -1359,11 +1359,11 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
}
break;
}
case IC_RetainRV:
case ARCInstKind::RetainRV:
if (OptimizeRetainRVCall(F, Inst))
continue;
break;
case IC_AutoreleaseRV:
case ARCInstKind::AutoreleaseRV:
OptimizeAutoreleaseRVCall(F, Inst, Class);
break;
}
@ -1391,7 +1391,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
EraseInstruction(Call);
Inst = NewCall;
Class = IC_Release;
Class = ARCInstKind::Release;
}
}
@ -1422,7 +1422,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
}
if (!IsNoopOnNull(Class)) {
UsedInThisFunction |= 1 << Class;
UsedInThisFunction |= 1 << unsigned(Class);
continue;
}
@ -1440,7 +1440,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
// Keep track of which of retain, release, autorelease, and retain_block
// are actually present in this function.
UsedInThisFunction |= 1 << Class;
UsedInThisFunction |= 1 << unsigned(Class);
// If Arg is a PHI, and one or more incoming values to the
// PHI are null, and the call is control-equivalent to the PHI, and there
@ -1480,25 +1480,25 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
// Check that there is nothing that cares about the reference
// count between the call and the phi.
switch (Class) {
case IC_Retain:
case IC_RetainBlock:
case ARCInstKind::Retain:
case ARCInstKind::RetainBlock:
// These can always be moved up.
break;
case IC_Release:
case ARCInstKind::Release:
// These can't be moved across things that care about the retain
// count.
FindDependencies(NeedsPositiveRetainCount, Arg,
Inst->getParent(), Inst,
DependingInstructions, Visited, PA);
break;
case IC_Autorelease:
case ARCInstKind::Autorelease:
// These can't be moved across autorelease pool scope boundaries.
FindDependencies(AutoreleasePoolBoundary, Arg,
Inst->getParent(), Inst,
DependingInstructions, Visited, PA);
break;
case IC_RetainRV:
case IC_AutoreleaseRV:
case ARCInstKind::RetainRV:
case ARCInstKind::AutoreleaseRV:
// Don't move these; the RV optimization depends on the autoreleaseRV
// being tail called, and the retainRV being immediately after a call
// (which might still happen if we get lucky with codegen layout, but
@ -1711,13 +1711,13 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
MapVector<Value *, RRInfo> &Retains,
BBState &MyStates) {
bool NestingDetected = false;
InstructionClass Class = GetInstructionClass(Inst);
ARCInstKind Class = GetARCInstKind(Inst);
const Value *Arg = nullptr;
DEBUG(dbgs() << "Class: " << Class << "\n");
switch (Class) {
case IC_Release: {
case ARCInstKind::Release: {
Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrBottomUpState(Arg);
@ -1745,13 +1745,13 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
S.SetKnownPositiveRefCount();
break;
}
case IC_RetainBlock:
case ARCInstKind::RetainBlock:
// In OptimizeIndividualCalls, we have strength reduced all optimizable
// objc_retainBlocks to objc_retains. Thus at this point any
// objc_retainBlocks that we see are not optimizable.
break;
case IC_Retain:
case IC_RetainRV: {
case ARCInstKind::Retain:
case ARCInstKind::RetainRV: {
Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrBottomUpState(Arg);
@ -1769,9 +1769,10 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
S.ClearReverseInsertPts();
// FALL THROUGH
case S_CanRelease:
// Don't do retain+release tracking for IC_RetainRV, because it's
// Don't do retain+release tracking for ARCInstKind::RetainRV,
// because it's
// better to let it remain as the first instruction after a call.
if (Class != IC_RetainRV)
if (Class != ARCInstKind::RetainRV)
Retains[Inst] = S.GetRRInfo();
S.ClearSequenceProgress();
break;
@ -1784,15 +1785,15 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
// A retain moving bottom up can be a use.
break;
}
case IC_AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPop:
// Conservatively, clear MyStates for all known pointers.
MyStates.clearBottomUpPointers();
return NestingDetected;
case IC_AutoreleasepoolPush:
case IC_None:
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::None:
// These are irrelevant.
return NestingDetected;
case IC_User:
case ARCInstKind::User:
// If we have a store into an alloca of a pointer we are tracking, the
// pointer has multiple owners implying that we must be more conservative.
//
@ -1967,24 +1968,25 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
DenseMap<Value *, RRInfo> &Releases,
BBState &MyStates) {
bool NestingDetected = false;
InstructionClass Class = GetInstructionClass(Inst);
ARCInstKind Class = GetARCInstKind(Inst);
const Value *Arg = nullptr;
switch (Class) {
case IC_RetainBlock:
case ARCInstKind::RetainBlock:
// In OptimizeIndividualCalls, we have strength reduced all optimizable
// objc_retainBlocks to objc_retains. Thus at this point any
// objc_retainBlocks that we see are not optimizable.
break;
case IC_Retain:
case IC_RetainRV: {
case ARCInstKind::Retain:
case ARCInstKind::RetainRV: {
Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrTopDownState(Arg);
// Don't do retain+release tracking for IC_RetainRV, because it's
// Don't do retain+release tracking for ARCInstKind::RetainRV, because
// it's
// better to let it remain as the first instruction after a call.
if (Class != IC_RetainRV) {
if (Class != ARCInstKind::RetainRV) {
// If we see two retains in a row on the same pointer. If so, make
// a note, and we'll cicle back to revisit it after we've
// hopefully eliminated the second retain, which may allow us to
@ -2007,7 +2009,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
// code below.
break;
}
case IC_Release: {
case ARCInstKind::Release: {
Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrTopDownState(Arg);
@ -2039,12 +2041,12 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
}
break;
}
case IC_AutoreleasepoolPop:
case ARCInstKind::AutoreleasepoolPop:
// Conservatively, clear MyStates for all known pointers.
MyStates.clearTopDownPointers();
return NestingDetected;
case IC_AutoreleasepoolPush:
case IC_None:
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::None:
// These are irrelevant.
return NestingDetected;
default:
@ -2640,12 +2642,13 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
DEBUG(dbgs() << "Visiting: " << *Inst << "\n");
InstructionClass Class = GetBasicInstructionClass(Inst);
if (Class != IC_LoadWeak && Class != IC_LoadWeakRetained)
ARCInstKind Class = GetBasicARCInstKind(Inst);
if (Class != ARCInstKind::LoadWeak &&
Class != ARCInstKind::LoadWeakRetained)
continue;
// Delete objc_loadWeak calls with no users.
if (Class == IC_LoadWeak && Inst->use_empty()) {
if (Class == ARCInstKind::LoadWeak && Inst->use_empty()) {
Inst->eraseFromParent();
continue;
}
@ -2660,10 +2663,10 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
J = Current.getInstructionIterator();
J != B; --J) {
Instruction *EarlierInst = &*std::prev(J);
InstructionClass EarlierClass = GetInstructionClass(EarlierInst);
ARCInstKind EarlierClass = GetARCInstKind(EarlierInst);
switch (EarlierClass) {
case IC_LoadWeak:
case IC_LoadWeakRetained: {
case ARCInstKind::LoadWeak:
case ARCInstKind::LoadWeakRetained: {
// If this is loading from the same pointer, replace this load's value
// with that one.
CallInst *Call = cast<CallInst>(Inst);
@ -2674,7 +2677,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
case AliasAnalysis::MustAlias:
Changed = true;
// If the load has a builtin retain, insert a plain retain for it.
if (Class == IC_LoadWeakRetained) {
if (Class == ARCInstKind::LoadWeakRetained) {
Constant *Decl = EP.get(ARCRuntimeEntryPoints::EPT_Retain);
CallInst *CI = CallInst::Create(Decl, EarlierCall, "", Call);
CI->setTailCall();
@ -2691,8 +2694,8 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
}
break;
}
case IC_StoreWeak:
case IC_InitWeak: {
case ARCInstKind::StoreWeak:
case ARCInstKind::InitWeak: {
// If this is storing to the same pointer and has the same size etc.
// replace this load's value with the stored value.
CallInst *Call = cast<CallInst>(Inst);
@ -2703,7 +2706,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
case AliasAnalysis::MustAlias:
Changed = true;
// If the load has a builtin retain, insert a plain retain for it.
if (Class == IC_LoadWeakRetained) {
if (Class == ARCInstKind::LoadWeakRetained) {
Constant *Decl = EP.get(ARCRuntimeEntryPoints::EPT_Retain);
CallInst *CI = CallInst::Create(Decl, EarlierCall, "", Call);
CI->setTailCall();
@ -2720,14 +2723,14 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
}
break;
}
case IC_MoveWeak:
case IC_CopyWeak:
case ARCInstKind::MoveWeak:
case ARCInstKind::CopyWeak:
// TOOD: Grab the copied value.
goto clobbered;
case IC_AutoreleasepoolPush:
case IC_None:
case IC_IntrinsicUser:
case IC_User:
case ARCInstKind::AutoreleasepoolPush:
case ARCInstKind::None:
case ARCInstKind::IntrinsicUser:
case ARCInstKind::User:
// Weak pointers are only modified through the weak entry points
// (and arbitrary calls, which could call the weak entry points).
break;
@ -2743,8 +2746,8 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
// the alloca and all its users can be zapped.
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;
InstructionClass Class = GetBasicInstructionClass(Inst);
if (Class != IC_DestroyWeak)
ARCInstKind Class = GetBasicARCInstKind(Inst);
if (Class != ARCInstKind::DestroyWeak)
continue;
CallInst *Call = cast<CallInst>(Inst);
@ -2752,10 +2755,10 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
if (AllocaInst *Alloca = dyn_cast<AllocaInst>(Arg)) {
for (User *U : Alloca->users()) {
const Instruction *UserInst = cast<Instruction>(U);
switch (GetBasicInstructionClass(UserInst)) {
case IC_InitWeak:
case IC_StoreWeak:
case IC_DestroyWeak:
switch (GetBasicARCInstKind(UserInst)) {
case ARCInstKind::InitWeak:
case ARCInstKind::StoreWeak:
case ARCInstKind::DestroyWeak:
continue;
default:
goto done;
@ -2764,13 +2767,13 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
Changed = true;
for (auto UI = Alloca->user_begin(), UE = Alloca->user_end(); UI != UE;) {
CallInst *UserInst = cast<CallInst>(*UI++);
switch (GetBasicInstructionClass(UserInst)) {
case IC_InitWeak:
case IC_StoreWeak:
switch (GetBasicARCInstKind(UserInst)) {
case ARCInstKind::InitWeak:
case ARCInstKind::StoreWeak:
// These functions return their second argument.
UserInst->replaceAllUsesWith(UserInst->getArgOperand(1));
break;
case IC_DestroyWeak:
case ARCInstKind::DestroyWeak:
// No return value.
break;
default:
@ -2833,8 +2836,8 @@ HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain,
return false;
// Check that the call is a regular call.
InstructionClass Class = GetBasicInstructionClass(Call);
if (Class != IC_CallOrUser && Class != IC_Call)
ARCInstKind Class = GetBasicARCInstKind(Call);
if (Class != ARCInstKind::CallOrUser && Class != ARCInstKind::Call)
return false;
return true;
@ -2858,8 +2861,7 @@ FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB,
dyn_cast_or_null<CallInst>(*DepInsts.begin());
// Check that we found a retain with the same argument.
if (!Retain ||
!IsRetain(GetBasicInstructionClass(Retain)) ||
if (!Retain || !IsRetain(GetBasicARCInstKind(Retain)) ||
GetArgRCIdentityRoot(Retain) != Arg) {
return nullptr;
}
@ -2885,7 +2887,7 @@ FindPredecessorAutoreleaseWithSafePath(const Value *Arg, BasicBlock *BB,
dyn_cast_or_null<CallInst>(*DepInsts.begin());
if (!Autorelease)
return nullptr;
InstructionClass AutoreleaseClass = GetBasicInstructionClass(Autorelease);
ARCInstKind AutoreleaseClass = GetBasicARCInstKind(Autorelease);
if (!IsAutorelease(AutoreleaseClass))
return nullptr;
if (GetArgRCIdentityRoot(Autorelease) != Arg)
@ -2974,13 +2976,13 @@ ObjCARCOpt::GatherStatistics(Function &F, bool AfterOptimization) {
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;
switch (GetBasicInstructionClass(Inst)) {
switch (GetBasicARCInstKind(Inst)) {
default:
break;
case IC_Retain:
case ARCInstKind::Retain:
++NumRetains;
break;
case IC_Release:
case ARCInstKind::Release:
++NumReleases;
break;
}
@ -3052,27 +3054,27 @@ bool ObjCARCOpt::runOnFunction(Function &F) {
OptimizeIndividualCalls(F);
// Optimizations for weak pointers.
if (UsedInThisFunction & ((1 << IC_LoadWeak) |
(1 << IC_LoadWeakRetained) |
(1 << IC_StoreWeak) |
(1 << IC_InitWeak) |
(1 << IC_CopyWeak) |
(1 << IC_MoveWeak) |
(1 << IC_DestroyWeak)))
if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::LoadWeak)) |
(1 << unsigned(ARCInstKind::LoadWeakRetained)) |
(1 << unsigned(ARCInstKind::StoreWeak)) |
(1 << unsigned(ARCInstKind::InitWeak)) |
(1 << unsigned(ARCInstKind::CopyWeak)) |
(1 << unsigned(ARCInstKind::MoveWeak)) |
(1 << unsigned(ARCInstKind::DestroyWeak))))
OptimizeWeakCalls(F);
// Optimizations for retain+release pairs.
if (UsedInThisFunction & ((1 << IC_Retain) |
(1 << IC_RetainRV) |
(1 << IC_RetainBlock)))
if (UsedInThisFunction & (1 << IC_Release))
if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::Retain)) |
(1 << unsigned(ARCInstKind::RetainRV)) |
(1 << unsigned(ARCInstKind::RetainBlock))))
if (UsedInThisFunction & (1 << unsigned(ARCInstKind::Release)))
// Run OptimizeSequences until it either stops making changes or
// no retain+release pair nesting is detected.
while (OptimizeSequences(F)) {}
// Optimizations if objc_autorelease is used.
if (UsedInThisFunction & ((1 << IC_Autorelease) |
(1 << IC_AutoreleaseRV)))
if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::Autorelease)) |
(1 << unsigned(ARCInstKind::AutoreleaseRV))))
OptimizeReturns(F);
// Gather statistics after optimization.

View File

@ -1,254 +0,0 @@
//===- ObjCARCUtil.cpp - ObjC ARC Optimization ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines several utility functions used by various ARC
/// optimizations which are IMHO too big to be in a header file.
///
/// WARNING: This file knows about certain library functions. It recognizes them
/// by name, and hardwires knowledge of their semantics.
///
/// WARNING: This file knows about how certain Objective-C library functions are
/// used. Naive LLVM IR transformations which would otherwise be
/// behavior-preserving may break these assumptions.
///
//===----------------------------------------------------------------------===//
#include "ObjCARC.h"
#include "llvm/IR/Intrinsics.h"
using namespace llvm;
using namespace llvm::objcarc;
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS,
const InstructionClass Class) {
switch (Class) {
case IC_Retain:
return OS << "IC_Retain";
case IC_RetainRV:
return OS << "IC_RetainRV";
case IC_RetainBlock:
return OS << "IC_RetainBlock";
case IC_Release:
return OS << "IC_Release";
case IC_Autorelease:
return OS << "IC_Autorelease";
case IC_AutoreleaseRV:
return OS << "IC_AutoreleaseRV";
case IC_AutoreleasepoolPush:
return OS << "IC_AutoreleasepoolPush";
case IC_AutoreleasepoolPop:
return OS << "IC_AutoreleasepoolPop";
case IC_NoopCast:
return OS << "IC_NoopCast";
case IC_FusedRetainAutorelease:
return OS << "IC_FusedRetainAutorelease";
case IC_FusedRetainAutoreleaseRV:
return OS << "IC_FusedRetainAutoreleaseRV";
case IC_LoadWeakRetained:
return OS << "IC_LoadWeakRetained";
case IC_StoreWeak:
return OS << "IC_StoreWeak";
case IC_InitWeak:
return OS << "IC_InitWeak";
case IC_LoadWeak:
return OS << "IC_LoadWeak";
case IC_MoveWeak:
return OS << "IC_MoveWeak";
case IC_CopyWeak:
return OS << "IC_CopyWeak";
case IC_DestroyWeak:
return OS << "IC_DestroyWeak";
case IC_StoreStrong:
return OS << "IC_StoreStrong";
case IC_CallOrUser:
return OS << "IC_CallOrUser";
case IC_Call:
return OS << "IC_Call";
case IC_User:
return OS << "IC_User";
case IC_IntrinsicUser:
return OS << "IC_IntrinsicUser";
case IC_None:
return OS << "IC_None";
}
llvm_unreachable("Unknown instruction class!");
}
InstructionClass llvm::objcarc::GetFunctionClass(const Function *F) {
Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
// No (mandatory) arguments.
if (AI == AE)
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_autoreleasePoolPush", IC_AutoreleasepoolPush)
.Case("clang.arc.use", IC_IntrinsicUser)
.Default(IC_CallOrUser);
// One argument.
const Argument *A0 = AI++;
if (AI == AE)
// Argument is a pointer.
if (PointerType *PTy = dyn_cast<PointerType>(A0->getType())) {
Type *ETy = PTy->getElementType();
// Argument is i8*.
if (ETy->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_retain", IC_Retain)
.Case("objc_retainAutoreleasedReturnValue", IC_RetainRV)
.Case("objc_retainBlock", IC_RetainBlock)
.Case("objc_release", IC_Release)
.Case("objc_autorelease", IC_Autorelease)
.Case("objc_autoreleaseReturnValue", IC_AutoreleaseRV)
.Case("objc_autoreleasePoolPop", IC_AutoreleasepoolPop)
.Case("objc_retainedObject", IC_NoopCast)
.Case("objc_unretainedObject", IC_NoopCast)
.Case("objc_unretainedPointer", IC_NoopCast)
.Case("objc_retain_autorelease", IC_FusedRetainAutorelease)
.Case("objc_retainAutorelease", IC_FusedRetainAutorelease)
.Case("objc_retainAutoreleaseReturnValue",IC_FusedRetainAutoreleaseRV)
.Case("objc_sync_enter", IC_User)
.Case("objc_sync_exit", IC_User)
.Default(IC_CallOrUser);
// Argument is i8**
if (PointerType *Pte = dyn_cast<PointerType>(ETy))
if (Pte->getElementType()->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_loadWeakRetained", IC_LoadWeakRetained)
.Case("objc_loadWeak", IC_LoadWeak)
.Case("objc_destroyWeak", IC_DestroyWeak)
.Default(IC_CallOrUser);
}
// Two arguments, first is i8**.
const Argument *A1 = AI++;
if (AI == AE)
if (PointerType *PTy = dyn_cast<PointerType>(A0->getType()))
if (PointerType *Pte = dyn_cast<PointerType>(PTy->getElementType()))
if (Pte->getElementType()->isIntegerTy(8))
if (PointerType *PTy1 = dyn_cast<PointerType>(A1->getType())) {
Type *ETy1 = PTy1->getElementType();
// Second argument is i8*
if (ETy1->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_storeWeak", IC_StoreWeak)
.Case("objc_initWeak", IC_InitWeak)
.Case("objc_storeStrong", IC_StoreStrong)
.Default(IC_CallOrUser);
// Second argument is i8**.
if (PointerType *Pte1 = dyn_cast<PointerType>(ETy1))
if (Pte1->getElementType()->isIntegerTy(8))
return StringSwitch<InstructionClass>(F->getName())
.Case("objc_moveWeak", IC_MoveWeak)
.Case("objc_copyWeak", IC_CopyWeak)
// Ignore annotation calls. This is important to stop the
// optimizer from treating annotations as uses which would
// make the state of the pointers they are attempting to
// elucidate to be incorrect.
.Case("llvm.arc.annotation.topdown.bbstart", IC_None)
.Case("llvm.arc.annotation.topdown.bbend", IC_None)
.Case("llvm.arc.annotation.bottomup.bbstart", IC_None)
.Case("llvm.arc.annotation.bottomup.bbend", IC_None)
.Default(IC_CallOrUser);
}
// Anything else.
return IC_CallOrUser;
}
/// \brief Determine what kind of construct V is.
InstructionClass
llvm::objcarc::GetInstructionClass(const Value *V) {
if (const Instruction *I = dyn_cast<Instruction>(V)) {
// Any instruction other than bitcast and gep with a pointer operand have a
// use of an objc pointer. Bitcasts, GEPs, Selects, PHIs transfer a pointer
// to a subsequent use, rather than using it themselves, in this sense.
// As a short cut, several other opcodes are known to have no pointer
// operands of interest. And ret is never followed by a release, so it's
// not interesting to examine.
switch (I->getOpcode()) {
case Instruction::Call: {
const CallInst *CI = cast<CallInst>(I);
// Check for calls to special functions.
if (const Function *F = CI->getCalledFunction()) {
InstructionClass Class = GetFunctionClass(F);
if (Class != IC_CallOrUser)
return Class;
// None of the intrinsic functions do objc_release. For intrinsics, the
// only question is whether or not they may be users.
switch (F->getIntrinsicID()) {
case Intrinsic::returnaddress: case Intrinsic::frameaddress:
case Intrinsic::stacksave: case Intrinsic::stackrestore:
case Intrinsic::vastart: case Intrinsic::vacopy: case Intrinsic::vaend:
case Intrinsic::objectsize: case Intrinsic::prefetch:
case Intrinsic::stackprotector:
case Intrinsic::eh_return_i32: case Intrinsic::eh_return_i64:
case Intrinsic::eh_typeid_for: case Intrinsic::eh_dwarf_cfa:
case Intrinsic::eh_sjlj_lsda: case Intrinsic::eh_sjlj_functioncontext:
case Intrinsic::init_trampoline: case Intrinsic::adjust_trampoline:
case Intrinsic::lifetime_start: case Intrinsic::lifetime_end:
case Intrinsic::invariant_start: case Intrinsic::invariant_end:
// Don't let dbg info affect our results.
case Intrinsic::dbg_declare: case Intrinsic::dbg_value:
// Short cut: Some intrinsics obviously don't use ObjC pointers.
return IC_None;
default:
break;
}
}
return GetCallSiteClass(CI);
}
case Instruction::Invoke:
return GetCallSiteClass(cast<InvokeInst>(I));
case Instruction::BitCast:
case Instruction::GetElementPtr:
case Instruction::Select: case Instruction::PHI:
case Instruction::Ret: case Instruction::Br:
case Instruction::Switch: case Instruction::IndirectBr:
case Instruction::Alloca: case Instruction::VAArg:
case Instruction::Add: case Instruction::FAdd:
case Instruction::Sub: case Instruction::FSub:
case Instruction::Mul: case Instruction::FMul:
case Instruction::SDiv: case Instruction::UDiv: case Instruction::FDiv:
case Instruction::SRem: case Instruction::URem: case Instruction::FRem:
case Instruction::Shl: case Instruction::LShr: case Instruction::AShr:
case Instruction::And: case Instruction::Or: case Instruction::Xor:
case Instruction::SExt: case Instruction::ZExt: case Instruction::Trunc:
case Instruction::IntToPtr: case Instruction::FCmp:
case Instruction::FPTrunc: case Instruction::FPExt:
case Instruction::FPToUI: case Instruction::FPToSI:
case Instruction::UIToFP: case Instruction::SIToFP:
case Instruction::InsertElement: case Instruction::ExtractElement:
case Instruction::ShuffleVector:
case Instruction::ExtractValue:
break;
case Instruction::ICmp:
// Comparing a pointer with null, or any other constant, isn't an
// interesting use, because we don't care what the pointer points to, or
// about the values of any other dynamic reference-counted pointers.
if (IsPotentialRetainableObjPtr(I->getOperand(1)))
return IC_User;
break;
default:
// For anything else, check all the operands.
// Note that this includes both operands of a Store: while the first
// operand isn't actually being dereferenced, it is being stored to
// memory where we can no longer track who might read it and dereference
// it, so we have to consider it potentially used.
for (User::const_op_iterator OI = I->op_begin(), OE = I->op_end();
OI != OE; ++OI)
if (IsPotentialRetainableObjPtr(*OI))
return IC_User;
}
}
// Otherwise, it's totally inert for ARC purposes.
return IC_None;
}