summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/ExplodedGraph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/ExplodedGraph.cpp')
-rw-r--r--clang/lib/Analysis/ExplodedGraph.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/clang/lib/Analysis/ExplodedGraph.cpp b/clang/lib/Analysis/ExplodedGraph.cpp
new file mode 100644
index 00000000000..2ba46d77d63
--- /dev/null
+++ b/clang/lib/Analysis/ExplodedGraph.cpp
@@ -0,0 +1,227 @@
+//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the template classes ExplodedNode and ExplodedGraph,
+// which represent a path-sensitive, intra-procedural "exploded graph."
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+#include <list>
+
+using namespace clang;
+
+
+static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) {
+ return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P);
+}
+
+void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) {
+
+ assert ((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
+ assert (!getFlag());
+
+ if (getKind() == Size1) {
+ if (ExplodedNodeImpl* NOld = getNode()) {
+ std::vector<ExplodedNodeImpl*>* V = new std::vector<ExplodedNodeImpl*>();
+ assert ((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
+ V->push_back(NOld);
+ V->push_back(N);
+ P = reinterpret_cast<uintptr_t>(V) | SizeOther;
+ assert (getPtr() == (void*) V);
+ assert (getKind() == SizeOther);
+ }
+ else {
+ P = reinterpret_cast<uintptr_t>(N);
+ assert (getKind() == Size1);
+ }
+ }
+ else {
+ assert (getKind() == SizeOther);
+ getVector(getPtr()).push_back(N);
+ }
+}
+
+
+unsigned ExplodedNodeImpl::NodeGroup::size() const {
+ if (getFlag())
+ return 0;
+
+ if (getKind() == Size1)
+ return getNode() ? 1 : 0;
+ else
+ return getVector(getPtr()).size();
+}
+
+ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const {
+ if (getFlag())
+ return NULL;
+
+ if (getKind() == Size1)
+ return (ExplodedNodeImpl**) (getPtr() ? &P : NULL);
+ else
+ return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin()));
+}
+
+ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const {
+ if (getFlag())
+ return NULL;
+
+ if (getKind() == Size1)
+ return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL);
+ else
+ return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).end()));
+}
+
+ExplodedNodeImpl::NodeGroup::~NodeGroup() {
+ if (getKind() == SizeOther) delete &getVector(getPtr());
+}
+
+ExplodedGraphImpl* ExplodedGraphImpl::Trim(ExplodedNodeImpl** BeginSources,
+ ExplodedNodeImpl** EndSources) const{
+
+ typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass1Ty;
+ typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty;
+
+ Pass1Ty Pass1;
+ Pass2Ty Pass2;
+
+ llvm::SmallVector<ExplodedNodeImpl*, 10> WL2;
+
+ { // ===- Pass 1 (reverse BFS) -===
+
+ // Enqueue the source nodes to the first worklist.
+
+ std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1;
+
+ for (ExplodedNodeImpl** I = BeginSources; I != EndSources; ++I)
+ WL1.push_back(std::make_pair(*I, *I));
+
+ // Process the worklist.
+
+ while (!WL1.empty()) {
+
+ ExplodedNodeImpl* N = WL1.back().first;
+ ExplodedNodeImpl* 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)
+ WL1.push_front(std::make_pair(*I, Src));
+ }
+ }
+
+ if (WL2.empty())
+ return NULL;
+
+ ExplodedGraphImpl* G = MakeEmptyGraph();
+
+ // ===- Pass 2 (forward DFS to construct the new graph) -===
+
+ while (!WL2.empty()) {
+
+ 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.
+
+ ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL);
+ Pass2[N] = NewN;
+
+ 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.
+
+ for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
+
+ Pass2Ty::iterator PI = Pass2.find(*I);
+
+ if (PI == Pass2.end())
+ continue;
+
+ NewN->addPredecessor(PI->second);
+ }
+
+ // In the case that some of the intended successors of NewN have already
+ // 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);
+
+ 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 (N->isSink())
+ NewN->markAsSink();
+ }
+
+ return G;
+}
OpenPOWER on IntegriCloud