llvm::DenseMap<const void*, const void*> *InverseMap)
const {
- typedef llvm::DenseMap<const ExplodedNodeImpl*,
- const ExplodedNodeImpl*> Pass1Ty;
+ typedef llvm::DenseSet<const ExplodedNodeImpl*> Pass1Ty;
Pass1Ty Pass1;
- typedef llvm::DenseMap<const ExplodedNodeImpl*,
- ExplodedNodeImpl*> Pass2Ty;
-
+ typedef llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty;
Pass2Ty& Pass2 = M->M;
+ std::list<const ExplodedNodeImpl*> WL1;
llvm::SmallVector<const ExplodedNodeImpl*, 10> WL2;
- { // ===- Pass 1 (reverse BFS) -===
-
- // Enqueue the source nodes to the first worklist.
+ // ===- Pass 1 (reverse BFS) -===
+ for (const ExplodedNodeImpl* const* I = BeginSources; I != EndSources; ++I) {
+ assert(*I);
+ WL1.push_back(*I);
+ }
- std::list<std::pair<const ExplodedNodeImpl*,
- const ExplodedNodeImpl*> > WL1, WL1_Loops;
-
- for (const ExplodedNodeImpl* const* I = BeginSources; I != EndSources; ++I){
- assert(*I);
- WL1.push_back(std::make_pair(*I, *I));
- }
+ // Process the first worklist until it is empty. Because it is a std::list
+ // it acts like a FIFO queue.
+ while (!WL1.empty()) {
+ const ExplodedNodeImpl *N = WL1.back();
+ WL1.pop_back();
- // Process the worklist.
-
- while (!WL1.empty() || !WL1_Loops.empty()) {
- // Only dequeue from the "loops" worklist if WL1 has no items.
- // Thus we prioritize for paths that don't span loop boundaries.
- const ExplodedNodeImpl *N = 0, *Src = 0;
+ // Have we already visited this node? If so, continue to the next one.
+ if (Pass1.count(N))
+ continue;
- if (WL1.empty()) {
- assert(!WL1_Loops.empty());
- N = WL1_Loops.back().first;
- assert(N);
- Src = WL1_Loops.back().second;
- WL1_Loops.pop_back();
- }
- else {
- N = WL1.back().first;
- assert(N);
- Src = WL1.back().second;
- WL1.pop_back();
- }
-
- if (Pass1.find(N) != Pass1.end())
- continue;
-
- bool PredHasSameSource = false;
- bool VisitPreds = true;
-
- for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
- I!=E; ++I) {
-
- Pass1Ty::iterator pi = Pass1.find(*I);
-
- if (pi == Pass1.end())
- continue;
-
- VisitPreds = false;
-
- if (pi->second == Src) {
- PredHasSameSource = true;
- break;
- }
- }
-
- if (VisitPreds || !PredHasSameSource) {
-
- Pass1[N] = Src;
-
- if (N->Preds.empty()) {
- WL2.push_back(N);
- continue;
- }
- }
- else
- Pass1[N] = NULL;
-
- if (VisitPreds)
- for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
- I!=E; ++I) {
-
- ProgramPoint P = Src->getLocation();
-
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
- if (Stmt* T = BE->getSrc()->getTerminator())
- switch (T->getStmtClass()) {
- default: break;
- case Stmt::ForStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
- assert(*I);
- WL1_Loops.push_front(std::make_pair(*I, Src));
- continue;
-
- }
-
- assert(*I);
- WL1.push_front(std::make_pair(*I, Src));
- }
+ // Otherwise, mark this node as visited.
+ Pass1.insert(N);
+
+ // If this is a root enqueue it to the second worklist.
+ if (N->Preds.empty()) {
+ WL2.push_back(N);
+ continue;
}
+
+ // Visit our predecessors and enqueue them.
+ for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I)
+ WL1.push_front(*I);
}
+ // We didn't hit a root? Return with a null pointer for the new graph.
if (WL2.empty())
return 0;
+ // Create an empty graph.
ExplodedGraphImpl* G = MakeEmptyGraph();
- // ===- Pass 2 (forward DFS to construct the new graph) -===
-
+ // ===- Pass 2 (forward DFS to construct the new graph) -===
while (!WL2.empty()) {
-
const ExplodedNodeImpl* N = WL2.back();
WL2.pop_back();
// Skip this node if we have already processed it.
-
if (Pass2.find(N) != Pass2.end())
continue;
- // Create the corresponding node in the new graph.
-
+ // Create the corresponding node in the new graph and record the mapping
+ // from the old node to the new node.
ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL);
Pass2[N] = NewN;
+
+ // Also record the reverse mapping from the new node to the old node.
if (InverseMap) (*InverseMap)[NewN] = N;
+ // If this node is a root, designate it as such in the graph.
if (N->Preds.empty())
G->addRoot(NewN);
// In the case that some of the intended predecessors of NewN have already
// been created, we should hook them up as predecessors.
-
+
+ // Walk through the predecessors of 'N' and hook up their corresponding
+ // nodes in the new graph (if any) to the freshly created node.
for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
-
Pass2Ty::iterator PI = Pass2.find(*I);
-
if (PI == Pass2.end())
continue;
// been created, we should hook them up as successors. Otherwise, enqueue
// the new nodes from the original graph that should have nodes created
// in the new graph.
-
for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
-
- Pass2Ty::iterator PI = Pass2.find(*I);
-
+ Pass2Ty::iterator PI = Pass2.find(*I);
if (PI != Pass2.end()) {
PI->second->addPredecessor(NewN);
continue;
}
// Enqueue nodes to the worklist that were marked during pass 1.
-
- Pass1Ty::iterator pi = Pass1.find(*I);
-
- if (pi == Pass1.end() || pi->second == NULL)
- continue;
-
- WL2.push_back(*I);
+ if (Pass1.count(*I))
+ WL2.push_back(*I);
}
+ // Finally, explictly mark all nodes without any successors as sinks.
if (N->isSink())
NewN->markAsSink();
}