blob: 9972583272f4ff90b2973545ddf475ad5695ed15 [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"
28#include "llvm/Support/Compiler.h"
29
30using namespace clang;
31using llvm::APInt;
32using llvm::APFloat;
33using llvm::dyn_cast;
34using llvm::cast;
35
36//===----------------------------------------------------------------------===//
37/// DeclStmtPtr - A variant smart pointer that wraps either a Decl* or a
38/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
39//===----------------------------------------------------------------------===//
40namespace {
41class VISIBILITY_HIDDEN DeclStmtPtr {
42 const uintptr_t Raw;
43public:
44 enum VariantKind { IsDecl=0x1, IsBlkLvl=0x2, IsSubExp=0x3, Flags=0x3 };
45 inline void* getPtr() const { return reinterpret_cast<void*>(Raw & ~Flags); }
46 inline VariantKind getKind() const { return (VariantKind) (Raw & Flags); }
47
48 DeclStmtPtr(Decl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsDecl) {}
49 DeclStmtPtr(Stmt* S, bool isBlkLvl)
50 : Raw(reinterpret_cast<uintptr_t>(S) | (isBlkLvl ? IsBlkLvl : IsSubExp)) {}
51
52 bool isSubExpr() const { return getKind() == IsSubExp; }
53
54 inline void Profile(llvm::FoldingSetNodeID& ID) const {
55 ID.AddPointer(getPtr());
56 }
57 inline bool operator==(const DeclStmtPtr& X) const { return Raw == X.Raw; }
58 inline bool operator!=(const DeclStmtPtr& X) const { return Raw != X.Raw; }
59 inline bool operator<(const DeclStmtPtr& X) const { return Raw < X.Raw; }
60};
61} // end anonymous namespace
62
63// Machinery to get cast<> and dyn_cast<> working with DeclStmtPtr.
64namespace llvm {
65 template<> inline bool isa<Decl,DeclStmtPtr>(const DeclStmtPtr& V) {
66 return V.getKind() == DeclStmtPtr::IsDecl;
67 }
68 template<> inline bool isa<Stmt,DeclStmtPtr>(const DeclStmtPtr& V) {
69 return ((unsigned) V.getKind()) > DeclStmtPtr::IsDecl;
70 }
71 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Decl,DeclStmtPtr> {
72 typedef const Decl* ret_type;
73 };
74 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DeclStmtPtr> {
75 typedef const Stmt* ret_type;
76 };
77 template<> struct VISIBILITY_HIDDEN simplify_type<DeclStmtPtr> {
78 typedef void* SimpleType;
79 static inline SimpleType getSimplifiedValue(const DeclStmtPtr &V) {
80 return V.getPtr();
81 }
82 };
83} // end llvm namespace
84
85//===----------------------------------------------------------------------===//
86// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
87//
88// FIXME: We may eventually use APSInt, or a mixture of APSInt and
89// integer primitives to do this right; this will handle both
90// different bit-widths and allow us to detect integer overflows, etc.
91//
92//===----------------------------------------------------------------------===//
93
94typedef llvm::ImmutableMap<DeclStmtPtr,uint64_t> DeclStmtMapTy;
95
96namespace clang {
97template<>
98struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
99 static inline void* toPtr(DeclStmtMapTy M) {
100 return reinterpret_cast<void*>(M.getRoot());
101 }
102 static inline DeclStmtMapTy toState(void* P) {
103 return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
104 }
105};
106}
107
108//===----------------------------------------------------------------------===//
109// The Checker!
110//===----------------------------------------------------------------------===//
111
112namespace {
113class VISIBILITY_HIDDEN ExprVariantTy {
114 const uint64_t val;
115 const bool isConstant;
116public:
117 ExprVariantTy() : val(0), isConstant(false) {}
118 ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
119
120 operator bool() const { return isConstant; }
121 uint64_t getVal() const { assert (isConstant); return val; }
122
123 ExprVariantTy operator+(const ExprVariantTy& X) const {
124 if (!isConstant || !X.isConstant) return ExprVariantTy();
125 else return ExprVariantTy(val+X.val);
126 }
127
128 ExprVariantTy operator-(const ExprVariantTy& X) const {
129 if (!isConstant || !X.isConstant) return ExprVariantTy();
130 else return ExprVariantTy(val+X.val);
131 }
132};
133} // end anonymous namespace
134
135//===----------------------------------------------------------------------===//
136// The Checker!
137//===----------------------------------------------------------------------===//
138
139namespace {
140class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
141
142public:
143 typedef DeclStmtMapTy StateTy;
144 typedef GRNodeBuilder<GRConstants> NodeBuilder;
145 typedef ExplodedNode<StateTy> NodeTy;
146
147protected:
148 // Liveness - live-variables information the Decl* and Expr* (block-level)
149 // in the CFG. Used to prune out dead state.
150 LiveVariables* Liveness;
151
152 // Builder - The current GRNodeBuilder which is used when building the nodes
153 // for a given statement.
154 NodeBuilder* Builder;
155
156 DeclStmtMapTy::Factory StateFactory;
157
158 // cfg - the current CFG.
159 CFG* cfg;
160
161 typedef llvm::SmallPtrSet<NodeTy*,16> NodeSetTy;
162 NodeSetTy NodeSetA;
163 NodeSetTy NodeSetB;
164 NodeSetTy* Nodes;
165 NodeSetTy* OldNodes;
166 NodeTy* Pred;
167
168 bool DoNotSwitch;
169
170public:
171 GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
172 Nodes(&NodeSetA), OldNodes(&NodeSetB), Pred(NULL), DoNotSwitch(false) {}
173
174 ~GRConstants() { delete Liveness; }
175
176 CFG& getCFG() { assert (cfg); return *cfg; }
177
178 void Initialize(CFG& c) {
179 cfg = &c;
180 Liveness = new LiveVariables(c);
181 Liveness->runOnCFG(c);
182 }
183
184 StateTy getInitialState() {
185 return StateFactory.GetEmptyMap();
186 }
187
188 void ProcessStmt(Stmt* S, NodeBuilder& builder);
189 void SwitchNodeSets();
190 void DoStmt(Stmt* S);
191
192 void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
193 ExprVariantTy GetBinding(Expr* E);
194
195 void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
196 void VisitStmt(Stmt* S) { DoNotSwitch = true; }
197
198 void VisitAssign(BinaryOperator* O);
199 void VisitIntegerLiteral(IntegerLiteral* L);
200 void VisitBinAdd(BinaryOperator* O);
201 void VisitBinSub(BinaryOperator* O);
202};
203} // end anonymous namespace
204
205void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
206 Builder = &builder;
207 Nodes->clear();
208 OldNodes->clear();
209 NodeTy* N = Builder->getLastNode();
210 assert (N);
211 OldNodes->insert(N);
212 DoNotSwitch = true;
213 BlockStmt_Visit(S);
214 Builder = NULL;
215}
216
217ExprVariantTy GRConstants::GetBinding(Expr* E) {
218 DeclStmtPtr P(E, getCFG().isBlkExpr(E));
219 StateTy M = Pred->getState();
220 StateTy::iterator I = M.find(P);
221
222 if (I == M.end())
223 return ExprVariantTy();
224
225 return (*I).second;
226}
227
228void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
229 if (!V) {
230 Nodes->insert(Pred);
231 return;
232 }
233
234 StateTy M = Pred->getState();
235 StateTy MNew = StateFactory.Add(M, DeclStmtPtr(E,isBlkLvl), V.getVal());
236 NodeTy* N = Builder->generateNode(E, MNew, Pred);
237 if (N) Nodes->insert(N);
238}
239
240void GRConstants::SwitchNodeSets() {
241 NodeSetTy* Tmp = OldNodes;
242 OldNodes = Nodes;
243 Nodes = Tmp;
244 Nodes->clear();
245}
246
247
248void GRConstants::DoStmt(Stmt* S) {
249 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
250 DoStmt(*I);
251
252 if (!DoNotSwitch) SwitchNodeSets();
253 DoNotSwitch = false;
254
255 for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
256 Pred = *I;
257 Visit(S);
258 Pred = NULL;
259 }
260}
261
262void GRConstants::VisitIntegerLiteral(IntegerLiteral* L) {
263 AddBinding(L, L->getValue().getZExtValue());
264}
265
266void GRConstants::VisitBinAdd(BinaryOperator* B) {
267 AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
268}
269
270void GRConstants::VisitBinSub(BinaryOperator* B) {
271 AddBinding(B, GetBinding(B->getLHS()) - GetBinding(B->getRHS()));
272}
273