Skip to content

Commit de8d62b

Browse files
committed
Added skeleton implementation of new constant-prop. analysis using
the graph reachability engine. llvm-svn: 46036
1 parent 03bc2af commit de8d62b

File tree

1 file changed

+273
-0
lines changed

1 file changed

+273
-0
lines changed

clang/Analysis/GRConstants.cpp

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
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

Comments
 (0)