Add new GRWorkList class that uses two queues:

- one queue (FIFO) to queue up nodes at block entrances
- another queue (LIFO) to queue up other nodes
- The idea is to explore basic blocks to completion, but to do a BFS exploration of blocks.

llvm-svn: 61106
This commit is contained in:
Ted Kremenek 2008-12-16 22:13:33 +00:00
parent 9e08ff40da
commit d9de9f148e
3 changed files with 66 additions and 6 deletions

View File

@ -613,7 +613,8 @@ public:
/// Construct a GRCoreEngine object to analyze the provided CFG using /// Construct a GRCoreEngine object to analyze the provided CFG using
/// a DFS exploration of the exploded graph. /// a DFS exploration of the exploded graph.
GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine) GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), GRWorkList::MakeDFS()), : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
GRWorkList::MakeBFSBlockDFSContents()),
SubEngine(subengine) {} SubEngine(subengine) {}
/// Construct a GRCoreEngine object to analyze the provided CFG and to /// Construct a GRCoreEngine object to analyze the provided CFG and to

View File

@ -69,6 +69,7 @@ public:
GRBlockCounter getBlockCounter() const { return CurrentCounter; } GRBlockCounter getBlockCounter() const { return CurrentCounter; }
static GRWorkList* MakeDFS(); static GRWorkList* MakeDFS();
static GRWorkList* MakeBFSBlockDFSContents();
}; };
} // end clang namespace } // end clang namespace
#endif #endif

View File

@ -18,11 +18,16 @@
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include <vector> #include <vector>
#include <queue>
using llvm::cast; using llvm::cast;
using llvm::isa; using llvm::isa;
using namespace clang; using namespace clang;
//===----------------------------------------------------------------------===//
// Worklist classes for exploration of reachable states.
//===----------------------------------------------------------------------===//
namespace { namespace {
class VISIBILITY_HIDDEN DFS : public GRWorkList { class VISIBILITY_HIDDEN DFS : public GRWorkList {
llvm::SmallVector<GRWorkListUnit,20> Stack; llvm::SmallVector<GRWorkListUnit,20> Stack;
@ -50,6 +55,48 @@ GRWorkList::~GRWorkList() {}
GRWorkList* GRWorkList::MakeDFS() { return new DFS(); } GRWorkList* GRWorkList::MakeDFS() { return new DFS(); }
namespace {
class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList {
std::queue<GRWorkListUnit> Queue;
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
return !Queue.empty() || !Stack.empty();
}
virtual void Enqueue(const GRWorkListUnit& U) {
if (isa<BlockEntrance>(U.getNode()->getLocation()))
Queue.push(U);
else
Stack.push_back(U);
}
virtual GRWorkListUnit Dequeue() {
// Process all basic blocks to completion.
if (!Stack.empty()) {
const GRWorkListUnit& U = Stack.back();
Stack.pop_back(); // This technically "invalidates" U, but we are fine.
return U;
}
assert(!Queue.empty());
// Don't use const reference. The subsequent pop_back() might make it
// unsafe.
GRWorkListUnit U = Queue.front();
Queue.pop();
return U;
}
};
} // end anonymous namespace
GRWorkList* GRWorkList::MakeBFSBlockDFSContents() {
return new BFSBlockDFSContents();
}
//===----------------------------------------------------------------------===//
// Core analysis engine.
//===----------------------------------------------------------------------===//
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) { bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
@ -90,8 +137,7 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
// Dispatch on the location type. // Dispatch on the location type.
switch (Node->getLocation().getKind()) { switch (Node->getLocation().getKind()) {
default: case ProgramPoint::BlockEdgeKind:
assert (isa<BlockEdge>(Node->getLocation()));
HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node); HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
break; break;
@ -102,9 +148,9 @@ bool GRCoreEngineImpl::ExecuteWorkList(unsigned Steps) {
case ProgramPoint::BlockExitKind: case ProgramPoint::BlockExitKind:
assert (false && "BlockExit location never occur in forward analysis."); assert (false && "BlockExit location never occur in forward analysis.");
break; break;
case ProgramPoint::PostLoadKind: default:
case ProgramPoint::PostStmtKind: assert(isa<PostStmt>(Node->getLocation()));
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(), HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
WU.getIndex(), Node); WU.getIndex(), Node);
break; break;
@ -332,6 +378,18 @@ static inline ProgramPoint GetPostLoc(Stmt* S, ProgramPoint::Kind K) {
case ProgramPoint::PostLoadKind: case ProgramPoint::PostLoadKind:
return PostLoad(S); return PostLoad(S);
case ProgramPoint::PostUndefLocationCheckFailedKind:
return PostUndefLocationCheckFailed(S);
case ProgramPoint::PostLocationChecksSucceedKind:
return PostLocationChecksSucceed(S);
case ProgramPoint::PostOutOfBoundsCheckFailedKind:
return PostOutOfBoundsCheckFailed(S);
case ProgramPoint::PostNullCheckFailedKind:
return PostNullCheckFailed(S);
case ProgramPoint::PostStoreKind: case ProgramPoint::PostStoreKind:
return PostStore(S); return PostStore(S);