diff options
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp | 673 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ARCInstKind.h | 123 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/CMakeLists.txt | 2 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ObjCARC.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ObjCARC.h | 242 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp | 162 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.h | 72 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/PtrState.h | 2 |
9 files changed, 4 insertions, 1282 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp b/llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp deleted file mode 100644 index afb873a355a..00000000000 --- a/llvm/lib/Transforms/ObjCARC/ARCInstKind.cpp +++ /dev/null @@ -1,673 +0,0 @@ -//===- 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; -} - -// A whitelist of intrinsics that we know do not use objc pointers or decrement -// ref counts. -static bool isInertIntrinsic(unsigned ID) { - // TODO: Make this into a covered switch. - switch (ID) { - 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 true; - default: - return false; - } -} - -// A whitelist of intrinsics that we know do not use objc pointers or decrement -// ref counts. -static bool isUseOnlyIntrinsic(unsigned ID) { - // We are conservative and even though intrinsics are unlikely to touch - // reference counts, we white list them for safety. - // - // TODO: Expand this into a covered switch. There is a lot more here. - switch (ID) { - case Intrinsic::memcpy: - case Intrinsic::memmove: - case Intrinsic::memset: - return true; - default: - return false; - } -} - -/// \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); - // See if we have a function that we know something about. - if (const Function *F = CI->getCalledFunction()) { - ARCInstKind Class = GetFunctionClass(F); - if (Class != ARCInstKind::CallOrUser) - return Class; - Intrinsic::ID ID = F->getIntrinsicID(); - if (isInertIntrinsic(ID)) - return ARCInstKind::None; - if (isUseOnlyIntrinsic(ID)) - return ARCInstKind::User; - } - - // Otherwise, be conservative. - return GetCallSiteClass(CI); - } - case Instruction::Invoke: - // Otherwise, be conservative. - 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; -} - -/// \brief Test if the given class is a kind of user. -bool llvm::objcarc::IsUser(ARCInstKind Class) { - switch (Class) { - case ARCInstKind::User: - case ARCInstKind::CallOrUser: - case ARCInstKind::IntrinsicUser: - return true; - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::RetainBlock: - case ARCInstKind::Release: - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::NoopCast: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::Call: - case ARCInstKind::None: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class is objc_retain or equivalent. -bool llvm::objcarc::IsRetain(ARCInstKind Class) { - switch (Class) { - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - return true; - // I believe we treat retain block as not a retain since it can copy its - // block. - case ARCInstKind::RetainBlock: - case ARCInstKind::Release: - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::NoopCast: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class is objc_autorelease or equivalent. -bool llvm::objcarc::IsAutorelease(ARCInstKind Class) { - switch (Class) { - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - return true; - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::RetainBlock: - case ARCInstKind::Release: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::NoopCast: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class represents instructions which return their -/// argument verbatim. -bool llvm::objcarc::IsForwarding(ARCInstKind Class) { - switch (Class) { - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::NoopCast: - return true; - case ARCInstKind::RetainBlock: - case ARCInstKind::Release: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class represents instructions which do nothing if -/// passed a null pointer. -bool llvm::objcarc::IsNoopOnNull(ARCInstKind Class) { - switch (Class) { - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::Release: - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::RetainBlock: - return true; - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - case ARCInstKind::NoopCast: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class represents instructions which are always safe -/// to mark with the "tail" keyword. -bool llvm::objcarc::IsAlwaysTail(ARCInstKind Class) { - // ARCInstKind::RetainBlock may be given a stack argument. - switch (Class) { - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::AutoreleaseRV: - return true; - case ARCInstKind::Release: - case ARCInstKind::Autorelease: - case ARCInstKind::RetainBlock: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - case ARCInstKind::NoopCast: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class represents instructions which are never safe -/// to mark with the "tail" keyword. -bool llvm::objcarc::IsNeverTail(ARCInstKind Class) { - /// It is never safe to tail call objc_autorelease since by tail calling - /// objc_autorelease: fast autoreleasing causing our object to be potentially - /// reclaimed from the autorelease pool which violates the semantics of - /// __autoreleasing types in ARC. - switch (Class) { - case ARCInstKind::Autorelease: - return true; - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::Release: - case ARCInstKind::RetainBlock: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - case ARCInstKind::NoopCast: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// \brief Test if the given class represents instructions which are always safe -/// to mark with the nounwind attribute. -bool llvm::objcarc::IsNoThrow(ARCInstKind Class) { - // objc_retainBlock is not nounwind because it calls user copy constructors - // which could theoretically throw. - switch (Class) { - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::Release: - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - return true; - case ARCInstKind::RetainBlock: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - case ARCInstKind::User: - case ARCInstKind::None: - case ARCInstKind::NoopCast: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -/// Test whether the given instruction can autorelease any pointer or cause an -/// autoreleasepool pop. -/// -/// This means that it *could* interrupt the RV optimization. -bool llvm::objcarc::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; - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::Release: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::RetainBlock: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::User: - case ARCInstKind::None: - case ARCInstKind::NoopCast: - return false; - } - llvm_unreachable("covered switch isn't covered?"); -} - -bool llvm::objcarc::CanDecrementRefCount(ARCInstKind Kind) { - switch (Kind) { - case ARCInstKind::Retain: - case ARCInstKind::RetainRV: - case ARCInstKind::Autorelease: - case ARCInstKind::AutoreleaseRV: - case ARCInstKind::NoopCast: - case ARCInstKind::FusedRetainAutorelease: - case ARCInstKind::FusedRetainAutoreleaseRV: - case ARCInstKind::IntrinsicUser: - case ARCInstKind::User: - case ARCInstKind::None: - return false; - - // The cases below are conservative. - - // RetainBlock can result in user defined copy constructors being called - // implying releases may occur. - case ARCInstKind::RetainBlock: - case ARCInstKind::Release: - case ARCInstKind::AutoreleasepoolPush: - case ARCInstKind::AutoreleasepoolPop: - case ARCInstKind::LoadWeakRetained: - case ARCInstKind::StoreWeak: - case ARCInstKind::InitWeak: - case ARCInstKind::LoadWeak: - case ARCInstKind::MoveWeak: - case ARCInstKind::CopyWeak: - case ARCInstKind::DestroyWeak: - case ARCInstKind::StoreStrong: - case ARCInstKind::CallOrUser: - case ARCInstKind::Call: - return true; - } - - llvm_unreachable("covered switch isn't covered?"); -} diff --git a/llvm/lib/Transforms/ObjCARC/ARCInstKind.h b/llvm/lib/Transforms/ObjCARC/ARCInstKind.h deleted file mode 100644 index 636c65c9b62..00000000000 --- a/llvm/lib/Transforms/ObjCARC/ARCInstKind.h +++ /dev/null @@ -1,123 +0,0 @@ -//===--- 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 that is inert from an ARC perspective. -}; - -raw_ostream &operator<<(raw_ostream &OS, const ARCInstKind Class); - -/// \brief Test if the given class is a kind of user. -bool IsUser(ARCInstKind Class); - -/// \brief Test if the given class is objc_retain or equivalent. -bool IsRetain(ARCInstKind Class); - -/// \brief Test if the given class is objc_autorelease or equivalent. -bool IsAutorelease(ARCInstKind Class); - -/// \brief Test if the given class represents instructions which return their -/// argument verbatim. -bool IsForwarding(ARCInstKind Class); - -/// \brief Test if the given class represents instructions which do nothing if -/// passed a null pointer. -bool IsNoopOnNull(ARCInstKind Class); - -/// \brief Test if the given class represents instructions which are always safe -/// to mark with the "tail" keyword. -bool IsAlwaysTail(ARCInstKind Class); - -/// \brief Test if the given class represents instructions which are never safe -/// to mark with the "tail" keyword. -bool IsNeverTail(ARCInstKind Class); - -/// \brief Test if the given class represents instructions which are always safe -/// to mark with the nounwind attribute. -bool IsNoThrow(ARCInstKind Class); - -/// Test whether the given instruction can autorelease any pointer or cause an -/// autoreleasepool pop. -bool CanInterruptRV(ARCInstKind Class); - -/// \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; -} - -/// Map V to its ARCInstKind equivalence class. -ARCInstKind GetARCInstKind(const Value *V); - -/// Returns false if conservatively we can prove that any instruction mapped to -/// this kind can not decrement ref counts. Returns true otherwise. -bool CanDecrementRefCount(ARCInstKind Kind); - -} // end namespace objcarc -} // end namespace llvm - -#endif diff --git a/llvm/lib/Transforms/ObjCARC/CMakeLists.txt b/llvm/lib/Transforms/ObjCARC/CMakeLists.txt index fbcae29044c..98ad37f5d23 100644 --- a/llvm/lib/Transforms/ObjCARC/CMakeLists.txt +++ b/llvm/lib/Transforms/ObjCARC/CMakeLists.txt @@ -3,8 +3,6 @@ add_llvm_library(LLVMObjCARCOpts ObjCARCOpts.cpp ObjCARCExpand.cpp ObjCARCAPElim.cpp - ObjCARCAliasAnalysis.cpp - ARCInstKind.cpp ObjCARCContract.cpp DependencyAnalysis.cpp ProvenanceAnalysis.cpp diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp index 6ea038b8ba8..2960c9b689a 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp @@ -26,14 +26,6 @@ namespace llvm { using namespace llvm; using namespace llvm::objcarc; -/// \brief A handy option to enable/disable all ARC Optimizations. -bool llvm::objcarc::EnableARCOpts; -static cl::opt<bool, true> -EnableARCOptimizations("enable-objc-arc-opts", - cl::desc("enable/disable all ARC Optimizations"), - cl::location(EnableARCOpts), - cl::init(true)); - /// initializeObjCARCOptsPasses - Initialize all passes linked into the /// ObjCARCOpts library. void llvm::initializeObjCARCOpts(PassRegistry &Registry) { diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h b/llvm/lib/Transforms/ObjCARC/ObjCARC.h index 7595e2db1a7..5fd45b00af1 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h @@ -26,6 +26,8 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Optional.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/ObjCARCAnalysisUtils.h" +#include "llvm/Analysis/ObjCARCInstKind.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CallSite.h" @@ -34,7 +36,6 @@ #include "llvm/Pass.h" #include "llvm/Transforms/ObjCARC.h" #include "llvm/Transforms/Utils/Local.h" -#include "ARCInstKind.h" namespace llvm { class raw_ostream; @@ -43,99 +44,6 @@ class raw_ostream; namespace llvm { namespace objcarc { -/// \brief A handy option to enable/disable all ARC Optimizations. -extern bool EnableARCOpts; - -/// \brief Test if the given module looks interesting to run ARC optimization -/// on. -static inline bool ModuleHasARC(const Module &M) { - return - M.getNamedValue("objc_retain") || - M.getNamedValue("objc_release") || - M.getNamedValue("objc_autorelease") || - M.getNamedValue("objc_retainAutoreleasedReturnValue") || - M.getNamedValue("objc_retainBlock") || - M.getNamedValue("objc_autoreleaseReturnValue") || - M.getNamedValue("objc_autoreleasePoolPush") || - M.getNamedValue("objc_loadWeakRetained") || - M.getNamedValue("objc_loadWeak") || - M.getNamedValue("objc_destroyWeak") || - M.getNamedValue("objc_storeWeak") || - M.getNamedValue("objc_initWeak") || - M.getNamedValue("objc_moveWeak") || - M.getNamedValue("objc_copyWeak") || - M.getNamedValue("objc_retainedObject") || - M.getNamedValue("objc_unretainedObject") || - M.getNamedValue("objc_unretainedPointer") || - M.getNamedValue("clang.arc.use"); -} - -/// \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, - const DataLayout &DL) { - for (;;) { - V = GetUnderlyingObject(V, DL); - if (!IsForwarding(GetBasicARCInstKind(V))) - break; - V = cast<CallInst>(V)->getArgOperand(0); - } - - return V; -} - -/// The RCIdentity root of a value \p V is a dominating value U for which -/// retaining or releasing U is equivalent to retaining or releasing V. In other -/// words, ARC operations on \p V are equivalent to ARC operations on \p U. -/// -/// We use this in the ARC optimizer to make it easier to match up ARC -/// operations by always mapping ARC operations to RCIdentityRoots instead of -/// pointers themselves. -/// -/// The two ways that we see RCIdentical values in ObjC are via: -/// -/// 1. PointerCasts -/// 2. Forwarding Calls that return their argument verbatim. -/// -/// Thus this function strips off pointer casts and forwarding calls. *NOTE* -/// This implies that two RCIdentical values must alias. -static inline const Value *GetRCIdentityRoot(const Value *V) { - for (;;) { - V = V->stripPointerCasts(); - if (!IsForwarding(GetBasicARCInstKind(V))) - break; - V = cast<CallInst>(V)->getArgOperand(0); - } - return V; -} - -/// Helper which calls const Value *GetRCIdentityRoot(const Value *V) and just -/// casts away the const of the result. For documentation about what an -/// RCIdentityRoot (and by extension GetRCIdentityRoot is) look at that -/// function. -static inline Value *GetRCIdentityRoot(Value *V) { - return const_cast<Value *>(GetRCIdentityRoot((const Value *)V)); -} - -/// \brief Assuming the given instruction is one of the special calls such as -/// objc_retain or objc_release, return the RCIdentity root of the argument of -/// the call. -static inline Value *GetArgRCIdentityRoot(Value *Inst) { - return GetRCIdentityRoot(cast<CallInst>(Inst)->getArgOperand(0)); -} - -static inline bool IsNullOrUndef(const Value *V) { - return isa<ConstantPointerNull>(V) || isa<UndefValue>(V); -} - -static inline bool IsNoopInstruction(const Instruction *I) { - return isa<BitCastInst>(I) || - (isa<GetElementPtrInst>(I) && - cast<GetElementPtrInst>(I)->hasAllZeroIndices()); -} - - /// \brief Erase the given instruction. /// /// Many ObjC calls return their argument verbatim, @@ -162,152 +70,6 @@ static inline void EraseInstruction(Instruction *CI) { RecursivelyDeleteTriviallyDeadInstructions(OldArg); } -/// \brief Test whether the given value is possible a retainable object pointer. -static inline bool IsPotentialRetainableObjPtr(const Value *Op) { - // Pointers to static or stack storage are not valid retainable object - // pointers. - if (isa<Constant>(Op) || isa<AllocaInst>(Op)) - return false; - // Special arguments can not be a valid retainable object pointer. - if (const Argument *Arg = dyn_cast<Argument>(Op)) - if (Arg->hasByValAttr() || - Arg->hasInAllocaAttr() || - Arg->hasNestAttr() || - Arg->hasStructRetAttr()) - return false; - // Only consider values with pointer types. - // - // It seemes intuitive to exclude function pointer types as well, since - // functions are never retainable object pointers, however clang occasionally - // bitcasts retainable object pointers to function-pointer type temporarily. - PointerType *Ty = dyn_cast<PointerType>(Op->getType()); - if (!Ty) - return false; - // Conservatively assume anything else is a potential retainable object - // pointer. - return true; -} - -static inline bool IsPotentialRetainableObjPtr(const Value *Op, - AliasAnalysis &AA) { - // First make the rudimentary check. - if (!IsPotentialRetainableObjPtr(Op)) - return false; - - // Objects in constant memory are not reference-counted. - if (AA.pointsToConstantMemory(Op)) - return false; - - // Pointers in constant memory are not pointing to reference-counted objects. - if (const LoadInst *LI = dyn_cast<LoadInst>(Op)) - if (AA.pointsToConstantMemory(LI->getPointerOperand())) - return false; - - // Otherwise assume the worst. - return true; -} - -/// \brief Helper for GetARCInstKind. Determines what kind of construct CS -/// is. -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() ? ARCInstKind::User : ARCInstKind::CallOrUser; - - return CS.onlyReadsMemory() ? ARCInstKind::None : ARCInstKind::Call; -} - -/// \brief Return true if this value refers to a distinct and identifiable -/// object. -/// -/// This is similar to AliasAnalysis's isIdentifiedObject, except that it uses -/// special knowledge of ObjC conventions. -static inline bool IsObjCIdentifiedObject(const Value *V) { - // Assume that call results and arguments have their own "provenance". - // Constants (including GlobalVariables) and Allocas are never - // reference-counted. - if (isa<CallInst>(V) || isa<InvokeInst>(V) || - isa<Argument>(V) || isa<Constant>(V) || - isa<AllocaInst>(V)) - return true; - - if (const LoadInst *LI = dyn_cast<LoadInst>(V)) { - const Value *Pointer = - GetRCIdentityRoot(LI->getPointerOperand()); - if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Pointer)) { - // A constant pointer can't be pointing to an object on the heap. It may - // be reference-counted, but it won't be deleted. - if (GV->isConstant()) - return true; - StringRef Name = GV->getName(); - // These special variables are known to hold values which are not - // reference-counted pointers. - if (Name.startswith("\01l_objc_msgSend_fixup_")) - return true; - - StringRef Section = GV->getSection(); - if (Section.find("__message_refs") != StringRef::npos || - Section.find("__objc_classrefs") != StringRef::npos || - Section.find("__objc_superrefs") != StringRef::npos || - Section.find("__objc_methname") != StringRef::npos || - Section.find("__cstring") != StringRef::npos) - return true; - } - } - - return false; -} - -enum class ARCMDKindID { - ImpreciseRelease, - CopyOnEscape, - NoObjCARCExceptions, -}; - -/// A cache of MDKinds used by various ARC optimizations. -class ARCMDKindCache { - Module *M; - - /// The Metadata Kind for clang.imprecise_release metadata. - llvm::Optional<unsigned> ImpreciseReleaseMDKind; - - /// The Metadata Kind for clang.arc.copy_on_escape metadata. - llvm::Optional<unsigned> CopyOnEscapeMDKind; - - /// The Metadata Kind for clang.arc.no_objc_arc_exceptions metadata. - llvm::Optional<unsigned> NoObjCARCExceptionsMDKind; - -public: - void init(Module *Mod) { - M = Mod; - ImpreciseReleaseMDKind = NoneType::None; - CopyOnEscapeMDKind = NoneType::None; - NoObjCARCExceptionsMDKind = NoneType::None; - } - - unsigned get(ARCMDKindID ID) { - switch (ID) { - case ARCMDKindID::ImpreciseRelease: - if (!ImpreciseReleaseMDKind) - ImpreciseReleaseMDKind = - M->getContext().getMDKindID("clang.imprecise_release"); - return *ImpreciseReleaseMDKind; - case ARCMDKindID::CopyOnEscape: - if (!CopyOnEscapeMDKind) - CopyOnEscapeMDKind = - M->getContext().getMDKindID("clang.arc.copy_on_escape"); - return *CopyOnEscapeMDKind; - case ARCMDKindID::NoObjCARCExceptions: - if (!NoObjCARCExceptionsMDKind) - NoObjCARCExceptionsMDKind = - M->getContext().getMDKindID("clang.arc.no_objc_arc_exceptions"); - return *NoObjCARCExceptionsMDKind; - } - llvm_unreachable("Covered switch isn't covered?!"); - } -}; - } // end namespace objcarc } // end namespace llvm diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp deleted file mode 100644 index 7de4b7f8b9d..00000000000 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp +++ /dev/null @@ -1,162 +0,0 @@ -//===- ObjCARCAliasAnalysis.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 a simple ARC-aware AliasAnalysis using special knowledge -/// of Objective C to enhance other optimization passes which rely on the Alias -/// Analysis infrastructure. -/// -/// 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 "ObjCARCAliasAnalysis.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Value.h" -#include "llvm/InitializePasses.h" -#include "llvm/PassAnalysisSupport.h" -#include "llvm/PassSupport.h" - -#define DEBUG_TYPE "objc-arc-aa" - -using namespace llvm; -using namespace llvm::objcarc; - -// Register this pass... -char ObjCARCAliasAnalysis::ID = 0; -INITIALIZE_AG_PASS(ObjCARCAliasAnalysis, AliasAnalysis, "objc-arc-aa", - "ObjC-ARC-Based Alias Analysis", false, true, false) - -ImmutablePass *llvm::createObjCARCAliasAnalysisPass() { - return new ObjCARCAliasAnalysis(); -} - -bool ObjCARCAliasAnalysis::doInitialization(Module &M) { - InitializeAliasAnalysis(this, &M.getDataLayout()); - return true; -} - -void ObjCARCAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AliasAnalysis::getAnalysisUsage(AU); -} - -AliasResult ObjCARCAliasAnalysis::alias(const MemoryLocation &LocA, - const MemoryLocation &LocB) { - if (!EnableARCOpts) - return AliasAnalysis::alias(LocA, LocB); - - // First, strip off no-ops, including ObjC-specific no-ops, and try making a - // precise alias query. - const Value *SA = GetRCIdentityRoot(LocA.Ptr); - const Value *SB = GetRCIdentityRoot(LocB.Ptr); - AliasResult Result = - AliasAnalysis::alias(MemoryLocation(SA, LocA.Size, LocA.AATags), - MemoryLocation(SB, LocB.Size, LocB.AATags)); - if (Result != MayAlias) - return Result; - - // If that failed, climb to the underlying object, including climbing through - // ObjC-specific no-ops, and try making an imprecise alias query. - const Value *UA = GetUnderlyingObjCPtr(SA, *DL); - const Value *UB = GetUnderlyingObjCPtr(SB, *DL); - if (UA != SA || UB != SB) { - Result = AliasAnalysis::alias(MemoryLocation(UA), MemoryLocation(UB)); - // We can't use MustAlias or PartialAlias results here because - // GetUnderlyingObjCPtr may return an offsetted pointer value. - if (Result == NoAlias) - return NoAlias; - } - - // If that failed, fail. We don't need to chain here, since that's covered - // by the earlier precise query. - return MayAlias; -} - -bool ObjCARCAliasAnalysis::pointsToConstantMemory(const MemoryLocation &Loc, - bool OrLocal) { - if (!EnableARCOpts) - return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); - - // First, strip off no-ops, including ObjC-specific no-ops, and try making - // a precise alias query. - const Value *S = GetRCIdentityRoot(Loc.Ptr); - if (AliasAnalysis::pointsToConstantMemory( - MemoryLocation(S, Loc.Size, Loc.AATags), OrLocal)) - return true; - - // If that failed, climb to the underlying object, including climbing through - // ObjC-specific no-ops, and try making an imprecise alias query. - const Value *U = GetUnderlyingObjCPtr(S, *DL); - if (U != S) - return AliasAnalysis::pointsToConstantMemory(MemoryLocation(U), OrLocal); - - // If that failed, fail. We don't need to chain here, since that's covered - // by the earlier precise query. - return false; -} - -FunctionModRefBehavior -ObjCARCAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { - // We have nothing to do. Just chain to the next AliasAnalysis. - return AliasAnalysis::getModRefBehavior(CS); -} - -FunctionModRefBehavior -ObjCARCAliasAnalysis::getModRefBehavior(const Function *F) { - if (!EnableARCOpts) - return AliasAnalysis::getModRefBehavior(F); - - switch (GetFunctionClass(F)) { - case ARCInstKind::NoopCast: - return FMRB_DoesNotAccessMemory; - default: - break; - } - - return AliasAnalysis::getModRefBehavior(F); -} - -ModRefInfo ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS, - const MemoryLocation &Loc) { - if (!EnableARCOpts) - return AliasAnalysis::getModRefInfo(CS, Loc); - - 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. - return MRI_NoModRef; - default: - break; - } - - return AliasAnalysis::getModRefInfo(CS, Loc); -} - -ModRefInfo ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS1, - ImmutableCallSite CS2) { - // TODO: Theoretically we could check for dependencies between objc_* calls - // and FMRB_OnlyAccessesArgumentPointees calls or other well-behaved calls. - return AliasAnalysis::getModRefInfo(CS1, CS2); -} diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.h b/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.h deleted file mode 100644 index 5e75c65dd39..00000000000 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.h +++ /dev/null @@ -1,72 +0,0 @@ -//===- ObjCARCAliasAnalysis.h - ObjC ARC Optimization -*- C++ -*-----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// \file -/// This file declares a simple ARC-aware AliasAnalysis using special knowledge -/// of Objective C to enhance other optimization passes which rely on the Alias -/// Analysis infrastructure. -/// -/// 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. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARCALIASANALYSIS_H -#define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARCALIASANALYSIS_H - -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Pass.h" - -namespace llvm { -namespace objcarc { - -/// \brief This is a simple alias analysis implementation that uses knowledge -/// of ARC constructs to answer queries. -/// -/// TODO: This class could be generalized to know about other ObjC-specific -/// tricks. Such as knowing that ivars in the non-fragile ABI are non-aliasing -/// even though their offsets are dynamic. -class ObjCARCAliasAnalysis : public ImmutablePass, public AliasAnalysis { -public: - static char ID; // Class identification, replacement for typeinfo - ObjCARCAliasAnalysis() : ImmutablePass(ID) { - initializeObjCARCAliasAnalysisPass(*PassRegistry::getPassRegistry()); - } - -private: - bool doInitialization(Module &M) override; - - /// This method is used when a pass implements an analysis interface through - /// multiple inheritance. If needed, it should override this to adjust the - /// this pointer as needed for the specified pass info. - void *getAdjustedAnalysisPointer(const void *PI) override { - if (PI == &AliasAnalysis::ID) - return static_cast<AliasAnalysis *>(this); - return this; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override; - AliasResult alias(const MemoryLocation &LocA, - const MemoryLocation &LocB) override; - bool pointsToConstantMemory(const MemoryLocation &Loc, bool OrLocal) override; - FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS) override; - FunctionModRefBehavior getModRefBehavior(const Function *F) override; - ModRefInfo getModRefInfo(ImmutableCallSite CS, - const MemoryLocation &Loc) override; - ModRefInfo getModRefInfo(ImmutableCallSite CS1, - ImmutableCallSite CS2) override; -}; - -} // namespace objcarc -} // namespace llvm - -#endif diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index b2d11e7035f..e5b61defc37 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -28,7 +28,6 @@ #include "ARCRuntimeEntryPoints.h" #include "BlotMapVector.h" #include "DependencyAnalysis.h" -#include "ObjCARCAliasAnalysis.h" #include "ProvenanceAnalysis.h" #include "PtrState.h" #include "llvm/ADT/DenseMap.h" @@ -36,6 +35,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/ObjCARCAliasAnalysis.h" #include "llvm/IR/CFG.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" diff --git a/llvm/lib/Transforms/ObjCARC/PtrState.h b/llvm/lib/Transforms/ObjCARC/PtrState.h index a8c6ff1ed62..9749e44822b 100644 --- a/llvm/lib/Transforms/ObjCARC/PtrState.h +++ b/llvm/lib/Transforms/ObjCARC/PtrState.h @@ -17,8 +17,8 @@ #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H #define LLVM_LIB_TRANSFORMS_OBJCARC_PTRSTATE_H -#include "ARCInstKind.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/ObjCARCInstKind.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Value.h" #include "llvm/Support/raw_ostream.h" |