From: Michael Gottesman Date: Thu, 19 Feb 2015 19:51:32 +0000 (+0000) Subject: [objc-arc] Change the InstructionClass to be an enum class called ARCInstKind. X-Git-Tag: llvmorg-3.7.0-rc1~11451 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6f729fa6754414064160fa4105346bbe1cd46968;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp b/llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp new file mode 100644 index 0000000..e65a057 --- /dev/null +++ b/llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp @@ -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(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(A0->getType())) { + Type *ETy = PTy->getElementType(); + // Argument is i8*. + if (ETy->isIntegerTy(8)) + return StringSwitch(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(ETy)) + if (Pte->getElementType()->isIntegerTy(8)) + return StringSwitch(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(A0->getType())) + if (PointerType *Pte = dyn_cast(PTy->getElementType())) + if (Pte->getElementType()->isIntegerTy(8)) + if (PointerType *PTy1 = dyn_cast(A1->getType())) { + Type *ETy1 = PTy1->getElementType(); + // Second argument is i8* + if (ETy1->isIntegerTy(8)) + return StringSwitch(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(ETy1)) + if (Pte1->getElementType()->isIntegerTy(8)) + return StringSwitch(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(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(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(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; +} diff --git a/llvm/lib/Transforms/ObjCARC/ARCInstKind.h b/llvm/lib/Transforms/ObjCARC/ARCInstKind.h new file mode 100644 index 0000000..a09e846 --- /dev/null +++ b/llvm/lib/Transforms/ObjCARC/ARCInstKind.h @@ -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(V)) { + if (const Function *F = CI->getCalledFunction()) + return GetFunctionClass(F); + // Otherwise, be conservative. + return ARCInstKind::CallOrUser; + } + + // Otherwise, be conservative. + return isa(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 diff --git a/llvm/lib/Transforms/ObjCARC/CMakeLists.txt b/llvm/lib/Transforms/ObjCARC/CMakeLists.txt index b0f5549..2adea88 100644 --- a/llvm/lib/Transforms/ObjCARC/CMakeLists.txt +++ b/llvm/lib/Transforms/ObjCARC/CMakeLists.txt @@ -4,7 +4,7 @@ add_llvm_library(LLVMObjCARCOpts ObjCARCExpand.cpp ObjCARCAPElim.cpp ObjCARCAliasAnalysis.cpp - ObjCARCUtil.cpp + ARCInstKind.cpp ObjCARCContract.cpp DependencyAnalysis.cpp ProvenanceAnalysis.cpp diff --git a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp index 9160493..9eb91a5 100644 --- a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp +++ b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp @@ -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, - ProvenanceAnalysis &PA, - InstructionClass Class) { +bool llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr, + ProvenanceAnalysis &PA, + 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"); diff --git a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h index 7b5601a..77e4bdf 100644 --- a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h +++ b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h @@ -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 diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h b/llvm/lib/Transforms/ObjCARC/ObjCARC.h index 66fcc98..df29f05 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h @@ -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(V)) { - if (const Function *F = CI->getCalledFunction()) - return GetFunctionClass(F); - // Otherwise, be conservative. - return IC_CallOrUser; - } - - // Otherwise, be conservative. - return isa(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(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(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(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 diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp index 1a25391..d318643 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp @@ -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(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; diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp index ad18ea2..be291a0 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp @@ -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. diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp index 19fcd00..f413c64 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -83,7 +83,7 @@ namespace { bool contractAutorelease(Function &F, Instruction *Autorelease, - InstructionClass Class, + ARCInstKind Class, SmallPtrSetImpl &DependingInstructions, SmallPtrSetImpl &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 &DependingInstructions, SmallPtrSetImpl &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(*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(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(Inst)) TailOkForStoreStrongs = false; return true; - case IC_IntrinsicUser: + case ARCInstKind::IntrinsicUser: // Remove calls to @clang.arc.use(...). Inst->eraseFromParent(); return true; diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp index bf9fcbb..53c19c3 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp @@ -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 diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 992cd46..f55b77f 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -153,7 +153,7 @@ static const Value *FindSingleUseIdentifiedObject(const Value *Arg) { if (const GetElementPtrInst *GEP = dyn_cast(Arg)) if (GEP->hasAllZeroIndices()) return FindSingleUseIdentifiedObject(GEP->getPointerOperand()); - if (IsForwarding(GetBasicInstructionClass(Arg))) + if (IsForwarding(GetBasicARCInstKind(Arg))) return FindSingleUseIdentifiedObject( cast(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 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(U) || GetBasicInstructionClass(U) == IC_RetainRV) + if (isa(U) || GetBasicARCInstKind(U) == ARCInstKind::RetainRV) return; if (isa(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(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(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 &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 &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(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(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(Inst); @@ -2752,10 +2755,10 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) { if (AllocaInst *Alloca = dyn_cast(Arg)) { for (User *U : Alloca->users()) { const Instruction *UserInst = cast(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(*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(*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(*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. diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCUtil.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCUtil.cpp deleted file mode 100644 index 53c077e..0000000 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCUtil.cpp +++ /dev/null @@ -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(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(A0->getType())) { - Type *ETy = PTy->getElementType(); - // Argument is i8*. - if (ETy->isIntegerTy(8)) - return StringSwitch(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(ETy)) - if (Pte->getElementType()->isIntegerTy(8)) - return StringSwitch(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(A0->getType())) - if (PointerType *Pte = dyn_cast(PTy->getElementType())) - if (Pte->getElementType()->isIntegerTy(8)) - if (PointerType *PTy1 = dyn_cast(A1->getType())) { - Type *ETy1 = PTy1->getElementType(); - // Second argument is i8* - if (ETy1->isIntegerTy(8)) - return StringSwitch(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(ETy1)) - if (Pte1->getElementType()->isIntegerTy(8)) - return StringSwitch(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(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(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(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; -}