blob: 95904cd3878fea4f9948ea803bc6b2ffc34c2c8e [file] [log] [blame]
Ted Kremenek9eb49a42008-01-13 04:56:13 +00001//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the template classes ExplodedNode and ExplodedGraph,
11// which represent a path-sensitive, intra-procedural "exploded graph."
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
Ted Kremenek33c63692008-04-16 15:51:26 +000016#include "clang/AST/Stmt.h"
Ted Kremenekffe0f432008-03-07 22:58:01 +000017#include "llvm/ADT/DenseSet.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/SmallVector.h"
Ted Kremenek9eb49a42008-01-13 04:56:13 +000020#include <vector>
Ted Kremenek7ec07fd2008-03-12 17:18:20 +000021#include <list>
Ted Kremenek9eb49a42008-01-13 04:56:13 +000022
23using namespace clang;
24
25
26static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) {
27 return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P);
28}
29
30void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) {
Ted Kremenek596f0a12008-03-05 19:08:55 +000031
32 assert ((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
Ted Kremenekffe0f432008-03-07 22:58:01 +000033 assert (!getFlag());
Ted Kremenek596f0a12008-03-05 19:08:55 +000034
Ted Kremenek9eb49a42008-01-13 04:56:13 +000035 if (getKind() == Size1) {
36 if (ExplodedNodeImpl* NOld = getNode()) {
37 std::vector<ExplodedNodeImpl*>* V = new std::vector<ExplodedNodeImpl*>();
Ted Kremenek596f0a12008-03-05 19:08:55 +000038 assert ((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000039 V->push_back(NOld);
40 V->push_back(N);
Ted Kremenek45c63bd2008-01-29 23:31:09 +000041 P = reinterpret_cast<uintptr_t>(V) | SizeOther;
Ted Kremenek596f0a12008-03-05 19:08:55 +000042 assert (getPtr() == (void*) V);
43 assert (getKind() == SizeOther);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000044 }
Ted Kremenek596f0a12008-03-05 19:08:55 +000045 else {
Ted Kremenek9eb49a42008-01-13 04:56:13 +000046 P = reinterpret_cast<uintptr_t>(N);
Ted Kremenek596f0a12008-03-05 19:08:55 +000047 assert (getKind() == Size1);
48 }
Ted Kremenek9eb49a42008-01-13 04:56:13 +000049 }
Ted Kremenek596f0a12008-03-05 19:08:55 +000050 else {
51 assert (getKind() == SizeOther);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000052 getVector(getPtr()).push_back(N);
Ted Kremenek596f0a12008-03-05 19:08:55 +000053 }
Ted Kremenek9eb49a42008-01-13 04:56:13 +000054}
55
Ted Kremenek9eb49a42008-01-13 04:56:13 +000056
57unsigned ExplodedNodeImpl::NodeGroup::size() const {
Ted Kremenekffe0f432008-03-07 22:58:01 +000058 if (getFlag())
59 return 0;
60
Ted Kremenek9eb49a42008-01-13 04:56:13 +000061 if (getKind() == Size1)
62 return getNode() ? 1 : 0;
63 else
64 return getVector(getPtr()).size();
65}
66
67ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const {
Ted Kremenekffe0f432008-03-07 22:58:01 +000068 if (getFlag())
69 return NULL;
70
Ted Kremenek9eb49a42008-01-13 04:56:13 +000071 if (getKind() == Size1)
Ted Kremenekffe0f432008-03-07 22:58:01 +000072 return (ExplodedNodeImpl**) (getPtr() ? &P : NULL);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000073 else
74 return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin()));
75}
76
77ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const {
Ted Kremenekffe0f432008-03-07 22:58:01 +000078 if (getFlag())
79 return NULL;
80
Ted Kremenek9eb49a42008-01-13 04:56:13 +000081 if (getKind() == Size1)
Ted Kremenekffe0f432008-03-07 22:58:01 +000082 return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL);
Ted Kremenek7b989572008-04-20 23:54:24 +000083 else {
84 // Dereferencing end() is undefined behaviour. The vector is not empty, so
Argyrios Kyrtzidis5fc073f2008-04-22 07:37:18 +000085 // we can dereference the last elem and then add 1 to the result.
86 return const_cast<ExplodedNodeImpl**>(&getVector(getPtr()).back()) + 1;
Ted Kremenek7b989572008-04-20 23:54:24 +000087 }
Ted Kremenek9eb49a42008-01-13 04:56:13 +000088}
89
90ExplodedNodeImpl::NodeGroup::~NodeGroup() {
91 if (getKind() == SizeOther) delete &getVector(getPtr());
92}
Ted Kremenekffe0f432008-03-07 22:58:01 +000093
94ExplodedGraphImpl* ExplodedGraphImpl::Trim(ExplodedNodeImpl** BeginSources,
95 ExplodedNodeImpl** EndSources) const{
96
Ted Kremenek7ec07fd2008-03-12 17:18:20 +000097 typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass1Ty;
Ted Kremenekffe0f432008-03-07 22:58:01 +000098 typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty;
99
100 Pass1Ty Pass1;
101 Pass2Ty Pass2;
102
103 llvm::SmallVector<ExplodedNodeImpl*, 10> WL2;
104
105 { // ===- Pass 1 (reverse BFS) -===
106
107 // Enqueue the source nodes to the first worklist.
108
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000109 std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1;
Ted Kremenek33c63692008-04-16 15:51:26 +0000110 std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1_Loops;
Ted Kremenekffe0f432008-03-07 22:58:01 +0000111
112 for (ExplodedNodeImpl** I = BeginSources; I != EndSources; ++I)
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000113 WL1.push_back(std::make_pair(*I, *I));
Ted Kremenekffe0f432008-03-07 22:58:01 +0000114
115 // Process the worklist.
116
Ted Kremenek33c63692008-04-16 15:51:26 +0000117 while (! (WL1.empty() && WL1_Loops.empty())) {
Ted Kremenekffe0f432008-03-07 22:58:01 +0000118
Ted Kremenek33c63692008-04-16 15:51:26 +0000119 ExplodedNodeImpl *N, *Src;
120
121 // Only dequeue from the "loops" worklist if WL1 has no items.
122 // Thus we prioritize for paths that don't span loop boundaries.
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000123
Ted Kremenek33c63692008-04-16 15:51:26 +0000124 if (WL1.empty()) {
125 N = WL1_Loops.back().first;
126 Src = WL1_Loops.back().second;
127 WL1_Loops.pop_back();
128 }
129 else {
130 N = WL1.back().first;
131 Src = WL1.back().second;
132 WL1.pop_back();
133 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000134
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000135 if (Pass1.find(N) != Pass1.end())
Ted Kremenekffe0f432008-03-07 22:58:01 +0000136 continue;
137
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000138 bool PredHasSameSource = false;
139 bool VisitPreds = true;
140
141 for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
142 I!=E; ++I) {
143
144 Pass1Ty::iterator pi = Pass1.find(*I);
145
146 if (pi == Pass1.end())
147 continue;
148
149 VisitPreds = false;
150
151 if (pi->second == Src) {
152 PredHasSameSource = true;
153 break;
154 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000155 }
156
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000157 if (VisitPreds || !PredHasSameSource) {
158
159 Pass1[N] = Src;
160
161 if (N->Preds.empty()) {
162 WL2.push_back(N);
163 continue;
164 }
165 }
166 else
167 Pass1[N] = NULL;
168
169 if (VisitPreds)
170 for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
Ted Kremenek33c63692008-04-16 15:51:26 +0000171 I!=E; ++I) {
172
173 ProgramPoint P = Src->getLocation();
174
175 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
176 if (Stmt* T = BE->getSrc()->getTerminator())
177 switch (T->getStmtClass()) {
178 default: break;
179 case Stmt::ForStmtClass:
180 case Stmt::WhileStmtClass:
181 case Stmt::DoStmtClass:
182 WL1_Loops.push_front(std::make_pair(*I, Src));
183 continue;
184
185 }
186
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000187 WL1.push_front(std::make_pair(*I, Src));
Ted Kremenek33c63692008-04-16 15:51:26 +0000188 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000189 }
190 }
191
192 if (WL2.empty())
193 return NULL;
194
195 ExplodedGraphImpl* G = MakeEmptyGraph();
196
197 // ===- Pass 2 (forward DFS to construct the new graph) -===
198
199 while (!WL2.empty()) {
200
201 ExplodedNodeImpl* N = WL2.back();
202 WL2.pop_back();
203
204 // Skip this node if we have already processed it.
205
206 if (Pass2.find(N) != Pass2.end())
207 continue;
208
209 // Create the corresponding node in the new graph.
210
211 ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL);
212 Pass2[N] = NewN;
213
214 if (N->Preds.empty())
215 G->addRoot(NewN);
216
217 // In the case that some of the intended predecessors of NewN have already
218 // been created, we should hook them up as predecessors.
219
220 for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
221
222 Pass2Ty::iterator PI = Pass2.find(*I);
223
224 if (PI == Pass2.end())
225 continue;
226
227 NewN->addPredecessor(PI->second);
228 }
229
230 // In the case that some of the intended successors of NewN have already
231 // been created, we should hook them up as successors. Otherwise, enqueue
232 // the new nodes from the original graph that should have nodes created
233 // in the new graph.
234
235 for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
236
237 Pass2Ty::iterator PI = Pass2.find(*I);
238
239 if (PI != Pass2.end()) {
240 PI->second->addPredecessor(NewN);
241 continue;
242 }
243
244 // Enqueue nodes to the worklist that were marked during pass 1.
245
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000246 Pass1Ty::iterator pi = Pass1.find(*I);
247
248 if (pi == Pass1.end() || pi->second == NULL)
249 continue;
250
251 WL2.push_back(*I);
Ted Kremenekffe0f432008-03-07 22:58:01 +0000252 }
253
254 if (N->isSink())
255 NewN->markAsSink();
256 }
257
258 return G;
259}