mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
Refactor ObjCARCAliasAnalysis into its own file.
llvm-svn: 173662
This commit is contained in:
parent
fbc4fffb48
commit
86d4759cc7
@ -3,6 +3,7 @@ add_llvm_library(LLVMObjCARCOpts
|
||||
ObjCARCOpts.cpp
|
||||
ObjCARCExpand.cpp
|
||||
ObjCARCAPElim.cpp
|
||||
ObjCARCAliasAnalysis.cpp
|
||||
)
|
||||
|
||||
add_dependencies(LLVMObjCARCOpts intrinsics_gen)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
@ -145,10 +146,81 @@ static raw_ostream &operator<<(raw_ostream &OS, const InstructionClass Class) {
|
||||
llvm_unreachable("Unknown instruction class!");
|
||||
}
|
||||
|
||||
/// \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) {
|
||||
// objc_retainBlock technically doesn't always return its argument
|
||||
// verbatim, but it doesn't matter for our purposes here.
|
||||
return Class == IC_Retain ||
|
||||
Class == IC_RetainRV ||
|
||||
Class == IC_Autorelease ||
|
||||
Class == IC_AutoreleaseRV ||
|
||||
Class == IC_RetainBlock ||
|
||||
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;
|
||||
}
|
||||
|
||||
/// \brief Determine if F is one of the special known Functions. If it isn't,
|
||||
/// return IC_CallOrUser.
|
||||
static inline InstructionClass GetFunctionClass(const Function *F) {
|
||||
static InstructionClass GetFunctionClass(const Function *F)
|
||||
LLVM_ATTRIBUTE_USED;
|
||||
static InstructionClass GetFunctionClass(const Function *F) {
|
||||
Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end();
|
||||
|
||||
// No arguments.
|
||||
@ -236,6 +308,48 @@ static inline InstructionClass GetBasicInstructionClass(const Value *V) {
|
||||
return isa<InvokeInst>(V) ? IC_CallOrUser : IC_User;
|
||||
}
|
||||
|
||||
|
||||
/// \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)))
|
||||
break;
|
||||
V = cast<CallInst>(V)->getArgOperand(0);
|
||||
}
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
/// \brief This is a wrapper around Value::stripPointerCasts 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 *StripPointerCastsAndObjCCalls(const Value *V) {
|
||||
for (;;) {
|
||||
V = V->stripPointerCasts();
|
||||
if (!IsForwarding(GetBasicInstructionClass(V)))
|
||||
break;
|
||||
V = cast<CallInst>(V)->getArgOperand(0);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
/// \brief This is a wrapper around Value::stripPointerCasts which also knows
|
||||
/// how to look through objc_retain and objc_autorelease calls, which we know to
|
||||
/// return their argument verbatim.
|
||||
static inline Value *StripPointerCastsAndObjCCalls(Value *V) {
|
||||
for (;;) {
|
||||
V = V->stripPointerCasts();
|
||||
if (!IsForwarding(GetBasicInstructionClass(V)))
|
||||
break;
|
||||
V = cast<CallInst>(V)->getArgOperand(0);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace objcarc
|
||||
} // end namespace llvm
|
||||
|
||||
|
164
lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp
Normal file
164
lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
//===- ObjCARCAliasAnalysis.cpp - ObjC ARC Optimization -*- mode: 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 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.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "objc-arc-aa"
|
||||
#include "ObjCARC.h"
|
||||
#include "ObjCARCAliasAnalysis.h"
|
||||
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/PassAnalysisSupport.h"
|
||||
#include "llvm/PassSupport.h"
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class Value;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void
|
||||
ObjCARCAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AliasAnalysis::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
AliasAnalysis::AliasResult
|
||||
ObjCARCAliasAnalysis::alias(const Location &LocA, const Location &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 = StripPointerCastsAndObjCCalls(LocA.Ptr);
|
||||
const Value *SB = StripPointerCastsAndObjCCalls(LocB.Ptr);
|
||||
AliasResult Result =
|
||||
AliasAnalysis::alias(Location(SA, LocA.Size, LocA.TBAATag),
|
||||
Location(SB, LocB.Size, LocB.TBAATag));
|
||||
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);
|
||||
const Value *UB = GetUnderlyingObjCPtr(SB);
|
||||
if (UA != SA || UB != SB) {
|
||||
Result = AliasAnalysis::alias(Location(UA), Location(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 Location &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 = StripPointerCastsAndObjCCalls(Loc.Ptr);
|
||||
if (AliasAnalysis::pointsToConstantMemory(Location(S, Loc.Size, Loc.TBAATag),
|
||||
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);
|
||||
if (U != S)
|
||||
return AliasAnalysis::pointsToConstantMemory(Location(U), OrLocal);
|
||||
|
||||
// If that failed, fail. We don't need to chain here, since that's covered
|
||||
// by the earlier precise query.
|
||||
return false;
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefBehavior
|
||||
ObjCARCAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
|
||||
// We have nothing to do. Just chain to the next AliasAnalysis.
|
||||
return AliasAnalysis::getModRefBehavior(CS);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefBehavior
|
||||
ObjCARCAliasAnalysis::getModRefBehavior(const Function *F) {
|
||||
if (!EnableARCOpts)
|
||||
return AliasAnalysis::getModRefBehavior(F);
|
||||
|
||||
switch (GetFunctionClass(F)) {
|
||||
case IC_NoopCast:
|
||||
return DoesNotAccessMemory;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return AliasAnalysis::getModRefBehavior(F);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
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:
|
||||
// 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 NoModRef;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return AliasAnalysis::getModRefInfo(CS, Loc);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2) {
|
||||
// TODO: Theoretically we could check for dependencies between objc_* calls
|
||||
// and OnlyAccessesArgumentPointees calls or other well-behaved calls.
|
||||
return AliasAnalysis::getModRefInfo(CS1, CS2);
|
||||
}
|
||||
|
71
lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.h
Normal file
71
lib/Transforms/ObjCARC/ObjCARCAliasAnalysis.h
Normal file
@ -0,0 +1,71 @@
|
||||
//===- ObjCARCAliasAnalysis.h - ObjC ARC Optimization -*- mode: 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_TRANSFORMS_OBJCARC_OBJCARCALIASANALYSIS_H
|
||||
#define LLVM_TRANSFORMS_OBJCARC_OBJCARCALIASANALYSIS_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:
|
||||
virtual void initializePass() {
|
||||
InitializeAliasAnalysis(this);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
virtual void *getAdjustedAnalysisPointer(const void *PI) {
|
||||
if (PI == &AliasAnalysis::ID)
|
||||
return static_cast<AliasAnalysis *>(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
virtual AliasResult alias(const Location &LocA, const Location &LocB);
|
||||
virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal);
|
||||
virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
virtual ModRefBehavior getModRefBehavior(const Function *F);
|
||||
virtual ModRefResult getModRefInfo(ImmutableCallSite CS,
|
||||
const Location &Loc);
|
||||
virtual ModRefResult getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2);
|
||||
};
|
||||
|
||||
} // namespace objcarc
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_OBJCARC_OBJCARCALIASANALYSIS_H
|
@ -30,6 +30,7 @@
|
||||
|
||||
#define DEBUG_TYPE "objc-arc-opts"
|
||||
#include "ObjCARC.h"
|
||||
#include "ObjCARCAliasAnalysis.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
@ -131,7 +132,6 @@ namespace {
|
||||
/// \defgroup ARCUtilities Utility declarations/definitions specific to ARC.
|
||||
/// @{
|
||||
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
@ -260,76 +260,6 @@ static InstructionClass GetInstructionClass(const Value *V) {
|
||||
return IC_None;
|
||||
}
|
||||
|
||||
/// \brief Test if the given class is objc_retain or equivalent.
|
||||
static bool IsRetain(InstructionClass Class) {
|
||||
return Class == IC_Retain ||
|
||||
Class == IC_RetainRV;
|
||||
}
|
||||
|
||||
/// \brief Test if the given class is objc_autorelease or equivalent.
|
||||
static 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 bool IsForwarding(InstructionClass Class) {
|
||||
// objc_retainBlock technically doesn't always return its argument
|
||||
// verbatim, but it doesn't matter for our purposes here.
|
||||
return Class == IC_Retain ||
|
||||
Class == IC_RetainRV ||
|
||||
Class == IC_Autorelease ||
|
||||
Class == IC_AutoreleaseRV ||
|
||||
Class == IC_RetainBlock ||
|
||||
Class == IC_NoopCast;
|
||||
}
|
||||
|
||||
/// \brief Test if the given class represents instructions which do nothing if
|
||||
/// passed a null pointer.
|
||||
static 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 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 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 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;
|
||||
}
|
||||
|
||||
/// \brief Erase the given instruction.
|
||||
///
|
||||
/// Many ObjC calls return their argument verbatim,
|
||||
@ -354,46 +284,6 @@ static void EraseInstruction(Instruction *CI) {
|
||||
RecursivelyDeleteTriviallyDeadInstructions(OldArg);
|
||||
}
|
||||
|
||||
/// \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 const Value *GetUnderlyingObjCPtr(const Value *V) {
|
||||
for (;;) {
|
||||
V = GetUnderlyingObject(V);
|
||||
if (!IsForwarding(GetBasicInstructionClass(V)))
|
||||
break;
|
||||
V = cast<CallInst>(V)->getArgOperand(0);
|
||||
}
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
/// \brief This is a wrapper around Value::stripPointerCasts which also knows
|
||||
/// how to look through objc_retain and objc_autorelease calls, which we know to
|
||||
/// return their argument verbatim.
|
||||
static const Value *StripPointerCastsAndObjCCalls(const Value *V) {
|
||||
for (;;) {
|
||||
V = V->stripPointerCasts();
|
||||
if (!IsForwarding(GetBasicInstructionClass(V)))
|
||||
break;
|
||||
V = cast<CallInst>(V)->getArgOperand(0);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
/// \brief This is a wrapper around Value::stripPointerCasts which also knows
|
||||
/// how to look through objc_retain and objc_autorelease calls, which we know to
|
||||
/// return their argument verbatim.
|
||||
static Value *StripPointerCastsAndObjCCalls(Value *V) {
|
||||
for (;;) {
|
||||
V = V->stripPointerCasts();
|
||||
if (!IsForwarding(GetBasicInstructionClass(V)))
|
||||
break;
|
||||
V = cast<CallInst>(V)->getArgOperand(0);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
/// \brief Assuming the given instruction is one of the special calls such as
|
||||
/// objc_retain or objc_release, return the argument value, stripped of no-op
|
||||
/// casts and forwarding calls.
|
||||
@ -551,177 +441,6 @@ static bool DoesObjCBlockEscape(const Value *BlockPtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
///
|
||||
/// \defgroup ARCAA Extends alias analysis using ObjC specific knowledge.
|
||||
/// @{
|
||||
|
||||
namespace {
|
||||
/// \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:
|
||||
virtual void initializePass() {
|
||||
InitializeAliasAnalysis(this);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
virtual void *getAdjustedAnalysisPointer(const void *PI) {
|
||||
if (PI == &AliasAnalysis::ID)
|
||||
return static_cast<AliasAnalysis *>(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
virtual AliasResult alias(const Location &LocA, const Location &LocB);
|
||||
virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal);
|
||||
virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS);
|
||||
virtual ModRefBehavior getModRefBehavior(const Function *F);
|
||||
virtual ModRefResult getModRefInfo(ImmutableCallSite CS,
|
||||
const Location &Loc);
|
||||
virtual ModRefResult getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2);
|
||||
};
|
||||
} // End of anonymous namespace
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
void
|
||||
ObjCARCAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AliasAnalysis::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
AliasAnalysis::AliasResult
|
||||
ObjCARCAliasAnalysis::alias(const Location &LocA, const Location &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 = StripPointerCastsAndObjCCalls(LocA.Ptr);
|
||||
const Value *SB = StripPointerCastsAndObjCCalls(LocB.Ptr);
|
||||
AliasResult Result =
|
||||
AliasAnalysis::alias(Location(SA, LocA.Size, LocA.TBAATag),
|
||||
Location(SB, LocB.Size, LocB.TBAATag));
|
||||
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);
|
||||
const Value *UB = GetUnderlyingObjCPtr(SB);
|
||||
if (UA != SA || UB != SB) {
|
||||
Result = AliasAnalysis::alias(Location(UA), Location(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 Location &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 = StripPointerCastsAndObjCCalls(Loc.Ptr);
|
||||
if (AliasAnalysis::pointsToConstantMemory(Location(S, Loc.Size, Loc.TBAATag),
|
||||
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);
|
||||
if (U != S)
|
||||
return AliasAnalysis::pointsToConstantMemory(Location(U), OrLocal);
|
||||
|
||||
// If that failed, fail. We don't need to chain here, since that's covered
|
||||
// by the earlier precise query.
|
||||
return false;
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefBehavior
|
||||
ObjCARCAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
|
||||
// We have nothing to do. Just chain to the next AliasAnalysis.
|
||||
return AliasAnalysis::getModRefBehavior(CS);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefBehavior
|
||||
ObjCARCAliasAnalysis::getModRefBehavior(const Function *F) {
|
||||
if (!EnableARCOpts)
|
||||
return AliasAnalysis::getModRefBehavior(F);
|
||||
|
||||
switch (GetFunctionClass(F)) {
|
||||
case IC_NoopCast:
|
||||
return DoesNotAccessMemory;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return AliasAnalysis::getModRefBehavior(F);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
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:
|
||||
// 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 NoModRef;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return AliasAnalysis::getModRefInfo(CS, Loc);
|
||||
}
|
||||
|
||||
AliasAnalysis::ModRefResult
|
||||
ObjCARCAliasAnalysis::getModRefInfo(ImmutableCallSite CS1,
|
||||
ImmutableCallSite CS2) {
|
||||
// TODO: Theoretically we could check for dependencies between objc_* calls
|
||||
// and OnlyAccessesArgumentPointees calls or other well-behaved calls.
|
||||
return AliasAnalysis::getModRefInfo(CS1, CS2);
|
||||
}
|
||||
|
||||
/// @}
|
||||
///
|
||||
/// \defgroup ARCOpt ARC Optimization.
|
||||
|
Loading…
Reference in New Issue
Block a user