]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/ProfileData/GCOV.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / include / llvm / ProfileData / GCOV.h
1 //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
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_PROFILEDATA_GCOV_H
16 #define LLVM_PROFILEDATA_GCOV_H
17
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/MapVector.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/StringMap.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ADT/iterator.h"
24 #include "llvm/ADT/iterator_range.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <cassert>
28 #include <cstddef>
29 #include <cstdint>
30 #include <memory>
31 #include <string>
32 #include <utility>
33
34 namespace llvm {
35
36 class GCOVFunction;
37 class GCOVBlock;
38 class FileInfo;
39
40 namespace GCOV {
41
42 enum GCOVVersion { V402, V404, V704 };
43
44 /// A struct for passing gcov options between functions.
45 struct Options {
46   Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
47       : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
48         PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
49
50   bool AllBlocks;
51   bool BranchInfo;
52   bool BranchCount;
53   bool FuncCoverage;
54   bool PreservePaths;
55   bool UncondBranch;
56   bool LongFileNames;
57   bool NoOutput;
58 };
59
60 } // end namespace GCOV
61
62 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
63 /// read operations.
64 class GCOVBuffer {
65 public:
66   GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
67
68   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
69   bool readGCNOFormat() {
70     StringRef File = Buffer->getBuffer().slice(0, 4);
71     if (File != "oncg") {
72       errs() << "Unexpected file type: " << File << ".\n";
73       return false;
74     }
75     Cursor = 4;
76     return true;
77   }
78
79   /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
80   bool readGCDAFormat() {
81     StringRef File = Buffer->getBuffer().slice(0, 4);
82     if (File != "adcg") {
83       errs() << "Unexpected file type: " << File << ".\n";
84       return false;
85     }
86     Cursor = 4;
87     return true;
88   }
89
90   /// readGCOVVersion - Read GCOV version.
91   bool readGCOVVersion(GCOV::GCOVVersion &Version) {
92     StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
93     if (VersionStr == "*204") {
94       Cursor += 4;
95       Version = GCOV::V402;
96       return true;
97     }
98     if (VersionStr == "*404") {
99       Cursor += 4;
100       Version = GCOV::V404;
101       return true;
102     }
103     if (VersionStr == "*704") {
104       Cursor += 4;
105       Version = GCOV::V704;
106       return true;
107     }
108     errs() << "Unexpected version: " << VersionStr << ".\n";
109     return false;
110   }
111
112   /// readFunctionTag - If cursor points to a function tag then increment the
113   /// cursor and return true otherwise return false.
114   bool readFunctionTag() {
115     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
116     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
117         Tag[3] != '\1') {
118       return false;
119     }
120     Cursor += 4;
121     return true;
122   }
123
124   /// readBlockTag - If cursor points to a block tag then increment the
125   /// cursor and return true otherwise return false.
126   bool readBlockTag() {
127     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
128     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
129         Tag[3] != '\x01') {
130       return false;
131     }
132     Cursor += 4;
133     return true;
134   }
135
136   /// readEdgeTag - If cursor points to an edge tag then increment the
137   /// cursor and return true otherwise return false.
138   bool readEdgeTag() {
139     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
140     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
141         Tag[3] != '\x01') {
142       return false;
143     }
144     Cursor += 4;
145     return true;
146   }
147
148   /// readLineTag - If cursor points to a line tag then increment the
149   /// cursor and return true otherwise return false.
150   bool readLineTag() {
151     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
152     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
153         Tag[3] != '\x01') {
154       return false;
155     }
156     Cursor += 4;
157     return true;
158   }
159
160   /// readArcTag - If cursor points to an gcda arc tag then increment the
161   /// cursor and return true otherwise return false.
162   bool readArcTag() {
163     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
164     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
165         Tag[3] != '\1') {
166       return false;
167     }
168     Cursor += 4;
169     return true;
170   }
171
172   /// readObjectTag - If cursor points to an object summary tag then increment
173   /// the cursor and return true otherwise return false.
174   bool readObjectTag() {
175     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
176     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
177         Tag[3] != '\xa1') {
178       return false;
179     }
180     Cursor += 4;
181     return true;
182   }
183
184   /// readProgramTag - If cursor points to a program summary tag then increment
185   /// the cursor and return true otherwise return false.
186   bool readProgramTag() {
187     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
188     if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
189         Tag[3] != '\xa3') {
190       return false;
191     }
192     Cursor += 4;
193     return true;
194   }
195
196   bool readInt(uint32_t &Val) {
197     if (Buffer->getBuffer().size() < Cursor + 4) {
198       errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
199       return false;
200     }
201     StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
202     Cursor += 4;
203     Val = *(const uint32_t *)(Str.data());
204     return true;
205   }
206
207   bool readInt64(uint64_t &Val) {
208     uint32_t Lo, Hi;
209     if (!readInt(Lo) || !readInt(Hi))
210       return false;
211     Val = ((uint64_t)Hi << 32) | Lo;
212     return true;
213   }
214
215   bool readString(StringRef &Str) {
216     uint32_t Len = 0;
217     // Keep reading until we find a non-zero length. This emulates gcov's
218     // behaviour, which appears to do the same.
219     while (Len == 0)
220       if (!readInt(Len))
221         return false;
222     Len *= 4;
223     if (Buffer->getBuffer().size() < Cursor + Len) {
224       errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
225       return false;
226     }
227     Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
228     Cursor += Len;
229     return true;
230   }
231
232   uint64_t getCursor() const { return Cursor; }
233   void advanceCursor(uint32_t n) { Cursor += n * 4; }
234
235 private:
236   MemoryBuffer *Buffer;
237   uint64_t Cursor = 0;
238 };
239
240 /// GCOVFile - Collects coverage information for one pair of coverage file
241 /// (.gcno and .gcda).
242 class GCOVFile {
243 public:
244   GCOVFile() = default;
245
246   bool readGCNO(GCOVBuffer &Buffer);
247   bool readGCDA(GCOVBuffer &Buffer);
248   uint32_t getChecksum() const { return Checksum; }
249   void print(raw_ostream &OS) const;
250   void dump() const;
251   void collectLineCounts(FileInfo &FI);
252
253 private:
254   bool GCNOInitialized = false;
255   GCOV::GCOVVersion Version;
256   uint32_t Checksum = 0;
257   SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
258   uint32_t RunCount = 0;
259   uint32_t ProgramCount = 0;
260 };
261
262 /// GCOVEdge - Collects edge information.
263 struct GCOVEdge {
264   GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
265
266   GCOVBlock &Src;
267   GCOVBlock &Dst;
268   uint64_t Count = 0;
269 };
270
271 /// GCOVFunction - Collects function information.
272 class GCOVFunction {
273 public:
274   using BlockIterator = pointee_iterator<SmallVectorImpl<
275       std::unique_ptr<GCOVBlock>>::const_iterator>;
276
277   GCOVFunction(GCOVFile &P) : Parent(P) {}
278
279   bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
280   bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
281   StringRef getName() const { return Name; }
282   StringRef getFilename() const { return Filename; }
283   size_t getNumBlocks() const { return Blocks.size(); }
284   uint64_t getEntryCount() const;
285   uint64_t getExitCount() const;
286
287   BlockIterator block_begin() const { return Blocks.begin(); }
288   BlockIterator block_end() const { return Blocks.end(); }
289   iterator_range<BlockIterator> blocks() const {
290     return make_range(block_begin(), block_end());
291   }
292
293   void print(raw_ostream &OS) const;
294   void dump() const;
295   void collectLineCounts(FileInfo &FI);
296
297 private:
298   GCOVFile &Parent;
299   uint32_t Ident = 0;
300   uint32_t Checksum;
301   uint32_t LineNumber = 0;
302   StringRef Name;
303   StringRef Filename;
304   SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
305   SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
306 };
307
308 /// GCOVBlock - Collects block information.
309 class GCOVBlock {
310   struct EdgeWeight {
311     EdgeWeight(GCOVBlock *D) : Dst(D) {}
312
313     GCOVBlock *Dst;
314     uint64_t Count = 0;
315   };
316
317   struct SortDstEdgesFunctor {
318     bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
319       return E1->Dst.Number < E2->Dst.Number;
320     }
321   };
322
323 public:
324   using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator;
325
326   GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
327   ~GCOVBlock();
328
329   const GCOVFunction &getParent() const { return Parent; }
330   void addLine(uint32_t N) { Lines.push_back(N); }
331   uint32_t getLastLine() const { return Lines.back(); }
332   void addCount(size_t DstEdgeNo, uint64_t N);
333   uint64_t getCount() const { return Counter; }
334
335   void addSrcEdge(GCOVEdge *Edge) {
336     assert(&Edge->Dst == this); // up to caller to ensure edge is valid
337     SrcEdges.push_back(Edge);
338   }
339
340   void addDstEdge(GCOVEdge *Edge) {
341     assert(&Edge->Src == this); // up to caller to ensure edge is valid
342     // Check if adding this edge causes list to become unsorted.
343     if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
344       DstEdgesAreSorted = false;
345     DstEdges.push_back(Edge);
346   }
347
348   size_t getNumSrcEdges() const { return SrcEdges.size(); }
349   size_t getNumDstEdges() const { return DstEdges.size(); }
350   void sortDstEdges();
351
352   EdgeIterator src_begin() const { return SrcEdges.begin(); }
353   EdgeIterator src_end() const { return SrcEdges.end(); }
354   iterator_range<EdgeIterator> srcs() const {
355     return make_range(src_begin(), src_end());
356   }
357
358   EdgeIterator dst_begin() const { return DstEdges.begin(); }
359   EdgeIterator dst_end() const { return DstEdges.end(); }
360   iterator_range<EdgeIterator> dsts() const {
361     return make_range(dst_begin(), dst_end());
362   }
363
364   void print(raw_ostream &OS) const;
365   void dump() const;
366   void collectLineCounts(FileInfo &FI);
367
368 private:
369   GCOVFunction &Parent;
370   uint32_t Number;
371   uint64_t Counter = 0;
372   bool DstEdgesAreSorted = true;
373   SmallVector<GCOVEdge *, 16> SrcEdges;
374   SmallVector<GCOVEdge *, 16> DstEdges;
375   SmallVector<uint32_t, 16> Lines;
376 };
377
378 class FileInfo {
379 protected:
380   // It is unlikely--but possible--for multiple functions to be on the same
381   // line.
382   // Therefore this typedef allows LineData.Functions to store multiple
383   // functions
384   // per instance. This is rare, however, so optimize for the common case.
385   using FunctionVector = SmallVector<const GCOVFunction *, 1>;
386   using FunctionLines = DenseMap<uint32_t, FunctionVector>;
387   using BlockVector = SmallVector<const GCOVBlock *, 4>;
388   using BlockLines = DenseMap<uint32_t, BlockVector>;
389
390   struct LineData {
391     LineData() = default;
392
393     BlockLines Blocks;
394     FunctionLines Functions;
395     uint32_t LastLine = 0;
396   };
397
398   struct GCOVCoverage {
399     GCOVCoverage(StringRef Name) : Name(Name) {}
400
401     StringRef Name;
402
403     uint32_t LogicalLines = 0;
404     uint32_t LinesExec = 0;
405
406     uint32_t Branches = 0;
407     uint32_t BranchesExec = 0;
408     uint32_t BranchesTaken = 0;
409   };
410
411 public:
412   FileInfo(const GCOV::Options &Options) : Options(Options) {}
413
414   void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
415     if (Line > LineInfo[Filename].LastLine)
416       LineInfo[Filename].LastLine = Line;
417     LineInfo[Filename].Blocks[Line - 1].push_back(Block);
418   }
419
420   void addFunctionLine(StringRef Filename, uint32_t Line,
421                        const GCOVFunction *Function) {
422     if (Line > LineInfo[Filename].LastLine)
423       LineInfo[Filename].LastLine = Line;
424     LineInfo[Filename].Functions[Line - 1].push_back(Function);
425   }
426
427   void setRunCount(uint32_t Runs) { RunCount = Runs; }
428   void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
429   void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
430              StringRef GCDAFile);
431
432 protected:
433   std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
434   std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
435   void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const;
436   void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
437                       uint32_t LineIndex, uint32_t &BlockNo) const;
438   void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
439                        GCOVCoverage &Coverage, uint32_t &EdgeNo);
440   void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
441                              uint64_t Count) const;
442
443   void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
444   void printFuncCoverage(raw_ostream &OS) const;
445   void printFileCoverage(raw_ostream &OS) const;
446
447   const GCOV::Options &Options;
448   StringMap<LineData> LineInfo;
449   uint32_t RunCount = 0;
450   uint32_t ProgramCount = 0;
451
452   using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
453   using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
454
455   FileCoverageList FileCoverages;
456   FuncCoverageMap FuncCoverages;
457 };
458
459 } // end namespace llvm
460
461 #endif // LLVM_SUPPORT_GCOV_H