When computing reverse-CFG reverse-post-order, skip backedges, as

detected in the forward-CFG DFS. This prevents the reverse-CFG from
visiting blocks inside loops after blocks that dominate them in the
case where loops have multiple exits.

No testcase, because this fixes a bug which in practice only shows
up in a full optimizer run, due to the use-list order.

This fixes rdar://10422791 and others.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146408 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dan Gohman 2011-12-12 19:42:25 +00:00
parent 37e7ecf52b
commit 59a1c93e95

View File

@ -896,8 +896,9 @@ bool ObjCARCExpand::runOnFunction(Function &F) {
#include "llvm/LLVMContext.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/CFG.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/DenseSet.h"
STATISTIC(NumNoops, "Number of no-op objc calls eliminated");
STATISTIC(NumPartialNoops, "Number of partially no-op objc calls eliminated");
@ -2490,18 +2491,16 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
if (Pred == BB)
continue;
DenseMap<const BasicBlock *, BBState>::iterator I = BBStates.find(Pred);
assert(I != BBStates.end());
// If we haven't seen this node yet, then we've found a CFG cycle.
// Be optimistic here; it's CheckForCFGHazards' job detect trouble.
if (!I->second.isVisitedTopDown())
if (I == BBStates.end() || !I->second.isVisitedTopDown())
continue;
MyStates.InitFromPred(I->second);
while (PI != PE) {
Pred = *PI++;
if (Pred != BB) {
I = BBStates.find(Pred);
assert(I != BBStates.end());
if (I->second.isVisitedTopDown())
if (I == BBStates.end() || I->second.isVisitedTopDown())
MyStates.MergePred(I->second);
}
}
@ -2657,49 +2656,106 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
return NestingDetected;
}
static void
ComputePostOrders(Function &F,
SmallVectorImpl<BasicBlock *> &PostOrder,
SmallVectorImpl<BasicBlock *> &ReverseCFGPostOrder) {
/// Backedges - Backedges detected in the DFS. These edges will be
/// ignored in the reverse-CFG DFS, so that loops with multiple exits will be
/// traversed in the desired order.
DenseSet<std::pair<BasicBlock *, BasicBlock *> > Backedges;
/// Visited - The visited set, for doing DFS walks.
SmallPtrSet<BasicBlock *, 16> Visited;
// Do DFS, computing the PostOrder.
SmallPtrSet<BasicBlock *, 16> OnStack;
SmallVector<std::pair<BasicBlock *, succ_iterator>, 16> SuccStack;
BasicBlock *EntryBB = &F.getEntryBlock();
SuccStack.push_back(std::make_pair(EntryBB, succ_begin(EntryBB)));
Visited.insert(EntryBB);
OnStack.insert(EntryBB);
do {
dfs_next_succ:
succ_iterator End = succ_end(SuccStack.back().first);
while (SuccStack.back().second != End) {
BasicBlock *BB = *SuccStack.back().second++;
if (Visited.insert(BB)) {
SuccStack.push_back(std::make_pair(BB, succ_begin(BB)));
OnStack.insert(BB);
goto dfs_next_succ;
}
if (OnStack.count(BB))
Backedges.insert(std::make_pair(SuccStack.back().first, BB));
}
OnStack.erase(SuccStack.back().first);
PostOrder.push_back(SuccStack.pop_back_val().first);
} while (!SuccStack.empty());
Visited.clear();
// Compute the exits, which are the starting points for reverse-CFG DFS.
SmallVector<BasicBlock *, 4> Exits;
for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) {
BasicBlock *BB = I;
if (BB->getTerminator()->getNumSuccessors() == 0)
Exits.push_back(BB);
}
// Do reverse-CFG DFS, computing the reverse-CFG PostOrder.
SmallVector<std::pair<BasicBlock *, pred_iterator>, 16> PredStack;
for (SmallVectorImpl<BasicBlock *>::iterator I = Exits.begin(), E = Exits.end();
I != E; ++I) {
BasicBlock *ExitBB = *I;
PredStack.push_back(std::make_pair(ExitBB, pred_begin(ExitBB)));
Visited.insert(ExitBB);
while (!PredStack.empty()) {
reverse_dfs_next_succ:
pred_iterator End = pred_end(PredStack.back().first);
while (PredStack.back().second != End) {
BasicBlock *BB = *PredStack.back().second++;
// Skip backedges detected in the forward-CFG DFS.
if (Backedges.count(std::make_pair(BB, PredStack.back().first)))
continue;
if (Visited.insert(BB)) {
PredStack.push_back(std::make_pair(BB, pred_begin(BB)));
goto reverse_dfs_next_succ;
}
}
ReverseCFGPostOrder.push_back(PredStack.pop_back_val().first);
}
}
}
// Visit - Visit the function both top-down and bottom-up.
bool
ObjCARCOpt::Visit(Function &F,
DenseMap<const BasicBlock *, BBState> &BBStates,
MapVector<Value *, RRInfo> &Retains,
DenseMap<Value *, RRInfo> &Releases) {
// Use reverse-postorder on the reverse CFG for bottom-up, because we
// magically know that loops will be well behaved, i.e. they won't repeatedly
// call retain on a single pointer without doing a release. We can't use
// ReversePostOrderTraversal here because we want to walk up from each
// function exit point.
SmallPtrSet<BasicBlock *, 16> Visited;
SmallVector<std::pair<BasicBlock *, pred_iterator>, 16> Stack;
SmallVector<BasicBlock *, 16> Order;
for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) {
BasicBlock *BB = I;
if (BB->getTerminator()->getNumSuccessors() == 0)
Stack.push_back(std::make_pair(BB, pred_begin(BB)));
}
while (!Stack.empty()) {
pred_iterator End = pred_end(Stack.back().first);
while (Stack.back().second != End) {
BasicBlock *BB = *Stack.back().second++;
if (Visited.insert(BB))
Stack.push_back(std::make_pair(BB, pred_begin(BB)));
}
Order.push_back(Stack.pop_back_val().first);
}
// Use reverse-postorder traversals, because we magically know that loops
// will be well behaved, i.e. they won't repeatedly call retain on a single
// pointer without doing a release. We can't use the ReversePostOrderTraversal
// class here because we want the reverse-CFG postorder to consider each
// function exit point, and we want to ignore selected cycle edges.
SmallVector<BasicBlock *, 16> PostOrder;
SmallVector<BasicBlock *, 16> ReverseCFGPostOrder;
ComputePostOrders(F, PostOrder, ReverseCFGPostOrder);
// Use reverse-postorder on the reverse CFG for bottom-up.
bool BottomUpNestingDetected = false;
for (SmallVectorImpl<BasicBlock *>::const_reverse_iterator I =
Order.rbegin(), E = Order.rend(); I != E; ++I) {
BasicBlock *BB = *I;
BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);
}
ReverseCFGPostOrder.rbegin(), E = ReverseCFGPostOrder.rend();
I != E; ++I)
BottomUpNestingDetected |= VisitBottomUp(*I, BBStates, Retains);
// Use regular reverse-postorder for top-down.
// Use reverse-postorder for top-down.
bool TopDownNestingDetected = false;
typedef ReversePostOrderTraversal<Function *> RPOTType;
RPOTType RPOT(&F);
for (RPOTType::rpo_iterator I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
BasicBlock *BB = *I;
TopDownNestingDetected |= VisitTopDown(BB, BBStates, Releases);
}
for (SmallVectorImpl<BasicBlock *>::const_reverse_iterator I =
PostOrder.rbegin(), E = PostOrder.rend();
I != E; ++I)
TopDownNestingDetected |= VisitTopDown(*I, BBStates, Releases);
return TopDownNestingDetected && BottomUpNestingDetected;
}