1 //===- CoverageMapping.h - Code coverage mapping support --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Code coverage mapping data is generated by clang and read by
10 // llvm-cov to show code coverage statistics for a file.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
15 #define LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
16
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/BitVector.h"
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/ADT/DenseSet.h"
21 #include "llvm/ADT/Hashing.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ADT/iterator.h"
24 #include "llvm/ADT/iterator_range.h"
25 #include "llvm/Object/BuildID.h"
26 #include "llvm/ProfileData/InstrProf.h"
27 #include "llvm/Support/Alignment.h"
28 #include "llvm/Support/Compiler.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/Endian.h"
31 #include "llvm/Support/Error.h"
32 #include "llvm/Support/raw_ostream.h"
33 #include <cassert>
34 #include <cstdint>
35 #include <iterator>
36 #include <memory>
37 #include <sstream>
38 #include <string>
39 #include <system_error>
40 #include <tuple>
41 #include <utility>
42 #include <vector>
43
44 namespace llvm {
45
46 class IndexedInstrProfReader;
47
48 namespace object {
49 class BuildIDFetcher;
50 } // namespace object
51
52 namespace vfs {
53 class FileSystem;
54 } // namespace vfs
55
56 namespace coverage {
57
58 class CoverageMappingReader;
59 struct CoverageMappingRecord;
60
61 enum class coveragemap_error {
62 success = 0,
63 eof,
64 no_data_found,
65 unsupported_version,
66 truncated,
67 malformed,
68 decompression_failed,
69 invalid_or_missing_arch_specifier
70 };
71
72 const std::error_category &coveragemap_category();
73
make_error_code(coveragemap_error E)74 inline std::error_code make_error_code(coveragemap_error E) {
75 return std::error_code(static_cast<int>(E), coveragemap_category());
76 }
77
78 class CoverageMapError : public ErrorInfo<CoverageMapError> {
79 public:
80 CoverageMapError(coveragemap_error Err, const Twine &ErrStr = Twine())
Err(Err)81 : Err(Err), Msg(ErrStr.str()) {
82 assert(Err != coveragemap_error::success && "Not an error");
83 }
84
85 std::string message() const override;
86
log(raw_ostream & OS)87 void log(raw_ostream &OS) const override { OS << message(); }
88
convertToErrorCode()89 std::error_code convertToErrorCode() const override {
90 return make_error_code(Err);
91 }
92
get()93 coveragemap_error get() const { return Err; }
getMessage()94 const std::string &getMessage() const { return Msg; }
95
96 static char ID;
97
98 private:
99 coveragemap_error Err;
100 std::string Msg;
101 };
102
103 /// A Counter is an abstract value that describes how to compute the
104 /// execution count for a region of code using the collected profile count data.
105 struct Counter {
106 /// The CounterExpression kind (Add or Subtract) is encoded in bit 0 next to
107 /// the CounterKind. This means CounterKind has to leave bit 0 free.
108 enum CounterKind { Zero, CounterValueReference, Expression };
109 static const unsigned EncodingTagBits = 2;
110 static const unsigned EncodingTagMask = 0x3;
111 static const unsigned EncodingCounterTagAndExpansionRegionTagBits =
112 EncodingTagBits + 1;
113
114 private:
115 CounterKind Kind = Zero;
116 unsigned ID = 0;
117
CounterCounter118 Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {}
119
120 public:
121 Counter() = default;
122
getKindCounter123 CounterKind getKind() const { return Kind; }
124
isZeroCounter125 bool isZero() const { return Kind == Zero; }
126
isExpressionCounter127 bool isExpression() const { return Kind == Expression; }
128
getCounterIDCounter129 unsigned getCounterID() const { return ID; }
130
getExpressionIDCounter131 unsigned getExpressionID() const { return ID; }
132
133 friend bool operator==(const Counter &LHS, const Counter &RHS) {
134 return LHS.Kind == RHS.Kind && LHS.ID == RHS.ID;
135 }
136
137 friend bool operator!=(const Counter &LHS, const Counter &RHS) {
138 return !(LHS == RHS);
139 }
140
141 friend bool operator<(const Counter &LHS, const Counter &RHS) {
142 return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID);
143 }
144
145 /// Return the counter that represents the number zero.
getZeroCounter146 static Counter getZero() { return Counter(); }
147
148 /// Return the counter that corresponds to a specific profile counter.
getCounterCounter149 static Counter getCounter(unsigned CounterId) {
150 return Counter(CounterValueReference, CounterId);
151 }
152
153 /// Return the counter that corresponds to a specific addition counter
154 /// expression.
getExpressionCounter155 static Counter getExpression(unsigned ExpressionId) {
156 return Counter(Expression, ExpressionId);
157 }
158 };
159
160 /// A Counter expression is a value that represents an arithmetic operation
161 /// with two counters.
162 struct CounterExpression {
163 enum ExprKind { Subtract, Add };
164 ExprKind Kind;
165 Counter LHS, RHS;
166
CounterExpressionCounterExpression167 CounterExpression(ExprKind Kind, Counter LHS, Counter RHS)
168 : Kind(Kind), LHS(LHS), RHS(RHS) {}
169 };
170
171 /// A Counter expression builder is used to construct the counter expressions.
172 /// It avoids unnecessary duplication and simplifies algebraic expressions.
173 class CounterExpressionBuilder {
174 /// A list of all the counter expressions
175 std::vector<CounterExpression> Expressions;
176
177 /// A lookup table for the index of a given expression.
178 DenseMap<CounterExpression, unsigned> ExpressionIndices;
179
180 /// Return the counter which corresponds to the given expression.
181 ///
182 /// If the given expression is already stored in the builder, a counter
183 /// that references that expression is returned. Otherwise, the given
184 /// expression is added to the builder's collection of expressions.
185 Counter get(const CounterExpression &E);
186
187 /// Represents a term in a counter expression tree.
188 struct Term {
189 unsigned CounterID;
190 int Factor;
191
TermTerm192 Term(unsigned CounterID, int Factor)
193 : CounterID(CounterID), Factor(Factor) {}
194 };
195
196 /// Gather the terms of the expression tree for processing.
197 ///
198 /// This collects each addition and subtraction referenced by the counter into
199 /// a sequence that can be sorted and combined to build a simplified counter
200 /// expression.
201 void extractTerms(Counter C, int Sign, SmallVectorImpl<Term> &Terms);
202
203 /// Simplifies the given expression tree
204 /// by getting rid of algebraically redundant operations.
205 Counter simplify(Counter ExpressionTree);
206
207 public:
getExpressions()208 ArrayRef<CounterExpression> getExpressions() const { return Expressions; }
209
210 /// Return a counter that represents the expression that adds LHS and RHS.
211 Counter add(Counter LHS, Counter RHS, bool Simplify = true);
212
213 /// Return a counter that represents the expression that subtracts RHS from
214 /// LHS.
215 Counter subtract(Counter LHS, Counter RHS, bool Simplify = true);
216 };
217
218 using LineColPair = std::pair<unsigned, unsigned>;
219
220 /// A Counter mapping region associates a source range with a specific counter.
221 struct CounterMappingRegion {
222 enum RegionKind {
223 /// A CodeRegion associates some code with a counter
224 CodeRegion,
225
226 /// An ExpansionRegion represents a file expansion region that associates
227 /// a source range with the expansion of a virtual source file, such as
228 /// for a macro instantiation or #include file.
229 ExpansionRegion,
230
231 /// A SkippedRegion represents a source range with code that was skipped
232 /// by a preprocessor or similar means.
233 SkippedRegion,
234
235 /// A GapRegion is like a CodeRegion, but its count is only set as the
236 /// line execution count when its the only region in the line.
237 GapRegion,
238
239 /// A BranchRegion represents leaf-level boolean expressions and is
240 /// associated with two counters, each representing the number of times the
241 /// expression evaluates to true or false.
242 BranchRegion,
243
244 /// A DecisionRegion represents a top-level boolean expression and is
245 /// associated with a variable length bitmap index and condition number.
246 MCDCDecisionRegion,
247
248 /// A Branch Region can be extended to include IDs to facilitate MC/DC.
249 MCDCBranchRegion
250 };
251
252 using MCDCConditionID = unsigned int;
253 struct MCDCParameters {
254 /// Byte Index of Bitmap Coverage Object for a Decision Region.
255 unsigned BitmapIdx = 0;
256
257 /// Number of Conditions used for a Decision Region.
258 unsigned NumConditions = 0;
259
260 /// IDs used to represent a branch region and other branch regions
261 /// evaluated based on True and False branches.
262 MCDCConditionID ID = 0, TrueID = 0, FalseID = 0;
263 };
264
265 /// Primary Counter that is also used for Branch Regions (TrueCount).
266 Counter Count;
267
268 /// Secondary Counter used for Branch Regions (FalseCount).
269 Counter FalseCount;
270
271 /// Parameters used for Modified Condition/Decision Coverage
272 MCDCParameters MCDCParams;
273
274 unsigned FileID = 0;
275 unsigned ExpandedFileID = 0;
276 unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
277
278 RegionKind Kind;
279
CounterMappingRegionCounterMappingRegion280 CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID,
281 unsigned LineStart, unsigned ColumnStart,
282 unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind)
283 : Count(Count), FileID(FileID), ExpandedFileID(ExpandedFileID),
284 LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
285 ColumnEnd(ColumnEnd), Kind(Kind) {}
286
CounterMappingRegionCounterMappingRegion287 CounterMappingRegion(Counter Count, Counter FalseCount,
288 MCDCParameters MCDCParams, unsigned FileID,
289 unsigned ExpandedFileID, unsigned LineStart,
290 unsigned ColumnStart, unsigned LineEnd,
291 unsigned ColumnEnd, RegionKind Kind)
292 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
293 FileID(FileID), ExpandedFileID(ExpandedFileID), LineStart(LineStart),
294 ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
295 Kind(Kind) {}
296
CounterMappingRegionCounterMappingRegion297 CounterMappingRegion(MCDCParameters MCDCParams, unsigned FileID,
298 unsigned LineStart, unsigned ColumnStart,
299 unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind)
300 : MCDCParams(MCDCParams), FileID(FileID), LineStart(LineStart),
301 ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd),
302 Kind(Kind) {}
303
304 static CounterMappingRegion
makeRegionCounterMappingRegion305 makeRegion(Counter Count, unsigned FileID, unsigned LineStart,
306 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
307 return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart,
308 LineEnd, ColumnEnd, CodeRegion);
309 }
310
311 static CounterMappingRegion
makeExpansionCounterMappingRegion312 makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart,
313 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
314 return CounterMappingRegion(Counter(), FileID, ExpandedFileID, LineStart,
315 ColumnStart, LineEnd, ColumnEnd,
316 ExpansionRegion);
317 }
318
319 static CounterMappingRegion
makeSkippedCounterMappingRegion320 makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart,
321 unsigned LineEnd, unsigned ColumnEnd) {
322 return CounterMappingRegion(Counter(), FileID, 0, LineStart, ColumnStart,
323 LineEnd, ColumnEnd, SkippedRegion);
324 }
325
326 static CounterMappingRegion
makeGapRegionCounterMappingRegion327 makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart,
328 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) {
329 return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart,
330 LineEnd, (1U << 31) | ColumnEnd, GapRegion);
331 }
332
333 static CounterMappingRegion
makeBranchRegionCounterMappingRegion334 makeBranchRegion(Counter Count, Counter FalseCount, unsigned FileID,
335 unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
336 unsigned ColumnEnd) {
337 return CounterMappingRegion(Count, FalseCount, MCDCParameters(), FileID, 0,
338 LineStart, ColumnStart, LineEnd, ColumnEnd,
339 BranchRegion);
340 }
341
342 static CounterMappingRegion
makeBranchRegionCounterMappingRegion343 makeBranchRegion(Counter Count, Counter FalseCount, MCDCParameters MCDCParams,
344 unsigned FileID, unsigned LineStart, unsigned ColumnStart,
345 unsigned LineEnd, unsigned ColumnEnd) {
346 return CounterMappingRegion(Count, FalseCount, MCDCParams, FileID, 0,
347 LineStart, ColumnStart, LineEnd, ColumnEnd,
348 MCDCParams.ID == 0 ? BranchRegion
349 : MCDCBranchRegion);
350 }
351
352 static CounterMappingRegion
makeDecisionRegionCounterMappingRegion353 makeDecisionRegion(MCDCParameters MCDCParams, unsigned FileID,
354 unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
355 unsigned ColumnEnd) {
356 return CounterMappingRegion(MCDCParams, FileID, LineStart, ColumnStart,
357 LineEnd, ColumnEnd, MCDCDecisionRegion);
358 }
359
startLocCounterMappingRegion360 inline LineColPair startLoc() const {
361 return LineColPair(LineStart, ColumnStart);
362 }
363
endLocCounterMappingRegion364 inline LineColPair endLoc() const { return LineColPair(LineEnd, ColumnEnd); }
365 };
366
367 /// Associates a source range with an execution count.
368 struct CountedRegion : public CounterMappingRegion {
369 uint64_t ExecutionCount;
370 uint64_t FalseExecutionCount;
371 bool Folded;
372
CountedRegionCountedRegion373 CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
374 : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
375 FalseExecutionCount(0), Folded(false) {}
376
CountedRegionCountedRegion377 CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
378 uint64_t FalseExecutionCount)
379 : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
380 FalseExecutionCount(FalseExecutionCount), Folded(false) {}
381 };
382
383 /// MCDC Record grouping all information together.
384 struct MCDCRecord {
385 /// CondState represents the evaluation of a condition in an executed test
386 /// vector, which can be True or False. A DontCare is used to mask an
387 /// unevaluatable condition resulting from short-circuit behavior of logical
388 /// operators in languages like C/C++. When comparing the evaluation of a
389 /// condition across executed test vectors, comparisons against a DontCare
390 /// are effectively ignored.
391 enum CondState { MCDC_DontCare = -1, MCDC_False = 0, MCDC_True = 1 };
392
393 using TestVector = llvm::SmallVector<CondState>;
394 using TestVectors = llvm::SmallVector<TestVector>;
395 using BoolVector = llvm::SmallVector<bool>;
396 using TVRowPair = std::pair<unsigned, unsigned>;
397 using TVPairMap = llvm::DenseMap<unsigned, TVRowPair>;
398 using CondIDMap = llvm::DenseMap<unsigned, unsigned>;
399 using LineColPairMap = llvm::DenseMap<unsigned, LineColPair>;
400
401 private:
402 CounterMappingRegion Region;
403 TestVectors TV;
404 TVPairMap IndependencePairs;
405 BoolVector Folded;
406 CondIDMap PosToID;
407 LineColPairMap CondLoc;
408
409 public:
MCDCRecordMCDCRecord410 MCDCRecord(CounterMappingRegion Region, TestVectors TV,
411 TVPairMap IndependencePairs, BoolVector Folded, CondIDMap PosToID,
412 LineColPairMap CondLoc)
413 : Region(Region), TV(TV), IndependencePairs(IndependencePairs),
414 Folded(Folded), PosToID(PosToID), CondLoc(CondLoc){};
415
getDecisionRegionMCDCRecord416 CounterMappingRegion getDecisionRegion() const { return Region; }
getNumConditionsMCDCRecord417 unsigned getNumConditions() const {
418 assert(Region.MCDCParams.NumConditions != 0 &&
419 "In MC/DC, NumConditions should never be zero!");
420 return Region.MCDCParams.NumConditions;
421 }
getNumTestVectorsMCDCRecord422 unsigned getNumTestVectors() const { return TV.size(); }
isCondFoldedMCDCRecord423 bool isCondFolded(unsigned Condition) const { return Folded[Condition]; }
424
425 /// Return the evaluation of a condition (indicated by Condition) in an
426 /// executed test vector (indicated by TestVectorIndex), which will be True,
427 /// False, or DontCare if the condition is unevaluatable. Because condition
428 /// IDs are not associated based on their position in the expression,
429 /// accessing conditions in the TestVectors requires a translation from a
430 /// ordinal position to actual condition ID. This is done via PosToID[].
getTVConditionMCDCRecord431 CondState getTVCondition(unsigned TestVectorIndex, unsigned Condition) {
432 return TV[TestVectorIndex][PosToID[Condition]];
433 }
434
435 /// Return the Result evaluation for an executed test vector.
436 /// See MCDCRecordProcessor::RecordTestVector().
getTVResultMCDCRecord437 CondState getTVResult(unsigned TestVectorIndex) {
438 return TV[TestVectorIndex][getNumConditions()];
439 }
440
441 /// Determine whether a given condition (indicated by Condition) is covered
442 /// by an Independence Pair. Because condition IDs are not associated based
443 /// on their position in the expression, accessing conditions in the
444 /// TestVectors requires a translation from a ordinal position to actual
445 /// condition ID. This is done via PosToID[].
isConditionIndependencePairCoveredMCDCRecord446 bool isConditionIndependencePairCovered(unsigned Condition) const {
447 auto It = PosToID.find(Condition);
448 if (It != PosToID.end())
449 return IndependencePairs.contains(It->second);
450 llvm_unreachable("Condition ID without an Ordinal mapping");
451 }
452
453 /// Return the Independence Pair that covers the given condition. Because
454 /// condition IDs are not associated based on their position in the
455 /// expression, accessing conditions in the TestVectors requires a
456 /// translation from a ordinal position to actual condition ID. This is done
457 /// via PosToID[].
getConditionIndependencePairMCDCRecord458 TVRowPair getConditionIndependencePair(unsigned Condition) {
459 assert(isConditionIndependencePairCovered(Condition));
460 return IndependencePairs[PosToID[Condition]];
461 }
462
getPercentCoveredMCDCRecord463 float getPercentCovered() const {
464 unsigned Folded = 0;
465 unsigned Covered = 0;
466 for (unsigned C = 0; C < getNumConditions(); C++) {
467 if (isCondFolded(C))
468 Folded++;
469 else if (isConditionIndependencePairCovered(C))
470 Covered++;
471 }
472
473 unsigned Total = getNumConditions() - Folded;
474 if (Total == 0)
475 return 0.0;
476 return (static_cast<double>(Covered) / static_cast<double>(Total)) * 100.0;
477 }
478
getConditionHeaderStringMCDCRecord479 std::string getConditionHeaderString(unsigned Condition) {
480 std::ostringstream OS;
481 OS << "Condition C" << Condition + 1 << " --> (";
482 OS << CondLoc[Condition].first << ":" << CondLoc[Condition].second;
483 OS << ")\n";
484 return OS.str();
485 }
486
getTestVectorHeaderStringMCDCRecord487 std::string getTestVectorHeaderString() const {
488 std::ostringstream OS;
489 if (getNumTestVectors() == 0) {
490 OS << "None.\n";
491 return OS.str();
492 }
493 const auto NumConditions = getNumConditions();
494 for (unsigned I = 0; I < NumConditions; I++) {
495 OS << "C" << I + 1;
496 if (I != NumConditions - 1)
497 OS << ", ";
498 }
499 OS << " Result\n";
500 return OS.str();
501 }
502
getTestVectorStringMCDCRecord503 std::string getTestVectorString(unsigned TestVectorIndex) {
504 assert(TestVectorIndex < getNumTestVectors() &&
505 "TestVector index out of bounds!");
506 std::ostringstream OS;
507 const auto NumConditions = getNumConditions();
508 // Add individual condition values to the string.
509 OS << " " << TestVectorIndex + 1 << " { ";
510 for (unsigned Condition = 0; Condition < NumConditions; Condition++) {
511 if (isCondFolded(Condition))
512 OS << "C";
513 else {
514 switch (getTVCondition(TestVectorIndex, Condition)) {
515 case MCDCRecord::MCDC_DontCare:
516 OS << "-";
517 break;
518 case MCDCRecord::MCDC_True:
519 OS << "T";
520 break;
521 case MCDCRecord::MCDC_False:
522 OS << "F";
523 break;
524 }
525 }
526 if (Condition != NumConditions - 1)
527 OS << ", ";
528 }
529
530 // Add result value to the string.
531 OS << " = ";
532 if (getTVResult(TestVectorIndex) == MCDC_True)
533 OS << "T";
534 else
535 OS << "F";
536 OS << " }\n";
537
538 return OS.str();
539 }
540
getConditionCoverageStringMCDCRecord541 std::string getConditionCoverageString(unsigned Condition) {
542 assert(Condition < getNumConditions() &&
543 "Condition index is out of bounds!");
544 std::ostringstream OS;
545
546 OS << " C" << Condition + 1 << "-Pair: ";
547 if (isCondFolded(Condition)) {
548 OS << "constant folded\n";
549 } else if (isConditionIndependencePairCovered(Condition)) {
550 TVRowPair rows = getConditionIndependencePair(Condition);
551 OS << "covered: (" << rows.first << ",";
552 OS << rows.second << ")\n";
553 } else
554 OS << "not covered\n";
555
556 return OS.str();
557 }
558 };
559
560 /// A Counter mapping context is used to connect the counters, expressions
561 /// and the obtained counter values.
562 class CounterMappingContext {
563 ArrayRef<CounterExpression> Expressions;
564 ArrayRef<uint64_t> CounterValues;
565 ArrayRef<uint8_t> BitmapBytes;
566
567 public:
568 CounterMappingContext(ArrayRef<CounterExpression> Expressions,
569 ArrayRef<uint64_t> CounterValues = std::nullopt)
Expressions(Expressions)570 : Expressions(Expressions), CounterValues(CounterValues) {}
571
setCounts(ArrayRef<uint64_t> Counts)572 void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; }
setBitmapBytes(ArrayRef<uint8_t> Bytes)573 void setBitmapBytes(ArrayRef<uint8_t> Bytes) { BitmapBytes = Bytes; }
574
575 void dump(const Counter &C, raw_ostream &OS) const;
dump(const Counter & C)576 void dump(const Counter &C) const { dump(C, dbgs()); }
577
578 /// Return the number of times that a region of code associated with this
579 /// counter was executed.
580 Expected<int64_t> evaluate(const Counter &C) const;
581
582 /// Return the number of times that a region of code associated with this
583 /// counter was executed.
584 Expected<BitVector>
585 evaluateBitmap(const CounterMappingRegion *MCDCDecision) const;
586
587 /// Return an MCDC record that indicates executed test vectors and condition
588 /// pairs.
589 Expected<MCDCRecord>
590 evaluateMCDCRegion(const CounterMappingRegion &Region,
591 const BitVector &Bitmap,
592 ArrayRef<const CounterMappingRegion *> Branches);
593
594 unsigned getMaxCounterID(const Counter &C) const;
595 };
596
597 /// Code coverage information for a single function.
598 struct FunctionRecord {
599 /// Raw function name.
600 std::string Name;
601 /// Mapping from FileID (i.e. vector index) to filename. Used to support
602 /// macro expansions within a function in which the macro and function are
603 /// defined in separate files.
604 ///
605 /// TODO: Uniquing filenames across all function records may be a performance
606 /// optimization.
607 std::vector<std::string> Filenames;
608 /// Regions in the function along with their counts.
609 std::vector<CountedRegion> CountedRegions;
610 /// Branch Regions in the function along with their counts.
611 std::vector<CountedRegion> CountedBranchRegions;
612 /// MCDC Records record a DecisionRegion and associated BranchRegions.
613 std::vector<MCDCRecord> MCDCRecords;
614 /// The number of times this function was executed.
615 uint64_t ExecutionCount = 0;
616
FunctionRecordFunctionRecord617 FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
618 : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
619
620 FunctionRecord(FunctionRecord &&FR) = default;
621 FunctionRecord &operator=(FunctionRecord &&) = default;
622
pushMCDCRecordFunctionRecord623 void pushMCDCRecord(MCDCRecord Record) { MCDCRecords.push_back(Record); }
624
pushRegionFunctionRecord625 void pushRegion(CounterMappingRegion Region, uint64_t Count,
626 uint64_t FalseCount) {
627 if (Region.Kind == CounterMappingRegion::BranchRegion ||
628 Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
629 CountedBranchRegions.emplace_back(Region, Count, FalseCount);
630 // If both counters are hard-coded to zero, then this region represents a
631 // constant-folded branch.
632 if (Region.Count.isZero() && Region.FalseCount.isZero())
633 CountedBranchRegions.back().Folded = true;
634 return;
635 }
636 if (CountedRegions.empty())
637 ExecutionCount = Count;
638 CountedRegions.emplace_back(Region, Count, FalseCount);
639 }
640 };
641
642 /// Iterator over Functions, optionally filtered to a single file.
643 class FunctionRecordIterator
644 : public iterator_facade_base<FunctionRecordIterator,
645 std::forward_iterator_tag, FunctionRecord> {
646 ArrayRef<FunctionRecord> Records;
647 ArrayRef<FunctionRecord>::iterator Current;
648 StringRef Filename;
649
650 /// Skip records whose primary file is not \c Filename.
651 void skipOtherFiles();
652
653 public:
654 FunctionRecordIterator(ArrayRef<FunctionRecord> Records_,
655 StringRef Filename = "")
Records(Records_)656 : Records(Records_), Current(Records.begin()), Filename(Filename) {
657 skipOtherFiles();
658 }
659
FunctionRecordIterator()660 FunctionRecordIterator() : Current(Records.begin()) {}
661
662 bool operator==(const FunctionRecordIterator &RHS) const {
663 return Current == RHS.Current && Filename == RHS.Filename;
664 }
665
666 const FunctionRecord &operator*() const { return *Current; }
667
668 FunctionRecordIterator &operator++() {
669 assert(Current != Records.end() && "incremented past end");
670 ++Current;
671 skipOtherFiles();
672 return *this;
673 }
674 };
675
676 /// Coverage information for a macro expansion or #included file.
677 ///
678 /// When covered code has pieces that can be expanded for more detail, such as a
679 /// preprocessor macro use and its definition, these are represented as
680 /// expansions whose coverage can be looked up independently.
681 struct ExpansionRecord {
682 /// The abstract file this expansion covers.
683 unsigned FileID;
684 /// The region that expands to this record.
685 const CountedRegion &Region;
686 /// Coverage for the expansion.
687 const FunctionRecord &Function;
688
ExpansionRecordExpansionRecord689 ExpansionRecord(const CountedRegion &Region,
690 const FunctionRecord &Function)
691 : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {}
692 };
693
694 /// The execution count information starting at a point in a file.
695 ///
696 /// A sequence of CoverageSegments gives execution counts for a file in format
697 /// that's simple to iterate through for processing.
698 struct CoverageSegment {
699 /// The line where this segment begins.
700 unsigned Line;
701 /// The column where this segment begins.
702 unsigned Col;
703 /// The execution count, or zero if no count was recorded.
704 uint64_t Count;
705 /// When false, the segment was uninstrumented or skipped.
706 bool HasCount;
707 /// Whether this enters a new region or returns to a previous count.
708 bool IsRegionEntry;
709 /// Whether this enters a gap region.
710 bool IsGapRegion;
711
CoverageSegmentCoverageSegment712 CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry)
713 : Line(Line), Col(Col), Count(0), HasCount(false),
714 IsRegionEntry(IsRegionEntry), IsGapRegion(false) {}
715
716 CoverageSegment(unsigned Line, unsigned Col, uint64_t Count,
717 bool IsRegionEntry, bool IsGapRegion = false,
718 bool IsBranchRegion = false)
LineCoverageSegment719 : Line(Line), Col(Col), Count(Count), HasCount(true),
720 IsRegionEntry(IsRegionEntry), IsGapRegion(IsGapRegion) {}
721
722 friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) {
723 return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry,
724 L.IsGapRegion) == std::tie(R.Line, R.Col, R.Count,
725 R.HasCount, R.IsRegionEntry,
726 R.IsGapRegion);
727 }
728 };
729
730 /// An instantiation group contains a \c FunctionRecord list, such that each
731 /// record corresponds to a distinct instantiation of the same function.
732 ///
733 /// Note that it's possible for a function to have more than one instantiation
734 /// (consider C++ template specializations or static inline functions).
735 class InstantiationGroup {
736 friend class CoverageMapping;
737
738 unsigned Line;
739 unsigned Col;
740 std::vector<const FunctionRecord *> Instantiations;
741
InstantiationGroup(unsigned Line,unsigned Col,std::vector<const FunctionRecord * > Instantiations)742 InstantiationGroup(unsigned Line, unsigned Col,
743 std::vector<const FunctionRecord *> Instantiations)
744 : Line(Line), Col(Col), Instantiations(std::move(Instantiations)) {}
745
746 public:
747 InstantiationGroup(const InstantiationGroup &) = delete;
748 InstantiationGroup(InstantiationGroup &&) = default;
749
750 /// Get the number of instantiations in this group.
size()751 size_t size() const { return Instantiations.size(); }
752
753 /// Get the line where the common function was defined.
getLine()754 unsigned getLine() const { return Line; }
755
756 /// Get the column where the common function was defined.
getColumn()757 unsigned getColumn() const { return Col; }
758
759 /// Check if the instantiations in this group have a common mangled name.
hasName()760 bool hasName() const {
761 for (unsigned I = 1, E = Instantiations.size(); I < E; ++I)
762 if (Instantiations[I]->Name != Instantiations[0]->Name)
763 return false;
764 return true;
765 }
766
767 /// Get the common mangled name for instantiations in this group.
getName()768 StringRef getName() const {
769 assert(hasName() && "Instantiations don't have a shared name");
770 return Instantiations[0]->Name;
771 }
772
773 /// Get the total execution count of all instantiations in this group.
getTotalExecutionCount()774 uint64_t getTotalExecutionCount() const {
775 uint64_t Count = 0;
776 for (const FunctionRecord *F : Instantiations)
777 Count += F->ExecutionCount;
778 return Count;
779 }
780
781 /// Get the instantiations in this group.
getInstantiations()782 ArrayRef<const FunctionRecord *> getInstantiations() const {
783 return Instantiations;
784 }
785 };
786
787 /// Coverage information to be processed or displayed.
788 ///
789 /// This represents the coverage of an entire file, expansion, or function. It
790 /// provides a sequence of CoverageSegments to iterate through, as well as the
791 /// list of expansions that can be further processed.
792 class CoverageData {
793 friend class CoverageMapping;
794
795 std::string Filename;
796 std::vector<CoverageSegment> Segments;
797 std::vector<ExpansionRecord> Expansions;
798 std::vector<CountedRegion> BranchRegions;
799 std::vector<MCDCRecord> MCDCRecords;
800
801 public:
802 CoverageData() = default;
803
CoverageData(StringRef Filename)804 CoverageData(StringRef Filename) : Filename(Filename) {}
805
806 /// Get the name of the file this data covers.
getFilename()807 StringRef getFilename() const { return Filename; }
808
809 /// Get an iterator over the coverage segments for this object. The segments
810 /// are guaranteed to be uniqued and sorted by location.
begin()811 std::vector<CoverageSegment>::const_iterator begin() const {
812 return Segments.begin();
813 }
814
end()815 std::vector<CoverageSegment>::const_iterator end() const {
816 return Segments.end();
817 }
818
empty()819 bool empty() const { return Segments.empty(); }
820
821 /// Expansions that can be further processed.
getExpansions()822 ArrayRef<ExpansionRecord> getExpansions() const { return Expansions; }
823
824 /// Branches that can be further processed.
getBranches()825 ArrayRef<CountedRegion> getBranches() const { return BranchRegions; }
826
827 /// MCDC Records that can be further processed.
getMCDCRecords()828 ArrayRef<MCDCRecord> getMCDCRecords() const { return MCDCRecords; }
829 };
830
831 /// The mapping of profile information to coverage data.
832 ///
833 /// This is the main interface to get coverage information, using a profile to
834 /// fill out execution counts.
835 class CoverageMapping {
836 DenseMap<size_t, DenseSet<size_t>> RecordProvenance;
837 std::vector<FunctionRecord> Functions;
838 DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
839 std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
840
841 CoverageMapping() = default;
842
843 // Load coverage records from readers.
844 static Error loadFromReaders(
845 ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
846 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage);
847
848 // Load coverage records from file.
849 static Error
850 loadFromFile(StringRef Filename, StringRef Arch, StringRef CompilationDir,
851 IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage,
852 bool &DataFound,
853 SmallVectorImpl<object::BuildID> *FoundBinaryIDs = nullptr);
854
855 /// Add a function record corresponding to \p Record.
856 Error loadFunctionRecord(const CoverageMappingRecord &Record,
857 IndexedInstrProfReader &ProfileReader);
858
859 /// Look up the indices for function records which are at least partially
860 /// defined in the specified file. This is guaranteed to return a superset of
861 /// such records: extra records not in the file may be included if there is
862 /// a hash collision on the filename. Clients must be robust to collisions.
863 ArrayRef<unsigned>
864 getImpreciseRecordIndicesForFilename(StringRef Filename) const;
865
866 public:
867 CoverageMapping(const CoverageMapping &) = delete;
868 CoverageMapping &operator=(const CoverageMapping &) = delete;
869
870 /// Load the coverage mapping using the given readers.
871 static Expected<std::unique_ptr<CoverageMapping>>
872 load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
873 IndexedInstrProfReader &ProfileReader);
874
875 /// Load the coverage mapping from the given object files and profile. If
876 /// \p Arches is non-empty, it must specify an architecture for each object.
877 /// Ignores non-instrumented object files unless all are not instrumented.
878 static Expected<std::unique_ptr<CoverageMapping>>
879 load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
880 vfs::FileSystem &FS, ArrayRef<StringRef> Arches = std::nullopt,
881 StringRef CompilationDir = "",
882 const object::BuildIDFetcher *BIDFetcher = nullptr,
883 bool CheckBinaryIDs = false);
884
885 /// The number of functions that couldn't have their profiles mapped.
886 ///
887 /// This is a count of functions whose profile is out of date or otherwise
888 /// can't be associated with any coverage information.
getMismatchedCount()889 unsigned getMismatchedCount() const { return FuncHashMismatches.size(); }
890
891 /// A hash mismatch occurs when a profile record for a symbol does not have
892 /// the same hash as a coverage mapping record for the same symbol. This
893 /// returns a list of hash mismatches, where each mismatch is a pair of the
894 /// symbol name and its coverage mapping hash.
getHashMismatches()895 ArrayRef<std::pair<std::string, uint64_t>> getHashMismatches() const {
896 return FuncHashMismatches;
897 }
898
899 /// Returns a lexicographically sorted, unique list of files that are
900 /// covered.
901 std::vector<StringRef> getUniqueSourceFiles() const;
902
903 /// Get the coverage for a particular file.
904 ///
905 /// The given filename must be the name as recorded in the coverage
906 /// information. That is, only names returned from getUniqueSourceFiles will
907 /// yield a result.
908 CoverageData getCoverageForFile(StringRef Filename) const;
909
910 /// Get the coverage for a particular function.
911 CoverageData getCoverageForFunction(const FunctionRecord &Function) const;
912
913 /// Get the coverage for an expansion within a coverage set.
914 CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const;
915
916 /// Gets all of the functions covered by this profile.
getCoveredFunctions()917 iterator_range<FunctionRecordIterator> getCoveredFunctions() const {
918 return make_range(FunctionRecordIterator(Functions),
919 FunctionRecordIterator());
920 }
921
922 /// Gets all of the functions in a particular file.
923 iterator_range<FunctionRecordIterator>
getCoveredFunctions(StringRef Filename)924 getCoveredFunctions(StringRef Filename) const {
925 return make_range(FunctionRecordIterator(Functions, Filename),
926 FunctionRecordIterator());
927 }
928
929 /// Get the list of function instantiation groups in a particular file.
930 ///
931 /// Every instantiation group in a program is attributed to exactly one file:
932 /// the file in which the definition for the common function begins.
933 std::vector<InstantiationGroup>
934 getInstantiationGroups(StringRef Filename) const;
935 };
936
937 /// Coverage statistics for a single line.
938 class LineCoverageStats {
939 uint64_t ExecutionCount;
940 bool HasMultipleRegions;
941 bool Mapped;
942 unsigned Line;
943 ArrayRef<const CoverageSegment *> LineSegments;
944 const CoverageSegment *WrappedSegment;
945
946 friend class LineCoverageIterator;
947 LineCoverageStats() = default;
948
949 public:
950 LineCoverageStats(ArrayRef<const CoverageSegment *> LineSegments,
951 const CoverageSegment *WrappedSegment, unsigned Line);
952
getExecutionCount()953 uint64_t getExecutionCount() const { return ExecutionCount; }
954
hasMultipleRegions()955 bool hasMultipleRegions() const { return HasMultipleRegions; }
956
isMapped()957 bool isMapped() const { return Mapped; }
958
getLine()959 unsigned getLine() const { return Line; }
960
getLineSegments()961 ArrayRef<const CoverageSegment *> getLineSegments() const {
962 return LineSegments;
963 }
964
getWrappedSegment()965 const CoverageSegment *getWrappedSegment() const { return WrappedSegment; }
966 };
967
968 /// An iterator over the \c LineCoverageStats objects for lines described by
969 /// a \c CoverageData instance.
970 class LineCoverageIterator
971 : public iterator_facade_base<LineCoverageIterator,
972 std::forward_iterator_tag,
973 const LineCoverageStats> {
974 public:
LineCoverageIterator(const CoverageData & CD)975 LineCoverageIterator(const CoverageData &CD)
976 : LineCoverageIterator(CD, CD.begin()->Line) {}
977
LineCoverageIterator(const CoverageData & CD,unsigned Line)978 LineCoverageIterator(const CoverageData &CD, unsigned Line)
979 : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false),
980 Line(Line) {
981 this->operator++();
982 }
983
984 bool operator==(const LineCoverageIterator &R) const {
985 return &CD == &R.CD && Next == R.Next && Ended == R.Ended;
986 }
987
988 const LineCoverageStats &operator*() const { return Stats; }
989
990 LineCoverageIterator &operator++();
991
getEnd()992 LineCoverageIterator getEnd() const {
993 auto EndIt = *this;
994 EndIt.Next = CD.end();
995 EndIt.Ended = true;
996 return EndIt;
997 }
998
999 private:
1000 const CoverageData &CD;
1001 const CoverageSegment *WrappedSegment;
1002 std::vector<CoverageSegment>::const_iterator Next;
1003 bool Ended;
1004 unsigned Line;
1005 SmallVector<const CoverageSegment *, 4> Segments;
1006 LineCoverageStats Stats;
1007 };
1008
1009 /// Get a \c LineCoverageIterator range for the lines described by \p CD.
1010 static inline iterator_range<LineCoverageIterator>
getLineCoverageStats(const coverage::CoverageData & CD)1011 getLineCoverageStats(const coverage::CoverageData &CD) {
1012 auto Begin = LineCoverageIterator(CD);
1013 auto End = Begin.getEnd();
1014 return make_range(Begin, End);
1015 }
1016
1017 // Coverage mappping data (V2) has the following layout:
1018 // IPSK_covmap:
1019 // [CoverageMapFileHeader]
1020 // [ArrayStart]
1021 // [CovMapFunctionRecordV2]
1022 // [CovMapFunctionRecordV2]
1023 // ...
1024 // [ArrayEnd]
1025 // [Encoded Filenames and Region Mapping Data]
1026 //
1027 // Coverage mappping data (V3) has the following layout:
1028 // IPSK_covmap:
1029 // [CoverageMapFileHeader]
1030 // [Encoded Filenames]
1031 // IPSK_covfun:
1032 // [ArrayStart]
1033 // odr_name_1: [CovMapFunctionRecordV3]
1034 // odr_name_2: [CovMapFunctionRecordV3]
1035 // ...
1036 // [ArrayEnd]
1037 //
1038 // Both versions of the coverage mapping format encode the same information,
1039 // but the V3 format does so more compactly by taking advantage of linkonce_odr
1040 // semantics (it allows exactly 1 function record per name reference).
1041
1042 /// This namespace defines accessors shared by different versions of coverage
1043 /// mapping records.
1044 namespace accessors {
1045
1046 /// Return the structural hash associated with the function.
1047 template <class FuncRecordTy, llvm::endianness Endian>
getFuncHash(const FuncRecordTy * Record)1048 uint64_t getFuncHash(const FuncRecordTy *Record) {
1049 return support::endian::byte_swap<uint64_t, Endian>(Record->FuncHash);
1050 }
1051
1052 /// Return the coverage map data size for the function.
1053 template <class FuncRecordTy, llvm::endianness Endian>
getDataSize(const FuncRecordTy * Record)1054 uint64_t getDataSize(const FuncRecordTy *Record) {
1055 return support::endian::byte_swap<uint32_t, Endian>(Record->DataSize);
1056 }
1057
1058 /// Return the function lookup key. The value is considered opaque.
1059 template <class FuncRecordTy, llvm::endianness Endian>
getFuncNameRef(const FuncRecordTy * Record)1060 uint64_t getFuncNameRef(const FuncRecordTy *Record) {
1061 return support::endian::byte_swap<uint64_t, Endian>(Record->NameRef);
1062 }
1063
1064 /// Return the PGO name of the function. Used for formats in which the name is
1065 /// a hash.
1066 template <class FuncRecordTy, llvm::endianness Endian>
getFuncNameViaRef(const FuncRecordTy * Record,InstrProfSymtab & ProfileNames,StringRef & FuncName)1067 Error getFuncNameViaRef(const FuncRecordTy *Record,
1068 InstrProfSymtab &ProfileNames, StringRef &FuncName) {
1069 uint64_t NameRef = getFuncNameRef<FuncRecordTy, Endian>(Record);
1070 FuncName = ProfileNames.getFuncOrVarName(NameRef);
1071 return Error::success();
1072 }
1073
1074 /// Read coverage mapping out-of-line, from \p MappingBuf. This is used when the
1075 /// coverage mapping is attached to the file header, instead of to the function
1076 /// record.
1077 template <class FuncRecordTy, llvm::endianness Endian>
getCoverageMappingOutOfLine(const FuncRecordTy * Record,const char * MappingBuf)1078 StringRef getCoverageMappingOutOfLine(const FuncRecordTy *Record,
1079 const char *MappingBuf) {
1080 return {MappingBuf, size_t(getDataSize<FuncRecordTy, Endian>(Record))};
1081 }
1082
1083 /// Advance to the next out-of-line coverage mapping and its associated
1084 /// function record.
1085 template <class FuncRecordTy, llvm::endianness Endian>
1086 std::pair<const char *, const FuncRecordTy *>
advanceByOneOutOfLine(const FuncRecordTy * Record,const char * MappingBuf)1087 advanceByOneOutOfLine(const FuncRecordTy *Record, const char *MappingBuf) {
1088 return {MappingBuf + getDataSize<FuncRecordTy, Endian>(Record), Record + 1};
1089 }
1090
1091 } // end namespace accessors
1092
1093 LLVM_PACKED_START
1094 template <class IntPtrT>
1095 struct CovMapFunctionRecordV1 {
1096 using ThisT = CovMapFunctionRecordV1<IntPtrT>;
1097
1098 #define COVMAP_V1
1099 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
1100 #include "llvm/ProfileData/InstrProfData.inc"
1101 #undef COVMAP_V1
1102 CovMapFunctionRecordV1() = delete;
1103
getFuncHashCovMapFunctionRecordV11104 template <llvm::endianness Endian> uint64_t getFuncHash() const {
1105 return accessors::getFuncHash<ThisT, Endian>(this);
1106 }
1107
getDataSizeCovMapFunctionRecordV11108 template <llvm::endianness Endian> uint64_t getDataSize() const {
1109 return accessors::getDataSize<ThisT, Endian>(this);
1110 }
1111
1112 /// Return function lookup key. The value is consider opaque.
getFuncNameRefCovMapFunctionRecordV11113 template <llvm::endianness Endian> IntPtrT getFuncNameRef() const {
1114 return support::endian::byte_swap<IntPtrT, Endian>(NamePtr);
1115 }
1116
1117 /// Return the PGO name of the function.
1118 template <llvm::endianness Endian>
getFuncNameCovMapFunctionRecordV11119 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
1120 IntPtrT NameRef = getFuncNameRef<Endian>();
1121 uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize);
1122 FuncName = ProfileNames.getFuncName(NameRef, NameS);
1123 if (NameS && FuncName.empty())
1124 return make_error<CoverageMapError>(coveragemap_error::malformed,
1125 "function name is empty");
1126 return Error::success();
1127 }
1128
1129 template <llvm::endianness Endian>
1130 std::pair<const char *, const ThisT *>
advanceByOneCovMapFunctionRecordV11131 advanceByOne(const char *MappingBuf) const {
1132 return accessors::advanceByOneOutOfLine<ThisT, Endian>(this, MappingBuf);
1133 }
1134
getFilenamesRefCovMapFunctionRecordV11135 template <llvm::endianness Endian> uint64_t getFilenamesRef() const {
1136 llvm_unreachable("V1 function format does not contain a filenames ref");
1137 }
1138
1139 template <llvm::endianness Endian>
getCoverageMappingCovMapFunctionRecordV11140 StringRef getCoverageMapping(const char *MappingBuf) const {
1141 return accessors::getCoverageMappingOutOfLine<ThisT, Endian>(this,
1142 MappingBuf);
1143 }
1144 };
1145
1146 struct CovMapFunctionRecordV2 {
1147 using ThisT = CovMapFunctionRecordV2;
1148
1149 #define COVMAP_V2
1150 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
1151 #include "llvm/ProfileData/InstrProfData.inc"
1152 #undef COVMAP_V2
1153 CovMapFunctionRecordV2() = delete;
1154
getFuncHashCovMapFunctionRecordV21155 template <llvm::endianness Endian> uint64_t getFuncHash() const {
1156 return accessors::getFuncHash<ThisT, Endian>(this);
1157 }
1158
getDataSizeCovMapFunctionRecordV21159 template <llvm::endianness Endian> uint64_t getDataSize() const {
1160 return accessors::getDataSize<ThisT, Endian>(this);
1161 }
1162
getFuncNameRefCovMapFunctionRecordV21163 template <llvm::endianness Endian> uint64_t getFuncNameRef() const {
1164 return accessors::getFuncNameRef<ThisT, Endian>(this);
1165 }
1166
1167 template <llvm::endianness Endian>
getFuncNameCovMapFunctionRecordV21168 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
1169 return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
1170 FuncName);
1171 }
1172
1173 template <llvm::endianness Endian>
1174 std::pair<const char *, const ThisT *>
advanceByOneCovMapFunctionRecordV21175 advanceByOne(const char *MappingBuf) const {
1176 return accessors::advanceByOneOutOfLine<ThisT, Endian>(this, MappingBuf);
1177 }
1178
getFilenamesRefCovMapFunctionRecordV21179 template <llvm::endianness Endian> uint64_t getFilenamesRef() const {
1180 llvm_unreachable("V2 function format does not contain a filenames ref");
1181 }
1182
1183 template <llvm::endianness Endian>
getCoverageMappingCovMapFunctionRecordV21184 StringRef getCoverageMapping(const char *MappingBuf) const {
1185 return accessors::getCoverageMappingOutOfLine<ThisT, Endian>(this,
1186 MappingBuf);
1187 }
1188 };
1189
1190 struct CovMapFunctionRecordV3 {
1191 using ThisT = CovMapFunctionRecordV3;
1192
1193 #define COVMAP_V3
1194 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
1195 #include "llvm/ProfileData/InstrProfData.inc"
1196 #undef COVMAP_V3
1197 CovMapFunctionRecordV3() = delete;
1198
getFuncHashCovMapFunctionRecordV31199 template <llvm::endianness Endian> uint64_t getFuncHash() const {
1200 return accessors::getFuncHash<ThisT, Endian>(this);
1201 }
1202
getDataSizeCovMapFunctionRecordV31203 template <llvm::endianness Endian> uint64_t getDataSize() const {
1204 return accessors::getDataSize<ThisT, Endian>(this);
1205 }
1206
getFuncNameRefCovMapFunctionRecordV31207 template <llvm::endianness Endian> uint64_t getFuncNameRef() const {
1208 return accessors::getFuncNameRef<ThisT, Endian>(this);
1209 }
1210
1211 template <llvm::endianness Endian>
getFuncNameCovMapFunctionRecordV31212 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const {
1213 return accessors::getFuncNameViaRef<ThisT, Endian>(this, ProfileNames,
1214 FuncName);
1215 }
1216
1217 /// Get the filename set reference.
getFilenamesRefCovMapFunctionRecordV31218 template <llvm::endianness Endian> uint64_t getFilenamesRef() const {
1219 return support::endian::byte_swap<uint64_t, Endian>(FilenamesRef);
1220 }
1221
1222 /// Read the inline coverage mapping. Ignore the buffer parameter, it is for
1223 /// out-of-line coverage mapping data only.
1224 template <llvm::endianness Endian>
getCoverageMappingCovMapFunctionRecordV31225 StringRef getCoverageMapping(const char *) const {
1226 return StringRef(&CoverageMapping, getDataSize<Endian>());
1227 }
1228
1229 // Advance to the next inline coverage mapping and its associated function
1230 // record. Ignore the out-of-line coverage mapping buffer.
1231 template <llvm::endianness Endian>
1232 std::pair<const char *, const CovMapFunctionRecordV3 *>
advanceByOneCovMapFunctionRecordV31233 advanceByOne(const char *) const {
1234 assert(isAddrAligned(Align(8), this) && "Function record not aligned");
1235 const char *Next = ((const char *)this) + sizeof(CovMapFunctionRecordV3) -
1236 sizeof(char) + getDataSize<Endian>();
1237 // Each function record has an alignment of 8, so we need to adjust
1238 // alignment before reading the next record.
1239 Next += offsetToAlignedAddr(Next, Align(8));
1240 return {nullptr, reinterpret_cast<const CovMapFunctionRecordV3 *>(Next)};
1241 }
1242 };
1243
1244 // Per module coverage mapping data header, i.e. CoverageMapFileHeader
1245 // documented above.
1246 struct CovMapHeader {
1247 #define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
1248 #include "llvm/ProfileData/InstrProfData.inc"
getNRecordsCovMapHeader1249 template <llvm::endianness Endian> uint32_t getNRecords() const {
1250 return support::endian::byte_swap<uint32_t, Endian>(NRecords);
1251 }
1252
getFilenamesSizeCovMapHeader1253 template <llvm::endianness Endian> uint32_t getFilenamesSize() const {
1254 return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize);
1255 }
1256
getCoverageSizeCovMapHeader1257 template <llvm::endianness Endian> uint32_t getCoverageSize() const {
1258 return support::endian::byte_swap<uint32_t, Endian>(CoverageSize);
1259 }
1260
getVersionCovMapHeader1261 template <llvm::endianness Endian> uint32_t getVersion() const {
1262 return support::endian::byte_swap<uint32_t, Endian>(Version);
1263 }
1264 };
1265
1266 LLVM_PACKED_END
1267
1268 enum CovMapVersion {
1269 Version1 = 0,
1270 // Function's name reference from CovMapFuncRecord is changed from raw
1271 // name string pointer to MD5 to support name section compression. Name
1272 // section is also compressed.
1273 Version2 = 1,
1274 // A new interpretation of the columnEnd field is added in order to mark
1275 // regions as gap areas.
1276 Version3 = 2,
1277 // Function records are named, uniqued, and moved to a dedicated section.
1278 Version4 = 3,
1279 // Branch regions referring to two counters are added
1280 Version5 = 4,
1281 // Compilation directory is stored separately and combined with relative
1282 // filenames to produce an absolute file path.
1283 Version6 = 5,
1284 // Branch regions extended and Decision Regions added for MC/DC.
1285 Version7 = 6,
1286 // The current version is Version7.
1287 CurrentVersion = INSTR_PROF_COVMAP_VERSION
1288 };
1289
1290 // Correspond to "llvmcovm", in little-endian.
1291 constexpr uint64_t TestingFormatMagic = 0x6d766f636d766c6c;
1292
1293 enum class TestingFormatVersion : uint64_t {
1294 // The first version's number corresponds to the string "testdata" in
1295 // little-endian. This is for a historical reason.
1296 Version1 = 0x6174616474736574,
1297 // Version1 has a defect that it can't store multiple file records. Version2
1298 // fix this problem by adding a new field before the file records section.
1299 Version2 = 1,
1300 // The current testing format version is Version2.
1301 CurrentVersion = Version2
1302 };
1303
1304 template <int CovMapVersion, class IntPtrT> struct CovMapTraits {
1305 using CovMapFuncRecordType = CovMapFunctionRecordV3;
1306 using NameRefType = uint64_t;
1307 };
1308
1309 template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version3, IntPtrT> {
1310 using CovMapFuncRecordType = CovMapFunctionRecordV2;
1311 using NameRefType = uint64_t;
1312 };
1313
1314 template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version2, IntPtrT> {
1315 using CovMapFuncRecordType = CovMapFunctionRecordV2;
1316 using NameRefType = uint64_t;
1317 };
1318
1319 template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> {
1320 using CovMapFuncRecordType = CovMapFunctionRecordV1<IntPtrT>;
1321 using NameRefType = IntPtrT;
1322 };
1323
1324 } // end namespace coverage
1325
1326 /// Provide DenseMapInfo for CounterExpression
1327 template<> struct DenseMapInfo<coverage::CounterExpression> {
1328 static inline coverage::CounterExpression getEmptyKey() {
1329 using namespace coverage;
1330
1331 return CounterExpression(CounterExpression::ExprKind::Subtract,
1332 Counter::getCounter(~0U),
1333 Counter::getCounter(~0U));
1334 }
1335
1336 static inline coverage::CounterExpression getTombstoneKey() {
1337 using namespace coverage;
1338
1339 return CounterExpression(CounterExpression::ExprKind::Add,
1340 Counter::getCounter(~0U),
1341 Counter::getCounter(~0U));
1342 }
1343
1344 static unsigned getHashValue(const coverage::CounterExpression &V) {
1345 return static_cast<unsigned>(
1346 hash_combine(V.Kind, V.LHS.getKind(), V.LHS.getCounterID(),
1347 V.RHS.getKind(), V.RHS.getCounterID()));
1348 }
1349
1350 static bool isEqual(const coverage::CounterExpression &LHS,
1351 const coverage::CounterExpression &RHS) {
1352 return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS && LHS.RHS == RHS.RHS;
1353 }
1354 };
1355
1356 } // end namespace llvm
1357
1358 #endif // LLVM_PROFILEDATA_COVERAGE_COVERAGEMAPPING_H
1359