forked from OSchip/llvm-project
Removed some files related to the path-sensitive solver as part of some
code restructuring. (new files will be introduced shortly) llvm-svn: 45785
This commit is contained in:
parent
c6edcbdb5d
commit
fed4cce0cc
|
@ -1,96 +0,0 @@
|
|||
//===-- GRConstantPropagation.cpp --------------------------------*- 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/ExplodedGraph.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/ImmutableMap.h"
|
||||
|
||||
using namespace clang;
|
||||
using llvm::APInt;
|
||||
using llvm::APFloat;
|
||||
using llvm::dyn_cast;
|
||||
using llvm::cast;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConstV - Represents a variant over APInt, APFloat, and const char
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class ConstV {
|
||||
uintptr_t Data;
|
||||
public:
|
||||
enum VariantType { VTString = 0x0, VTObjCString = 0x1,
|
||||
VTFloat = 0x2, VTInt = 0x3,
|
||||
Flags = 0x3 };
|
||||
|
||||
ConstV(const StringLiteral* v)
|
||||
: Data(reinterpret_cast<uintptr_t>(v) | VTString) {}
|
||||
|
||||
ConstV(const ObjCStringLiteral* v)
|
||||
: Data(reinterpret_cast<uintptr_t>(v) | VTObjCString) {}
|
||||
|
||||
ConstV(llvm::APInt* v)
|
||||
: Data(reinterpret_cast<uintptr_t>(v) | VTInt) {}
|
||||
|
||||
ConstV(llvm::APFloat* v)
|
||||
: Data(reinterpret_cast<uintptr_t>(v) | VTFloat) {}
|
||||
|
||||
|
||||
inline void* getData() const { return (void*) (Data & ~Flags); }
|
||||
inline VariantType getVT() const { return (VariantType) (Data & Flags); }
|
||||
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddPointer(getData());
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// Overload machinery for casting from ConstV to contained classes.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
#define CV_OBJ_CAST(CLASS,FLAG)\
|
||||
template<> inline bool isa<CLASS,ConstV>(const ConstV& V) {\
|
||||
return V.getVT() == FLAG;\
|
||||
}\
|
||||
\
|
||||
template <> struct cast_retty_impl<CLASS, ConstV> {\
|
||||
typedef const CLASS* ret_type;\
|
||||
};
|
||||
|
||||
CV_OBJ_CAST(APInt,ConstV::VTInt)
|
||||
CV_OBJ_CAST(APFloat,ConstV::VTFloat)
|
||||
CV_OBJ_CAST(StringLiteral,ConstV::VTString)
|
||||
CV_OBJ_CAST(ObjCStringLiteral,ConstV::VTObjCString)
|
||||
|
||||
#undef CV_OBJ_CAST
|
||||
|
||||
template <> struct simplify_type<ConstV> {
|
||||
typedef void* SimpleType;
|
||||
static SimpleType getSimplifiedValue(const ConstV &Val) {
|
||||
return Val.getData();
|
||||
}
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
//= ReachabilityEngine.cpp - Path-Sens. Dataflow Engine ------------*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a generic engine for intraprocedural, path-sensitive,
|
||||
// dataflow analysis via graph reachability engine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/PathSensitive/ReachabilityEngine.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
using namespace clang;
|
||||
using clang::reng::WorkList;
|
||||
using llvm::isa;
|
||||
using llvm::cast;
|
||||
|
||||
// Place dstor here so that all of the virtual functions in DFS have their
|
||||
// code placed in the object file of this translation unit.
|
||||
clang::reng::DFS::~DFS() {}
|
||||
|
||||
ReachabilityEngineImpl::ReachabilityEngineImpl(CFG& c,
|
||||
clang::reng::WorkList* wlist)
|
||||
: cfg(c), WList(wlist) {}
|
||||
|
||||
ExplodedNodeImpl* ReachabilityEngineImpl::getNode(const ProgramEdge& Loc,
|
||||
void* State,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
|
||||
bool IsNew;
|
||||
ExplodedNodeImpl* V = G->getNodeImpl(Loc,State,&IsNew);
|
||||
|
||||
// Link the node with its predecessor.
|
||||
V->addUntypedPredecessor(Pred);
|
||||
|
||||
if (IsNew) {
|
||||
// Only add the node to the worklist if it was freshly generated.
|
||||
WList->Enqueue(V);
|
||||
|
||||
// Check if the node's edge is a StmtStmtEdge where the destination
|
||||
// statement is not a BlockLevelExpr. In this case, we must lazily
|
||||
// populate ParentMap.
|
||||
if (isa<StmtStmtEdge>(Loc)) {
|
||||
Stmt* S = cast<StmtStmtEdge>(Loc).Dst();
|
||||
assert (CurrentBlkExpr != NULL);
|
||||
|
||||
if (S != CurrentBlkExpr && ParentMap.find(S) == ParentMap.end()) {
|
||||
// Populate ParentMap starting from CurrentBlkExpr.
|
||||
PopulateParentMap(CurrentBlkExpr);
|
||||
assert (ParentMap.find(S) != ParentMap.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
void ReachabilityEngineImpl::PopulateParentMap(Stmt* Parent) {
|
||||
for (Stmt::child_iterator I=Parent->child_begin(),
|
||||
E=Parent->child_end(); I!=E; ++I) {
|
||||
|
||||
assert (ParentMap.find(*I) == ParentMap.end());
|
||||
ParentMap[*I] = Parent;
|
||||
PopulateParentMap(*I);
|
||||
}
|
||||
}
|
||||
|
||||
bool ReachabilityEngineImpl::ExecuteWorkList(unsigned Steps) {
|
||||
|
||||
// Initialize the analysis by constructing the root if none exists.
|
||||
if (G->num_roots() == 0) {
|
||||
// Get the entry block. Make sure that it has 1 (and only 1) successor.
|
||||
CFGBlock* Entry = &cfg.getEntry();
|
||||
assert (Entry->empty() && "Entry block must be empty.");
|
||||
assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
|
||||
|
||||
// Get the first (and only) successor of Entry.
|
||||
CFGBlock* Succ = *(Entry->succ_begin());
|
||||
|
||||
// Construct an edge representing the starting location in the function.
|
||||
BlkBlkEdge StartLoc(Entry,Succ);
|
||||
|
||||
// Create the root node.
|
||||
WList->Enqueue(G->addRoot(G->getNodeImpl(StartLoc,getInitialState(),NULL)));
|
||||
}
|
||||
|
||||
while (Steps && WList->hasWork()) {
|
||||
--Steps;
|
||||
ExplodedNodeImpl* V = WList->Dequeue();
|
||||
|
||||
// Dispatch on the location type.
|
||||
switch (V->getLocation().getKind()) {
|
||||
case ProgramEdge::BlkBlk:
|
||||
ProcessBlkBlk(cast<BlkBlkEdge>(V->getLocation()),V);
|
||||
break;
|
||||
|
||||
case ProgramEdge::BlkStmt:
|
||||
ProcessBlkStmt(cast<BlkStmtEdge>(V->getLocation()),V);
|
||||
break;
|
||||
|
||||
case ProgramEdge::StmtBlk:
|
||||
ProcessStmtBlk(cast<StmtBlkEdge>(V->getLocation()),V);
|
||||
break;
|
||||
|
||||
case ProgramEdge::StmtStmt:
|
||||
ProcessStmt(cast<StmtStmtEdge>(V->getLocation()).Dst(),V);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (false && "Unsupported edge type.");
|
||||
}
|
||||
}
|
||||
|
||||
return WList->hasWork();
|
||||
}
|
||||
|
||||
|
||||
void ReachabilityEngineImpl::ProcessBlkBlk(const BlkBlkEdge& E,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
|
||||
CFGBlock* Blk = E.Dst();
|
||||
|
||||
// Check if we are entering the EXIT block.
|
||||
if (Blk == &cfg.getExit()) {
|
||||
assert (cfg.getExit().size() == 0 && "EXIT block cannot contain Stmts.");
|
||||
// Process the End-Of-Path.
|
||||
void* State = ProcessEOP(Blk, Pred->State);
|
||||
bool IsNew;
|
||||
ExplodedNodeImpl* V = G->getNodeImpl(BlkStmtEdge(Blk,NULL),State,&IsNew);
|
||||
V->addUntypedPredecessor(Pred);
|
||||
if (IsNew) G->addEndOfPath(V);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: we will dispatch to a function that manipulates the state
|
||||
// at the entrance to a block.
|
||||
|
||||
if (!Blk->empty()) {
|
||||
// If 'Blk' has at least one statement, create a BlkStmtEdge and create
|
||||
// the appropriate node. This is the common case.
|
||||
getNode(BlkStmtEdge(Blk,Blk->front()), Pred->State, Pred);
|
||||
}
|
||||
else {
|
||||
// Otherwise, create a node at the BlkStmtEdge right before the terminator
|
||||
// (if any) is evaluated.
|
||||
getNode(StmtBlkEdge(NULL,Blk),Pred->State, Pred);
|
||||
}
|
||||
}
|
||||
|
||||
void ReachabilityEngineImpl::ProcessBlkStmt(const BlkStmtEdge& E,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
if (Stmt* S = E.Dst())
|
||||
ProcessStmt(S,Pred);
|
||||
else {
|
||||
// No statement. Create an edge right before the terminator is evaluated.
|
||||
getNode(StmtBlkEdge(NULL,E.Src()), Pred->State, Pred);
|
||||
}
|
||||
}
|
||||
|
||||
void ReachabilityEngineImpl::ProcessStmtBlk(const StmtBlkEdge& E,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
CFGBlock* Blk = E.Dst();
|
||||
|
||||
if (Stmt* Terminator = Blk->getTerminator())
|
||||
ProcessTerminator(Terminator,Pred);
|
||||
else {
|
||||
// No terminator. We should have only 1 successor.
|
||||
assert (Blk->succ_size() == 1);
|
||||
getNode(BlkBlkEdge(Blk,*(Blk->succ_begin())), Pred);
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
//==- ReachabilityEngine.h - Path-Sens. Dataflow Engine ------------*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a generic engine for intraprocedural, path-sensitive,
|
||||
// dataflow analysis via graph reachability engine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_REACHABILITYENGINE
|
||||
#define LLVM_CLANG_ANALYSIS_REACHABILITYENGINE
|
||||
|
||||
#include "clang/AST/CFG.h"
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace reng {
|
||||
class WorkList {
|
||||
public:
|
||||
virtual ~WorkList();
|
||||
virtual bool hasWork() const = 0;
|
||||
virtual void Enqueue(ExplodedNodeImpl* V) = 0;
|
||||
virtual ExplodedNodeImpl* Dequeue() = 0;
|
||||
};
|
||||
|
||||
class DFS : public WorkList {
|
||||
llvm::SmallVector<ExplodedNodeImpl*,20> Stack;
|
||||
public:
|
||||
virtual ~DFS();
|
||||
|
||||
virtual bool hasWork() const {
|
||||
return !Stack.empty();
|
||||
}
|
||||
|
||||
virtual void Enqueue(ExplodedNodeImpl* V) {
|
||||
Stack.push_back(V);
|
||||
}
|
||||
|
||||
virtual ExplodedNodeImpl* Dequeue() {
|
||||
ExplodedNodeImpl* V = Stack.back();
|
||||
Stack.pop_back();
|
||||
return V;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class ReachabilityEngineImpl {
|
||||
protected:
|
||||
typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
|
||||
|
||||
/// cfg - The control-flow graph of the function being analyzed.
|
||||
CFG& cfg;
|
||||
|
||||
/// G - The simulation graph. Each node is a (location,state) pair.
|
||||
llvm::OwningPtr<ExplodedGraphImpl> G;
|
||||
|
||||
/// ParentMap - A lazily populated map from a Stmt* to its parent Stmt*.
|
||||
ParentMapTy ParentMap;
|
||||
|
||||
/// CurrentBlkExpr - The current Block-level expression being processed.
|
||||
/// This is used when lazily populating ParentMap.
|
||||
Stmt* CurrentBlkExpr;
|
||||
|
||||
/// WList - A set of queued nodes that need to be processed by the
|
||||
/// worklist algorithm. It is up to the implementation of WList to decide
|
||||
/// the order that nodes are processed.
|
||||
llvm::OwningPtr<reng::WorkList> WList;
|
||||
|
||||
//==----------------------------------------------------------------------==//
|
||||
// Internal methods.
|
||||
|
||||
/// getNode - Implemented by ReachabilityEngine<> subclass.
|
||||
/// Creates/fetches a node and inserts it into the
|
||||
ExplodedNodeImpl* getNode(const ProgramEdge& Loc, void* State,
|
||||
ExplodedNodeImpl* Pred);
|
||||
|
||||
inline ExplodedNodeImpl* getNode(const ProgramEdge& Loc,
|
||||
ExplodedNodeImpl* Pred) {
|
||||
|
||||
return getNode(Loc,Pred->State,Pred);
|
||||
}
|
||||
|
||||
/// getInitialState - Gets the void* representing the initial 'state'
|
||||
/// of the analysis. This is simply a wrapper (implemented
|
||||
/// in ReachabilityEngine) that performs type erasure on the initial
|
||||
/// state returned by the checker object.
|
||||
virtual void* getInitialState() = 0;
|
||||
|
||||
/// PopulateParentMap - Populates ParentMap starting from the specified
|
||||
/// expression.
|
||||
void PopulateParentMap(Stmt* Parent);
|
||||
|
||||
void ProcessBlkBlk(const BlkBlkEdge& E, ExplodedNodeImpl* Pred);
|
||||
void ProcessBlkStmt(const BlkStmtEdge& E, ExplodedNodeImpl* Pred);
|
||||
void ProcessStmtBlk(const StmtBlkEdge& E, ExplodedNodeImpl* Pred);
|
||||
|
||||
virtual void* ProcessEOP(CFGBlock* Blk, void* State);
|
||||
virtual void ProcessStmt(Stmt* S, ExplodedNodeImpl* Pred);
|
||||
virtual void ProcessTerminator(Stmt* Terminator, ExplodedNodeImpl* Pred);
|
||||
|
||||
private:
|
||||
ReachabilityEngineImpl(const ReachabilityEngineImpl&); // Do not implement.
|
||||
ReachabilityEngineImpl& operator=(const ReachabilityEngineImpl&);
|
||||
|
||||
protected:
|
||||
ReachabilityEngineImpl(CFG& c, reng::WorkList* wl);
|
||||
|
||||
public:
|
||||
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
|
||||
/// steps. Returns true if there is still simulation state on the worklist.
|
||||
bool ExecuteWorkList(unsigned Steps = 1000000);
|
||||
|
||||
virtual ~ReachabilityEngineImpl() {}
|
||||
};
|
||||
|
||||
|
||||
template<typename CHECKER>
|
||||
class ReachabilityEngine : public ReachabilityEngineImpl {
|
||||
public:
|
||||
typedef CHECKER CheckerTy;
|
||||
typedef typename CheckerTy::StateTy StateTy;
|
||||
typedef ExplodedGraph<CheckerTy> GraphTy;
|
||||
typedef typename GraphTy::NodeTy NodeTy;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void* getInitialState() {
|
||||
return (void*) getCheckerState()->getInitialState();
|
||||
}
|
||||
|
||||
virtual void* ProcessEOP(CFGBlock* Blk, void* State) {
|
||||
// FIXME: Perform dispatch to adjust state.
|
||||
return State;
|
||||
}
|
||||
|
||||
virtual void ProcessStmt(Stmt* S, ExplodedNodeImpl* Pred) {
|
||||
CurrentBlkExpr = S;
|
||||
assert(false && "Not implemented.");
|
||||
CurrentBlkExpr = NULL;
|
||||
}
|
||||
|
||||
virtual void ProcessTerminator(Stmt* Terminator, ExplodedNodeImpl* Pred) {
|
||||
assert(false && "Not implemented.");
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/// Construct a ReachabilityEngine object to analyze the provided CFG using
|
||||
/// a DFS exploration of the exploded graph.
|
||||
ReachabilityEngine(CFG& Cfg)
|
||||
: ReachabilityEngineImpl(cfg,new reng::DFS()) {}
|
||||
|
||||
/// Construct a ReachabilityEngine object to analyze the provided CFG and to
|
||||
/// use the provided worklist object to execute the worklist algorithm.
|
||||
/// The ReachabilityEngine object assumes ownership of 'wlist'.
|
||||
ReachabilityEngine(CFG& cfg, reng::WorkList* wlist)
|
||||
: ReachabilityEngineImpl(cfg,wlist) {}
|
||||
|
||||
/// getGraph - Returns the exploded graph.
|
||||
GraphTy& getGraph() { return *static_cast<GraphTy*>(G.get()); }
|
||||
|
||||
/// getCheckerState - Returns the internal checker state.
|
||||
CheckerTy& getCheckerState() {
|
||||
return *static_cast<GraphTy*>(G.get())->getCheckerState();
|
||||
}
|
||||
|
||||
/// takeGraph - Returns the exploded graph. Ownership of the graph is
|
||||
/// transfered to the caller.
|
||||
GraphTy* takeGraph() { return static_cast<GraphTy*>(G.take()); }
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue