2015-03-06 07:29:03 +08:00
|
|
|
//===--- PtrState.cpp -----------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-03-06 07:57:07 +08:00
|
|
|
#define DEBUG_TYPE "objc-arc-ptr-state"
|
|
|
|
#include "llvm/Support/Debug.h"
|
2015-03-06 07:29:03 +08:00
|
|
|
#include "PtrState.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::objcarc;
|
|
|
|
|
2015-03-06 07:57:07 +08:00
|
|
|
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
|
2015-03-06 07:29:03 +08:00
|
|
|
switch (S) {
|
|
|
|
case S_None:
|
|
|
|
return OS << "S_None";
|
|
|
|
case S_Retain:
|
|
|
|
return OS << "S_Retain";
|
|
|
|
case S_CanRelease:
|
|
|
|
return OS << "S_CanRelease";
|
|
|
|
case S_Use:
|
|
|
|
return OS << "S_Use";
|
|
|
|
case S_Release:
|
|
|
|
return OS << "S_Release";
|
|
|
|
case S_MovableRelease:
|
|
|
|
return OS << "S_MovableRelease";
|
|
|
|
case S_Stop:
|
|
|
|
return OS << "S_Stop";
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown sequence type.");
|
|
|
|
}
|
|
|
|
|
|
|
|
static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
|
|
|
|
// The easy cases.
|
|
|
|
if (A == B)
|
|
|
|
return A;
|
|
|
|
if (A == S_None || B == S_None)
|
|
|
|
return S_None;
|
|
|
|
|
|
|
|
if (A > B)
|
|
|
|
std::swap(A, B);
|
|
|
|
if (TopDown) {
|
|
|
|
// Choose the side which is further along in the sequence.
|
|
|
|
if ((A == S_Retain || A == S_CanRelease) &&
|
|
|
|
(B == S_CanRelease || B == S_Use))
|
|
|
|
return B;
|
|
|
|
} else {
|
|
|
|
// Choose the side which is further along in the sequence.
|
|
|
|
if ((A == S_Use || A == S_CanRelease) &&
|
|
|
|
(B == S_Use || B == S_Release || B == S_Stop || B == S_MovableRelease))
|
|
|
|
return A;
|
|
|
|
// If both sides are releases, choose the more conservative one.
|
|
|
|
if (A == S_Stop && (B == S_Release || B == S_MovableRelease))
|
|
|
|
return A;
|
|
|
|
if (A == S_Release && B == S_MovableRelease)
|
|
|
|
return A;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RRInfo::clear() {
|
|
|
|
KnownSafe = false;
|
|
|
|
IsTailCallRelease = false;
|
|
|
|
ReleaseMetadata = nullptr;
|
|
|
|
Calls.clear();
|
|
|
|
ReverseInsertPts.clear();
|
|
|
|
CFGHazardAfflicted = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RRInfo::Merge(const RRInfo &Other) {
|
|
|
|
// Conservatively merge the ReleaseMetadata information.
|
|
|
|
if (ReleaseMetadata != Other.ReleaseMetadata)
|
|
|
|
ReleaseMetadata = nullptr;
|
|
|
|
|
|
|
|
// Conservatively merge the boolean state.
|
|
|
|
KnownSafe &= Other.KnownSafe;
|
|
|
|
IsTailCallRelease &= Other.IsTailCallRelease;
|
|
|
|
CFGHazardAfflicted |= Other.CFGHazardAfflicted;
|
|
|
|
|
|
|
|
// Merge the call sets.
|
|
|
|
Calls.insert(Other.Calls.begin(), Other.Calls.end());
|
|
|
|
|
|
|
|
// Merge the insert point sets. If there are any differences,
|
|
|
|
// that makes this a partial merge.
|
|
|
|
bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
|
|
|
|
for (Instruction *Inst : Other.ReverseInsertPts)
|
|
|
|
Partial |= ReverseInsertPts.insert(Inst).second;
|
|
|
|
return Partial;
|
|
|
|
}
|
|
|
|
|
2015-03-06 07:57:07 +08:00
|
|
|
void PtrState::SetKnownPositiveRefCount() {
|
|
|
|
DEBUG(dbgs() << "Setting Known Positive.\n");
|
|
|
|
KnownPositiveRefCount = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PtrState::ClearKnownPositiveRefCount() {
|
|
|
|
DEBUG(dbgs() << "Clearing Known Positive.\n");
|
|
|
|
KnownPositiveRefCount = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PtrState::SetSeq(Sequence NewSeq) {
|
|
|
|
DEBUG(dbgs() << "Old: " << Seq << "; New: " << NewSeq << "\n");
|
|
|
|
Seq = NewSeq;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PtrState::ResetSequenceProgress(Sequence NewSeq) {
|
|
|
|
DEBUG(dbgs() << "Resetting sequence progress.\n");
|
|
|
|
SetSeq(NewSeq);
|
|
|
|
Partial = false;
|
|
|
|
RRI.clear();
|
|
|
|
}
|
|
|
|
|
2015-03-06 07:29:03 +08:00
|
|
|
void PtrState::Merge(const PtrState &Other, bool TopDown) {
|
|
|
|
Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
|
|
|
|
KnownPositiveRefCount &= Other.KnownPositiveRefCount;
|
|
|
|
|
|
|
|
// If we're not in a sequence (anymore), drop all associated state.
|
|
|
|
if (Seq == S_None) {
|
|
|
|
Partial = false;
|
|
|
|
RRI.clear();
|
|
|
|
} else if (Partial || Other.Partial) {
|
|
|
|
// If we're doing a merge on a path that's previously seen a partial
|
|
|
|
// merge, conservatively drop the sequence, to avoid doing partial
|
|
|
|
// RR elimination. If the branch predicates for the two merge differ,
|
|
|
|
// mixing them is unsafe.
|
|
|
|
ClearSequenceProgress();
|
|
|
|
} else {
|
|
|
|
// Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
|
|
|
|
// point, we know that currently we are not partial. Stash whether or not
|
|
|
|
// the merge operation caused us to undergo a partial merging of reverse
|
|
|
|
// insertion points.
|
|
|
|
Partial = RRI.Merge(Other.RRI);
|
|
|
|
}
|
|
|
|
}
|