• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //=-- CoverageMapping.h - Code coverage mapping support ---------*- 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 // Code coverage mapping data is generated by clang and read by
11 // llvm-cov to show code coverage statistics for a file.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_H_
16 #define LLVM_PROFILEDATA_COVERAGEMAPPING_H_
17 
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/ADT/Hashing.h"
21 #include "llvm/ADT/Triple.h"
22 #include "llvm/ADT/iterator.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/ErrorOr.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include <system_error>
27 #include <tuple>
28 
29 namespace llvm {
30 class IndexedInstrProfReader;
31 namespace coverage {
32 
33 class CoverageMappingReader;
34 
35 class CoverageMapping;
36 struct CounterExpressions;
37 
38 enum CoverageMappingVersion { CoverageMappingVersion1 };
39 
40 /// \brief A Counter is an abstract value that describes how to compute the
41 /// execution count for a region of code using the collected profile count data.
42 struct Counter {
43   enum CounterKind { Zero, CounterValueReference, Expression };
44   static const unsigned EncodingTagBits = 2;
45   static const unsigned EncodingTagMask = 0x3;
46   static const unsigned EncodingCounterTagAndExpansionRegionTagBits =
47       EncodingTagBits + 1;
48 
49 private:
50   CounterKind Kind;
51   unsigned ID;
52 
CounterCounter53   Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {}
54 
55 public:
CounterCounter56   Counter() : Kind(Zero), ID(0) {}
57 
getKindCounter58   CounterKind getKind() const { return Kind; }
59 
isZeroCounter60   bool isZero() const { return Kind == Zero; }
61 
isExpressionCounter62   bool isExpression() const { return Kind == Expression; }
63 
getCounterIDCounter64   unsigned getCounterID() const { return ID; }
65 
getExpressionIDCounter66   unsigned getExpressionID() const { return ID; }
67 
68   friend bool operator==(const Counter &LHS, const Counter &RHS) {
69     return LHS.Kind == RHS.Kind && LHS.ID == RHS.ID;
70   }
71 
72   friend bool operator!=(const Counter &LHS, const Counter &RHS) {
73     return !(LHS == RHS);
74   }
75 
76   friend bool operator<(const Counter &LHS, const Counter &RHS) {
77     return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID);
78   }
79 
80   /// \brief Return the counter that represents the number zero.
getZeroCounter81   static Counter getZero() { return Counter(); }
82 
83   /// \brief Return the counter that corresponds to a specific profile counter.
getCounterCounter84   static Counter getCounter(unsigned CounterId) {
85     return Counter(CounterValueReference, CounterId);
86   }
87 
88   /// \brief Return the counter that corresponds to a specific
89   /// addition counter expression.
getExpressionCounter90   static Counter getExpression(unsigned ExpressionId) {
91     return Counter(Expression, ExpressionId);
92   }
93 };
94 
95 /// \brief A Counter expression is a value that represents an arithmetic
96 /// operation with two counters.
97 struct CounterExpression {
98   enum ExprKind { Subtract, Add };
99   ExprKind Kind;
100   Counter LHS, RHS;
101 
CounterExpressionCounterExpression102   CounterExpression(ExprKind Kind, Counter LHS, Counter RHS)
103       : Kind(Kind), LHS(LHS), RHS(RHS) {}
104 };
105 
106 /// \brief A Counter expression builder is used to construct the
107 /// counter expressions. It avoids unnecessary duplication
108 /// and simplifies algebraic expressions.
109 class CounterExpressionBuilder {
110   /// \brief A list of all the counter expressions
111   std::vector<CounterExpression> Expressions;
112   /// \brief A lookup table for the index of a given expression.
113   llvm::DenseMap<CounterExpression, unsigned> ExpressionIndices;
114 
115   /// \brief Return the counter which corresponds to the given expression.
116   ///
117   /// If the given expression is already stored in the builder, a counter
118   /// that references that expression is returned. Otherwise, the given
119   /// expression is added to the builder's collection of expressions.
120   Counter get(const CounterExpression &E);
121 
122   /// \brief Gather the terms of the expression tree for processing.
123   ///
124   /// This collects each addition and subtraction referenced by the counter into
125   /// a sequence that can be sorted and combined to build a simplified counter
126   /// expression.
127   void extractTerms(Counter C, int Sign,
128                     SmallVectorImpl<std::pair<unsigned, int>> &Terms);
129 
130   /// \brief Simplifies the given expression tree
131   /// by getting rid of algebraically redundant operations.
132   Counter simplify(Counter ExpressionTree);
133 
134 public:
getExpressions()135   ArrayRef<CounterExpression> getExpressions() const { return Expressions; }
136 
137   /// \brief Return a counter that represents the expression
138   /// that adds LHS and RHS.
139   Counter add(Counter LHS, Counter RHS);
140 
141   /// \brief Return a counter that represents the expression
142   /// that subtracts RHS from LHS.
143   Counter subtract(Counter LHS, Counter RHS);
144 };
145 
146 /// \brief A Counter mapping region associates a source range with
147 /// a specific counter.
148 struct CounterMappingRegion {
149   enum RegionKind {
150     /// \brief A CodeRegion associates some code with a counter
151     CodeRegion,
152 
153     /// \brief An ExpansionRegion represents a file expansion region that
154     /// associates a source range with the expansion of a virtual source file,
155     /// such as for a macro instantiation or #include file.
156     ExpansionRegion,
157 
158     /// \brief A SkippedRegion represents a source range with code that
159     /// was skipped by a preprocessor or similar means.
160     SkippedRegion
161   };
162 
163   Counter Count;
164   unsigned FileID, ExpandedFileID;
165   unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
166   RegionKind Kind;
167 
CounterMappingRegionCounterMappingRegion168   CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID,
169                        unsigned LineStart, unsigned ColumnStart,
170                        unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind)
171       : Count(Count), FileID(FileID), ExpandedFileID(ExpandedFileID),
172         LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
173         ColumnEnd(ColumnEnd), Kind(Kind) {}
174 
175   static CounterMappingRegion
makeRegionCounterMappingRegion176   makeRegion(Counter Count, unsigned FileID, unsigned LineStart,
177              unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
178     return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart,
179                                 LineEnd, ColumnEnd, CodeRegion);
180   }
181 
182   static CounterMappingRegion
makeExpansionCounterMappingRegion183   makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart,
184                 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
185     return CounterMappingRegion(Counter(), FileID, ExpandedFileID, LineStart,
186                                 ColumnStart, LineEnd, ColumnEnd,
187                                 ExpansionRegion);
188   }
189 
190   static CounterMappingRegion
makeSkippedCounterMappingRegion191   makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart,
192               unsigned LineEnd, unsigned ColumnEnd) {
193     return CounterMappingRegion(Counter(), FileID, 0, LineStart, ColumnStart,
194                                 LineEnd, ColumnEnd, SkippedRegion);
195   }
196 
197 
startLocCounterMappingRegion198   inline std::pair<unsigned, unsigned> startLoc() const {
199     return std::pair<unsigned, unsigned>(LineStart, ColumnStart);
200   }
201 
endLocCounterMappingRegion202   inline std::pair<unsigned, unsigned> endLoc() const {
203     return std::pair<unsigned, unsigned>(LineEnd, ColumnEnd);
204   }
205 
206   bool operator<(const CounterMappingRegion &Other) const {
207     if (FileID != Other.FileID)
208       return FileID < Other.FileID;
209     return startLoc() < Other.startLoc();
210   }
211 
containsCounterMappingRegion212   bool contains(const CounterMappingRegion &Other) const {
213     if (FileID != Other.FileID)
214       return false;
215     if (startLoc() > Other.startLoc())
216       return false;
217     if (endLoc() < Other.endLoc())
218       return false;
219     return true;
220   }
221 };
222 
223 /// \brief Associates a source range with an execution count.
224 struct CountedRegion : public CounterMappingRegion {
225   uint64_t ExecutionCount;
226 
CountedRegionCountedRegion227   CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
228       : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {}
229 };
230 
231 /// \brief A Counter mapping context is used to connect the counters,
232 /// expressions and the obtained counter values.
233 class CounterMappingContext {
234   ArrayRef<CounterExpression> Expressions;
235   ArrayRef<uint64_t> CounterValues;
236 
237 public:
238   CounterMappingContext(ArrayRef<CounterExpression> Expressions,
239                         ArrayRef<uint64_t> CounterValues = None)
Expressions(Expressions)240       : Expressions(Expressions), CounterValues(CounterValues) {}
241 
setCounts(ArrayRef<uint64_t> Counts)242   void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; }
243 
244   void dump(const Counter &C, llvm::raw_ostream &OS) const;
dump(const Counter & C)245   void dump(const Counter &C) const { dump(C, dbgs()); }
246 
247   /// \brief Return the number of times that a region of code associated with
248   /// this counter was executed.
249   ErrorOr<int64_t> evaluate(const Counter &C) const;
250 };
251 
252 /// \brief Code coverage information for a single function.
253 struct FunctionRecord {
254   /// \brief Raw function name.
255   std::string Name;
256   /// \brief Associated files.
257   std::vector<std::string> Filenames;
258   /// \brief Regions in the function along with their counts.
259   std::vector<CountedRegion> CountedRegions;
260   /// \brief The number of times this function was executed.
261   uint64_t ExecutionCount;
262 
FunctionRecordFunctionRecord263   FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
264       : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
265 
pushRegionFunctionRecord266   void pushRegion(CounterMappingRegion Region, uint64_t Count) {
267     if (CountedRegions.empty())
268       ExecutionCount = Count;
269     CountedRegions.emplace_back(Region, Count);
270   }
271 };
272 
273 /// \brief Iterator over Functions, optionally filtered to a single file.
274 class FunctionRecordIterator
275     : public iterator_facade_base<FunctionRecordIterator,
276                                   std::forward_iterator_tag, FunctionRecord> {
277   ArrayRef<FunctionRecord> Records;
278   ArrayRef<FunctionRecord>::iterator Current;
279   StringRef Filename;
280 
281   /// \brief Skip records whose primary file is not \c Filename.
282   void skipOtherFiles();
283 
284 public:
285   FunctionRecordIterator(ArrayRef<FunctionRecord> Records_,
286                          StringRef Filename = "")
Records(Records_)287       : Records(Records_), Current(Records.begin()), Filename(Filename) {
288     skipOtherFiles();
289   }
290 
FunctionRecordIterator()291   FunctionRecordIterator() : Current(Records.begin()) {}
292 
293   bool operator==(const FunctionRecordIterator &RHS) const {
294     return Current == RHS.Current && Filename == RHS.Filename;
295   }
296 
297   const FunctionRecord &operator*() const { return *Current; }
298 
299   FunctionRecordIterator &operator++() {
300     assert(Current != Records.end() && "incremented past end");
301     ++Current;
302     skipOtherFiles();
303     return *this;
304   }
305 };
306 
307 /// \brief Coverage information for a macro expansion or #included file.
308 ///
309 /// When covered code has pieces that can be expanded for more detail, such as a
310 /// preprocessor macro use and its definition, these are represented as
311 /// expansions whose coverage can be looked up independently.
312 struct ExpansionRecord {
313   /// \brief The abstract file this expansion covers.
314   unsigned FileID;
315   /// \brief The region that expands to this record.
316   const CountedRegion &Region;
317   /// \brief Coverage for the expansion.
318   const FunctionRecord &Function;
319 
ExpansionRecordExpansionRecord320   ExpansionRecord(const CountedRegion &Region,
321                   const FunctionRecord &Function)
322       : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {}
323 };
324 
325 /// \brief The execution count information starting at a point in a file.
326 ///
327 /// A sequence of CoverageSegments gives execution counts for a file in format
328 /// that's simple to iterate through for processing.
329 struct CoverageSegment {
330   /// \brief The line where this segment begins.
331   unsigned Line;
332   /// \brief The column where this segment begins.
333   unsigned Col;
334   /// \brief The execution count, or zero if no count was recorded.
335   uint64_t Count;
336   /// \brief When false, the segment was uninstrumented or skipped.
337   bool HasCount;
338   /// \brief Whether this enters a new region or returns to a previous count.
339   bool IsRegionEntry;
340 
CoverageSegmentCoverageSegment341   CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry)
342       : Line(Line), Col(Col), Count(0), HasCount(false),
343         IsRegionEntry(IsRegionEntry) {}
344 
CoverageSegmentCoverageSegment345   CoverageSegment(unsigned Line, unsigned Col, uint64_t Count,
346                   bool IsRegionEntry)
347       : Line(Line), Col(Col), Count(Count), HasCount(true),
348         IsRegionEntry(IsRegionEntry) {}
349 
350   friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) {
351     return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) ==
352            std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry);
353   }
354 
setCountCoverageSegment355   void setCount(uint64_t NewCount) {
356     Count = NewCount;
357     HasCount = true;
358   }
359 
addCountCoverageSegment360   void addCount(uint64_t NewCount) { setCount(Count + NewCount); }
361 };
362 
363 /// \brief Coverage information to be processed or displayed.
364 ///
365 /// This represents the coverage of an entire file, expansion, or function. It
366 /// provides a sequence of CoverageSegments to iterate through, as well as the
367 /// list of expansions that can be further processed.
368 class CoverageData {
369   std::string Filename;
370   std::vector<CoverageSegment> Segments;
371   std::vector<ExpansionRecord> Expansions;
372   friend class CoverageMapping;
373 
374 public:
CoverageData()375   CoverageData() {}
376 
CoverageData(StringRef Filename)377   CoverageData(StringRef Filename) : Filename(Filename) {}
378 
CoverageData(CoverageData && RHS)379   CoverageData(CoverageData &&RHS)
380       : Filename(std::move(RHS.Filename)), Segments(std::move(RHS.Segments)),
381         Expansions(std::move(RHS.Expansions)) {}
382 
383   /// \brief Get the name of the file this data covers.
getFilename()384   StringRef getFilename() { return Filename; }
385 
begin()386   std::vector<CoverageSegment>::iterator begin() { return Segments.begin(); }
end()387   std::vector<CoverageSegment>::iterator end() { return Segments.end(); }
empty()388   bool empty() { return Segments.empty(); }
389 
390   /// \brief Expansions that can be further processed.
getExpansions()391   std::vector<ExpansionRecord> getExpansions() { return Expansions; }
392 };
393 
394 /// \brief The mapping of profile information to coverage data.
395 ///
396 /// This is the main interface to get coverage information, using a profile to
397 /// fill out execution counts.
398 class CoverageMapping {
399   std::vector<FunctionRecord> Functions;
400   unsigned MismatchedFunctionCount;
401 
CoverageMapping()402   CoverageMapping() : MismatchedFunctionCount(0) {}
403 
404 public:
405   /// \brief Load the coverage mapping using the given readers.
406   static ErrorOr<std::unique_ptr<CoverageMapping>>
407   load(CoverageMappingReader &CoverageReader,
408        IndexedInstrProfReader &ProfileReader);
409 
410   /// \brief Load the coverage mapping from the given files.
411   static ErrorOr<std::unique_ptr<CoverageMapping>>
412   load(StringRef ObjectFilename, StringRef ProfileFilename,
413        StringRef Arch = StringRef());
414 
415   /// \brief The number of functions that couldn't have their profiles mapped.
416   ///
417   /// This is a count of functions whose profile is out of date or otherwise
418   /// can't be associated with any coverage information.
getMismatchedCount()419   unsigned getMismatchedCount() { return MismatchedFunctionCount; }
420 
421   /// \brief Returns the list of files that are covered.
422   std::vector<StringRef> getUniqueSourceFiles() const;
423 
424   /// \brief Get the coverage for a particular file.
425   ///
426   /// The given filename must be the name as recorded in the coverage
427   /// information. That is, only names returned from getUniqueSourceFiles will
428   /// yield a result.
429   CoverageData getCoverageForFile(StringRef Filename);
430 
431   /// \brief Gets all of the functions covered by this profile.
getCoveredFunctions()432   iterator_range<FunctionRecordIterator> getCoveredFunctions() const {
433     return make_range(FunctionRecordIterator(Functions),
434                       FunctionRecordIterator());
435   }
436 
437   /// \brief Gets all of the functions in a particular file.
438   iterator_range<FunctionRecordIterator>
getCoveredFunctions(StringRef Filename)439   getCoveredFunctions(StringRef Filename) const {
440     return make_range(FunctionRecordIterator(Functions, Filename),
441                       FunctionRecordIterator());
442   }
443 
444   /// \brief Get the list of function instantiations in the file.
445   ///
446   /// Functions that are instantiated more than once, such as C++ template
447   /// specializations, have distinct coverage records for each instantiation.
448   std::vector<const FunctionRecord *> getInstantiations(StringRef Filename);
449 
450   /// \brief Get the coverage for a particular function.
451   CoverageData getCoverageForFunction(const FunctionRecord &Function);
452 
453   /// \brief Get the coverage for an expansion within a coverage set.
454   CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion);
455 };
456 
457 } // end namespace coverage
458 
459 /// \brief Provide DenseMapInfo for CounterExpression
460 template<> struct DenseMapInfo<coverage::CounterExpression> {
461   static inline coverage::CounterExpression getEmptyKey() {
462     using namespace coverage;
463     return CounterExpression(CounterExpression::ExprKind::Subtract,
464                              Counter::getCounter(~0U),
465                              Counter::getCounter(~0U));
466   }
467 
468   static inline coverage::CounterExpression getTombstoneKey() {
469     using namespace coverage;
470     return CounterExpression(CounterExpression::ExprKind::Add,
471                              Counter::getCounter(~0U),
472                              Counter::getCounter(~0U));
473   }
474 
475   static unsigned getHashValue(const coverage::CounterExpression &V) {
476     return static_cast<unsigned>(
477         hash_combine(V.Kind, V.LHS.getKind(), V.LHS.getCounterID(),
478                      V.RHS.getKind(), V.RHS.getCounterID()));
479   }
480 
481   static bool isEqual(const coverage::CounterExpression &LHS,
482                       const coverage::CounterExpression &RHS) {
483     return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS && LHS.RHS == RHS.RHS;
484   }
485 };
486 
487 const std::error_category &coveragemap_category();
488 
489 enum class coveragemap_error {
490   success = 0,
491   eof,
492   no_data_found,
493   unsupported_version,
494   truncated,
495   malformed
496 };
497 
498 inline std::error_code make_error_code(coveragemap_error E) {
499   return std::error_code(static_cast<int>(E), coveragemap_category());
500 }
501 
502 } // end namespace llvm
503 
504 namespace std {
505 template <>
506 struct is_error_code_enum<llvm::coveragemap_error> : std::true_type {};
507 }
508 
509 #endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_
510