blob: e83afb79eef150e5de135495e694140c216f7a81 [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//===----------------------------------------------------------------------===//
Ted Kremenekcb448ca2008-01-16 00:53:15 +000037/// DSPtr - A variant smart pointer that wraps either a Decl* or a
Ted Kremenekd27f8162008-01-15 23:55:06 +000038/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
39//===----------------------------------------------------------------------===//
40namespace {
Ted Kremenekcb448ca2008-01-16 00:53:15 +000041class VISIBILITY_HIDDEN DSPtr {
Ted Kremenekd27f8162008-01-15 23:55:06 +000042 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
Ted Kremenekcb448ca2008-01-16 00:53:15 +000048 DSPtr(Decl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsDecl) {}
49 DSPtr(Stmt* S, bool isBlkLvl)
Ted Kremenekd27f8162008-01-15 23:55:06 +000050 : 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 {
Ted Kremenek98491852008-01-16 05:51:13 +000055 ID.AddPointer(getPtr());
56 ID.AddInteger((unsigned) getKind());
Ted Kremenekd27f8162008-01-15 23:55:06 +000057 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000058 inline bool operator==(const DSPtr& X) const { return Raw == X.Raw; }
59 inline bool operator!=(const DSPtr& X) const { return Raw != X.Raw; }
60 inline bool operator<(const DSPtr& X) const { return Raw < X.Raw; }
Ted Kremenekd27f8162008-01-15 23:55:06 +000061};
62} // end anonymous namespace
63
Ted Kremenekcb448ca2008-01-16 00:53:15 +000064// Machinery to get cast<> and dyn_cast<> working with DSPtr.
Ted Kremenekd27f8162008-01-15 23:55:06 +000065namespace llvm {
Ted Kremenekcb448ca2008-01-16 00:53:15 +000066 template<> inline bool isa<Decl,DSPtr>(const DSPtr& V) {
67 return V.getKind() == DSPtr::IsDecl;
Ted Kremenekd27f8162008-01-15 23:55:06 +000068 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000069 template<> inline bool isa<Stmt,DSPtr>(const DSPtr& V) {
70 return ((unsigned) V.getKind()) > DSPtr::IsDecl;
Ted Kremenekd27f8162008-01-15 23:55:06 +000071 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000072 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Decl,DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000073 typedef const Decl* ret_type;
74 };
Ted Kremenekcb448ca2008-01-16 00:53:15 +000075 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000076 typedef const Stmt* ret_type;
77 };
Ted Kremenekcb448ca2008-01-16 00:53:15 +000078 template<> struct VISIBILITY_HIDDEN simplify_type<DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000079 typedef void* SimpleType;
Ted Kremenekcb448ca2008-01-16 00:53:15 +000080 static inline SimpleType getSimplifiedValue(const DSPtr &V) {
Ted Kremenekd27f8162008-01-15 23:55:06 +000081 return V.getPtr();
82 }
83 };
84} // end llvm namespace
85
86//===----------------------------------------------------------------------===//
87// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
88//
89// FIXME: We may eventually use APSInt, or a mixture of APSInt and
90// integer primitives to do this right; this will handle both
91// different bit-widths and allow us to detect integer overflows, etc.
92//
93//===----------------------------------------------------------------------===//
94
Ted Kremenekcb448ca2008-01-16 00:53:15 +000095typedef llvm::ImmutableMap<DSPtr,uint64_t> DeclStmtMapTy;
Ted Kremenekd27f8162008-01-15 23:55:06 +000096
97namespace clang {
98template<>
99struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
100 static inline void* toPtr(DeclStmtMapTy M) {
101 return reinterpret_cast<void*>(M.getRoot());
102 }
103 static inline DeclStmtMapTy toState(void* P) {
104 return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
105 }
106};
107}
108
109//===----------------------------------------------------------------------===//
110// The Checker!
111//===----------------------------------------------------------------------===//
112
113namespace {
114class VISIBILITY_HIDDEN ExprVariantTy {
115 const uint64_t val;
116 const bool isConstant;
117public:
118 ExprVariantTy() : val(0), isConstant(false) {}
119 ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
120
121 operator bool() const { return isConstant; }
122 uint64_t getVal() const { assert (isConstant); return val; }
123
124 ExprVariantTy operator+(const ExprVariantTy& X) const {
125 if (!isConstant || !X.isConstant) return ExprVariantTy();
126 else return ExprVariantTy(val+X.val);
127 }
128
129 ExprVariantTy operator-(const ExprVariantTy& X) const {
130 if (!isConstant || !X.isConstant) return ExprVariantTy();
131 else return ExprVariantTy(val+X.val);
132 }
133};
134} // end anonymous namespace
135
136//===----------------------------------------------------------------------===//
137// The Checker!
138//===----------------------------------------------------------------------===//
139
140namespace {
141class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
142
143public:
144 typedef DeclStmtMapTy StateTy;
145 typedef GRNodeBuilder<GRConstants> NodeBuilder;
146 typedef ExplodedNode<StateTy> NodeTy;
147
148protected:
149 // Liveness - live-variables information the Decl* and Expr* (block-level)
150 // in the CFG. Used to prune out dead state.
151 LiveVariables* Liveness;
152
153 // Builder - The current GRNodeBuilder which is used when building the nodes
154 // for a given statement.
155 NodeBuilder* Builder;
156
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000157 DeclStmtMapTy::Factory StateMgr;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000158
159 // cfg - the current CFG.
160 CFG* cfg;
161
162 typedef llvm::SmallPtrSet<NodeTy*,16> NodeSetTy;
163 NodeSetTy NodeSetA;
164 NodeSetTy NodeSetB;
165 NodeSetTy* Nodes;
166 NodeSetTy* OldNodes;
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000167 StateTy CurrentState;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000168
169 bool DoNotSwitch;
170
171public:
172 GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000173 Nodes(&NodeSetA), OldNodes(&NodeSetB),
174 CurrentState(StateMgr.GetEmptyMap()), DoNotSwitch(false) {}
Ted Kremenekd27f8162008-01-15 23:55:06 +0000175
176 ~GRConstants() { delete Liveness; }
177
178 CFG& getCFG() { assert (cfg); return *cfg; }
179
180 void Initialize(CFG& c) {
181 cfg = &c;
182 Liveness = new LiveVariables(c);
183 Liveness->runOnCFG(c);
184 }
185
186 StateTy getInitialState() {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000187 return StateMgr.GetEmptyMap();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000188 }
189
190 void ProcessStmt(Stmt* S, NodeBuilder& builder);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000191 void SwitchNodeSets();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000192 void DoStmt(Stmt* S);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000193 StateTy RemoveGrandchildrenMappings(Stmt* S, StateTy M);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000194
195 void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
196 ExprVariantTy GetBinding(Expr* E);
197
198 void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
199 void VisitStmt(Stmt* S) { DoNotSwitch = true; }
200
201 void VisitAssign(BinaryOperator* O);
202 void VisitIntegerLiteral(IntegerLiteral* L);
203 void VisitBinAdd(BinaryOperator* O);
204 void VisitBinSub(BinaryOperator* O);
205};
206} // end anonymous namespace
207
208void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
209 Builder = &builder;
210 Nodes->clear();
211 OldNodes->clear();
212 NodeTy* N = Builder->getLastNode();
213 assert (N);
214 OldNodes->insert(N);
215 DoNotSwitch = true;
216 BlockStmt_Visit(S);
217 Builder = NULL;
218}
219
220ExprVariantTy GRConstants::GetBinding(Expr* E) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000221 DSPtr P(E, getCFG().isBlkExpr(E));
222 StateTy::iterator I = CurrentState.find(P);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000223
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000224 if (I == CurrentState.end())
Ted Kremenekd27f8162008-01-15 23:55:06 +0000225 return ExprVariantTy();
226
227 return (*I).second;
228}
229
230void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000231 CurrentState = StateMgr.Add(CurrentState, DSPtr(E,isBlkLvl), V.getVal());
Ted Kremenekd27f8162008-01-15 23:55:06 +0000232}
233
234void GRConstants::SwitchNodeSets() {
235 NodeSetTy* Tmp = OldNodes;
236 OldNodes = Nodes;
237 Nodes = Tmp;
238 Nodes->clear();
239}
240
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000241GRConstants::StateTy
242GRConstants::RemoveGrandchildrenMappings(Stmt* S, GRConstants::StateTy State) {
243
244 typedef Stmt::child_iterator iterator;
245
246 for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
247 if (Stmt* C = *I)
248 for (iterator CI=C->child_begin(), CE=C->child_end(); CI!=CE; ++CI) {
249 // Observe that this will only remove mappings to non-block level
250 // expressions. This is valid even if *CI is a block-level expression,
251 // since it simply won't be in the map in the first place.
252 State = StateMgr.Remove(State, DSPtr(*CI,false));
253 }
254
255 return State;
256}
Ted Kremenekd27f8162008-01-15 23:55:06 +0000257
258void GRConstants::DoStmt(Stmt* S) {
259 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000260 if (*I) DoStmt(*I);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000261
262 if (!DoNotSwitch) SwitchNodeSets();
263 DoNotSwitch = false;
264
265 for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000266 NodeTy* Pred = *I;
267 CurrentState = Pred->getState();
268
269 StateTy CleanedState = RemoveGrandchildrenMappings(S, CurrentState);
270 bool AlwaysGenerateNode = false;
271
272 if (CleanedState != CurrentState) {
273 CurrentState = CleanedState;
274 AlwaysGenerateNode = true;
275 }
276
Ted Kremenekd27f8162008-01-15 23:55:06 +0000277 Visit(S);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000278
279 if (AlwaysGenerateNode || CurrentState != CleanedState) {
280 NodeTy* N = Builder->generateNode(S, CurrentState, Pred);
281 if (N) Nodes->insert(N);
282 }
283 else Nodes->insert(Pred);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000284 }
285}
286
287void GRConstants::VisitIntegerLiteral(IntegerLiteral* L) {
288 AddBinding(L, L->getValue().getZExtValue());
289}
290
291void GRConstants::VisitBinAdd(BinaryOperator* B) {
292 AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
293}
294
295void GRConstants::VisitBinSub(BinaryOperator* B) {
296 AddBinding(B, GetBinding(B->getLHS()) - GetBinding(B->getRHS()));
297}
298