blob: 82402559f23b89f1629a90c8b226306cfd460ca5 [file] [log] [blame]
Ted Kremenekd27f8162008-01-15 23:55:06 +00001//===-- GRConstants.cpp - Simple, Path-Sens. Constant Prop. ------*- 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// Constant Propagation via Graph Reachability
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/GREngine.h"
19#include "clang/AST/Expr.h"
20#include "clang/Analysis/Analyses/LiveVariables.h"
21#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
22
23#include "llvm/Support/Casting.h"
24#include "llvm/Support/DataTypes.h"
25#include "llvm/ADT/APSInt.h"
26#include "llvm/ADT/FoldingSet.h"
27#include "llvm/ADT/ImmutableMap.h"
Ted Kremenek3c6c6722008-01-16 17:56:25 +000028#include "llvm/ADT/SmallVector.h"
Ted Kremenekd27f8162008-01-15 23:55:06 +000029#include "llvm/Support/Compiler.h"
30
Ted Kremenekaa66a322008-01-16 21:46:15 +000031#ifndef NDEBUG
32#include "llvm/Support/GraphWriter.h"
33#include <sstream>
34#endif
35
Ted Kremenekd27f8162008-01-15 23:55:06 +000036using namespace clang;
37using llvm::APInt;
38using llvm::APFloat;
39using llvm::dyn_cast;
40using llvm::cast;
41
42//===----------------------------------------------------------------------===//
Ted Kremenekaa66a322008-01-16 21:46:15 +000043/// DSPtr - A variant smart pointer that wraps either a ValueDecl* or a
Ted Kremenekd27f8162008-01-15 23:55:06 +000044/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
45//===----------------------------------------------------------------------===//
46namespace {
Ted Kremenekcb448ca2008-01-16 00:53:15 +000047class VISIBILITY_HIDDEN DSPtr {
Ted Kremenek0525a4f2008-01-16 19:47:19 +000048 uintptr_t Raw;
Ted Kremenekd27f8162008-01-15 23:55:06 +000049public:
Ted Kremenekaa66a322008-01-16 21:46:15 +000050 enum VariantKind { IsValueDecl=0x1, IsBlkLvl=0x2, IsSubExp=0x3, Flags=0x3 };
Ted Kremenekd27f8162008-01-15 23:55:06 +000051 inline void* getPtr() const { return reinterpret_cast<void*>(Raw & ~Flags); }
52 inline VariantKind getKind() const { return (VariantKind) (Raw & Flags); }
53
Ted Kremenekaa66a322008-01-16 21:46:15 +000054 DSPtr(ValueDecl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsValueDecl) {}
Ted Kremenekcb448ca2008-01-16 00:53:15 +000055 DSPtr(Stmt* S, bool isBlkLvl)
Ted Kremenekd27f8162008-01-15 23:55:06 +000056 : Raw(reinterpret_cast<uintptr_t>(S) | (isBlkLvl ? IsBlkLvl : IsSubExp)) {}
57
58 bool isSubExpr() const { return getKind() == IsSubExp; }
59
60 inline void Profile(llvm::FoldingSetNodeID& ID) const {
Ted Kremenek98491852008-01-16 05:51:13 +000061 ID.AddPointer(getPtr());
62 ID.AddInteger((unsigned) getKind());
Ted Kremenekd27f8162008-01-15 23:55:06 +000063 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000064 inline bool operator==(const DSPtr& X) const { return Raw == X.Raw; }
65 inline bool operator!=(const DSPtr& X) const { return Raw != X.Raw; }
66 inline bool operator<(const DSPtr& X) const { return Raw < X.Raw; }
Ted Kremenekd27f8162008-01-15 23:55:06 +000067};
68} // end anonymous namespace
69
Ted Kremenekcb448ca2008-01-16 00:53:15 +000070// Machinery to get cast<> and dyn_cast<> working with DSPtr.
Ted Kremenekd27f8162008-01-15 23:55:06 +000071namespace llvm {
Ted Kremenekaa66a322008-01-16 21:46:15 +000072 template<> inline bool isa<ValueDecl,DSPtr>(const DSPtr& V) {
73 return V.getKind() == DSPtr::IsValueDecl;
Ted Kremenekd27f8162008-01-15 23:55:06 +000074 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000075 template<> inline bool isa<Stmt,DSPtr>(const DSPtr& V) {
Ted Kremenekaa66a322008-01-16 21:46:15 +000076 return ((unsigned) V.getKind()) > DSPtr::IsValueDecl;
Ted Kremenekd27f8162008-01-15 23:55:06 +000077 }
Ted Kremenekaa66a322008-01-16 21:46:15 +000078 template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,DSPtr> {
79 typedef const ValueDecl* ret_type;
Ted Kremenekd27f8162008-01-15 23:55:06 +000080 };
Ted Kremenekcb448ca2008-01-16 00:53:15 +000081 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000082 typedef const Stmt* ret_type;
83 };
Ted Kremenekcb448ca2008-01-16 00:53:15 +000084 template<> struct VISIBILITY_HIDDEN simplify_type<DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000085 typedef void* SimpleType;
Ted Kremenekcb448ca2008-01-16 00:53:15 +000086 static inline SimpleType getSimplifiedValue(const DSPtr &V) {
Ted Kremenekd27f8162008-01-15 23:55:06 +000087 return V.getPtr();
88 }
89 };
90} // end llvm namespace
91
92//===----------------------------------------------------------------------===//
93// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
94//
95// FIXME: We may eventually use APSInt, or a mixture of APSInt and
96// integer primitives to do this right; this will handle both
97// different bit-widths and allow us to detect integer overflows, etc.
98//
99//===----------------------------------------------------------------------===//
100
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000101typedef llvm::ImmutableMap<DSPtr,uint64_t> DeclStmtMapTy;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000102
103namespace clang {
104template<>
105struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
106 static inline void* toPtr(DeclStmtMapTy M) {
107 return reinterpret_cast<void*>(M.getRoot());
108 }
109 static inline DeclStmtMapTy toState(void* P) {
110 return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
111 }
112};
113}
114
115//===----------------------------------------------------------------------===//
116// The Checker!
117//===----------------------------------------------------------------------===//
118
119namespace {
120class VISIBILITY_HIDDEN ExprVariantTy {
121 const uint64_t val;
122 const bool isConstant;
123public:
124 ExprVariantTy() : val(0), isConstant(false) {}
125 ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
126
127 operator bool() const { return isConstant; }
128 uint64_t getVal() const { assert (isConstant); return val; }
129
130 ExprVariantTy operator+(const ExprVariantTy& X) const {
131 if (!isConstant || !X.isConstant) return ExprVariantTy();
132 else return ExprVariantTy(val+X.val);
133 }
134
135 ExprVariantTy operator-(const ExprVariantTy& X) const {
136 if (!isConstant || !X.isConstant) return ExprVariantTy();
137 else return ExprVariantTy(val+X.val);
138 }
139};
140} // end anonymous namespace
141
142//===----------------------------------------------------------------------===//
143// The Checker!
144//===----------------------------------------------------------------------===//
145
146namespace {
147class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
148
149public:
150 typedef DeclStmtMapTy StateTy;
151 typedef GRNodeBuilder<GRConstants> NodeBuilder;
152 typedef ExplodedNode<StateTy> NodeTy;
153
154protected:
Ted Kremenekaa66a322008-01-16 21:46:15 +0000155 // Liveness - live-variables information the ValueDecl* and Expr* (block-level)
Ted Kremenekd27f8162008-01-15 23:55:06 +0000156 // in the CFG. Used to prune out dead state.
157 LiveVariables* Liveness;
158
159 // Builder - The current GRNodeBuilder which is used when building the nodes
160 // for a given statement.
161 NodeBuilder* Builder;
162
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000163 DeclStmtMapTy::Factory StateMgr;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000164
165 // cfg - the current CFG.
166 CFG* cfg;
167
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000168 typedef llvm::SmallVector<NodeTy*,8> NodeSetTy;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000169 NodeSetTy NodeSetA;
170 NodeSetTy NodeSetB;
171 NodeSetTy* Nodes;
172 NodeSetTy* OldNodes;
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000173 StateTy CurrentState;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000174
Ted Kremenekd27f8162008-01-15 23:55:06 +0000175public:
176 GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000177 Nodes(&NodeSetA), OldNodes(&NodeSetB),
178 CurrentState(StateMgr.GetEmptyMap()) {}
Ted Kremenekd27f8162008-01-15 23:55:06 +0000179
180 ~GRConstants() { delete Liveness; }
181
182 CFG& getCFG() { assert (cfg); return *cfg; }
183
184 void Initialize(CFG& c) {
185 cfg = &c;
186 Liveness = new LiveVariables(c);
187 Liveness->runOnCFG(c);
188 }
189
190 StateTy getInitialState() {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000191 return StateMgr.GetEmptyMap();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000192 }
193
194 void ProcessStmt(Stmt* S, NodeBuilder& builder);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000195 void SwitchNodeSets();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000196 void DoStmt(Stmt* S);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000197 StateTy RemoveGrandchildrenMappings(Stmt* S, StateTy M);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000198
199 void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
Ted Kremenekaa66a322008-01-16 21:46:15 +0000200 void AddBinding(ValueDecl* D, ExprVariantTy V);
Ted Kremenek1ccd31c2008-01-16 19:42:59 +0000201
Ted Kremenekd27f8162008-01-15 23:55:06 +0000202 ExprVariantTy GetBinding(Expr* E);
203
204 void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
Ted Kremenekd27f8162008-01-15 23:55:06 +0000205
206 void VisitAssign(BinaryOperator* O);
207 void VisitIntegerLiteral(IntegerLiteral* L);
208 void VisitBinAdd(BinaryOperator* O);
209 void VisitBinSub(BinaryOperator* O);
Ted Kremenek1ccd31c2008-01-16 19:42:59 +0000210 void VisitBinAssign(BinaryOperator* D);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000211};
212} // end anonymous namespace
213
214void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
215 Builder = &builder;
216 Nodes->clear();
217 OldNodes->clear();
218 NodeTy* N = Builder->getLastNode();
219 assert (N);
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000220 OldNodes->push_back(N);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000221 BlockStmt_Visit(S);
222 Builder = NULL;
223}
224
225ExprVariantTy GRConstants::GetBinding(Expr* E) {
Ted Kremenek0525a4f2008-01-16 19:47:19 +0000226 DSPtr P(NULL);
227
228 if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(E)) P = DSPtr(D->getDecl());
229 else P = DSPtr(E, getCFG().isBlkExpr(E));
230
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000231 StateTy::iterator I = CurrentState.find(P);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000232
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000233 if (I == CurrentState.end())
Ted Kremenekd27f8162008-01-15 23:55:06 +0000234 return ExprVariantTy();
235
236 return (*I).second;
237}
238
239void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
Ted Kremenek22f0d972008-01-16 19:28:16 +0000240 if (V)
241 CurrentState = StateMgr.Add(CurrentState, DSPtr(E,isBlkLvl), V.getVal());
Ted Kremenekd27f8162008-01-15 23:55:06 +0000242}
243
Ted Kremenekaa66a322008-01-16 21:46:15 +0000244void GRConstants::AddBinding(ValueDecl* D, ExprVariantTy V) {
Ted Kremenek1ccd31c2008-01-16 19:42:59 +0000245 if (V)
246 CurrentState = StateMgr.Add(CurrentState, DSPtr(D), V.getVal());
247 else
248 CurrentState = StateMgr.Remove(CurrentState, DSPtr(D));
249}
250
Ted Kremenekd27f8162008-01-15 23:55:06 +0000251void GRConstants::SwitchNodeSets() {
252 NodeSetTy* Tmp = OldNodes;
253 OldNodes = Nodes;
254 Nodes = Tmp;
255 Nodes->clear();
256}
257
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000258GRConstants::StateTy
259GRConstants::RemoveGrandchildrenMappings(Stmt* S, GRConstants::StateTy State) {
260
261 typedef Stmt::child_iterator iterator;
262
263 for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
264 if (Stmt* C = *I)
265 for (iterator CI=C->child_begin(), CE=C->child_end(); CI!=CE; ++CI) {
266 // Observe that this will only remove mappings to non-block level
267 // expressions. This is valid even if *CI is a block-level expression,
268 // since it simply won't be in the map in the first place.
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000269 // Note: This should also work if 'C' is a block-level expression,
270 // although ideally we would want to skip processing C's children.
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000271 State = StateMgr.Remove(State, DSPtr(*CI,false));
272 }
273
274 return State;
275}
Ted Kremenekd27f8162008-01-15 23:55:06 +0000276
277void GRConstants::DoStmt(Stmt* S) {
278 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000279 if (*I) DoStmt(*I);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000280
Ted Kremenekd27f8162008-01-15 23:55:06 +0000281 for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000282 NodeTy* Pred = *I;
283 CurrentState = Pred->getState();
284
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000285 StateTy OldState = CurrentState;
286 CurrentState = RemoveGrandchildrenMappings(S, CurrentState);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000287
Ted Kremenekd27f8162008-01-15 23:55:06 +0000288 Visit(S);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000289
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000290 if (CurrentState != OldState) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000291 NodeTy* N = Builder->generateNode(S, CurrentState, Pred);
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000292 if (N) Nodes->push_back(N);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000293 }
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000294 else Nodes->push_back(Pred);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000295 }
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000296
297 SwitchNodeSets();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000298}
299
300void GRConstants::VisitIntegerLiteral(IntegerLiteral* L) {
301 AddBinding(L, L->getValue().getZExtValue());
302}
303
304void GRConstants::VisitBinAdd(BinaryOperator* B) {
305 AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
306}
307
308void GRConstants::VisitBinSub(BinaryOperator* B) {
309 AddBinding(B, GetBinding(B->getLHS()) - GetBinding(B->getRHS()));
310}
Ted Kremenekee985462008-01-16 18:18:48 +0000311
Ted Kremenek1ccd31c2008-01-16 19:42:59 +0000312
313static inline Expr* IgnoreParen(Expr* E) {
314 while (ParenExpr* P = dyn_cast<ParenExpr>(E))
315 E = P->getSubExpr();
316
317 return E;
318}
319
320
321void GRConstants::VisitBinAssign(BinaryOperator* B) {
322 if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(IgnoreParen(B->getLHS())))
323 AddBinding(D->getDecl(), GetBinding(B->getRHS()));
324}
325
Ted Kremenekee985462008-01-16 18:18:48 +0000326//===----------------------------------------------------------------------===//
327// Driver.
328//===----------------------------------------------------------------------===//
329
Ted Kremenekaa66a322008-01-16 21:46:15 +0000330#ifndef NDEBUG
331namespace llvm {
332template<>
333struct VISIBILITY_HIDDEN DOTGraphTraits<GRConstants::NodeTy*> :
334 public DefaultDOTGraphTraits {
335
336 static std::string getNodeLabel(const GRConstants::NodeTy* N, void*) {
337 std::ostringstream Out;
338
339 Out << "Vertex: " << (void*) N << '\n';
340 ProgramPoint Loc = N->getLocation();
341
342 switch (Loc.getKind()) {
343 case ProgramPoint::BlockEntranceKind:
344 Out << "Block Entrance: B"
345 << cast<BlockEntrance>(Loc).getBlock()->getBlockID();
346 break;
347
348 case ProgramPoint::BlockExitKind:
349 assert (false);
350 break;
351
352 case ProgramPoint::PostStmtKind: {
353 const PostStmt& L = cast<PostStmt>(Loc);
354 Out << "Stmt: " << (void*) L.getStmt() << '\n';
355 L.getStmt()->printPretty(Out);
356 break;
357 }
358
359 default: {
360 const BlockEdge& E = cast<BlockEdge>(Loc);
361 Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
362 << E.getDst()->getBlockID() << ')';
363 }
364 }
365
366 Out << "\n{";
367
368 GRConstants::StateTy M = N->getState();
369 bool isFirst = true;
370
371 for (GRConstants::StateTy::iterator I=M.begin(), E=M.end(); I!=E; ++I) {
372 if (!isFirst)
373 Out << '\n';
374 else
375 isFirst = false;
376
377 if (ValueDecl* V = dyn_cast<ValueDecl>(I.getKey())) {
378 Out << "Decl: " << (void*) V << ", " << V->getName();
379 }
380 else {
381 Stmt* E = cast<Stmt>(I.getKey());
382 Out << "Stmt: " << (void*) E;
383 }
384
385 Out << " => " << I.getData();
386 }
387
388 Out << " }";
389
390 return Out.str();
391 }
392};
393} // end llvm namespace
394#endif
395
Ted Kremenekee985462008-01-16 18:18:48 +0000396namespace clang {
397void RunGRConstants(CFG& cfg) {
398 GREngine<GRConstants> Engine(cfg);
399 Engine.ExecuteWorkList();
Ted Kremenekaa66a322008-01-16 21:46:15 +0000400#ifndef NDEBUG
401 llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants");
402#endif
Ted Kremenekee985462008-01-16 18:18:48 +0000403}
404}