1
+ // ===-- 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
+
30
+ using namespace clang ;
31
+ using llvm::APInt;
32
+ using llvm::APFloat;
33
+ using llvm::dyn_cast;
34
+ using 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
+ // ===----------------------------------------------------------------------===//
40
+ namespace {
41
+ class VISIBILITY_HIDDEN DeclStmtPtr {
42
+ const uintptr_t Raw;
43
+ public:
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.
64
+ namespace 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
+
94
+ typedef llvm::ImmutableMap<DeclStmtPtr,uint64_t > DeclStmtMapTy;
95
+
96
+ namespace clang {
97
+ template <>
98
+ struct 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
+
112
+ namespace {
113
+ class VISIBILITY_HIDDEN ExprVariantTy {
114
+ const uint64_t val;
115
+ const bool isConstant;
116
+ public:
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
+
139
+ namespace {
140
+ class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
141
+
142
+ public:
143
+ typedef DeclStmtMapTy StateTy;
144
+ typedef GRNodeBuilder<GRConstants> NodeBuilder;
145
+ typedef ExplodedNode<StateTy> NodeTy;
146
+
147
+ protected:
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
+
170
+ public:
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
+
205
+ void 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
+
217
+ ExprVariantTy 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
+
228
+ void 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
+
240
+ void GRConstants::SwitchNodeSets () {
241
+ NodeSetTy* Tmp = OldNodes;
242
+ OldNodes = Nodes;
243
+ Nodes = Tmp;
244
+ Nodes->clear ();
245
+ }
246
+
247
+
248
+ void 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
+
262
+ void GRConstants::VisitIntegerLiteral (IntegerLiteral* L) {
263
+ AddBinding (L, L->getValue ().getZExtValue ());
264
+ }
265
+
266
+ void GRConstants::VisitBinAdd (BinaryOperator* B) {
267
+ AddBinding (B, GetBinding (B->getLHS ()) + GetBinding (B->getRHS ()));
268
+ }
269
+
270
+ void GRConstants::VisitBinSub (BinaryOperator* B) {
271
+ AddBinding (B, GetBinding (B->getLHS ()) - GetBinding (B->getRHS ()));
272
+ }
273
+
0 commit comments