llvm-cov: Added -c option for branch counts.
[oota-llvm.git] / include / llvm / Support / GCOV.h
1 //===- GCOV.h - LLVM coverage tool ----------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This header provides the interface to read and write coverage files that
11 // use 'gcov' format.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_SUPPORT_GCOV_H
16 #define LLVM_SUPPORT_GCOV_H
17
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/raw_ostream.h"
23
24 namespace llvm {
25
26 class GCOVFunction;
27 class GCOVBlock;
28 class FileInfo;
29
30 namespace GCOV {
31   enum GCOVVersion {
32     V402,
33     V404
34   };
35 } // end GCOV namespace
36
37 /// GCOVOptions - A struct for passing gcov options between functions.
38 struct GCOVOptions {
39   GCOVOptions(bool A, bool B, bool C, bool U) :
40     AllBlocks(A), BranchInfo(B), BranchCount(C), UncondBranch(U) {}
41
42   bool AllBlocks;
43   bool BranchInfo;
44   bool BranchCount;
45   bool UncondBranch;
46 };
47
48 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
49 /// read operations.
50 class GCOVBuffer {
51 public:
52   GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
53   
54   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
55   bool readGCNOFormat() {
56     StringRef File = Buffer->getBuffer().slice(0, 4);
57     if (File != "oncg") {
58       errs() << "Unexpected file type: " << File << ".\n";
59       return false;
60     }
61     Cursor = 4;
62     return true;
63   }
64
65   /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
66   bool readGCDAFormat() {
67     StringRef File = Buffer->getBuffer().slice(0, 4);
68     if (File != "adcg") {
69       errs() << "Unexpected file type: " << File << ".\n";
70       return false;
71     }
72     Cursor = 4;
73     return true;
74   }
75
76   /// readGCOVVersion - Read GCOV version.
77   bool readGCOVVersion(GCOV::GCOVVersion &Version) {
78     StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor+4);
79     if (VersionStr == "*204") {
80       Cursor += 4;
81       Version = GCOV::V402;
82       return true;
83     }
84     if (VersionStr == "*404") {
85       Cursor += 4;
86       Version = GCOV::V404;
87       return true;
88     }
89     errs() << "Unexpected version: " << VersionStr << ".\n";
90     return false;
91   }
92
93   /// readFunctionTag - If cursor points to a function tag then increment the
94   /// cursor and return true otherwise return false.
95   bool readFunctionTag() {
96     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
97     if (Tag.empty() || 
98         Tag[0] != '\0' || Tag[1] != '\0' ||
99         Tag[2] != '\0' || Tag[3] != '\1') {
100       return false;
101     }
102     Cursor += 4;
103     return true;
104   }
105
106   /// readBlockTag - If cursor points to a block tag then increment the
107   /// cursor and return true otherwise return false.
108   bool readBlockTag() {
109     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
110     if (Tag.empty() || 
111         Tag[0] != '\0' || Tag[1] != '\0' ||
112         Tag[2] != '\x41' || Tag[3] != '\x01') {
113       return false;
114     }
115     Cursor += 4;
116     return true;
117   }
118
119   /// readEdgeTag - If cursor points to an edge tag then increment the
120   /// cursor and return true otherwise return false.
121   bool readEdgeTag() {
122     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
123     if (Tag.empty() || 
124         Tag[0] != '\0' || Tag[1] != '\0' ||
125         Tag[2] != '\x43' || Tag[3] != '\x01') {
126       return false;
127     }
128     Cursor += 4;
129     return true;
130   }
131
132   /// readLineTag - If cursor points to a line tag then increment the
133   /// cursor and return true otherwise return false.
134   bool readLineTag() {
135     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
136     if (Tag.empty() || 
137         Tag[0] != '\0' || Tag[1] != '\0' ||
138         Tag[2] != '\x45' || Tag[3] != '\x01') {
139       return false;
140     }
141     Cursor += 4;
142     return true;
143   }
144
145   /// readArcTag - If cursor points to an gcda arc tag then increment the
146   /// cursor and return true otherwise return false.
147   bool readArcTag() {
148     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
149     if (Tag.empty() || 
150         Tag[0] != '\0' || Tag[1] != '\0' ||
151         Tag[2] != '\xa1' || Tag[3] != '\1') {
152       return false;
153     }
154     Cursor += 4;
155     return true;
156   }
157
158   /// readObjectTag - If cursor points to an object summary tag then increment
159   /// the cursor and return true otherwise return false.
160   bool readObjectTag() {
161     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
162     if (Tag.empty() ||
163         Tag[0] != '\0' || Tag[1] != '\0' ||
164         Tag[2] != '\0' || Tag[3] != '\xa1') {
165       return false;
166     }
167     Cursor += 4;
168     return true;
169   }
170
171   /// readProgramTag - If cursor points to a program summary tag then increment
172   /// the cursor and return true otherwise return false.
173   bool readProgramTag() {
174     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
175     if (Tag.empty() ||
176         Tag[0] != '\0' || Tag[1] != '\0' ||
177         Tag[2] != '\0' || Tag[3] != '\xa3') {
178       return false;
179     }
180     Cursor += 4;
181     return true;
182   }
183
184   bool readInt(uint32_t &Val) {
185     if (Buffer->getBuffer().size() < Cursor+4) {
186       errs() << "Unexpected end of memory buffer: " << Cursor+4 << ".\n";
187       return false;
188     }
189     StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
190     Cursor += 4;
191     Val = *(const uint32_t *)(Str.data());
192     return true;
193   }
194
195   bool readInt64(uint64_t &Val) {
196     uint32_t Lo, Hi;
197     if (!readInt(Lo) || !readInt(Hi)) return false;
198     Val = ((uint64_t)Hi << 32) | Lo;
199     return true;
200   }
201
202   bool readString(StringRef &Str) {
203     uint32_t Len;
204     if (!readInt(Len)) return false;
205     Len *= 4;
206     if (Buffer->getBuffer().size() < Cursor+Len) {
207       errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n";
208       return false;
209     }
210     Str = Buffer->getBuffer().slice(Cursor, Cursor+Len).split('\0').first;
211     Cursor += Len;
212     return true;
213   }
214
215   uint64_t getCursor() const { return Cursor; }
216   void advanceCursor(uint32_t n) { Cursor += n*4; }
217 private:
218   MemoryBuffer *Buffer;
219   uint64_t Cursor;
220 };
221
222 /// GCOVFile - Collects coverage information for one pair of coverage file
223 /// (.gcno and .gcda).
224 class GCOVFile {
225 public:
226   GCOVFile() : GCNOInitialized(false), Checksum(0), Functions(), RunCount(0),
227                ProgramCount(0) {}
228   ~GCOVFile();
229   bool readGCNO(GCOVBuffer &Buffer);
230   bool readGCDA(GCOVBuffer &Buffer);
231   uint32_t getChecksum() const { return Checksum; }
232   void dump() const;
233   void collectLineCounts(FileInfo &FI);
234 private:
235   bool GCNOInitialized;
236   GCOV::GCOVVersion Version;
237   uint32_t Checksum;
238   SmallVector<GCOVFunction *, 16> Functions;
239   uint32_t RunCount;
240   uint32_t ProgramCount;
241 };
242
243 /// GCOVEdge - Collects edge information.
244 struct GCOVEdge {
245   GCOVEdge(GCOVBlock *S, GCOVBlock *D): Src(S), Dst(D), Count(0) {}
246
247   GCOVBlock *Src;
248   GCOVBlock *Dst;
249   uint64_t Count;
250 };
251
252 /// GCOVFunction - Collects function information.
253 class GCOVFunction {
254 public:
255   typedef SmallVectorImpl<GCOVBlock *>::const_iterator BlockIterator;
256
257   GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {}
258   ~GCOVFunction();
259   bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
260   bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
261   StringRef getName() const { return Name; }
262   StringRef getFilename() const { return Filename; }
263   size_t getNumBlocks() const { return Blocks.size(); }
264   uint64_t getEntryCount() const;
265   uint64_t getExitCount() const;
266
267   BlockIterator block_begin() const { return Blocks.begin(); }
268   BlockIterator block_end() const { return Blocks.end(); }
269
270   void dump() const;
271   void collectLineCounts(FileInfo &FI);
272 private:
273   GCOVFile &Parent;
274   uint32_t Ident;
275   uint32_t Checksum;
276   uint32_t LineNumber;
277   StringRef Name;
278   StringRef Filename;
279   SmallVector<GCOVBlock *, 16> Blocks;
280   SmallVector<GCOVEdge *, 16> Edges;
281 };
282
283 /// GCOVBlock - Collects block information.
284 class GCOVBlock {
285   struct EdgeWeight {
286     EdgeWeight(GCOVBlock *D): Dst(D), Count(0) {}
287
288     GCOVBlock *Dst;
289     uint64_t Count;
290   };
291
292   struct SortDstEdgesFunctor {
293     bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
294       return E1->Dst->Number < E2->Dst->Number;
295     }
296   };
297 public:
298   typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
299
300   GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N), Counter(0),
301     DstEdgesAreSorted(true), SrcEdges(), DstEdges(), Lines() {}
302   ~GCOVBlock();
303   void addLine(uint32_t N) { Lines.push_back(N); }
304   uint32_t getLastLine() const { return Lines.back(); }
305   void addCount(size_t DstEdgeNo, uint64_t N);
306   uint64_t getCount() const { return Counter; }
307
308   void addSrcEdge(GCOVEdge *Edge) {
309     assert(Edge->Dst == this); // up to caller to ensure edge is valid
310     SrcEdges.push_back(Edge);
311   }
312   void addDstEdge(GCOVEdge *Edge) {
313     assert(Edge->Src == this); // up to caller to ensure edge is valid
314     // Check if adding this edge causes list to become unsorted.
315     if (DstEdges.size() && DstEdges.back()->Dst->Number > Edge->Dst->Number)
316       DstEdgesAreSorted = false;
317     DstEdges.push_back(Edge);
318   }
319   size_t getNumSrcEdges() const { return SrcEdges.size(); }
320   size_t getNumDstEdges() const { return DstEdges.size(); }
321   void sortDstEdges();
322
323   EdgeIterator src_begin() const { return SrcEdges.begin(); }
324   EdgeIterator src_end() const { return SrcEdges.end(); }
325   EdgeIterator dst_begin() const { return DstEdges.begin(); }
326   EdgeIterator dst_end() const { return DstEdges.end(); }
327
328   void dump() const;
329   void collectLineCounts(FileInfo &FI);
330 private:
331   GCOVFunction &Parent;
332   uint32_t Number;
333   uint64_t Counter;
334   bool DstEdgesAreSorted;
335   SmallVector<GCOVEdge *, 16> SrcEdges;
336   SmallVector<GCOVEdge *, 16> DstEdges;
337   SmallVector<uint32_t, 16> Lines;
338 };
339
340 class FileInfo {
341   // It is unlikely--but possible--for multiple functions to be on the same line.
342   // Therefore this typedef allows LineData.Functions to store multiple functions
343   // per instance. This is rare, however, so optimize for the common case.
344   typedef SmallVector<const GCOVFunction *, 1> FunctionVector;
345   typedef DenseMap<uint32_t, FunctionVector> FunctionLines;
346   typedef SmallVector<const GCOVBlock *, 4> BlockVector;
347   typedef DenseMap<uint32_t, BlockVector> BlockLines;
348
349   struct LineData {
350     BlockLines Blocks;
351     FunctionLines Functions;
352   };
353 public:
354   FileInfo(const GCOVOptions &Options) :
355     Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
356
357   void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
358     LineInfo[Filename].Blocks[Line-1].push_back(Block);
359   }
360   void addFunctionLine(StringRef Filename, uint32_t Line,
361                        const GCOVFunction *Function) {
362     LineInfo[Filename].Functions[Line-1].push_back(Function);
363   }
364   void setRunCount(uint32_t Runs) { RunCount = Runs; }
365   void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
366   void print(StringRef GCNOFile, StringRef GCDAFile) const;
367 private:
368   void printFunctionSummary(raw_fd_ostream &OS,
369                             const FunctionVector &Funcs) const;
370   void printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
371                       uint32_t LineIndex, uint32_t &BlockNo) const;
372   void printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
373                        uint32_t &EdgeNo) const;
374   void printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo,
375                              uint64_t Count) const;
376
377   const GCOVOptions &Options;
378   StringMap<LineData> LineInfo;
379   uint32_t RunCount;
380   uint32_t ProgramCount;
381 };
382
383 }
384
385 #endif