blob: ead92d7f38bc8c67147c2723f9fa4126d3a3f568 [file] [log] [blame]
Ted Kremenek79784522008-01-03 22:12:28 +00001//===-- GRConstantPropagation.cpp --------------------------------*- C++ -*-==//
2//
3// [ Constant Propagation via Graph Reachability ]
4//
5// The LLVM Compiler Infrastructure
6//
7// This file is distributed under the University of Illinois Open Source
8// License. See LICENSE.TXT for details.
9//
10//===----------------------------------------------------------------------===//
11//
12// This files defines a simple analysis that performs path-sensitive
13// constant propagation within a function. An example use of this analysis
14// is to perform simple checks for NULL dereferences.
15//
16//===----------------------------------------------------------------------===//
17
18#include "clang/Analysis/PathSensitive/SimulGraph.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/CFG.h"
21#include "llvm/Support/Casting.h"
22#include "llvm/Support/DataTypes.h"
23#include "llvm/ADT/APInt.h"
24#include "llvm/ADT/APFloat.h"
25#include "llvm/ADT/ImmutableMap.h"
26
27using namespace clang;
28using llvm::APInt;
29using llvm::APFloat;
30using llvm::dyn_cast;
31using llvm::cast;
32
33//===----------------------------------------------------------------------===//
34// ConstV - Represents a variant over APInt, APFloat, and const char
35//===----------------------------------------------------------------------===//
36
37namespace {
38class ConstV {
39 uintptr_t Data;
40public:
41 enum VariantType { VTString = 0x0, VTObjCString = 0x1,
42 VTFloat = 0x2, VTInt = 0x3,
43 Flags = 0x3 };
44
45 ConstV(const StringLiteral* v)
46 : Data(reinterpret_cast<uintptr_t>(v) | VTString) {}
47
48 ConstV(const ObjCStringLiteral* v)
49 : Data(reinterpret_cast<uintptr_t>(v) | VTObjCString) {}
50
51 ConstV(llvm::APInt* v)
52 : Data(reinterpret_cast<uintptr_t>(v) | VTInt) {}
53
54 ConstV(llvm::APFloat* v)
55 : Data(reinterpret_cast<uintptr_t>(v) | VTFloat) {}
56
57
58 inline void* getData() const { return (void*) (Data & ~Flags); }
59 inline VariantType getVT() const { return (VariantType) (Data & Flags); }
60
61 inline void Profile(llvm::FoldingSetNodeID& ID) const {
62 ID.AddPointer(getData());
63 }
64};
65} // end anonymous namespace
66
67// Overload machinery for casting from ConstV to contained classes.
68
69namespace llvm {
70
71#define CV_OBJ_CAST(CLASS,FLAG)\
72template<> inline bool isa<CLASS,ConstV>(const ConstV& V) {\
73 return V.getVT() == FLAG;\
74}\
75\
76template <> struct cast_retty_impl<CLASS, ConstV> {\
77 typedef const CLASS* ret_type;\
78};
79
80CV_OBJ_CAST(APInt,ConstV::VTInt)
81CV_OBJ_CAST(APFloat,ConstV::VTFloat)
82CV_OBJ_CAST(StringLiteral,ConstV::VTString)
83CV_OBJ_CAST(ObjCStringLiteral,ConstV::VTObjCString)
84
85#undef CV_OBJ_CAST
86
87template <> struct simplify_type<ConstV> {
88 typedef void* SimpleType;
89 static SimpleType getSimplifiedValue(const ConstV &Val) {
90 return Val.getData();
91 }
92};
93
94} // end llvm namespace
95
96//===----------------------------------------------------------------------===//
97/// The checker.
98//===----------------------------------------------------------------------===//
99
100namespace {
101
102
103class GRCP {
104
105 //==---------------------------------==//
106 // Type definitions.
107 //==---------------------------------==//
108
109public:
110 typedef llvm::ImmutableMap<Decl*,ConstV> StateTy;
111 typedef SimulVertex<StateTy> VertexTy;
112 typedef SimulGraph<VertexTy> GraphTy;
113 typedef llvm::SmallVector<Stmt*,20> StmtStackTy;
114 typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
115
116 /// DFSWorkList - A nested class that represents a worklist that processes
117 /// vertices in LIFO order.
118 class DFSWorkList {
119 llvm::SmallVector<VertexTy*,20> Vertices;
120 public:
121 bool hasWork() const { return !Vertices.empty(); }
122
123 /// Enqueue - Add a vertex to the worklist.
124 void Enqueue(VertexTy* V) { Vertices.push_back(V); }
125
126 /// Dequeue - Remove a vertex from the worklist.
127 VertexTy* Dequeue() {
128 assert (hasWork());
129 VertexTy* V = Vertices.back();
130 Vertices.pop_back();
131 return V;
132 }
133 };
134
135 //==---------------------------------==//
136 // Data.
137 //==---------------------------------==//
138
139private:
140 CFG& cfg;
141
142 /// StateFactory - States are simply maps from Decls to constants. This
143 /// object is a collection of all the states (immutable maps) that are
144 /// created by the analysis. This object owns the created maps.
145 StateTy::Factory StateFactory;
146
147 /// Graph - The simulation graph. Each vertex is a (location,state) pair.
148 GraphTy Graph;
149
150 /// ParentMap - A lazily populated map from a Stmt* to its parent Stmt*.
151 ParentMapTy ParentMap;
152
153 /// StmtStack - A stack of statements/expressions that records the
154 /// statement hierarchy starting from the Stmt* of the last dequeued
155 /// vertex. Used to lazily populate ParentMap.
156 StmtStackTy StmtStack;
157
158 /// WorkList - A set of queued vertices that need to be processed by the
159 /// worklist algorithm.
160 DFSWorkList WorkList;
161
162 //==---------------------------------==//
163 // Edge processing.
164 //==---------------------------------==//
165
166 void MakeVertex(const ProgramEdge& Loc, StateTy State, VertexTy* PredV) {
167 std::pair<VertexTy*,bool> V = Graph.getVertex(Loc,State);
168 V.first->addPredecessor(PredV);
169 if (V.second) WorkList.Enqueue(V.first);
170 }
171
172 void MakeVertex(const ProgramEdge& Loc, VertexTy* PredV) {
173 MakeVertex(Loc,PredV->getState(),PredV);
174 }
175
176 void VisitBlkBlk(const BlkBlkEdge& E, VertexTy* PredV);
177 void VisitBlkStmt(const BlkStmtEdge& E, VertexTy* PredV);
178 void VisitStmtBlk(const StmtBlkEdge& E, VertexTy* PredV);
179
180 void ProcessEOP(VertexTy* PredV);
181 void ProcessStmt(Stmt* S, VertexTy* PredV);
182 void ProcessTerminator(Stmt* Terminator ,VertexTy* PredV);
183
184 //==---------------------------------==//
185 // Disable copying.
186 //==---------------------------------==//
187
188 GRCP(const GRCP&); // Do not implement.
189 GRCP& operator=(const GRCP&);
190
191 //==--------------------------------==//
192 // Public API.
193 //==--------------------------------==//
194
195public:
196 GRCP(CFG& c);
197
198 /// getGraph - Returns the simulation graph.
199 const GraphTy& getGraph() const { return Graph; }
200
201 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
202 /// steps. Returns true if there is still simulation state on the worklist.
203 bool ExecuteWorkList(unsigned Steps = 1000000);
204};
205} // end anonymous namespace
206
207
208//==--------------------------------------------------------==//
209// Public API.
210//==--------------------------------------------------------==//
211
212GRCP::GRCP(CFG& c) : cfg(c) {
213 // Get the entry block. Make sure that it has 1 (and only 1) successor.
214 CFGBlock* Entry = &c.getEntry();
215
216 assert (Entry->empty() && "Entry block must be empty.");
217 assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
218
219 // Get the first (and only) successor of Entry.
220 CFGBlock* Succ = *(Entry->succ_begin());
221
222 // Construct an edge representing the starting location in the function.
223 BlkBlkEdge StartLoc(Entry,Succ);
224
225 // Get the vertex. Make it a root in the graph.
226 VertexTy* Root = Graph.getVertex(StartLoc,StateFactory.GetEmptyMap()).first;
227 Graph.addRoot(Root);
228
229 // Enqueue the root so that it can be processed by the worklist.
230 WorkList.Enqueue(Root);
231}
232
233
234bool GRCP::ExecuteWorkList(unsigned Steps) {
235 while (Steps && WorkList.hasWork()) {
236 --Steps;
237 VertexTy* V = WorkList.Dequeue();
238
239 // Dispatch on the location type.
240 switch (V->getLocation().getKind()) {
241 case ProgramEdge::BlkBlk:
242 VisitBlkBlk(cast<BlkBlkEdge>(V->getLocation()),V);
243 break;
244
245 case ProgramEdge::BlkStmt:
246 VisitBlkStmt(cast<BlkStmtEdge>(V->getLocation()),V);
247 break;
248
249 case ProgramEdge::StmtBlk:
250 VisitStmtBlk(cast<StmtBlkEdge>(V->getLocation()),V);
251 break;
252
253 default:
254 assert (false && "Unsupported edge type.");
255 }
256 }
257
258 return WorkList.hasWork();
259}
260
261//==--------------------------------------------------------==//
262// Edge processing.
263//==--------------------------------------------------------==//
264
265void GRCP::VisitBlkBlk(const BlkBlkEdge& E, GRCP::VertexTy* PredV) {
266
267 const CFGBlock* Blk = E.Dst();
268
269 // FIXME: we will dispatch to a function that manipulates the state
270 // at the entrance to a block.
271
272 if (!Blk->empty()) {
273 // If 'Blk' has at least one statement, create a BlkStmtEdge and create
274 // the appropriate vertex. This is the common case.
275 MakeVertex(BlkStmtEdge(Blk,Blk->front()), PredV->getState(), PredV);
276 }
277 else {
278 // Otherwise, create a vertex at the BlkStmtEdge right before the terminator
279 // (if any) is evaluated.
280 MakeVertex(StmtBlkEdge(NULL,Blk),PredV->getState(), PredV);
281 }
282}
283
284void GRCP::VisitBlkStmt(const BlkStmtEdge& E, GRCP::VertexTy* PredV) {
285
286 // Check if we are entering the EXIT block.
287 if (E.Src() == &cfg.getExit()) {
288 assert (cfg.getExit().size() == 0 && "EXIT block cannot contain Stmts.");
289 // Process the End-Of-Path.
290 ProcessEOP(PredV);
291 return;
292 }
293
294 // Normal block. Process as usual.
295 if (Stmt* S = E.Dst())
296 ProcessStmt(S,PredV);
297 else {
298 // No statement. Create an edge right before the terminator is evaluated.
299 MakeVertex(StmtBlkEdge(NULL,E.Src()), PredV->getState(), PredV);
300 }
301}
302
303void GRCP::VisitStmtBlk(const StmtBlkEdge& E, GRCP::VertexTy* PredV) {
304 CFGBlock* Blk = E.Dst();
305
306 if (Stmt* Terminator = Blk->getTerminator())
307 ProcessTerminator(Terminator,PredV);
308 else {
309 // No terminator. We should have only 1 successor.
310 assert (Blk->succ_size() == 1);
311 MakeVertex(BlkBlkEdge(Blk,*(Blk->succ_begin())), PredV);
312 }
313}
314
315void GRCP::ProcessEOP(GRCP::VertexTy* PredV) {
316 assert(false && "Not implemented.");
317}
318
319void GRCP::ProcessStmt(Stmt* S, GRCP::VertexTy* PredV) {
320 assert(false && "Not implemented.");
321}
322
323void GRCP::ProcessTerminator(Stmt* Terminator,GRCP::VertexTy* PredV) {
324 assert(false && "Not implemented.");
325}