diff options
Diffstat (limited to 'llvm/lib/Transforms/ObjCARC/PtrState.cpp')
-rw-r--r-- | llvm/lib/Transforms/ObjCARC/PtrState.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/PtrState.cpp b/llvm/lib/Transforms/ObjCARC/PtrState.cpp index 9a82f36c5c4..521158c8691 100644 --- a/llvm/lib/Transforms/ObjCARC/PtrState.cpp +++ b/llvm/lib/Transforms/ObjCARC/PtrState.cpp @@ -11,10 +11,15 @@ #include "llvm/Support/Debug.h" #include "PtrState.h" #include "ObjCARC.h" +#include "DependencyAnalysis.h" using namespace llvm; using namespace llvm::objcarc; +//===----------------------------------------------------------------------===// +// Utility +//===----------------------------------------------------------------------===// + raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) { switch (S) { case S_None: @@ -35,6 +40,10 @@ raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) { llvm_unreachable("Unknown sequence type."); } +//===----------------------------------------------------------------------===// +// Sequence +//===----------------------------------------------------------------------===// + static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) { // The easy cases. if (A == B) @@ -64,6 +73,10 @@ static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) { return S_None; } +//===----------------------------------------------------------------------===// +// RRInfo +//===----------------------------------------------------------------------===// + void RRInfo::clear() { KnownSafe = false; IsTailCallRelease = false; @@ -94,6 +107,10 @@ bool RRInfo::Merge(const RRInfo &Other) { return Partial; } +//===----------------------------------------------------------------------===// +// PtrState +//===----------------------------------------------------------------------===// + void PtrState::SetKnownPositiveRefCount() { DEBUG(dbgs() << "Setting Known Positive.\n"); KnownPositiveRefCount = true; @@ -139,6 +156,10 @@ void PtrState::Merge(const PtrState &Other, bool TopDown) { } } +//===----------------------------------------------------------------------===// +// BottomUpPtrState +//===----------------------------------------------------------------------===// + bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) { // 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 @@ -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 NestingDetected = false; // 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!"); } } + +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!"); + } +} |