blob: 56c450420921b99735f38f15848dec9974f840f3 [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
31using namespace clang;
32using llvm::APInt;
33using llvm::APFloat;
34using llvm::dyn_cast;
35using llvm::cast;
36
37//===----------------------------------------------------------------------===//
Ted Kremenekcb448ca2008-01-16 00:53:15 +000038/// DSPtr - A variant smart pointer that wraps either a Decl* or a
Ted Kremenekd27f8162008-01-15 23:55:06 +000039/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
40//===----------------------------------------------------------------------===//
41namespace {
Ted Kremenekcb448ca2008-01-16 00:53:15 +000042class VISIBILITY_HIDDEN DSPtr {
Ted Kremenekd27f8162008-01-15 23:55:06 +000043 const uintptr_t Raw;
44public:
45 enum VariantKind { IsDecl=0x1, IsBlkLvl=0x2, IsSubExp=0x3, Flags=0x3 };
46 inline void* getPtr() const { return reinterpret_cast<void*>(Raw & ~Flags); }
47 inline VariantKind getKind() const { return (VariantKind) (Raw & Flags); }
48
Ted Kremenekcb448ca2008-01-16 00:53:15 +000049 DSPtr(Decl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsDecl) {}
50 DSPtr(Stmt* S, bool isBlkLvl)
Ted Kremenekd27f8162008-01-15 23:55:06 +000051 : Raw(reinterpret_cast<uintptr_t>(S) | (isBlkLvl ? IsBlkLvl : IsSubExp)) {}
52
53 bool isSubExpr() const { return getKind() == IsSubExp; }
54
55 inline void Profile(llvm::FoldingSetNodeID& ID) const {
Ted Kremenek98491852008-01-16 05:51:13 +000056 ID.AddPointer(getPtr());
57 ID.AddInteger((unsigned) getKind());
Ted Kremenekd27f8162008-01-15 23:55:06 +000058 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000059 inline bool operator==(const DSPtr& X) const { return Raw == X.Raw; }
60 inline bool operator!=(const DSPtr& X) const { return Raw != X.Raw; }
61 inline bool operator<(const DSPtr& X) const { return Raw < X.Raw; }
Ted Kremenekd27f8162008-01-15 23:55:06 +000062};
63} // end anonymous namespace
64
Ted Kremenekcb448ca2008-01-16 00:53:15 +000065// Machinery to get cast<> and dyn_cast<> working with DSPtr.
Ted Kremenekd27f8162008-01-15 23:55:06 +000066namespace llvm {
Ted Kremenekcb448ca2008-01-16 00:53:15 +000067 template<> inline bool isa<Decl,DSPtr>(const DSPtr& V) {
68 return V.getKind() == DSPtr::IsDecl;
Ted Kremenekd27f8162008-01-15 23:55:06 +000069 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000070 template<> inline bool isa<Stmt,DSPtr>(const DSPtr& V) {
71 return ((unsigned) V.getKind()) > DSPtr::IsDecl;
Ted Kremenekd27f8162008-01-15 23:55:06 +000072 }
Ted Kremenekcb448ca2008-01-16 00:53:15 +000073 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Decl,DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000074 typedef const Decl* ret_type;
75 };
Ted Kremenekcb448ca2008-01-16 00:53:15 +000076 template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000077 typedef const Stmt* ret_type;
78 };
Ted Kremenekcb448ca2008-01-16 00:53:15 +000079 template<> struct VISIBILITY_HIDDEN simplify_type<DSPtr> {
Ted Kremenekd27f8162008-01-15 23:55:06 +000080 typedef void* SimpleType;
Ted Kremenekcb448ca2008-01-16 00:53:15 +000081 static inline SimpleType getSimplifiedValue(const DSPtr &V) {
Ted Kremenekd27f8162008-01-15 23:55:06 +000082 return V.getPtr();
83 }
84 };
85} // end llvm namespace
86
87//===----------------------------------------------------------------------===//
88// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
89//
90// FIXME: We may eventually use APSInt, or a mixture of APSInt and
91// integer primitives to do this right; this will handle both
92// different bit-widths and allow us to detect integer overflows, etc.
93//
94//===----------------------------------------------------------------------===//
95
Ted Kremenekcb448ca2008-01-16 00:53:15 +000096typedef llvm::ImmutableMap<DSPtr,uint64_t> DeclStmtMapTy;
Ted Kremenekd27f8162008-01-15 23:55:06 +000097
98namespace clang {
99template<>
100struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
101 static inline void* toPtr(DeclStmtMapTy M) {
102 return reinterpret_cast<void*>(M.getRoot());
103 }
104 static inline DeclStmtMapTy toState(void* P) {
105 return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
106 }
107};
108}
109
110//===----------------------------------------------------------------------===//
111// The Checker!
112//===----------------------------------------------------------------------===//
113
114namespace {
115class VISIBILITY_HIDDEN ExprVariantTy {
116 const uint64_t val;
117 const bool isConstant;
118public:
119 ExprVariantTy() : val(0), isConstant(false) {}
120 ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
121
122 operator bool() const { return isConstant; }
123 uint64_t getVal() const { assert (isConstant); return val; }
124
125 ExprVariantTy operator+(const ExprVariantTy& X) const {
126 if (!isConstant || !X.isConstant) return ExprVariantTy();
127 else return ExprVariantTy(val+X.val);
128 }
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} // end anonymous namespace
136
137//===----------------------------------------------------------------------===//
138// The Checker!
139//===----------------------------------------------------------------------===//
140
141namespace {
142class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
143
144public:
145 typedef DeclStmtMapTy StateTy;
146 typedef GRNodeBuilder<GRConstants> NodeBuilder;
147 typedef ExplodedNode<StateTy> NodeTy;
148
149protected:
150 // Liveness - live-variables information the Decl* and Expr* (block-level)
151 // in the CFG. Used to prune out dead state.
152 LiveVariables* Liveness;
153
154 // Builder - The current GRNodeBuilder which is used when building the nodes
155 // for a given statement.
156 NodeBuilder* Builder;
157
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000158 DeclStmtMapTy::Factory StateMgr;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000159
160 // cfg - the current CFG.
161 CFG* cfg;
162
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000163 typedef llvm::SmallVector<NodeTy*,8> NodeSetTy;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000164 NodeSetTy NodeSetA;
165 NodeSetTy NodeSetB;
166 NodeSetTy* Nodes;
167 NodeSetTy* OldNodes;
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000168 StateTy CurrentState;
Ted Kremenekd27f8162008-01-15 23:55:06 +0000169
Ted Kremenekd27f8162008-01-15 23:55:06 +0000170public:
171 GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000172 Nodes(&NodeSetA), OldNodes(&NodeSetB),
173 CurrentState(StateMgr.GetEmptyMap()) {}
Ted Kremenekd27f8162008-01-15 23:55:06 +0000174
175 ~GRConstants() { delete Liveness; }
176
177 CFG& getCFG() { assert (cfg); return *cfg; }
178
179 void Initialize(CFG& c) {
180 cfg = &c;
181 Liveness = new LiveVariables(c);
182 Liveness->runOnCFG(c);
183 }
184
185 StateTy getInitialState() {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000186 return StateMgr.GetEmptyMap();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000187 }
188
189 void ProcessStmt(Stmt* S, NodeBuilder& builder);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000190 void SwitchNodeSets();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000191 void DoStmt(Stmt* S);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000192 StateTy RemoveGrandchildrenMappings(Stmt* S, StateTy M);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000193
194 void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
195 ExprVariantTy GetBinding(Expr* E);
196
197 void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
Ted Kremenekd27f8162008-01-15 23:55:06 +0000198
199 void VisitAssign(BinaryOperator* O);
200 void VisitIntegerLiteral(IntegerLiteral* L);
201 void VisitBinAdd(BinaryOperator* O);
202 void VisitBinSub(BinaryOperator* O);
203};
204} // end anonymous namespace
205
206void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
207 Builder = &builder;
208 Nodes->clear();
209 OldNodes->clear();
210 NodeTy* N = Builder->getLastNode();
211 assert (N);
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000212 OldNodes->push_back(N);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000213 BlockStmt_Visit(S);
214 Builder = NULL;
215}
216
217ExprVariantTy GRConstants::GetBinding(Expr* E) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000218 DSPtr P(E, getCFG().isBlkExpr(E));
219 StateTy::iterator I = CurrentState.find(P);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000220
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000221 if (I == CurrentState.end())
Ted Kremenekd27f8162008-01-15 23:55:06 +0000222 return ExprVariantTy();
223
224 return (*I).second;
225}
226
227void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000228 CurrentState = StateMgr.Add(CurrentState, DSPtr(E,isBlkLvl), V.getVal());
Ted Kremenekd27f8162008-01-15 23:55:06 +0000229}
230
231void GRConstants::SwitchNodeSets() {
232 NodeSetTy* Tmp = OldNodes;
233 OldNodes = Nodes;
234 Nodes = Tmp;
235 Nodes->clear();
236}
237
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000238GRConstants::StateTy
239GRConstants::RemoveGrandchildrenMappings(Stmt* S, GRConstants::StateTy State) {
240
241 typedef Stmt::child_iterator iterator;
242
243 for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
244 if (Stmt* C = *I)
245 for (iterator CI=C->child_begin(), CE=C->child_end(); CI!=CE; ++CI) {
246 // Observe that this will only remove mappings to non-block level
247 // expressions. This is valid even if *CI is a block-level expression,
248 // since it simply won't be in the map in the first place.
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000249 // Note: This should also work if 'C' is a block-level expression,
250 // although ideally we would want to skip processing C's children.
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000251 State = StateMgr.Remove(State, DSPtr(*CI,false));
252 }
253
254 return State;
255}
Ted Kremenekd27f8162008-01-15 23:55:06 +0000256
257void GRConstants::DoStmt(Stmt* S) {
258 for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000259 if (*I) DoStmt(*I);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000260
Ted Kremenekd27f8162008-01-15 23:55:06 +0000261 for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000262 NodeTy* Pred = *I;
263 CurrentState = Pred->getState();
264
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000265 StateTy OldState = CurrentState;
266 CurrentState = RemoveGrandchildrenMappings(S, CurrentState);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000267
Ted Kremenekd27f8162008-01-15 23:55:06 +0000268 Visit(S);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000269
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000270 if (CurrentState != OldState) {
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000271 NodeTy* N = Builder->generateNode(S, CurrentState, Pred);
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000272 if (N) Nodes->push_back(N);
Ted Kremenekcb448ca2008-01-16 00:53:15 +0000273 }
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000274 else Nodes->push_back(Pred);
Ted Kremenekd27f8162008-01-15 23:55:06 +0000275 }
Ted Kremenek3c6c6722008-01-16 17:56:25 +0000276
277 SwitchNodeSets();
Ted Kremenekd27f8162008-01-15 23:55:06 +0000278}
279
280void GRConstants::VisitIntegerLiteral(IntegerLiteral* L) {
281 AddBinding(L, L->getValue().getZExtValue());
282}
283
284void GRConstants::VisitBinAdd(BinaryOperator* B) {
285 AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
286}
287
288void GRConstants::VisitBinSub(BinaryOperator* B) {
289 AddBinding(B, GetBinding(B->getLHS()) - GetBinding(B->getRHS()));
290}
Ted Kremenekee985462008-01-16 18:18:48 +0000291
292//===----------------------------------------------------------------------===//
293// Driver.
294//===----------------------------------------------------------------------===//
295
296namespace clang {
297void RunGRConstants(CFG& cfg) {
298 GREngine<GRConstants> Engine(cfg);
299 Engine.ExecuteWorkList();
300}
301}