2008-01-15 23:55:06 +00:00
|
|
|
//===-- GRConstants.cpp - Simple, Path-Sens. Constant Prop. ------*- C++ -*-==//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Constant Propagation via Graph Reachability
|
|
|
|
//
|
|
|
|
// This files defines a simple analysis that performs path-sensitive
|
|
|
|
// constant propagation within a function. An example use of this analysis
|
|
|
|
// is to perform simple checks for NULL dereferences.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Analysis/PathSensitive/GREngine.h"
|
|
|
|
#include "clang/AST/Expr.h"
|
|
|
|
#include "clang/Analysis/Analyses/LiveVariables.h"
|
|
|
|
#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
|
|
|
|
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/DataTypes.h"
|
|
|
|
#include "llvm/ADT/APSInt.h"
|
|
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
|
|
#include "llvm/ADT/ImmutableMap.h"
|
2008-01-16 17:56:25 +00:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2008-01-15 23:55:06 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
|
2008-01-16 21:46:15 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
#include "llvm/Support/GraphWriter.h"
|
|
|
|
#include <sstream>
|
|
|
|
#endif
|
|
|
|
|
2008-01-15 23:55:06 +00:00
|
|
|
using namespace clang;
|
|
|
|
using llvm::APInt;
|
|
|
|
using llvm::APFloat;
|
|
|
|
using llvm::dyn_cast;
|
|
|
|
using llvm::cast;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-01-16 21:46:15 +00:00
|
|
|
/// DSPtr - A variant smart pointer that wraps either a ValueDecl* or a
|
2008-01-15 23:55:06 +00:00
|
|
|
/// Stmt*. Use cast<> or dyn_cast<> to get actual pointer type
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
2008-01-16 00:53:15 +00:00
|
|
|
class VISIBILITY_HIDDEN DSPtr {
|
2008-01-16 19:47:19 +00:00
|
|
|
uintptr_t Raw;
|
2008-01-15 23:55:06 +00:00
|
|
|
public:
|
2008-01-16 23:35:31 +00:00
|
|
|
enum VariantKind { IsSubExp=0x0, IsValueDecl=0x1, IsBlkLvl=0x2, Flags=0x3 };
|
2008-01-15 23:55:06 +00:00
|
|
|
inline void* getPtr() const { return reinterpret_cast<void*>(Raw & ~Flags); }
|
|
|
|
inline VariantKind getKind() const { return (VariantKind) (Raw & Flags); }
|
|
|
|
|
2008-01-16 21:46:15 +00:00
|
|
|
DSPtr(ValueDecl* D) : Raw(reinterpret_cast<uintptr_t>(D) | IsValueDecl) {}
|
2008-01-16 00:53:15 +00:00
|
|
|
DSPtr(Stmt* S, bool isBlkLvl)
|
2008-01-15 23:55:06 +00:00
|
|
|
: Raw(reinterpret_cast<uintptr_t>(S) | (isBlkLvl ? IsBlkLvl : IsSubExp)) {}
|
|
|
|
|
|
|
|
bool isSubExpr() const { return getKind() == IsSubExp; }
|
|
|
|
|
|
|
|
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
2008-01-16 05:51:13 +00:00
|
|
|
ID.AddPointer(getPtr());
|
|
|
|
ID.AddInteger((unsigned) getKind());
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
2008-01-16 00:53:15 +00:00
|
|
|
inline bool operator==(const DSPtr& X) const { return Raw == X.Raw; }
|
|
|
|
inline bool operator!=(const DSPtr& X) const { return Raw != X.Raw; }
|
2008-01-16 23:33:44 +00:00
|
|
|
inline bool operator<(const DSPtr& X) const {
|
|
|
|
VariantKind k = getKind(), Xk = X.getKind();
|
|
|
|
return k == Xk ? getPtr() < X.getPtr() : k < Xk;
|
|
|
|
}
|
2008-01-15 23:55:06 +00:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2008-01-16 00:53:15 +00:00
|
|
|
// Machinery to get cast<> and dyn_cast<> working with DSPtr.
|
2008-01-15 23:55:06 +00:00
|
|
|
namespace llvm {
|
2008-01-16 21:46:15 +00:00
|
|
|
template<> inline bool isa<ValueDecl,DSPtr>(const DSPtr& V) {
|
|
|
|
return V.getKind() == DSPtr::IsValueDecl;
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
2008-01-16 00:53:15 +00:00
|
|
|
template<> inline bool isa<Stmt,DSPtr>(const DSPtr& V) {
|
2008-01-16 21:46:15 +00:00
|
|
|
return ((unsigned) V.getKind()) > DSPtr::IsValueDecl;
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
2008-01-16 21:46:15 +00:00
|
|
|
template<> struct VISIBILITY_HIDDEN cast_retty_impl<ValueDecl,DSPtr> {
|
|
|
|
typedef const ValueDecl* ret_type;
|
2008-01-15 23:55:06 +00:00
|
|
|
};
|
2008-01-16 00:53:15 +00:00
|
|
|
template<> struct VISIBILITY_HIDDEN cast_retty_impl<Stmt,DSPtr> {
|
2008-01-15 23:55:06 +00:00
|
|
|
typedef const Stmt* ret_type;
|
|
|
|
};
|
2008-01-16 00:53:15 +00:00
|
|
|
template<> struct VISIBILITY_HIDDEN simplify_type<DSPtr> {
|
2008-01-15 23:55:06 +00:00
|
|
|
typedef void* SimpleType;
|
2008-01-16 00:53:15 +00:00
|
|
|
static inline SimpleType getSimplifiedValue(const DSPtr &V) {
|
2008-01-15 23:55:06 +00:00
|
|
|
return V.getPtr();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end llvm namespace
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DeclStmtMapTy - A ImmutableMap type from Decl*/Stmt* to integers.
|
|
|
|
//
|
|
|
|
// FIXME: We may eventually use APSInt, or a mixture of APSInt and
|
|
|
|
// integer primitives to do this right; this will handle both
|
|
|
|
// different bit-widths and allow us to detect integer overflows, etc.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-01-16 00:53:15 +00:00
|
|
|
typedef llvm::ImmutableMap<DSPtr,uint64_t> DeclStmtMapTy;
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
template<>
|
|
|
|
struct VISIBILITY_HIDDEN GRTrait<DeclStmtMapTy> {
|
|
|
|
static inline void* toPtr(DeclStmtMapTy M) {
|
|
|
|
return reinterpret_cast<void*>(M.getRoot());
|
|
|
|
}
|
|
|
|
static inline DeclStmtMapTy toState(void* P) {
|
|
|
|
return DeclStmtMapTy(static_cast<DeclStmtMapTy::TreeTy*>(P));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// The Checker!
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN ExprVariantTy {
|
|
|
|
const uint64_t val;
|
|
|
|
const bool isConstant;
|
|
|
|
public:
|
|
|
|
ExprVariantTy() : val(0), isConstant(false) {}
|
|
|
|
ExprVariantTy(uint64_t v) : val(v), isConstant(true) {}
|
|
|
|
|
|
|
|
operator bool() const { return isConstant; }
|
|
|
|
uint64_t getVal() const { assert (isConstant); return val; }
|
|
|
|
|
|
|
|
ExprVariantTy operator+(const ExprVariantTy& X) const {
|
|
|
|
if (!isConstant || !X.isConstant) return ExprVariantTy();
|
|
|
|
else return ExprVariantTy(val+X.val);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprVariantTy operator-(const ExprVariantTy& X) const {
|
|
|
|
if (!isConstant || !X.isConstant) return ExprVariantTy();
|
2008-01-16 22:20:36 +00:00
|
|
|
else return ExprVariantTy(val-X.val);
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// The Checker!
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class VISIBILITY_HIDDEN GRConstants : public CFGStmtVisitor<GRConstants> {
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef DeclStmtMapTy StateTy;
|
|
|
|
typedef GRNodeBuilder<GRConstants> NodeBuilder;
|
|
|
|
typedef ExplodedNode<StateTy> NodeTy;
|
|
|
|
|
|
|
|
protected:
|
2008-01-16 21:46:15 +00:00
|
|
|
// Liveness - live-variables information the ValueDecl* and Expr* (block-level)
|
2008-01-15 23:55:06 +00:00
|
|
|
// in the CFG. Used to prune out dead state.
|
|
|
|
LiveVariables* Liveness;
|
|
|
|
|
|
|
|
// Builder - The current GRNodeBuilder which is used when building the nodes
|
|
|
|
// for a given statement.
|
|
|
|
NodeBuilder* Builder;
|
|
|
|
|
2008-01-16 00:53:15 +00:00
|
|
|
DeclStmtMapTy::Factory StateMgr;
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
// cfg - the current CFG.
|
|
|
|
CFG* cfg;
|
|
|
|
|
2008-01-16 17:56:25 +00:00
|
|
|
typedef llvm::SmallVector<NodeTy*,8> NodeSetTy;
|
2008-01-15 23:55:06 +00:00
|
|
|
NodeSetTy NodeSetA;
|
|
|
|
NodeSetTy NodeSetB;
|
|
|
|
NodeSetTy* Nodes;
|
|
|
|
NodeSetTy* OldNodes;
|
2008-01-16 00:53:15 +00:00
|
|
|
StateTy CurrentState;
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
GRConstants() : Liveness(NULL), Builder(NULL), cfg(NULL),
|
2008-01-16 17:56:25 +00:00
|
|
|
Nodes(&NodeSetA), OldNodes(&NodeSetB),
|
|
|
|
CurrentState(StateMgr.GetEmptyMap()) {}
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
~GRConstants() { delete Liveness; }
|
|
|
|
|
|
|
|
CFG& getCFG() { assert (cfg); return *cfg; }
|
|
|
|
|
|
|
|
void Initialize(CFG& c) {
|
|
|
|
cfg = &c;
|
|
|
|
Liveness = new LiveVariables(c);
|
|
|
|
Liveness->runOnCFG(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
StateTy getInitialState() {
|
2008-01-16 00:53:15 +00:00
|
|
|
return StateMgr.GetEmptyMap();
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ProcessStmt(Stmt* S, NodeBuilder& builder);
|
2008-01-16 00:53:15 +00:00
|
|
|
void SwitchNodeSets();
|
2008-01-15 23:55:06 +00:00
|
|
|
void DoStmt(Stmt* S);
|
2008-01-16 00:53:15 +00:00
|
|
|
StateTy RemoveGrandchildrenMappings(Stmt* S, StateTy M);
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
void AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl = false);
|
2008-01-16 21:46:15 +00:00
|
|
|
void AddBinding(ValueDecl* D, ExprVariantTy V);
|
2008-01-16 19:42:59 +00:00
|
|
|
|
2008-01-15 23:55:06 +00:00
|
|
|
ExprVariantTy GetBinding(Expr* E);
|
|
|
|
|
|
|
|
void BlockStmt_VisitStmt(Stmt* S) { DoStmt(S); }
|
|
|
|
|
|
|
|
void VisitAssign(BinaryOperator* O);
|
|
|
|
void VisitBinAdd(BinaryOperator* O);
|
|
|
|
void VisitBinSub(BinaryOperator* O);
|
2008-01-16 19:42:59 +00:00
|
|
|
void VisitBinAssign(BinaryOperator* D);
|
2008-01-15 23:55:06 +00:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2008-01-16 22:28:08 +00:00
|
|
|
static inline Expr* IgnoreParen(Expr* E) {
|
|
|
|
while (ParenExpr* P = dyn_cast<ParenExpr>(E))
|
|
|
|
E = P->getSubExpr();
|
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2008-01-15 23:55:06 +00:00
|
|
|
void GRConstants::ProcessStmt(Stmt* S, NodeBuilder& builder) {
|
|
|
|
Builder = &builder;
|
|
|
|
Nodes->clear();
|
|
|
|
OldNodes->clear();
|
|
|
|
NodeTy* N = Builder->getLastNode();
|
|
|
|
assert (N);
|
2008-01-16 17:56:25 +00:00
|
|
|
OldNodes->push_back(N);
|
2008-01-15 23:55:06 +00:00
|
|
|
BlockStmt_Visit(S);
|
|
|
|
Builder = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprVariantTy GRConstants::GetBinding(Expr* E) {
|
2008-01-16 19:47:19 +00:00
|
|
|
DSPtr P(NULL);
|
2008-01-16 22:28:08 +00:00
|
|
|
E = IgnoreParen(E);
|
2008-01-16 19:47:19 +00:00
|
|
|
|
2008-01-16 22:28:08 +00:00
|
|
|
switch (E->getStmtClass()) {
|
|
|
|
case Stmt::DeclRefExprClass:
|
|
|
|
P = DSPtr(cast<DeclRefExpr>(E)->getDecl());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Stmt::IntegerLiteralClass:
|
|
|
|
return cast<IntegerLiteral>(E)->getValue().getZExtValue();
|
|
|
|
|
|
|
|
default:
|
|
|
|
P = DSPtr(E, getCFG().isBlkExpr(E));
|
|
|
|
break;
|
|
|
|
}
|
2008-01-16 19:47:19 +00:00
|
|
|
|
2008-01-16 00:53:15 +00:00
|
|
|
StateTy::iterator I = CurrentState.find(P);
|
2008-01-15 23:55:06 +00:00
|
|
|
|
2008-01-16 00:53:15 +00:00
|
|
|
if (I == CurrentState.end())
|
2008-01-15 23:55:06 +00:00
|
|
|
return ExprVariantTy();
|
|
|
|
|
|
|
|
return (*I).second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GRConstants::AddBinding(Expr* E, ExprVariantTy V, bool isBlkLvl) {
|
2008-01-16 19:28:16 +00:00
|
|
|
if (V)
|
|
|
|
CurrentState = StateMgr.Add(CurrentState, DSPtr(E,isBlkLvl), V.getVal());
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
|
|
|
|
2008-01-16 21:46:15 +00:00
|
|
|
void GRConstants::AddBinding(ValueDecl* D, ExprVariantTy V) {
|
2008-01-16 19:42:59 +00:00
|
|
|
if (V)
|
|
|
|
CurrentState = StateMgr.Add(CurrentState, DSPtr(D), V.getVal());
|
|
|
|
else
|
|
|
|
CurrentState = StateMgr.Remove(CurrentState, DSPtr(D));
|
|
|
|
}
|
|
|
|
|
2008-01-15 23:55:06 +00:00
|
|
|
void GRConstants::SwitchNodeSets() {
|
|
|
|
NodeSetTy* Tmp = OldNodes;
|
|
|
|
OldNodes = Nodes;
|
|
|
|
Nodes = Tmp;
|
|
|
|
Nodes->clear();
|
|
|
|
}
|
|
|
|
|
2008-01-16 00:53:15 +00:00
|
|
|
GRConstants::StateTy
|
|
|
|
GRConstants::RemoveGrandchildrenMappings(Stmt* S, GRConstants::StateTy State) {
|
|
|
|
|
|
|
|
typedef Stmt::child_iterator iterator;
|
|
|
|
|
|
|
|
for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
|
|
|
|
if (Stmt* C = *I)
|
|
|
|
for (iterator CI=C->child_begin(), CE=C->child_end(); CI!=CE; ++CI) {
|
|
|
|
// Observe that this will only remove mappings to non-block level
|
|
|
|
// expressions. This is valid even if *CI is a block-level expression,
|
|
|
|
// since it simply won't be in the map in the first place.
|
2008-01-16 17:56:25 +00:00
|
|
|
// Note: This should also work if 'C' is a block-level expression,
|
|
|
|
// although ideally we would want to skip processing C's children.
|
2008-01-16 00:53:15 +00:00
|
|
|
State = StateMgr.Remove(State, DSPtr(*CI,false));
|
|
|
|
}
|
|
|
|
|
|
|
|
return State;
|
|
|
|
}
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
void GRConstants::DoStmt(Stmt* S) {
|
|
|
|
for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
|
2008-01-16 00:53:15 +00:00
|
|
|
if (*I) DoStmt(*I);
|
2008-01-15 23:55:06 +00:00
|
|
|
|
|
|
|
for (NodeSetTy::iterator I=OldNodes->begin(), E=OldNodes->end(); I!=E; ++I) {
|
2008-01-16 00:53:15 +00:00
|
|
|
NodeTy* Pred = *I;
|
|
|
|
CurrentState = Pred->getState();
|
|
|
|
|
2008-01-16 17:56:25 +00:00
|
|
|
StateTy OldState = CurrentState;
|
|
|
|
CurrentState = RemoveGrandchildrenMappings(S, CurrentState);
|
2008-01-16 00:53:15 +00:00
|
|
|
|
2008-01-15 23:55:06 +00:00
|
|
|
Visit(S);
|
2008-01-16 00:53:15 +00:00
|
|
|
|
2008-01-16 17:56:25 +00:00
|
|
|
if (CurrentState != OldState) {
|
2008-01-16 00:53:15 +00:00
|
|
|
NodeTy* N = Builder->generateNode(S, CurrentState, Pred);
|
2008-01-16 17:56:25 +00:00
|
|
|
if (N) Nodes->push_back(N);
|
2008-01-16 00:53:15 +00:00
|
|
|
}
|
2008-01-16 17:56:25 +00:00
|
|
|
else Nodes->push_back(Pred);
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
2008-01-16 17:56:25 +00:00
|
|
|
|
|
|
|
SwitchNodeSets();
|
2008-01-15 23:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GRConstants::VisitBinAdd(BinaryOperator* B) {
|
|
|
|
AddBinding(B, GetBinding(B->getLHS()) + GetBinding(B->getRHS()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GRConstants::VisitBinSub(BinaryOperator* B) {
|
|
|
|
AddBinding(B, GetBinding(B->getLHS()) - GetBinding(B->getRHS()));
|
|
|
|
}
|
2008-01-16 18:18:48 +00:00
|
|
|
|
2008-01-16 19:42:59 +00:00
|
|
|
|
|
|
|
void GRConstants::VisitBinAssign(BinaryOperator* B) {
|
|
|
|
if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(IgnoreParen(B->getLHS())))
|
|
|
|
AddBinding(D->getDecl(), GetBinding(B->getRHS()));
|
|
|
|
}
|
|
|
|
|
2008-01-16 18:18:48 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Driver.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-01-16 21:46:15 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
namespace llvm {
|
|
|
|
template<>
|
|
|
|
struct VISIBILITY_HIDDEN DOTGraphTraits<GRConstants::NodeTy*> :
|
|
|
|
public DefaultDOTGraphTraits {
|
|
|
|
|
|
|
|
static std::string getNodeLabel(const GRConstants::NodeTy* N, void*) {
|
|
|
|
std::ostringstream Out;
|
|
|
|
|
|
|
|
Out << "Vertex: " << (void*) N << '\n';
|
|
|
|
ProgramPoint Loc = N->getLocation();
|
|
|
|
|
|
|
|
switch (Loc.getKind()) {
|
|
|
|
case ProgramPoint::BlockEntranceKind:
|
|
|
|
Out << "Block Entrance: B"
|
|
|
|
<< cast<BlockEntrance>(Loc).getBlock()->getBlockID();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ProgramPoint::BlockExitKind:
|
|
|
|
assert (false);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ProgramPoint::PostStmtKind: {
|
|
|
|
const PostStmt& L = cast<PostStmt>(Loc);
|
|
|
|
Out << "Stmt: " << (void*) L.getStmt() << '\n';
|
|
|
|
L.getStmt()->printPretty(Out);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
const BlockEdge& E = cast<BlockEdge>(Loc);
|
|
|
|
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
|
|
|
|
<< E.getDst()->getBlockID() << ')';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Out << "\n{";
|
|
|
|
|
|
|
|
GRConstants::StateTy M = N->getState();
|
|
|
|
bool isFirst = true;
|
|
|
|
|
|
|
|
for (GRConstants::StateTy::iterator I=M.begin(), E=M.end(); I!=E; ++I) {
|
|
|
|
if (!isFirst)
|
|
|
|
Out << '\n';
|
|
|
|
else
|
|
|
|
isFirst = false;
|
|
|
|
|
|
|
|
if (ValueDecl* V = dyn_cast<ValueDecl>(I.getKey())) {
|
|
|
|
Out << "Decl: " << (void*) V << ", " << V->getName();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Stmt* E = cast<Stmt>(I.getKey());
|
|
|
|
Out << "Stmt: " << (void*) E;
|
|
|
|
}
|
|
|
|
|
|
|
|
Out << " => " << I.getData();
|
|
|
|
}
|
|
|
|
|
|
|
|
Out << " }";
|
|
|
|
|
|
|
|
return Out.str();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end llvm namespace
|
|
|
|
#endif
|
|
|
|
|
2008-01-16 18:18:48 +00:00
|
|
|
namespace clang {
|
|
|
|
void RunGRConstants(CFG& cfg) {
|
|
|
|
GREngine<GRConstants> Engine(cfg);
|
|
|
|
Engine.ExecuteWorkList();
|
2008-01-16 21:46:15 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants");
|
|
|
|
#endif
|
2008-01-16 18:18:48 +00:00
|
|
|
}
|
|
|
|
}
|