//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "objc-arc-ptr-state"
-#include "llvm/Support/Debug.h"
#include "PtrState.h"
+#include "DependencyAnalysis.h"
#include "ObjCARC.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::objcarc;
+#define DEBUG_TYPE "objc-arc-ptr-state"
+
+//===----------------------------------------------------------------------===//
+// Utility
+//===----------------------------------------------------------------------===//
+
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
switch (S) {
case S_None:
llvm_unreachable("Unknown sequence type.");
}
+//===----------------------------------------------------------------------===//
+// Sequence
+//===----------------------------------------------------------------------===//
+
static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
// The easy cases.
if (A == B)
return S_None;
}
+//===----------------------------------------------------------------------===//
+// RRInfo
+//===----------------------------------------------------------------------===//
+
void RRInfo::clear() {
KnownSafe = false;
IsTailCallRelease = false;
return Partial;
}
+//===----------------------------------------------------------------------===//
+// PtrState
+//===----------------------------------------------------------------------===//
+
void PtrState::SetKnownPositiveRefCount() {
- DEBUG(dbgs() << "Setting Known Positive.\n");
+ DEBUG(dbgs() << " Setting Known Positive.\n");
KnownPositiveRefCount = true;
}
void PtrState::ClearKnownPositiveRefCount() {
- DEBUG(dbgs() << "Clearing Known Positive.\n");
+ DEBUG(dbgs() << " Clearing Known Positive.\n");
KnownPositiveRefCount = false;
}
void PtrState::SetSeq(Sequence NewSeq) {
- DEBUG(dbgs() << "Old: " << Seq << "; New: " << NewSeq << "\n");
+ DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq << "\n");
Seq = NewSeq;
}
void PtrState::ResetSequenceProgress(Sequence NewSeq) {
- DEBUG(dbgs() << "Resetting sequence progress.\n");
+ DEBUG(dbgs() << " Resetting sequence progress.\n");
SetSeq(NewSeq);
Partial = false;
RRI.clear();
}
}
+//===----------------------------------------------------------------------===//
+// 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
// simple and avoids adding overhead for the non-nested case.
bool NestingDetected = false;
if (GetSeq() == S_Release || GetSeq() == S_MovableRelease) {
- DEBUG(dbgs() << "Found nested releases (i.e. a release pair)\n");
+ DEBUG(dbgs() << " Found nested releases (i.e. a release pair)\n");
NestingDetected = true;
}
- MDNode *ReleaseMetadata = I->getMetadata(Cache.ImpreciseReleaseMDKind);
+ MDNode *ReleaseMetadata =
+ I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
ResetSequenceProgress(NewSeq);
SetReleaseMetadata(ReleaseMetadata);
case S_Retain:
llvm_unreachable("bottom-up pointer in retain state!");
}
+ llvm_unreachable("Sequence unknown enum value");
}
+bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
+ const Value *Ptr,
+ ProvenanceAnalysis &PA,
+ ARCInstKind Class) {
+ Sequence S = GetSeq();
+
+ // Check for possible releases.
+ if (!CanAlterRefCount(Inst, Ptr, PA, Class))
+ return false;
+
+ DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " << *Ptr
+ << "\n");
+ switch (S) {
+ 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!");
+ }
+ llvm_unreachable("Sequence unknown enum value");
+}
+
+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: " << GetSeq() << "; " << *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: " << GetSeq() << "; "
+ << *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: " << GetSeq() << "; "
+ << *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
Sequence OldSeq = GetSeq();
- MDNode *ReleaseMetadata = Release->getMetadata(Cache.ImpreciseReleaseMDKind);
+ MDNode *ReleaseMetadata =
+ Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
switch (OldSeq) {
case S_Retain:
case S_MovableRelease:
llvm_unreachable("top-down pointer in bottom up state!");
}
+ llvm_unreachable("Sequence unknown enum value");
+}
+
+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: " << GetSeq() << "; " << *Ptr
+ << "\n");
+ ClearKnownPositiveRefCount();
+ switch (GetSeq()) {
+ 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: " << GetSeq() << "; " << *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!");
+ }
}