blob: 3788551be00bba633cc6d4176aac2b3341953339 [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 Kremenek9eb49a42008-01-13 04:56:13 +000083 else
Ted Kremenek596f0a12008-03-05 19:08:55 +000084 return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).end()));
Ted Kremenek9eb49a42008-01-13 04:56:13 +000085}
86
87ExplodedNodeImpl::NodeGroup::~NodeGroup() {
88 if (getKind() == SizeOther) delete &getVector(getPtr());
89}
Ted Kremenekffe0f432008-03-07 22:58:01 +000090
91ExplodedGraphImpl* ExplodedGraphImpl::Trim(ExplodedNodeImpl** BeginSources,
92 ExplodedNodeImpl** EndSources) const{
93
Ted Kremenek7ec07fd2008-03-12 17:18:20 +000094 typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass1Ty;
Ted Kremenekffe0f432008-03-07 22:58:01 +000095 typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty;
96
97 Pass1Ty Pass1;
98 Pass2Ty Pass2;
99
100 llvm::SmallVector<ExplodedNodeImpl*, 10> WL2;
101
102 { // ===- Pass 1 (reverse BFS) -===
103
104 // Enqueue the source nodes to the first worklist.
105
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000106 std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1;
Ted Kremenek33c63692008-04-16 15:51:26 +0000107 std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1_Loops;
Ted Kremenekffe0f432008-03-07 22:58:01 +0000108
109 for (ExplodedNodeImpl** I = BeginSources; I != EndSources; ++I)
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000110 WL1.push_back(std::make_pair(*I, *I));
Ted Kremenekffe0f432008-03-07 22:58:01 +0000111
112 // Process the worklist.
113
Ted Kremenek33c63692008-04-16 15:51:26 +0000114 while (! (WL1.empty() && WL1_Loops.empty())) {
Ted Kremenekffe0f432008-03-07 22:58:01 +0000115
Ted Kremenek33c63692008-04-16 15:51:26 +0000116 ExplodedNodeImpl *N, *Src;
117
118 // Only dequeue from the "loops" worklist if WL1 has no items.
119 // Thus we prioritize for paths that don't span loop boundaries.
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000120
Ted Kremenek33c63692008-04-16 15:51:26 +0000121 if (WL1.empty()) {
122 N = WL1_Loops.back().first;
123 Src = WL1_Loops.back().second;
124 WL1_Loops.pop_back();
125 }
126 else {
127 N = WL1.back().first;
128 Src = WL1.back().second;
129 WL1.pop_back();
130 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000131
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000132 if (Pass1.find(N) != Pass1.end())
Ted Kremenekffe0f432008-03-07 22:58:01 +0000133 continue;
134
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000135 bool PredHasSameSource = false;
136 bool VisitPreds = true;
137
138 for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
139 I!=E; ++I) {
140
141 Pass1Ty::iterator pi = Pass1.find(*I);
142
143 if (pi == Pass1.end())
144 continue;
145
146 VisitPreds = false;
147
148 if (pi->second == Src) {
149 PredHasSameSource = true;
150 break;
151 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000152 }
153
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000154 if (VisitPreds || !PredHasSameSource) {
155
156 Pass1[N] = Src;
157
158 if (N->Preds.empty()) {
159 WL2.push_back(N);
160 continue;
161 }
162 }
163 else
164 Pass1[N] = NULL;
165
166 if (VisitPreds)
167 for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
Ted Kremenek33c63692008-04-16 15:51:26 +0000168 I!=E; ++I) {
169
170 ProgramPoint P = Src->getLocation();
171
172 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
173 if (Stmt* T = BE->getSrc()->getTerminator())
174 switch (T->getStmtClass()) {
175 default: break;
176 case Stmt::ForStmtClass:
177 case Stmt::WhileStmtClass:
178 case Stmt::DoStmtClass:
179 WL1_Loops.push_front(std::make_pair(*I, Src));
180 continue;
181
182 }
183
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000184 WL1.push_front(std::make_pair(*I, Src));
Ted Kremenek33c63692008-04-16 15:51:26 +0000185 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000186 }
187 }
188
189 if (WL2.empty())
190 return NULL;
191
192 ExplodedGraphImpl* G = MakeEmptyGraph();
193
194 // ===- Pass 2 (forward DFS to construct the new graph) -===
195
196 while (!WL2.empty()) {
197
198 ExplodedNodeImpl* N = WL2.back();
199 WL2.pop_back();
200
201 // Skip this node if we have already processed it.
202
203 if (Pass2.find(N) != Pass2.end())
204 continue;
205
206 // Create the corresponding node in the new graph.
207
208 ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL);
209 Pass2[N] = NewN;
210
211 if (N->Preds.empty())
212 G->addRoot(NewN);
213
214 // In the case that some of the intended predecessors of NewN have already
215 // been created, we should hook them up as predecessors.
216
217 for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
218
219 Pass2Ty::iterator PI = Pass2.find(*I);
220
221 if (PI == Pass2.end())
222 continue;
223
224 NewN->addPredecessor(PI->second);
225 }
226
227 // In the case that some of the intended successors of NewN have already
228 // been created, we should hook them up as successors. Otherwise, enqueue
229 // the new nodes from the original graph that should have nodes created
230 // in the new graph.
231
232 for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
233
234 Pass2Ty::iterator PI = Pass2.find(*I);
235
236 if (PI != Pass2.end()) {
237 PI->second->addPredecessor(NewN);
238 continue;
239 }
240
241 // Enqueue nodes to the worklist that were marked during pass 1.
242
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000243 Pass1Ty::iterator pi = Pass1.find(*I);
244
245 if (pi == Pass1.end() || pi->second == NULL)
246 continue;
247
248 WL2.push_back(*I);
Ted Kremenekffe0f432008-03-07 22:58:01 +0000249 }
250
251 if (N->isSink())
252 NewN->markAsSink();
253 }
254
255 return G;
256}