summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Support/GCOV.h36
-rw-r--r--lib/IR/GCOV.cpp51
2 files changed, 70 insertions, 17 deletions
diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h
index 9649a1dad3..ee81229ff8 100644
--- a/include/llvm/Support/GCOV.h
+++ b/include/llvm/Support/GCOV.h
@@ -205,6 +205,14 @@ private:
uint32_t ProgramCount;
};
+struct GCOVEdge {
+ GCOVEdge(GCOVBlock *S, GCOVBlock *D): Src(S), Dst(D), Count(0) {}
+
+ GCOVBlock *Src;
+ GCOVBlock *Dst;
+ uint64_t Count;
+};
+
/// GCOVFunction - Collects function information.
class GCOVFunction {
public:
@@ -221,25 +229,43 @@ private:
StringRef Name;
StringRef Filename;
SmallVector<GCOVBlock *, 16> Blocks;
+ SmallVector<GCOVEdge *, 16> Edges;
};
/// GCOVBlock - Collects block information.
class GCOVBlock {
public:
+ typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
+
GCOVBlock(GCOVFunction &P, uint32_t N) :
- Parent(P), Number(N), Counter(0), Edges(), Lines() {}
+ Parent(P), Number(N), Counter(0), SrcEdges(), DstEdges(), Lines() {}
~GCOVBlock();
- void addEdge(uint32_t N) { Edges.push_back(N); }
+ void addSrcEdge(GCOVEdge *Edge) {
+ assert(Edge->Dst == this); // up to caller to ensure edge is valid
+ SrcEdges.push_back(Edge);
+ }
+ void addDstEdge(GCOVEdge *Edge) {
+ assert(Edge->Src == this); // up to caller to ensure edge is valid
+ DstEdges.push_back(Edge);
+ }
void addLine(uint32_t N) { Lines.push_back(N); }
- void addCount(uint64_t N) { Counter += N; }
- size_t getNumEdges() const { return Edges.size(); }
+ void addCount(size_t DstEdgeNo, uint64_t N);
+ size_t getNumSrcEdges() const { return SrcEdges.size(); }
+ size_t getNumDstEdges() const { return DstEdges.size(); }
+
+ EdgeIterator src_begin() const { return SrcEdges.begin(); }
+ EdgeIterator src_end() const { return SrcEdges.end(); }
+ EdgeIterator dst_begin() const { return DstEdges.begin(); }
+ EdgeIterator dst_end() const { return DstEdges.end(); }
+
void dump() const;
void collectLineCounts(FileInfo &FI);
private:
GCOVFunction &Parent;
uint32_t Number;
uint64_t Counter;
- SmallVector<uint32_t, 16> Edges;
+ SmallVector<GCOVEdge *, 16> SrcEdges;
+ SmallVector<GCOVEdge *, 16> DstEdges;
SmallVector<uint32_t, 16> Lines;
};
diff --git a/lib/IR/GCOV.cpp b/lib/IR/GCOV.cpp
index 3b0dee4016..ebf10927fc 100644
--- a/lib/IR/GCOV.cpp
+++ b/lib/IR/GCOV.cpp
@@ -112,6 +112,7 @@ void GCOVFile::collectLineCounts(FileInfo &FI) {
/// ~GCOVFunction - Delete GCOVFunction and its content.
GCOVFunction::~GCOVFunction() {
DeleteContainerPointers(Blocks);
+ DeleteContainerPointers(Edges);
}
/// readGCNO - Read a function from the GCNO buffer. Return false if an error
@@ -154,7 +155,10 @@ bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
uint32_t Dst;
if (!Buff.readInt(Dst)) return false;
- Blocks[BlockNo]->addEdge(Dst);
+ GCOVEdge *Edge = new GCOVEdge(Blocks[BlockNo], Blocks[Dst]);
+ Edges.push_back(Edge);
+ Blocks[BlockNo]->addDstEdge(Edge);
+ Blocks[Dst]->addSrcEdge(Edge);
if (!Buff.readInt(Dummy)) return false; // Edge flag
}
}
@@ -208,26 +212,29 @@ bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVFormat Format) {
errs() << "Arc tag not found.\n";
return false;
}
+
uint32_t Count;
if (!Buff.readInt(Count)) return false;
Count /= 2;
// This for loop adds the counts for each block. A second nested loop is
// required to combine the edge counts that are contained in the GCDA file.
- for (uint32_t Line = 0; Count > 0; ++Line) {
- if (Line >= Blocks.size()) {
+ for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
+ // The last block is always reserved for exit block
+ if (BlockNo >= Blocks.size()-1) {
errs() << "Unexpected number of edges.\n";
return false;
}
- GCOVBlock &Block = *Blocks[Line];
- for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) {
+ GCOVBlock &Block = *Blocks[BlockNo];
+ for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End;
+ ++EdgeNo) {
if (Count == 0) {
errs() << "Unexpected number of edges.\n";
return false;
}
uint64_t ArcCount;
if (!Buff.readInt64(ArcCount)) return false;
- Block.addCount(ArcCount);
+ Block.addCount(EdgeNo, ArcCount);
--Count;
}
}
@@ -255,10 +262,21 @@ void GCOVFunction::collectLineCounts(FileInfo &FI) {
/// ~GCOVBlock - Delete GCOVBlock and its content.
GCOVBlock::~GCOVBlock() {
- Edges.clear();
+ SrcEdges.clear();
+ DstEdges.clear();
Lines.clear();
}
+/// addCount - Add to block counter while storing the edge count. If the
+/// destination has no outgoing edges, also update that block's count too.
+void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) {
+ assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid
+ DstEdges[DstEdgeNo]->Count = N;
+ Counter += N;
+ if (!DstEdges[DstEdgeNo]->Dst->getNumDstEdges())
+ DstEdges[DstEdgeNo]->Dst->Counter += N;
+}
+
/// collectLineCounts - Collect line counts. This must be used after
/// reading .gcno and .gcda files.
void GCOVBlock::collectLineCounts(FileInfo &FI) {
@@ -270,11 +288,20 @@ void GCOVBlock::collectLineCounts(FileInfo &FI) {
/// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
void GCOVBlock::dump() const {
dbgs() << "Block : " << Number << " Counter : " << Counter << "\n";
- if (!Edges.empty()) {
- dbgs() << "\tEdges : ";
- for (SmallVectorImpl<uint32_t>::const_iterator I = Edges.begin(), E = Edges.end();
- I != E; ++I)
- dbgs() << (*I) << ",";
+ if (!SrcEdges.empty()) {
+ dbgs() << "\tSource Edges : ";
+ for (EdgeIterator I = SrcEdges.begin(), E = SrcEdges.end(); I != E; ++I) {
+ const GCOVEdge *Edge = *I;
+ dbgs() << Edge->Src->Number << " (" << Edge->Count << "), ";
+ }
+ dbgs() << "\n";
+ }
+ if (!DstEdges.empty()) {
+ dbgs() << "\tDestination Edges : ";
+ for (EdgeIterator I = DstEdges.begin(), E = DstEdges.end(); I != E; ++I) {
+ const GCOVEdge *Edge = *I;
+ dbgs() << Edge->Dst->Number << " (" << Edge->Count << "), ";
+ }
dbgs() << "\n";
}
if (!Lines.empty()) {