diff options
Diffstat (limited to 'include/llvm/Support/GCOV.h')
-rw-r--r-- | include/llvm/Support/GCOV.h | 244 |
1 files changed, 201 insertions, 43 deletions
diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h index 0aa716a..902f2db 100644 --- a/include/llvm/Support/GCOV.h +++ b/include/llvm/Support/GCOV.h @@ -1,4 +1,4 @@ -//===-- llvm/Support/GCOV.h - LLVM coverage tool ----------------*- C++ -*-===// +//===- GCOV.h - LLVM coverage tool ----------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This header provides the interface to read and write coverage files that +// This header provides the interface to read and write coverage files that // use 'gcov' format. // //===----------------------------------------------------------------------===// @@ -16,6 +16,7 @@ #define LLVM_SUPPORT_GCOV_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/MemoryBuffer.h" @@ -28,36 +29,69 @@ class GCOVBlock; class FileInfo; namespace GCOV { - enum GCOVFormat { - InvalidGCOV, - GCNO_402, - GCNO_404, - GCDA_402, - GCDA_404 + enum GCOVVersion { + V402, + V404 }; } // end GCOV namespace +/// GCOVOptions - A struct for passing gcov options between functions. +struct GCOVOptions { + GCOVOptions(bool A, bool B, bool C, bool F, bool P, bool U) + : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), + PreservePaths(P), UncondBranch(U) {} + + bool AllBlocks; + bool BranchInfo; + bool BranchCount; + bool FuncCoverage; + bool PreservePaths; + bool UncondBranch; +}; + /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific /// read operations. class GCOVBuffer { public: GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {} - /// readGCOVFormat - Read GCOV signature at the beginning of buffer. - GCOV::GCOVFormat readGCOVFormat() { - StringRef Magic = Buffer->getBuffer().slice(0, 12); - Cursor = 12; - if (Magic == "oncg*404MVLL") - return GCOV::GCNO_404; - else if (Magic == "oncg*204MVLL") - return GCOV::GCNO_402; - else if (Magic == "adcg*404MVLL") - return GCOV::GCDA_404; - else if (Magic == "adcg*204MVLL") - return GCOV::GCDA_402; - - Cursor = 0; - return GCOV::InvalidGCOV; + /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer. + bool readGCNOFormat() { + StringRef File = Buffer->getBuffer().slice(0, 4); + if (File != "oncg") { + errs() << "Unexpected file type: " << File << ".\n"; + return false; + } + Cursor = 4; + return true; + } + + /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer. + bool readGCDAFormat() { + StringRef File = Buffer->getBuffer().slice(0, 4); + if (File != "adcg") { + errs() << "Unexpected file type: " << File << ".\n"; + return false; + } + Cursor = 4; + return true; + } + + /// readGCOVVersion - Read GCOV version. + bool readGCOVVersion(GCOV::GCOVVersion &Version) { + StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor+4); + if (VersionStr == "*204") { + Cursor += 4; + Version = GCOV::V402; + return true; + } + if (VersionStr == "*404") { + Cursor += 4; + Version = GCOV::V404; + return true; + } + errs() << "Unexpected version: " << VersionStr << ".\n"; + return false; } /// readFunctionTag - If cursor points to a function tag then increment the @@ -170,8 +204,11 @@ public: } bool readString(StringRef &Str) { - uint32_t Len; - if (!readInt(Len)) return false; + uint32_t Len = 0; + // Keep reading until we find a non-zero length. This emulates gcov's + // behaviour, which appears to do the same. + while (Len == 0) + if (!readInt(Len)) return false; Len *= 4; if (Buffer->getBuffer().size() < Cursor+Len) { errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n"; @@ -193,67 +230,188 @@ private: /// (.gcno and .gcda). class GCOVFile { public: - GCOVFile() : Functions(), RunCount(0), ProgramCount(0) {} + GCOVFile() : GCNOInitialized(false), Checksum(0), Functions(), RunCount(0), + ProgramCount(0) {} ~GCOVFile(); - bool read(GCOVBuffer &Buffer); - void dump(); + bool readGCNO(GCOVBuffer &Buffer); + bool readGCDA(GCOVBuffer &Buffer); + uint32_t getChecksum() const { return Checksum; } + void dump() const; void collectLineCounts(FileInfo &FI); private: + bool GCNOInitialized; + GCOV::GCOVVersion Version; + uint32_t Checksum; SmallVector<GCOVFunction *, 16> Functions; uint32_t RunCount; uint32_t ProgramCount; }; +/// GCOVEdge - Collects edge information. +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: - GCOVFunction() : Ident(0), LineNumber(0) {} + typedef SmallVectorImpl<GCOVBlock *>::const_iterator BlockIterator; + + GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {} ~GCOVFunction(); - bool read(GCOVBuffer &Buffer, GCOV::GCOVFormat Format); + bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); + bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); + StringRef getName() const { return Name; } StringRef getFilename() const { return Filename; } - void dump(); + size_t getNumBlocks() const { return Blocks.size(); } + uint64_t getEntryCount() const; + uint64_t getExitCount() const; + + BlockIterator block_begin() const { return Blocks.begin(); } + BlockIterator block_end() const { return Blocks.end(); } + + void dump() const; void collectLineCounts(FileInfo &FI); private: + GCOVFile &Parent; uint32_t Ident; + uint32_t Checksum; uint32_t LineNumber; StringRef Name; StringRef Filename; SmallVector<GCOVBlock *, 16> Blocks; + SmallVector<GCOVEdge *, 16> Edges; }; /// GCOVBlock - Collects block information. class GCOVBlock { + struct EdgeWeight { + EdgeWeight(GCOVBlock *D): Dst(D), Count(0) {} + + GCOVBlock *Dst; + uint64_t Count; + }; + + struct SortDstEdgesFunctor { + bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) { + return E1->Dst->Number < E2->Dst->Number; + } + }; public: - GCOVBlock(GCOVFunction &P, uint32_t N) : - Parent(P), Number(N), Counter(0), Edges(), Lines() {} + typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator; + + GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N), Counter(0), + DstEdgesAreSorted(true), SrcEdges(), DstEdges(), Lines() {} ~GCOVBlock(); - void addEdge(uint32_t N) { Edges.push_back(N); } + const GCOVFunction &getParent() const { return Parent; } void addLine(uint32_t N) { Lines.push_back(N); } - void addCount(uint64_t N) { Counter += N; } - size_t getNumEdges() { return Edges.size(); } - void dump(); + uint32_t getLastLine() const { return Lines.back(); } + void addCount(size_t DstEdgeNo, uint64_t N); + uint64_t getCount() const { return Counter; } + + 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 + // Check if adding this edge causes list to become unsorted. + if (DstEdges.size() && DstEdges.back()->Dst->Number > Edge->Dst->Number) + DstEdgesAreSorted = false; + DstEdges.push_back(Edge); + } + size_t getNumSrcEdges() const { return SrcEdges.size(); } + size_t getNumDstEdges() const { return DstEdges.size(); } + void sortDstEdges(); + + 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; + bool DstEdgesAreSorted; + SmallVector<GCOVEdge *, 16> SrcEdges; + SmallVector<GCOVEdge *, 16> DstEdges; SmallVector<uint32_t, 16> Lines; }; -typedef DenseMap<uint32_t, uint64_t> LineCounts; class FileInfo { + // It is unlikely--but possible--for multiple functions to be on the same line. + // Therefore this typedef allows LineData.Functions to store multiple functions + // per instance. This is rare, however, so optimize for the common case. + typedef SmallVector<const GCOVFunction *, 1> FunctionVector; + typedef DenseMap<uint32_t, FunctionVector> FunctionLines; + typedef SmallVector<const GCOVBlock *, 4> BlockVector; + typedef DenseMap<uint32_t, BlockVector> BlockLines; + + struct LineData { + BlockLines Blocks; + FunctionLines Functions; + }; + + struct GCOVCoverage { + GCOVCoverage(StringRef Name) : + Name(Name), LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0), + BranchesTaken(0) {} + + StringRef Name; + + uint32_t LogicalLines; + uint32_t LinesExec; + + uint32_t Branches; + uint32_t BranchesExec; + uint32_t BranchesTaken; + }; public: - void addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) { - LineInfo[Filename][Line-1] += Count; + FileInfo(const GCOVOptions &Options) : + Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {} + + void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) { + LineInfo[Filename].Blocks[Line-1].push_back(Block); + } + void addFunctionLine(StringRef Filename, uint32_t Line, + const GCOVFunction *Function) { + LineInfo[Filename].Functions[Line-1].push_back(Function); } void setRunCount(uint32_t Runs) { RunCount = Runs; } void setProgramCount(uint32_t Programs) { ProgramCount = Programs; } - void print(raw_fd_ostream &OS, StringRef gcnoFile, StringRef gcdaFile); + void print(StringRef GCNOFile, StringRef GCDAFile); private: - StringMap<LineCounts> LineInfo; + void printFunctionSummary(raw_fd_ostream &OS, + const FunctionVector &Funcs) const; + void printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block, + uint32_t LineIndex, uint32_t &BlockNo) const; + void printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block, + GCOVCoverage &Coverage, uint32_t &EdgeNo); + void printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo, + uint64_t Count) const; + + void printCoverage(const GCOVCoverage &Coverage) const; + void printFuncCoverage() const; + void printFileCoverage() const; + + const GCOVOptions &Options; + StringMap<LineData> LineInfo; uint32_t RunCount; uint32_t ProgramCount; + + typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4> + FileCoverageList; + typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap; + + FileCoverageList FileCoverages; + FuncCoverageMap FuncCoverages; }; } |