[objc-arc] Move the detection of potential uses or altering of a ref count onto PtrState.
llvm-svn: 231446
This commit is contained in:
parent
5dfe0ffb0c
commit
16e6a2057f
|
@ -1113,71 +1113,11 @@ bool ObjCARCOpt::VisitInstructionBottomUp(
|
||||||
if (Ptr == Arg)
|
if (Ptr == Arg)
|
||||||
continue; // Handled above.
|
continue; // Handled above.
|
||||||
BottomUpPtrState &S = MI->second;
|
BottomUpPtrState &S = MI->second;
|
||||||
Sequence Seq = S.GetSeq();
|
|
||||||
|
|
||||||
// Check for possible releases.
|
if (S.HandlePotentialAlterRefCount(Inst, Ptr, PA, Class))
|
||||||
if (CanAlterRefCount(Inst, Ptr, PA, Class)) {
|
continue;
|
||||||
DEBUG(dbgs() << "CanAlterRefCount: Seq: " << Seq << "; " << *Ptr
|
|
||||||
<< "\n");
|
|
||||||
S.ClearKnownPositiveRefCount();
|
|
||||||
switch (Seq) {
|
|
||||||
case S_Use:
|
|
||||||
S.SetSeq(S_CanRelease);
|
|
||||||
continue;
|
|
||||||
case S_CanRelease:
|
|
||||||
case S_Release:
|
|
||||||
case S_MovableRelease:
|
|
||||||
case S_Stop:
|
|
||||||
case S_None:
|
|
||||||
break;
|
|
||||||
case S_Retain:
|
|
||||||
llvm_unreachable("bottom-up pointer in retain state!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for possible direct uses.
|
S.HandlePotentialUse(BB, Inst, Ptr, PA, Class);
|
||||||
switch (Seq) {
|
|
||||||
case S_Release:
|
|
||||||
case S_MovableRelease:
|
|
||||||
if (CanUse(Inst, Ptr, PA, Class)) {
|
|
||||||
DEBUG(dbgs() << "CanUse: Seq: " << Seq << "; " << *Ptr
|
|
||||||
<< "\n");
|
|
||||||
assert(!S.HasReverseInsertPts());
|
|
||||||
// If this is an invoke instruction, we're scanning it as part of
|
|
||||||
// one of its successor blocks, since we can't insert code after it
|
|
||||||
// in its own block, and we don't want to split critical edges.
|
|
||||||
if (isa<InvokeInst>(Inst))
|
|
||||||
S.InsertReverseInsertPt(BB->getFirstInsertionPt());
|
|
||||||
else
|
|
||||||
S.InsertReverseInsertPt(std::next(BasicBlock::iterator(Inst)));
|
|
||||||
S.SetSeq(S_Use);
|
|
||||||
} else if (Seq == S_Release && IsUser(Class)) {
|
|
||||||
DEBUG(dbgs() << "PreciseReleaseUse: Seq: " << Seq << "; " << *Ptr
|
|
||||||
<< "\n");
|
|
||||||
// Non-movable releases depend on any possible objc pointer use.
|
|
||||||
S.SetSeq(S_Stop);
|
|
||||||
assert(!S.HasReverseInsertPts());
|
|
||||||
// As above; handle invoke specially.
|
|
||||||
if (isa<InvokeInst>(Inst))
|
|
||||||
S.InsertReverseInsertPt(BB->getFirstInsertionPt());
|
|
||||||
else
|
|
||||||
S.InsertReverseInsertPt(std::next(BasicBlock::iterator(Inst)));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case S_Stop:
|
|
||||||
if (CanUse(Inst, Ptr, PA, Class)) {
|
|
||||||
DEBUG(dbgs() << "PreciseStopUse: Seq: " << Seq << "; " << *Ptr
|
|
||||||
<< "\n");
|
|
||||||
S.SetSeq(S_Use);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case S_CanRelease:
|
|
||||||
case S_Use:
|
|
||||||
case S_None:
|
|
||||||
break;
|
|
||||||
case S_Retain:
|
|
||||||
llvm_unreachable("bottom-up pointer in retain state!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NestingDetected;
|
return NestingDetected;
|
||||||
|
@ -1294,52 +1234,10 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
|
||||||
if (Ptr == Arg)
|
if (Ptr == Arg)
|
||||||
continue; // Handled above.
|
continue; // Handled above.
|
||||||
TopDownPtrState &S = MI->second;
|
TopDownPtrState &S = MI->second;
|
||||||
Sequence Seq = S.GetSeq();
|
if (S.HandlePotentialAlterRefCount(Inst, Ptr, PA, Class))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Check for possible releases.
|
S.HandlePotentialUse(Inst, Ptr, PA, Class);
|
||||||
if (CanAlterRefCount(Inst, Ptr, PA, Class)) {
|
|
||||||
DEBUG(dbgs() << "CanAlterRefCount: Seq: " << Seq << "; " << *Ptr
|
|
||||||
<< "\n");
|
|
||||||
S.ClearKnownPositiveRefCount();
|
|
||||||
switch (Seq) {
|
|
||||||
case S_Retain:
|
|
||||||
S.SetSeq(S_CanRelease);
|
|
||||||
assert(!S.HasReverseInsertPts());
|
|
||||||
S.InsertReverseInsertPt(Inst);
|
|
||||||
|
|
||||||
// One call can't cause a transition from S_Retain to S_CanRelease
|
|
||||||
// and S_CanRelease to S_Use. If we've made the first transition,
|
|
||||||
// we're done.
|
|
||||||
continue;
|
|
||||||
case S_Use:
|
|
||||||
case S_CanRelease:
|
|
||||||
case S_None:
|
|
||||||
break;
|
|
||||||
case S_Stop:
|
|
||||||
case S_Release:
|
|
||||||
case S_MovableRelease:
|
|
||||||
llvm_unreachable("top-down pointer in release state!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for possible direct uses.
|
|
||||||
switch (Seq) {
|
|
||||||
case S_CanRelease:
|
|
||||||
if (CanUse(Inst, Ptr, PA, Class)) {
|
|
||||||
DEBUG(dbgs() << "CanUse: Seq: " << Seq << "; " << *Ptr
|
|
||||||
<< "\n");
|
|
||||||
S.SetSeq(S_Use);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case S_Retain:
|
|
||||||
case S_Use:
|
|
||||||
case S_None:
|
|
||||||
break;
|
|
||||||
case S_Stop:
|
|
||||||
case S_Release:
|
|
||||||
case S_MovableRelease:
|
|
||||||
llvm_unreachable("top-down pointer in release state!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NestingDetected;
|
return NestingDetected;
|
||||||
|
|
|
@ -11,10 +11,15 @@
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "PtrState.h"
|
#include "PtrState.h"
|
||||||
#include "ObjCARC.h"
|
#include "ObjCARC.h"
|
||||||
|
#include "DependencyAnalysis.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::objcarc;
|
using namespace llvm::objcarc;
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Utility
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
|
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
|
||||||
switch (S) {
|
switch (S) {
|
||||||
case S_None:
|
case S_None:
|
||||||
|
@ -35,6 +40,10 @@ raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
|
||||||
llvm_unreachable("Unknown sequence type.");
|
llvm_unreachable("Unknown sequence type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Sequence
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
|
static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
|
||||||
// The easy cases.
|
// The easy cases.
|
||||||
if (A == B)
|
if (A == B)
|
||||||
|
@ -64,6 +73,10 @@ static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
|
||||||
return S_None;
|
return S_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// RRInfo
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
void RRInfo::clear() {
|
void RRInfo::clear() {
|
||||||
KnownSafe = false;
|
KnownSafe = false;
|
||||||
IsTailCallRelease = false;
|
IsTailCallRelease = false;
|
||||||
|
@ -94,6 +107,10 @@ bool RRInfo::Merge(const RRInfo &Other) {
|
||||||
return Partial;
|
return Partial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// PtrState
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
void PtrState::SetKnownPositiveRefCount() {
|
void PtrState::SetKnownPositiveRefCount() {
|
||||||
DEBUG(dbgs() << "Setting Known Positive.\n");
|
DEBUG(dbgs() << "Setting Known Positive.\n");
|
||||||
KnownPositiveRefCount = true;
|
KnownPositiveRefCount = true;
|
||||||
|
@ -139,6 +156,10 @@ void PtrState::Merge(const PtrState &Other, bool TopDown) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// BottomUpPtrState
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
|
bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
|
||||||
// If we see two releases in a row on the same pointer. If so, make
|
// If we see two releases in a row on the same pointer. If so, make
|
||||||
// a note, and we'll cicle back to revisit it after we've
|
// a note, and we'll cicle back to revisit it after we've
|
||||||
|
@ -187,6 +208,84 @@ bool BottomUpPtrState::MatchWithRetain() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
|
||||||
|
const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA,
|
||||||
|
ARCInstKind Class) {
|
||||||
|
Sequence Seq = GetSeq();
|
||||||
|
|
||||||
|
// Check for possible releases.
|
||||||
|
if (!CanAlterRefCount(Inst, Ptr, PA, Class))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "CanAlterRefCount: Seq: " << Seq << "; " << *Ptr << "\n");
|
||||||
|
ClearKnownPositiveRefCount();
|
||||||
|
switch (Seq) {
|
||||||
|
case S_Use:
|
||||||
|
SetSeq(S_CanRelease);
|
||||||
|
return true;
|
||||||
|
case S_CanRelease:
|
||||||
|
case S_Release:
|
||||||
|
case S_MovableRelease:
|
||||||
|
case S_Stop:
|
||||||
|
case S_None:
|
||||||
|
return false;
|
||||||
|
case S_Retain:
|
||||||
|
llvm_unreachable("bottom-up pointer in retain state!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
|
||||||
|
const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA,
|
||||||
|
ARCInstKind Class) {
|
||||||
|
// Check for possible direct uses.
|
||||||
|
switch (GetSeq()) {
|
||||||
|
case S_Release:
|
||||||
|
case S_MovableRelease:
|
||||||
|
if (CanUse(Inst, Ptr, PA, Class)) {
|
||||||
|
DEBUG(dbgs() << "CanUse: Seq: " << Seq << "; " << *Ptr << "\n");
|
||||||
|
assert(!HasReverseInsertPts());
|
||||||
|
// If this is an invoke instruction, we're scanning it as part of
|
||||||
|
// one of its successor blocks, since we can't insert code after it
|
||||||
|
// in its own block, and we don't want to split critical edges.
|
||||||
|
if (isa<InvokeInst>(Inst))
|
||||||
|
InsertReverseInsertPt(BB->getFirstInsertionPt());
|
||||||
|
else
|
||||||
|
InsertReverseInsertPt(std::next(BasicBlock::iterator(Inst)));
|
||||||
|
SetSeq(S_Use);
|
||||||
|
} else if (Seq == S_Release && IsUser(Class)) {
|
||||||
|
DEBUG(dbgs() << "PreciseReleaseUse: Seq: " << Seq << "; " << *Ptr
|
||||||
|
<< "\n");
|
||||||
|
// Non-movable releases depend on any possible objc pointer use.
|
||||||
|
SetSeq(S_Stop);
|
||||||
|
assert(!HasReverseInsertPts());
|
||||||
|
// As above; handle invoke specially.
|
||||||
|
if (isa<InvokeInst>(Inst))
|
||||||
|
InsertReverseInsertPt(BB->getFirstInsertionPt());
|
||||||
|
else
|
||||||
|
InsertReverseInsertPt(std::next(BasicBlock::iterator(Inst)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_Stop:
|
||||||
|
if (CanUse(Inst, Ptr, PA, Class)) {
|
||||||
|
DEBUG(dbgs() << "PreciseStopUse: Seq: " << Seq << "; " << *Ptr << "\n");
|
||||||
|
SetSeq(S_Use);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_CanRelease:
|
||||||
|
case S_Use:
|
||||||
|
case S_None:
|
||||||
|
break;
|
||||||
|
case S_Retain:
|
||||||
|
llvm_unreachable("bottom-up pointer in retain state!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// TopDownPtrState
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
|
bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
|
||||||
bool NestingDetected = false;
|
bool NestingDetected = false;
|
||||||
// Don't do retain+release tracking for ARCInstKind::RetainRV, because
|
// Don't do retain+release tracking for ARCInstKind::RetainRV, because
|
||||||
|
@ -238,3 +337,57 @@ bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
|
||||||
llvm_unreachable("top-down pointer in bottom up state!");
|
llvm_unreachable("top-down pointer in bottom up state!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
|
||||||
|
const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA,
|
||||||
|
ARCInstKind Class) {
|
||||||
|
// Check for possible releases.
|
||||||
|
if (!CanAlterRefCount(Inst, Ptr, PA, Class))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "CanAlterRefCount: Seq: " << Seq << "; " << *Ptr << "\n");
|
||||||
|
ClearKnownPositiveRefCount();
|
||||||
|
switch (Seq) {
|
||||||
|
case S_Retain:
|
||||||
|
SetSeq(S_CanRelease);
|
||||||
|
assert(!HasReverseInsertPts());
|
||||||
|
InsertReverseInsertPt(Inst);
|
||||||
|
|
||||||
|
// One call can't cause a transition from S_Retain to S_CanRelease
|
||||||
|
// and S_CanRelease to S_Use. If we've made the first transition,
|
||||||
|
// we're done.
|
||||||
|
return true;
|
||||||
|
case S_Use:
|
||||||
|
case S_CanRelease:
|
||||||
|
case S_None:
|
||||||
|
return false;
|
||||||
|
case S_Stop:
|
||||||
|
case S_Release:
|
||||||
|
case S_MovableRelease:
|
||||||
|
llvm_unreachable("top-down pointer in release state!");
|
||||||
|
}
|
||||||
|
llvm_unreachable("covered switch is not covered!?");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA,
|
||||||
|
ARCInstKind Class) {
|
||||||
|
// Check for possible direct uses.
|
||||||
|
switch (GetSeq()) {
|
||||||
|
case S_CanRelease:
|
||||||
|
if (!CanUse(Inst, Ptr, PA, Class))
|
||||||
|
return;
|
||||||
|
DEBUG(dbgs() << "CanUse: Seq: " << Seq << "; " << *Ptr << "\n");
|
||||||
|
SetSeq(S_Use);
|
||||||
|
return;
|
||||||
|
case S_Retain:
|
||||||
|
case S_Use:
|
||||||
|
case S_None:
|
||||||
|
return;
|
||||||
|
case S_Stop:
|
||||||
|
case S_Release:
|
||||||
|
case S_MovableRelease:
|
||||||
|
llvm_unreachable("top-down pointer in release state!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace llvm {
|
||||||
namespace objcarc {
|
namespace objcarc {
|
||||||
|
|
||||||
struct ARCMDKindCache;
|
struct ARCMDKindCache;
|
||||||
|
class ProvenanceAnalysis;
|
||||||
|
|
||||||
/// \enum Sequence
|
/// \enum Sequence
|
||||||
///
|
///
|
||||||
|
@ -177,6 +178,11 @@ struct BottomUpPtrState : PtrState {
|
||||||
/// It is assumed that one has already checked that the RCIdentity of the
|
/// It is assumed that one has already checked that the RCIdentity of the
|
||||||
/// retain and the RCIdentity of this ptr state are the same.
|
/// retain and the RCIdentity of this ptr state are the same.
|
||||||
bool MatchWithRetain();
|
bool MatchWithRetain();
|
||||||
|
|
||||||
|
void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA, ARCInstKind Class);
|
||||||
|
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA, ARCInstKind Class);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TopDownPtrState : PtrState {
|
struct TopDownPtrState : PtrState {
|
||||||
|
@ -190,6 +196,12 @@ struct TopDownPtrState : PtrState {
|
||||||
/// release. Modifies state appropriately to reflect that the matching
|
/// release. Modifies state appropriately to reflect that the matching
|
||||||
/// occured.
|
/// occured.
|
||||||
bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release);
|
bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release);
|
||||||
|
|
||||||
|
void HandlePotentialUse(Instruction *Inst, const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA, ARCInstKind Class);
|
||||||
|
|
||||||
|
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr,
|
||||||
|
ProvenanceAnalysis &PA, ARCInstKind Class);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace objcarc
|
} // end namespace objcarc
|
||||||
|
|
Loading…
Reference in New Issue