[ObjCARC] Refactored out the inner most 2-loops from PerformCodePlacement into the method ConnectTDBUTraversals.

The method PerformCodePlacement was doing too much (i.e. 3x loops, lots of
different checking). This refactoring separates the analysis section of the
method into a separate function while leaving the actual code placement and
analysis preparation in PerformCodePlacement.

*NOTE* Really this part of ObjCARC should be refactored out of the main pass
class into its own seperate class/struct. But, it is not time to make that
change yet though (don't want to make such an invasive change without fixing all
of the bugs first).

llvm-svn: 173201
This commit is contained in:
Michael Gottesman 2013-01-22 21:49:00 +00:00
parent 3dffc5e2b7
commit 9de6f96ad5
1 changed files with 197 additions and 152 deletions

View File

@ -1849,6 +1849,19 @@ namespace {
SmallVectorImpl<Instruction *> &DeadInsts,
Module *M);
bool ConnectTDBUTraversals(DenseMap<const BasicBlock *, BBState> &BBStates,
MapVector<Value *, RRInfo> &Retains,
DenseMap<Value *, RRInfo> &Releases,
Module *M,
SmallVector<Instruction *, 4> &NewRetains,
SmallVector<Instruction *, 4> &NewReleases,
SmallVector<Instruction *, 8> &DeadInsts,
RRInfo &RetainsToMove,
RRInfo &ReleasesToMove,
Value *Arg,
bool KnownSafe,
bool &AnyPairsCompletelyEliminated);
bool PerformCodePlacement(DenseMap<const BasicBlock *, BBState> &BBStates,
MapVector<Value *, RRInfo> &Retains,
DenseMap<Value *, RRInfo> &Releases,
@ -3398,6 +3411,179 @@ void ObjCARCOpt::MoveCalls(Value *Arg,
}
}
bool
ObjCARCOpt::ConnectTDBUTraversals(DenseMap<const BasicBlock *, BBState>
&BBStates,
MapVector<Value *, RRInfo> &Retains,
DenseMap<Value *, RRInfo> &Releases,
Module *M,
SmallVector<Instruction *, 4> &NewRetains,
SmallVector<Instruction *, 4> &NewReleases,
SmallVector<Instruction *, 8> &DeadInsts,
RRInfo &RetainsToMove,
RRInfo &ReleasesToMove,
Value *Arg,
bool KnownSafe,
bool &AnyPairsCompletelyEliminated) {
// If a pair happens in a region where it is known that the reference count
// is already incremented, we can similarly ignore possible decrements.
bool KnownSafeTD = true, KnownSafeBU = true;
// Connect the dots between the top-down-collected RetainsToMove and
// bottom-up-collected ReleasesToMove to form sets of related calls.
// This is an iterative process so that we connect multiple releases
// to multiple retains if needed.
unsigned OldDelta = 0;
unsigned NewDelta = 0;
unsigned OldCount = 0;
unsigned NewCount = 0;
bool FirstRelease = true;
bool FirstRetain = true;
for (;;) {
for (SmallVectorImpl<Instruction *>::const_iterator
NI = NewRetains.begin(), NE = NewRetains.end(); NI != NE; ++NI) {
Instruction *NewRetain = *NI;
MapVector<Value *, RRInfo>::const_iterator It = Retains.find(NewRetain);
assert(It != Retains.end());
const RRInfo &NewRetainRRI = It->second;
KnownSafeTD &= NewRetainRRI.KnownSafe;
for (SmallPtrSet<Instruction *, 2>::const_iterator
LI = NewRetainRRI.Calls.begin(),
LE = NewRetainRRI.Calls.end(); LI != LE; ++LI) {
Instruction *NewRetainRelease = *LI;
DenseMap<Value *, RRInfo>::const_iterator Jt =
Releases.find(NewRetainRelease);
if (Jt == Releases.end())
return false;
const RRInfo &NewRetainReleaseRRI = Jt->second;
assert(NewRetainReleaseRRI.Calls.count(NewRetain));
if (ReleasesToMove.Calls.insert(NewRetainRelease)) {
OldDelta -=
BBStates[NewRetainRelease->getParent()].GetAllPathCount();
// Merge the ReleaseMetadata and IsTailCallRelease values.
if (FirstRelease) {
ReleasesToMove.ReleaseMetadata =
NewRetainReleaseRRI.ReleaseMetadata;
ReleasesToMove.IsTailCallRelease =
NewRetainReleaseRRI.IsTailCallRelease;
FirstRelease = false;
} else {
if (ReleasesToMove.ReleaseMetadata !=
NewRetainReleaseRRI.ReleaseMetadata)
ReleasesToMove.ReleaseMetadata = 0;
if (ReleasesToMove.IsTailCallRelease !=
NewRetainReleaseRRI.IsTailCallRelease)
ReleasesToMove.IsTailCallRelease = false;
}
// Collect the optimal insertion points.
if (!KnownSafe)
for (SmallPtrSet<Instruction *, 2>::const_iterator
RI = NewRetainReleaseRRI.ReverseInsertPts.begin(),
RE = NewRetainReleaseRRI.ReverseInsertPts.end();
RI != RE; ++RI) {
Instruction *RIP = *RI;
if (ReleasesToMove.ReverseInsertPts.insert(RIP))
NewDelta -= BBStates[RIP->getParent()].GetAllPathCount();
}
NewReleases.push_back(NewRetainRelease);
}
}
}
NewRetains.clear();
if (NewReleases.empty()) break;
// Back the other way.
for (SmallVectorImpl<Instruction *>::const_iterator
NI = NewReleases.begin(), NE = NewReleases.end(); NI != NE; ++NI) {
Instruction *NewRelease = *NI;
DenseMap<Value *, RRInfo>::const_iterator It =
Releases.find(NewRelease);
assert(It != Releases.end());
const RRInfo &NewReleaseRRI = It->second;
KnownSafeBU &= NewReleaseRRI.KnownSafe;
for (SmallPtrSet<Instruction *, 2>::const_iterator
LI = NewReleaseRRI.Calls.begin(),
LE = NewReleaseRRI.Calls.end(); LI != LE; ++LI) {
Instruction *NewReleaseRetain = *LI;
MapVector<Value *, RRInfo>::const_iterator Jt =
Retains.find(NewReleaseRetain);
if (Jt == Retains.end())
return false;
const RRInfo &NewReleaseRetainRRI = Jt->second;
assert(NewReleaseRetainRRI.Calls.count(NewRelease));
if (RetainsToMove.Calls.insert(NewReleaseRetain)) {
unsigned PathCount =
BBStates[NewReleaseRetain->getParent()].GetAllPathCount();
OldDelta += PathCount;
OldCount += PathCount;
// Merge the IsRetainBlock values.
if (FirstRetain) {
RetainsToMove.IsRetainBlock = NewReleaseRetainRRI.IsRetainBlock;
FirstRetain = false;
} else if (ReleasesToMove.IsRetainBlock !=
NewReleaseRetainRRI.IsRetainBlock)
// It's not possible to merge the sequences if one uses
// objc_retain and the other uses objc_retainBlock.
return false;
// Collect the optimal insertion points.
if (!KnownSafe)
for (SmallPtrSet<Instruction *, 2>::const_iterator
RI = NewReleaseRetainRRI.ReverseInsertPts.begin(),
RE = NewReleaseRetainRRI.ReverseInsertPts.end();
RI != RE; ++RI) {
Instruction *RIP = *RI;
if (RetainsToMove.ReverseInsertPts.insert(RIP)) {
PathCount = BBStates[RIP->getParent()].GetAllPathCount();
NewDelta += PathCount;
NewCount += PathCount;
}
}
NewRetains.push_back(NewReleaseRetain);
}
}
}
NewReleases.clear();
if (NewRetains.empty()) break;
}
// If the pointer is known incremented or nested, we can safely delete the
// pair regardless of what's between them.
if (KnownSafeTD || KnownSafeBU) {
RetainsToMove.ReverseInsertPts.clear();
ReleasesToMove.ReverseInsertPts.clear();
NewCount = 0;
} else {
// Determine whether the new insertion points we computed preserve the
// balance of retain and release calls through the program.
// TODO: If the fully aggressive solution isn't valid, try to find a
// less aggressive solution which is.
if (NewDelta != 0)
return false;
}
// Determine whether the original call points are balanced in the retain and
// release calls through the program. If not, conservatively don't touch
// them.
// TODO: It's theoretically possible to do code motion in this case, as
// long as the existing imbalances are maintained.
if (OldDelta != 0)
return false;
Changed = true;
assert(OldCount != 0 && "Unreachable code?");
NumRRs += OldCount - NewCount;
// Set to true if we completely removed any RR pairs.
AnyPairsCompletelyEliminated |= NewCount == 0;
// We can move calls!
return true;
}
/// Identify pairings between the retains and releases, and delete and/or move
/// them.
bool
@ -3440,164 +3626,23 @@ ObjCARCOpt::PerformCodePlacement(DenseMap<const BasicBlock *, BBState>
if (GV->isConstant())
KnownSafe = true;
// If a pair happens in a region where it is known that the reference count
// is already incremented, we can similarly ignore possible decrements.
bool KnownSafeTD = true, KnownSafeBU = true;
// Connect the dots between the top-down-collected RetainsToMove and
// bottom-up-collected ReleasesToMove to form sets of related calls.
// This is an iterative process so that we connect multiple releases
// to multiple retains if needed.
unsigned OldDelta = 0;
unsigned NewDelta = 0;
unsigned OldCount = 0;
unsigned NewCount = 0;
bool FirstRelease = true;
bool FirstRetain = true;
NewRetains.push_back(Retain);
for (;;) {
for (SmallVectorImpl<Instruction *>::const_iterator
NI = NewRetains.begin(), NE = NewRetains.end(); NI != NE; ++NI) {
Instruction *NewRetain = *NI;
MapVector<Value *, RRInfo>::const_iterator It = Retains.find(NewRetain);
assert(It != Retains.end());
const RRInfo &NewRetainRRI = It->second;
KnownSafeTD &= NewRetainRRI.KnownSafe;
for (SmallPtrSet<Instruction *, 2>::const_iterator
LI = NewRetainRRI.Calls.begin(),
LE = NewRetainRRI.Calls.end(); LI != LE; ++LI) {
Instruction *NewRetainRelease = *LI;
DenseMap<Value *, RRInfo>::const_iterator Jt =
Releases.find(NewRetainRelease);
if (Jt == Releases.end())
goto next_retain;
const RRInfo &NewRetainReleaseRRI = Jt->second;
assert(NewRetainReleaseRRI.Calls.count(NewRetain));
if (ReleasesToMove.Calls.insert(NewRetainRelease)) {
OldDelta -=
BBStates[NewRetainRelease->getParent()].GetAllPathCount();
bool PerformMoveCalls =
ConnectTDBUTraversals(BBStates, Retains, Releases, M, NewRetains,
NewReleases, DeadInsts, RetainsToMove,
ReleasesToMove, Arg, KnownSafe,
AnyPairsCompletelyEliminated);
// Merge the ReleaseMetadata and IsTailCallRelease values.
if (FirstRelease) {
ReleasesToMove.ReleaseMetadata =
NewRetainReleaseRRI.ReleaseMetadata;
ReleasesToMove.IsTailCallRelease =
NewRetainReleaseRRI.IsTailCallRelease;
FirstRelease = false;
} else {
if (ReleasesToMove.ReleaseMetadata !=
NewRetainReleaseRRI.ReleaseMetadata)
ReleasesToMove.ReleaseMetadata = 0;
if (ReleasesToMove.IsTailCallRelease !=
NewRetainReleaseRRI.IsTailCallRelease)
ReleasesToMove.IsTailCallRelease = false;
}
// Collect the optimal insertion points.
if (!KnownSafe)
for (SmallPtrSet<Instruction *, 2>::const_iterator
RI = NewRetainReleaseRRI.ReverseInsertPts.begin(),
RE = NewRetainReleaseRRI.ReverseInsertPts.end();
RI != RE; ++RI) {
Instruction *RIP = *RI;
if (ReleasesToMove.ReverseInsertPts.insert(RIP))
NewDelta -= BBStates[RIP->getParent()].GetAllPathCount();
}
NewReleases.push_back(NewRetainRelease);
}
}
}
NewRetains.clear();
if (NewReleases.empty()) break;
// Back the other way.
for (SmallVectorImpl<Instruction *>::const_iterator
NI = NewReleases.begin(), NE = NewReleases.end(); NI != NE; ++NI) {
Instruction *NewRelease = *NI;
DenseMap<Value *, RRInfo>::const_iterator It =
Releases.find(NewRelease);
assert(It != Releases.end());
const RRInfo &NewReleaseRRI = It->second;
KnownSafeBU &= NewReleaseRRI.KnownSafe;
for (SmallPtrSet<Instruction *, 2>::const_iterator
LI = NewReleaseRRI.Calls.begin(),
LE = NewReleaseRRI.Calls.end(); LI != LE; ++LI) {
Instruction *NewReleaseRetain = *LI;
MapVector<Value *, RRInfo>::const_iterator Jt =
Retains.find(NewReleaseRetain);
if (Jt == Retains.end())
goto next_retain;
const RRInfo &NewReleaseRetainRRI = Jt->second;
assert(NewReleaseRetainRRI.Calls.count(NewRelease));
if (RetainsToMove.Calls.insert(NewReleaseRetain)) {
unsigned PathCount =
BBStates[NewReleaseRetain->getParent()].GetAllPathCount();
OldDelta += PathCount;
OldCount += PathCount;
// Merge the IsRetainBlock values.
if (FirstRetain) {
RetainsToMove.IsRetainBlock = NewReleaseRetainRRI.IsRetainBlock;
FirstRetain = false;
} else if (ReleasesToMove.IsRetainBlock !=
NewReleaseRetainRRI.IsRetainBlock)
// It's not possible to merge the sequences if one uses
// objc_retain and the other uses objc_retainBlock.
goto next_retain;
// Collect the optimal insertion points.
if (!KnownSafe)
for (SmallPtrSet<Instruction *, 2>::const_iterator
RI = NewReleaseRetainRRI.ReverseInsertPts.begin(),
RE = NewReleaseRetainRRI.ReverseInsertPts.end();
RI != RE; ++RI) {
Instruction *RIP = *RI;
if (RetainsToMove.ReverseInsertPts.insert(RIP)) {
PathCount = BBStates[RIP->getParent()].GetAllPathCount();
NewDelta += PathCount;
NewCount += PathCount;
}
}
NewRetains.push_back(NewReleaseRetain);
}
}
}
NewReleases.clear();
if (NewRetains.empty()) break;
if (PerformMoveCalls) {
// Ok, everything checks out and we're all set. Let's move/delete some
// code!
MoveCalls(Arg, RetainsToMove, ReleasesToMove,
Retains, Releases, DeadInsts, M);
}
// If the pointer is known incremented or nested, we can safely delete the
// pair regardless of what's between them.
if (KnownSafeTD || KnownSafeBU) {
RetainsToMove.ReverseInsertPts.clear();
ReleasesToMove.ReverseInsertPts.clear();
NewCount = 0;
} else {
// Determine whether the new insertion points we computed preserve the
// balance of retain and release calls through the program.
// TODO: If the fully aggressive solution isn't valid, try to find a
// less aggressive solution which is.
if (NewDelta != 0)
goto next_retain;
}
// Determine whether the original call points are balanced in the retain and
// release calls through the program. If not, conservatively don't touch
// them.
// TODO: It's theoretically possible to do code motion in this case, as
// long as the existing imbalances are maintained.
if (OldDelta != 0)
goto next_retain;
// Ok, everything checks out and we're all set. Let's move some code!
Changed = true;
assert(OldCount != 0 && "Unreachable code?");
AnyPairsCompletelyEliminated = NewCount == 0;
NumRRs += OldCount - NewCount;
MoveCalls(Arg, RetainsToMove, ReleasesToMove,
Retains, Releases, DeadInsts, M);
next_retain:
// Clean up state for next retain.
NewReleases.clear();
NewRetains.clear();
RetainsToMove.clear();