forked from OSchip/llvm-project
Renamed ProgramEdge to ProgramPoint and changed subclasses of ProgramEdge
to have a much simpler, cleaner interpretation of what is a "location" in a function (as encoded by a CFG). llvm-svn: 45846
This commit is contained in:
parent
d7a7abed62
commit
e5ccf9a96c
|
@ -21,10 +21,12 @@
|
|||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <set>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
@ -1030,8 +1032,21 @@ unsigned CFG::getNumBlkExprs() {
|
|||
}
|
||||
}
|
||||
|
||||
typedef std::set<std::pair<CFGBlock*,CFGBlock*> > BlkEdgeSetTy;
|
||||
|
||||
const std::pair<CFGBlock*,CFGBlock*>*
|
||||
CFG::getBlockEdgeImpl(const CFGBlock* B1, const CFGBlock* B2) {
|
||||
|
||||
BlkEdgeSetTy*& p = reinterpret_cast<BlkEdgeSetTy*&>(BlkEdgeSet);
|
||||
if (!p) p = new BlkEdgeSetTy();
|
||||
|
||||
return &*(p->insert(std::make_pair(const_cast<CFGBlock*>(B1),
|
||||
const_cast<CFGBlock*>(B2))).first);
|
||||
}
|
||||
|
||||
CFG::~CFG() {
|
||||
delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
|
||||
delete reinterpret_cast<BlkEdgeSetTy*>(BlkEdgeSet);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -172,7 +172,7 @@ typedef DataflowSolver<LiveVariables,TransferFuncs,Merge> Solver;
|
|||
// External interface to run Liveness analysis.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void LiveVariables::runOnCFG(const CFG& cfg) {
|
||||
void LiveVariables::runOnCFG(CFG& cfg) {
|
||||
Solver S(*this);
|
||||
S.runOnCFG(cfg);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@
|
|||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class Expr;
|
||||
class CFG;
|
||||
class PrinterHelper;
|
||||
class BlockEdge;
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
/// It consists of:
|
||||
|
@ -273,7 +273,7 @@ public:
|
|||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
BlkExprMap(NULL) {};
|
||||
BlkExprMap(NULL), BlkEdgeSet(NULL) {};
|
||||
|
||||
~CFG();
|
||||
|
||||
|
@ -287,6 +287,22 @@ private:
|
|||
// opaque pointer to prevent inclusion of DenseMap.h. Map from expressions
|
||||
// to integers to record block-level expressions.
|
||||
void* BlkExprMap;
|
||||
|
||||
// opaque pointer to prevent inclusion of <set>. This records a set of
|
||||
// CFGBlock edges for using with ProgramPoint. These edges represent
|
||||
// the edges that cannot be succinctly represented, and in practice this
|
||||
// set should be small.
|
||||
void* BlkEdgeSet;
|
||||
|
||||
friend class BlockEdge;
|
||||
|
||||
/// getBlockEdgeImpl - Utility method used by the class BlockEdge. The CFG
|
||||
/// stores a set of interned std::pair<CFGBlock*,CFGBlock*> that can
|
||||
/// be used by BlockEdge to refer to edges that cannot be represented
|
||||
/// by a single pointer.
|
||||
const std::pair<CFGBlock*,CFGBlock*>* getBlockEdgeImpl(const CFGBlock* B1,
|
||||
const CFGBlock* B2);
|
||||
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ public:
|
|||
/// a given CFG. This is intended to be called by the dataflow solver.
|
||||
void InitializeValues(const CFG& cfg);
|
||||
|
||||
void runOnCFG(const CFG& cfg);
|
||||
void runOnCFG(CFG& cfg);
|
||||
void runOnAllBlocks(const CFG& cfg, ObserverTy& Obs);
|
||||
};
|
||||
|
||||
|
|
|
@ -69,12 +69,12 @@ template <> struct ItrTraits<forward_analysis_tag> {
|
|||
static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
|
||||
|
||||
static BlkBlkEdge PrevEdge(const CFGBlock* B, const CFGBlock* PrevBlk) {
|
||||
return BlkBlkEdge(PrevBlk,B);
|
||||
static BlockEdge PrevEdge(CFG& cfg, const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(cfg,Prev,B);
|
||||
}
|
||||
|
||||
static BlkBlkEdge NextEdge(const CFGBlock* B, const CFGBlock* NextBlk) {
|
||||
return BlkBlkEdge(B,NextBlk);
|
||||
static BlockEdge NextEdge(CFG& cfg, const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(cfg,B,Next);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -92,12 +92,12 @@ template <> struct ItrTraits<backward_analysis_tag> {
|
|||
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
|
||||
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
|
||||
|
||||
static BlkBlkEdge PrevEdge(const CFGBlock* B, const CFGBlock* PrevBlk) {
|
||||
return BlkBlkEdge(B,PrevBlk);
|
||||
static BlockEdge PrevEdge(CFG& cfg, const CFGBlock* B, const CFGBlock* Prev) {
|
||||
return BlockEdge(cfg,B,Prev);
|
||||
}
|
||||
|
||||
static BlkBlkEdge NextEdge(const CFGBlock* B, const CFGBlock* NextBlk) {
|
||||
return BlkBlkEdge(NextBlk,B);
|
||||
static BlockEdge NextEdge(CFG& cfg, const CFGBlock* B, const CFGBlock* Next) {
|
||||
return BlockEdge(cfg,Next,B);
|
||||
}
|
||||
};
|
||||
} // end namespace dataflow
|
||||
|
@ -140,7 +140,7 @@ public:
|
|||
~DataflowSolver() {}
|
||||
|
||||
/// runOnCFG - Computes dataflow values for all blocks in a CFG.
|
||||
void runOnCFG(const CFG& cfg) {
|
||||
void runOnCFG(CFG& cfg) {
|
||||
// Set initial dataflow values and boundary conditions.
|
||||
D.InitializeValues(cfg);
|
||||
// Solve the dataflow equations. This will populate D.EdgeDataMap
|
||||
|
@ -180,14 +180,14 @@ private:
|
|||
|
||||
/// SolveDataflowEquations - Perform the actual worklist algorithm
|
||||
/// to compute dataflow values.
|
||||
void SolveDataflowEquations(const CFG& cfg) {
|
||||
void SolveDataflowEquations(CFG& cfg) {
|
||||
EnqueueFirstBlock(cfg,AnalysisDirTag());
|
||||
|
||||
while (!WorkList.isEmpty()) {
|
||||
const CFGBlock* B = WorkList.dequeue();
|
||||
ProcessMerge(B);
|
||||
ProcessMerge(cfg,B);
|
||||
ProcessBlock(B);
|
||||
UpdateEdges(B,TF.getVal());
|
||||
UpdateEdges(cfg,B,TF.getVal());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ private:
|
|||
WorkList.enqueue(&cfg.getExit());
|
||||
}
|
||||
|
||||
void ProcessMerge(const CFGBlock* B) {
|
||||
void ProcessMerge(CFG& cfg, const CFGBlock* B) {
|
||||
// Merge dataflow values from all predecessors of this block.
|
||||
ValTy& V = TF.getVal();
|
||||
V.resetValues(D.getAnalysisData());
|
||||
|
@ -210,7 +210,8 @@ private:
|
|||
|
||||
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
|
||||
|
||||
typename EdgeDataMapTy::iterator EI = M.find(ItrTraits::PrevEdge(B,*I));
|
||||
typename EdgeDataMapTy::iterator EI =
|
||||
M.find(ItrTraits::PrevEdge(cfg,B,*I));
|
||||
|
||||
if (EI != M.end()) {
|
||||
if (firstMerge) {
|
||||
|
@ -236,13 +237,13 @@ private:
|
|||
/// block, update the dataflow value associated with the block's
|
||||
/// outgoing/incoming edges (depending on whether we do a
|
||||
// forward/backward analysis respectively)
|
||||
void UpdateEdges(const CFGBlock* B, ValTy& V) {
|
||||
void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
|
||||
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(B,*I),V,*I);
|
||||
UpdateEdgeValue(ItrTraits::NextEdge(cfg,B,*I),V,*I);
|
||||
}
|
||||
|
||||
/// UpdateEdgeValue - Update the value associated with a given edge.
|
||||
void UpdateEdgeValue(BlkBlkEdge E, ValTy& V, const CFGBlock* TargetBlock) {
|
||||
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
|
||||
|
||||
EdgeDataMapTy& M = D.getEdgeDataMap();
|
||||
typename EdgeDataMapTy::iterator I = M.find(E);
|
||||
|
@ -261,8 +262,7 @@ private:
|
|||
DFValuesTy& D;
|
||||
DataflowWorkListTy WorkList;
|
||||
TransferFuncsTy TF;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
#endif
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
typedef typename ValueTypes::ValTy ValTy;
|
||||
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
|
||||
typedef _AnalysisDirTag AnalysisDirTag;
|
||||
typedef llvm::DenseMap<ProgramEdge, ValTy> EdgeDataMapTy;
|
||||
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
|
||||
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -80,13 +80,13 @@ public:
|
|||
|
||||
/// getEdgeData - Retrieves the dataflow values associated with a
|
||||
/// CFG edge.
|
||||
ValTy& getEdgeData(const BlkBlkEdge& E) {
|
||||
ValTy& getEdgeData(const BlockEdge& E) {
|
||||
typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
|
||||
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const ValTy& getEdgeData(const BlkBlkEdge& E) const {
|
||||
const ValTy& getEdgeData(const BlockEdge& E) const {
|
||||
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//==- ProgramEdge.h - Program Points for Path-Sensitive Analysis --*- C++ -*-=//
|
||||
//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -7,13 +7,13 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface ProgramEdge, which identifies a distinct
|
||||
// location in a function based on edges within its CFG.
|
||||
// This file defines the interface ProgramPoint, which identifies a
|
||||
// distinct location in a function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_PATHSENS_PROGRAM_POINT
|
||||
#define LLVM_CLANG_ANALYSIS_PATHSENS_PROGRAM_POINT
|
||||
#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
|
||||
#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
@ -21,178 +21,137 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class CFG;
|
||||
class CFGBlock;
|
||||
class Stmt;
|
||||
|
||||
class ProgramEdge {
|
||||
uintptr_t Src, Dst;
|
||||
class ProgramPoint {
|
||||
public:
|
||||
enum EdgeKind { BExprBlk=0, BlkBExpr=1, BExprBExpr=2, BlkBlk=3,
|
||||
BExprSExpr=4, SExprSExpr=5, SExprBExpr=6, Infeasible=7 };
|
||||
|
||||
static bool classof(const ProgramEdge*) { return true; }
|
||||
|
||||
unsigned getKind() const { return (((unsigned) Src & 0x3) << 2) |
|
||||
((unsigned) Dst & 0x3); }
|
||||
|
||||
void* RawSrc() const { return reinterpret_cast<void*>(Src & ~0x3); }
|
||||
void* RawDst() const { return reinterpret_cast<void*>(Dst & ~0x3); }
|
||||
|
||||
bool operator==(const ProgramEdge & RHS) const {
|
||||
// comparing pointer values canoncalizes "NULL" edges where both pointers
|
||||
// are NULL without having to worry about edgekind. We can otherwise
|
||||
// ignore edgekind because no CFGBlock* or Stmt* will have the same value.
|
||||
return RawSrc() == RHS.RawSrc() && RawDst() == RHS.RawDst();
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramEdge& RHS) const {
|
||||
return RawSrc() != RHS.RawSrc() || RawDst() != RHS.RawDst();
|
||||
}
|
||||
|
||||
unsigned getHashValue() const {
|
||||
uintptr_t v1 = reinterpret_cast<uintptr_t>(RawSrc());
|
||||
uintptr_t v2 = reinterpret_cast<uintptr_t>(RawDst());
|
||||
return static_cast<unsigned>( (v1 >> 4) ^ (v1 >> 9) ^
|
||||
(v2 >> 5) ^ (v2 >> 10) );
|
||||
}
|
||||
|
||||
enum Kind { BlockEntranceKind=0, PostStmtKind=1, BlockExitKind=2,
|
||||
BlockEdgeSrcKind=3, BlockEdgeDstKind=4, BlockEdgeAuxKind=5 };
|
||||
protected:
|
||||
uintptr_t Data;
|
||||
|
||||
ProgramPoint(const void* Ptr, Kind k) {
|
||||
assert ((reinterpret_cast<uintptr_t>(const_cast<void*>(Ptr)) & 0x7) == 0
|
||||
&& "Address must have at least an 8-byte alignment.");
|
||||
|
||||
Data = reinterpret_cast<uintptr_t>(const_cast<void*>(Ptr)) & k;
|
||||
}
|
||||
|
||||
ProgramEdge(const void* src, const void* dst, EdgeKind k) {
|
||||
assert (k >= BExprBlk && k <= BlkBlk);
|
||||
Src = reinterpret_cast<uintptr_t>(const_cast<void*>(src)) | (k >> 2);
|
||||
Dst = reinterpret_cast<uintptr_t>(const_cast<void*>(dst)) | (k & 0x3);
|
||||
ProgramPoint() : Data(0) {}
|
||||
|
||||
public:
|
||||
unsigned getKind() const { return Data & 0x5; }
|
||||
void* getRawPtr() const { return reinterpret_cast<void*>(Data & ~0x7); }
|
||||
void* getRawData() const { return reinterpret_cast<void*>(Data); }
|
||||
|
||||
static bool classof(const ProgramPoint*) { return true; }
|
||||
bool operator==(const ProgramPoint & RHS) const { return Data == RHS.Data; }
|
||||
bool operator!=(const ProgramPoint& RHS) const { return Data != RHS.Data; }
|
||||
};
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock* B) : ProgramPoint(B, BlockEntranceKind) {}
|
||||
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getRawPtr());
|
||||
}
|
||||
|
||||
Stmt* getFirstStmt() const {
|
||||
CFGBlock* B = getBlock();
|
||||
return B->empty() ? NULL : B->front();
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockEntranceKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BExprBlkEdge : public ProgramEdge {
|
||||
class BlockExit : public ProgramPoint {
|
||||
public:
|
||||
BExprBlkEdge(const Stmt* S,const CFGBlock* B)
|
||||
: ProgramEdge(S,B,BExprBlk) {}
|
||||
BlockExit(const CFGBlock* B) : ProgramPoint(B, BlockExitKind) {}
|
||||
|
||||
Stmt* Src() const { return reinterpret_cast<Stmt*>(RawSrc()); }
|
||||
CFGBlock* Dst() const { return reinterpret_cast<CFGBlock*>(RawDst()); }
|
||||
CFGBlock* getBlock() const {
|
||||
return reinterpret_cast<CFGBlock*>(getRawPtr());
|
||||
}
|
||||
|
||||
Stmt* getLastStmt() const {
|
||||
CFGBlock* B = getBlock();
|
||||
return B->empty() ? NULL : B->back();
|
||||
}
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == BExprBlk;
|
||||
Stmt* getTerminator() const {
|
||||
return getBlock()->getTerminator();
|
||||
}
|
||||
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == BlockExitKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BlkBExprEdge : public ProgramEdge {
|
||||
public:
|
||||
BlkBExprEdge(const CFGBlock* B, const Stmt* S)
|
||||
: ProgramEdge(B,S,BlkBExpr) {}
|
||||
|
||||
CFGBlock* Src() const { return reinterpret_cast<CFGBlock*>(RawSrc()); }
|
||||
Stmt* Dst() const { return reinterpret_cast<Stmt*>(RawDst()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == BlkBExpr;
|
||||
}
|
||||
};
|
||||
|
||||
class BExprBExprEdge : public ProgramEdge {
|
||||
class PostStmt : public ProgramPoint {
|
||||
public:
|
||||
BExprBExprEdge(const Stmt* S1, const Stmt* S2)
|
||||
: ProgramEdge(S1,S2,BExprBExpr) {}
|
||||
PostStmt(const Stmt* S) : ProgramPoint(S, PostStmtKind) {}
|
||||
|
||||
Stmt* Src() const { return reinterpret_cast<Stmt*>(RawSrc()); }
|
||||
Stmt* Dst() const { return reinterpret_cast<Stmt*>(RawDst()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == BExprBExpr;
|
||||
}
|
||||
};
|
||||
|
||||
class BExprSExprEdge : public ProgramEdge {
|
||||
public:
|
||||
BExprSExprEdge(const Stmt* S1, const Expr* S2)
|
||||
: ProgramEdge(S1,S2,BExprSExpr) {}
|
||||
|
||||
Stmt* Src() const { return reinterpret_cast<Stmt*>(RawSrc()); }
|
||||
Expr* Dst() const { return reinterpret_cast<Expr*>(RawDst()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == BExprSExpr;
|
||||
}
|
||||
};
|
||||
|
||||
class SExprSExprEdge : public ProgramEdge {
|
||||
public:
|
||||
SExprSExprEdge(const Expr* S1, const Expr* S2)
|
||||
: ProgramEdge(S1,S2,SExprSExpr) {}
|
||||
|
||||
Expr* Src() const { return reinterpret_cast<Expr*>(RawSrc()); }
|
||||
Expr* Dst() const { return reinterpret_cast<Expr*>(RawDst()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == SExprSExpr;
|
||||
}
|
||||
};
|
||||
Stmt* getStmt() const { return (Stmt*) getRawPtr(); }
|
||||
|
||||
class SExprBExprEdge : public ProgramEdge {
|
||||
public:
|
||||
SExprBExprEdge(const Expr* S1, const Stmt* S2)
|
||||
: ProgramEdge(S1,S2,SExprBExpr) {}
|
||||
|
||||
Expr* Src() const { return reinterpret_cast<Expr*>(RawSrc()); }
|
||||
Stmt* Dst() const { return reinterpret_cast<Stmt*>(RawDst()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == SExprBExpr;
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
return Location->getKind() == PostStmtKind;
|
||||
}
|
||||
};
|
||||
|
||||
class BlockEdge : public ProgramPoint {
|
||||
typedef std::pair<CFGBlock*,CFGBlock*> BPair;
|
||||
public:
|
||||
BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2);
|
||||
|
||||
class BlkBlkEdge : public ProgramEdge {
|
||||
public:
|
||||
BlkBlkEdge(const CFGBlock* B1, const CFGBlock* B2)
|
||||
: ProgramEdge(B1,B2,BlkBlk) {}
|
||||
CFGBlock* getSrc() const;
|
||||
CFGBlock* getDst() const;
|
||||
|
||||
CFGBlock* Src() const { return reinterpret_cast<CFGBlock*>(RawSrc()); }
|
||||
CFGBlock* Dst() const { return reinterpret_cast<CFGBlock*>(RawDst()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == BlkBlk;
|
||||
static bool classof(const ProgramPoint* Location) {
|
||||
unsigned k = Location->getKind();
|
||||
return k >= BlockEdgeSrcKind && k <= BlockEdgeAuxKind;
|
||||
}
|
||||
};
|
||||
|
||||
class InfeasibleEdge : public ProgramEdge {
|
||||
public:
|
||||
InfeasibleEdge(Stmt* S) : ProgramEdge(S,NULL,Infeasible) {}
|
||||
|
||||
Stmt* getStmt() const { return reinterpret_cast<Stmt*>(RawSrc()); }
|
||||
|
||||
static bool classof(const ProgramEdge* E) {
|
||||
return E->getKind() == Infeasible;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
|
||||
namespace llvm { // Traits specialization for DenseMap
|
||||
|
||||
template <> struct DenseMapInfo<clang::ProgramEdge> {
|
||||
template <> struct DenseMapInfo<clang::ProgramPoint> {
|
||||
|
||||
static inline clang::ProgramEdge getEmptyKey() {
|
||||
return clang::BlkBlkEdge(0, 0);
|
||||
static inline clang::ProgramPoint getEmptyKey() {
|
||||
uintptr_t x =
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
|
||||
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
|
||||
}
|
||||
|
||||
static inline clang::ProgramEdge getTombstoneKey() {
|
||||
return clang::BlkBlkEdge(reinterpret_cast<clang::CFGBlock*>(-1),
|
||||
reinterpret_cast<clang::CFGBlock*>(-1));
|
||||
static inline clang::ProgramPoint getTombstoneKey() {
|
||||
uintptr_t x =
|
||||
reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
|
||||
|
||||
return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x));
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::ProgramEdge& E) {
|
||||
return E.getHashValue();
|
||||
static unsigned getHashValue(const clang::ProgramPoint& Loc) {
|
||||
return DenseMapInfo<void*>::getHashValue(Loc.getRawData());
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::ProgramEdge& LHS,
|
||||
const clang::ProgramEdge& RHS) {
|
||||
return LHS == RHS;
|
||||
static bool isEqual(const clang::ProgramPoint& L,
|
||||
const clang::ProgramPoint& R) {
|
||||
return L == R;
|
||||
}
|
||||
|
||||
static bool isPod() { return true; }
|
||||
static bool isPod() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
Loading…
Reference in New Issue